blob: a897c671049750b123ed59a1281e270c42e27ed2 [file] [log] [blame]
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16/*
17 * Garbage-collecting memory allocator.
18 */
19#include "Dalvik.h"
20#include "alloc/Heap.h"
21#include "alloc/HeapInternal.h"
Carl Shapiro41eb6e92010-08-17 13:30:48 -070022#include "alloc/HeapSource.h"
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080023
24#if WITH_HPROF && WITH_HPROF_STACK
25#include "hprof/Hprof.h"
26#endif
27
28
29/*
30 * Initialize the GC universe.
31 *
32 * We're currently using a memory-mapped arena to keep things off of the
33 * main heap. This needs to be replaced with something real.
34 */
35bool dvmGcStartup(void)
36{
37 dvmInitMutex(&gDvm.gcHeapLock);
38
39 return dvmHeapStartup();
40}
41
42/*
43 * Post-zygote heap initialization, including starting
44 * the HeapWorker thread.
45 */
46bool dvmGcStartupAfterZygote(void)
47{
48 if (!dvmHeapWorkerStartup()) {
49 return false;
50 }
Carl Shapiroec805ea2010-06-28 16:28:26 -070051 return dvmHeapStartupAfterZygote();
52}
53
54/*
55 * Shutdown the threads internal to the garbage collector.
56 */
57void dvmGcThreadShutdown(void)
58{
59 dvmHeapWorkerShutdown();
60 dvmHeapThreadShutdown();
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080061}
62
63/*
64 * Shut the GC down.
65 */
66void dvmGcShutdown(void)
67{
68 //TODO: grab and destroy the lock
69 dvmHeapShutdown();
70}
71
72/*
73 * Do any last-minute preparation before we call fork() for the first time.
74 */
75bool dvmGcPreZygoteFork(void)
76{
77 return dvmHeapSourceStartupBeforeFork();
78}
79
80/*
Andy McFadden7fc3ce82009-07-14 15:57:23 -070081 * Create a "stock instance" of an exception class.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080082 */
Andy McFadden7fc3ce82009-07-14 15:57:23 -070083static Object* createStockException(const char* descriptor, const char* msg)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080084{
Andy McFadden7fc3ce82009-07-14 15:57:23 -070085 Thread* self = dvmThreadSelf();
86 StringObject* msgStr = NULL;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080087 ClassObject* clazz;
88 Method* init;
89 Object* obj;
90
Andy McFadden7fc3ce82009-07-14 15:57:23 -070091 /* find class, initialize if necessary */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080092 clazz = dvmFindSystemClass(descriptor);
93 if (clazz == NULL) {
94 LOGE("Unable to find %s\n", descriptor);
95 return NULL;
96 }
97
Andy McFadden7fc3ce82009-07-14 15:57:23 -070098 init = dvmFindDirectMethodByDescriptor(clazz, "<init>",
99 "(Ljava/lang/String;)V");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800100 if (init == NULL) {
Andy McFadden7fc3ce82009-07-14 15:57:23 -0700101 LOGE("Unable to find String-arg constructor for %s\n", descriptor);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800102 return NULL;
103 }
104
105 obj = dvmAllocObject(clazz, ALLOC_DEFAULT);
106 if (obj == NULL)
107 return NULL;
108
Andy McFadden7fc3ce82009-07-14 15:57:23 -0700109 if (msg == NULL) {
110 msgStr = NULL;
111 } else {
Barry Hayes81f3ebe2010-06-15 16:17:37 -0700112 msgStr = dvmCreateStringFromCstr(msg);
Andy McFadden7fc3ce82009-07-14 15:57:23 -0700113 if (msgStr == NULL) {
114 LOGW("Could not allocate message string \"%s\"\n", msg);
115 dvmReleaseTrackedAlloc(obj, self);
116 return NULL;
117 }
118 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800119
Andy McFadden7fc3ce82009-07-14 15:57:23 -0700120 JValue unused;
121 dvmCallMethod(self, init, obj, &unused, msgStr);
122 if (dvmCheckException(self)) {
123 dvmReleaseTrackedAlloc((Object*) msgStr, self);
124 dvmReleaseTrackedAlloc(obj, self);
125 return NULL;
126 }
127
128 dvmReleaseTrackedAlloc((Object*) msgStr, self); // okay if msgStr NULL
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800129 return obj;
130}
131
132/*
Andy McFadden7fc3ce82009-07-14 15:57:23 -0700133 * Create some "stock" exceptions. These can be thrown when the system is
134 * too screwed up to allocate and initialize anything, or when we don't
135 * need a meaningful stack trace.
136 *
137 * We can't do this during the initial startup because we need to execute
138 * the constructors.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800139 */
Andy McFadden7fc3ce82009-07-14 15:57:23 -0700140bool dvmCreateStockExceptions(void)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800141{
142 /*
143 * Pre-allocate some throwables. These need to be explicitly added
Andy McFadden7fc3ce82009-07-14 15:57:23 -0700144 * to the GC's root set (see dvmHeapMarkRootSet()).
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800145 */
Andy McFadden7fc3ce82009-07-14 15:57:23 -0700146 gDvm.outOfMemoryObj = createStockException("Ljava/lang/OutOfMemoryError;",
147 "[memory exhausted]");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800148 dvmReleaseTrackedAlloc(gDvm.outOfMemoryObj, NULL);
Andy McFadden7fc3ce82009-07-14 15:57:23 -0700149 gDvm.internalErrorObj = createStockException("Ljava/lang/InternalError;",
150 "[pre-allocated]");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800151 dvmReleaseTrackedAlloc(gDvm.internalErrorObj, NULL);
Andy McFadden7fc3ce82009-07-14 15:57:23 -0700152 gDvm.noClassDefFoundErrorObj =
Andy McFadden4c691d12009-12-10 15:11:18 -0800153 createStockException("Ljava/lang/NoClassDefFoundError;",
154 "[generic]");
Andy McFadden7fc3ce82009-07-14 15:57:23 -0700155 dvmReleaseTrackedAlloc(gDvm.noClassDefFoundErrorObj, NULL);
156
157 if (gDvm.outOfMemoryObj == NULL || gDvm.internalErrorObj == NULL ||
158 gDvm.noClassDefFoundErrorObj == NULL)
159 {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800160 LOGW("Unable to create stock exceptions\n");
161 return false;
162 }
163
164 return true;
165}
166
167
168/*
169 * Create an instance of the specified class.
170 *
171 * Returns NULL and throws an exception on failure.
172 */
173Object* dvmAllocObject(ClassObject* clazz, int flags)
174{
175 Object* newObj;
176
177 assert(dvmIsClassInitialized(clazz) || dvmIsClassInitializing(clazz));
178
179 if (IS_CLASS_FLAG_SET(clazz, CLASS_ISFINALIZABLE)) {
180 flags |= ALLOC_FINALIZABLE;
181 }
182
183 /* allocate on GC heap; memory is zeroed out */
184 newObj = dvmMalloc(clazz->objectSize, flags);
185 if (newObj != NULL) {
186 DVM_OBJECT_INIT(newObj, clazz);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800187#if WITH_HPROF && WITH_HPROF_STACK
188 hprofFillInStackTrace(newObj);
189#endif
190 dvmTrackAllocation(clazz, clazz->objectSize);
191 }
192
193 return newObj;
194}
195
196/*
197 * Create a copy of an object, for Object.clone().
198 *
199 * We use the size actually allocated, rather than obj->clazz->objectSize,
200 * because the latter doesn't work for array objects.
201 */
202Object* dvmCloneObject(Object* obj)
203{
204 Object* copy;
205 int size;
206 int flags;
207
208 assert(dvmIsValidObject(obj));
209
210 /* Class.java shouldn't let us get here (java.lang.Class is final
211 * and does not implement Clonable), but make extra sure.
212 * A memcpy() clone will wreak havoc on a ClassObject's "innards".
213 */
214 assert(obj->clazz != gDvm.classJavaLangClass);
215
216 if (IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISFINALIZABLE))
217 flags = ALLOC_DEFAULT | ALLOC_FINALIZABLE;
218 else
219 flags = ALLOC_DEFAULT;
220
Carl Shapirobfe4dcc2010-04-16 17:55:27 -0700221 if (IS_CLASS_FLAG_SET(obj->clazz, CLASS_ISARRAY)) {
222 size = dvmArrayObjectSize((ArrayObject *)obj);
223 } else {
224 size = obj->clazz->objectSize;
225 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800226
227 copy = dvmMalloc(size, flags);
228 if (copy == NULL)
229 return NULL;
230#if WITH_HPROF && WITH_HPROF_STACK
231 hprofFillInStackTrace(copy);
232 dvmTrackAllocation(obj->clazz, size);
233#endif
234
235 memcpy(copy, obj, size);
236 DVM_LOCK_INIT(&copy->lock);
Barry Hayes364f9d92010-06-11 16:12:47 -0700237 dvmWriteBarrierObject(copy);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800238
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800239 return copy;
240}
241
242
243/*
244 * Track an object that was allocated internally and isn't yet part of the
245 * VM root set.
246 *
247 * We could do this per-thread or globally. If it's global we don't have
248 * to do the thread lookup but we do have to synchronize access to the list.
249 *
Andy McFaddenbd74b4b2010-09-22 12:37:49 -0700250 * "obj" must not be NULL.
251 *
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800252 * NOTE: "obj" is not a fully-formed object; in particular, obj->clazz will
253 * usually be NULL since we're being called from dvmMalloc().
254 */
255void dvmAddTrackedAlloc(Object* obj, Thread* self)
256{
257 if (self == NULL)
258 self = dvmThreadSelf();
259
Andy McFaddenbd74b4b2010-09-22 12:37:49 -0700260 assert(obj != NULL);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800261 assert(self != NULL);
262 if (!dvmAddToReferenceTable(&self->internalLocalRefTable, obj)) {
263 LOGE("threadid=%d: unable to add %p to internal ref table\n",
264 self->threadId, obj);
265 dvmDumpThread(self, false);
266 dvmAbort();
267 }
268}
269
270/*
271 * Stop tracking an object.
272 *
273 * We allow attempts to delete NULL "obj" so that callers don't have to wrap
274 * calls with "if != NULL".
275 */
276void dvmReleaseTrackedAlloc(Object* obj, Thread* self)
277{
278 if (obj == NULL)
279 return;
280
281 if (self == NULL)
282 self = dvmThreadSelf();
283 assert(self != NULL);
284
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800285 if (!dvmRemoveFromReferenceTable(&self->internalLocalRefTable,
286 self->internalLocalRefTable.table, obj))
287 {
288 LOGE("threadid=%d: failed to remove %p from internal ref table\n",
289 self->threadId, obj);
290 dvmAbort();
291 }
292}
293
294
295/*
296 * Explicitly initiate garbage collection.
297 */
298void dvmCollectGarbage(bool collectSoftReferences)
299{
300 dvmLockHeap();
Carl Shapiro43c54c02010-09-17 17:10:48 -0700301 while (gDvm.gcHeap->gcRunning) {
302 dvmWaitForConcurrentGcToComplete();
303 }
Barry Hayes1b9b4e42010-01-04 10:33:46 -0800304 dvmCollectGarbageInternal(collectSoftReferences, GC_EXPLICIT);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800305 dvmUnlockHeap();
306}
Carl Shapiro41eb6e92010-08-17 13:30:48 -0700307
308typedef struct {
309 const ClassObject *clazz;
310 size_t count;
311} CountInstancesOfClassContext;
312
Carl Shapiro57ee2702010-08-27 13:06:48 -0700313static void countInstancesOfClassCallback(void *ptr, void *arg)
Carl Shapiro41eb6e92010-08-17 13:30:48 -0700314{
315 CountInstancesOfClassContext *ctx = arg;
Carl Shapiro57ee2702010-08-27 13:06:48 -0700316 const Object *obj = ptr;
Carl Shapiro41eb6e92010-08-17 13:30:48 -0700317
318 assert(ctx != NULL);
Carl Shapiro57ee2702010-08-27 13:06:48 -0700319 if (obj->clazz == ctx->clazz) {
320 ctx->count += 1;
Carl Shapiro41eb6e92010-08-17 13:30:48 -0700321 }
322}
323
324size_t dvmCountInstancesOfClass(const ClassObject *clazz)
325{
326 CountInstancesOfClassContext ctx = { clazz, 0 };
327 HeapBitmap *bitmap = dvmHeapSourceGetLiveBits();
328 dvmLockHeap();
329 dvmHeapBitmapWalk(bitmap, countInstancesOfClassCallback, &ctx);
330 dvmUnlockHeap();
331 return ctx.count;
332}