blob: 31df25db7f09e70a485edbc395a5640e7810a933 [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
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080024/*
25 * Initialize the GC universe.
26 *
27 * We're currently using a memory-mapped arena to keep things off of the
28 * main heap. This needs to be replaced with something real.
29 */
Carl Shapiro1e1433e2011-04-20 16:51:38 -070030bool dvmGcStartup()
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080031{
32 dvmInitMutex(&gDvm.gcHeapLock);
33
34 return dvmHeapStartup();
35}
36
37/*
38 * Post-zygote heap initialization, including starting
39 * the HeapWorker thread.
40 */
Carl Shapiro1e1433e2011-04-20 16:51:38 -070041bool dvmGcStartupAfterZygote()
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080042{
Carl Shapiroec805ea2010-06-28 16:28:26 -070043 return dvmHeapStartupAfterZygote();
44}
45
46/*
47 * Shutdown the threads internal to the garbage collector.
48 */
Carl Shapiro1e1433e2011-04-20 16:51:38 -070049void dvmGcThreadShutdown()
Carl Shapiroec805ea2010-06-28 16:28:26 -070050{
Carl Shapiroec805ea2010-06-28 16:28:26 -070051 dvmHeapThreadShutdown();
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080052}
53
54/*
55 * Shut the GC down.
56 */
Carl Shapiro1e1433e2011-04-20 16:51:38 -070057void dvmGcShutdown()
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080058{
59 //TODO: grab and destroy the lock
60 dvmHeapShutdown();
61}
62
63/*
64 * Do any last-minute preparation before we call fork() for the first time.
65 */
Carl Shapiro1e1433e2011-04-20 16:51:38 -070066bool dvmGcPreZygoteFork()
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080067{
68 return dvmHeapSourceStartupBeforeFork();
69}
70
Carl Shapiro1e1433e2011-04-20 16:51:38 -070071bool dvmGcStartupClasses()
Carl Shapiroce87bfe2011-03-30 19:35:34 -070072{
73 {
74 const char *klassName = "Ljava/lang/ref/ReferenceQueueThread;";
75 ClassObject *klass = dvmFindSystemClass(klassName);
76 if (klass == NULL) {
77 return false;
78 }
79 const char *methodName = "startReferenceQueue";
80 Method *method = dvmFindDirectMethodByDescriptor(klass, methodName, "()V");
81 if (method == NULL) {
82 return false;
83 }
84 Thread *self = dvmThreadSelf();
85 assert(self != NULL);
86 JValue unusedResult;
87 dvmCallMethod(self, method, NULL, &unusedResult);
88 }
89 {
90 const char *klassName = "Ljava/lang/FinalizerThread;";
91 ClassObject *klass = dvmFindSystemClass(klassName);
92 if (klass == NULL) {
93 return false;
94 }
95 const char *methodName = "startFinalizer";
96 Method *method = dvmFindDirectMethodByDescriptor(klass, methodName, "()V");
97 if (method == NULL) {
98 return false;
99 }
100 Thread *self = dvmThreadSelf();
101 assert(self != NULL);
102 JValue unusedResult;
103 dvmCallMethod(self, method, NULL, &unusedResult);
104 }
105
106 return true;
107}
108
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800109/*
Andy McFadden7fc3ce82009-07-14 15:57:23 -0700110 * Create a "stock instance" of an exception class.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800111 */
Andy McFadden7fc3ce82009-07-14 15:57:23 -0700112static Object* createStockException(const char* descriptor, const char* msg)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800113{
Andy McFadden7fc3ce82009-07-14 15:57:23 -0700114 Thread* self = dvmThreadSelf();
115 StringObject* msgStr = NULL;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800116 ClassObject* clazz;
117 Method* init;
118 Object* obj;
119
Andy McFadden7fc3ce82009-07-14 15:57:23 -0700120 /* find class, initialize if necessary */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800121 clazz = dvmFindSystemClass(descriptor);
122 if (clazz == NULL) {
123 LOGE("Unable to find %s\n", descriptor);
124 return NULL;
125 }
126
Andy McFadden7fc3ce82009-07-14 15:57:23 -0700127 init = dvmFindDirectMethodByDescriptor(clazz, "<init>",
128 "(Ljava/lang/String;)V");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800129 if (init == NULL) {
Andy McFadden7fc3ce82009-07-14 15:57:23 -0700130 LOGE("Unable to find String-arg constructor for %s\n", descriptor);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800131 return NULL;
132 }
133
134 obj = dvmAllocObject(clazz, ALLOC_DEFAULT);
135 if (obj == NULL)
136 return NULL;
137
Andy McFadden7fc3ce82009-07-14 15:57:23 -0700138 if (msg == NULL) {
139 msgStr = NULL;
140 } else {
Barry Hayes81f3ebe2010-06-15 16:17:37 -0700141 msgStr = dvmCreateStringFromCstr(msg);
Andy McFadden7fc3ce82009-07-14 15:57:23 -0700142 if (msgStr == NULL) {
143 LOGW("Could not allocate message string \"%s\"\n", msg);
144 dvmReleaseTrackedAlloc(obj, self);
145 return NULL;
146 }
147 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800148
Andy McFadden7fc3ce82009-07-14 15:57:23 -0700149 JValue unused;
150 dvmCallMethod(self, init, obj, &unused, msgStr);
151 if (dvmCheckException(self)) {
152 dvmReleaseTrackedAlloc((Object*) msgStr, self);
153 dvmReleaseTrackedAlloc(obj, self);
154 return NULL;
155 }
156
157 dvmReleaseTrackedAlloc((Object*) msgStr, self); // okay if msgStr NULL
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800158 return obj;
159}
160
161/*
Andy McFadden7fc3ce82009-07-14 15:57:23 -0700162 * Create some "stock" exceptions. These can be thrown when the system is
163 * too screwed up to allocate and initialize anything, or when we don't
164 * need a meaningful stack trace.
165 *
166 * We can't do this during the initial startup because we need to execute
167 * the constructors.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800168 */
Carl Shapiro1e1433e2011-04-20 16:51:38 -0700169bool dvmCreateStockExceptions()
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800170{
171 /*
172 * Pre-allocate some throwables. These need to be explicitly added
Andy McFadden7fc3ce82009-07-14 15:57:23 -0700173 * to the GC's root set (see dvmHeapMarkRootSet()).
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800174 */
Andy McFadden7fc3ce82009-07-14 15:57:23 -0700175 gDvm.outOfMemoryObj = createStockException("Ljava/lang/OutOfMemoryError;",
176 "[memory exhausted]");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800177 dvmReleaseTrackedAlloc(gDvm.outOfMemoryObj, NULL);
Andy McFadden7fc3ce82009-07-14 15:57:23 -0700178 gDvm.internalErrorObj = createStockException("Ljava/lang/InternalError;",
179 "[pre-allocated]");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800180 dvmReleaseTrackedAlloc(gDvm.internalErrorObj, NULL);
Andy McFadden7fc3ce82009-07-14 15:57:23 -0700181 gDvm.noClassDefFoundErrorObj =
Andy McFadden4c691d12009-12-10 15:11:18 -0800182 createStockException("Ljava/lang/NoClassDefFoundError;",
183 "[generic]");
Andy McFadden7fc3ce82009-07-14 15:57:23 -0700184 dvmReleaseTrackedAlloc(gDvm.noClassDefFoundErrorObj, NULL);
185
186 if (gDvm.outOfMemoryObj == NULL || gDvm.internalErrorObj == NULL ||
187 gDvm.noClassDefFoundErrorObj == NULL)
188 {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800189 LOGW("Unable to create stock exceptions\n");
190 return false;
191 }
192
193 return true;
194}
195
196
197/*
198 * Create an instance of the specified class.
199 *
200 * Returns NULL and throws an exception on failure.
201 */
202Object* dvmAllocObject(ClassObject* clazz, int flags)
203{
204 Object* newObj;
205
Carl Shapiro3475f9c2011-03-21 13:35:24 -0700206 assert(clazz != NULL);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800207 assert(dvmIsClassInitialized(clazz) || dvmIsClassInitializing(clazz));
208
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800209 /* allocate on GC heap; memory is zeroed out */
Carl Shapirofc75f3e2010-12-07 11:43:38 -0800210 newObj = (Object*)dvmMalloc(clazz->objectSize, flags);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800211 if (newObj != NULL) {
212 DVM_OBJECT_INIT(newObj, clazz);
Andy McFadden6af2ddd2011-02-16 16:50:40 -0800213 dvmTrackAllocation(clazz, clazz->objectSize); /* notify DDMS */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800214 }
215
216 return newObj;
217}
218
219/*
220 * Create a copy of an object, for Object.clone().
221 *
222 * We use the size actually allocated, rather than obj->clazz->objectSize,
223 * because the latter doesn't work for array objects.
224 */
Andy McFadden0f27ad72011-02-22 13:56:47 -0800225Object* dvmCloneObject(Object* obj, int flags)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800226{
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800227 assert(dvmIsValidObject(obj));
Carl Shapiro122dac52011-04-20 18:07:44 -0700228 ClassObject* clazz = obj->clazz;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800229
230 /* Class.java shouldn't let us get here (java.lang.Class is final
231 * and does not implement Clonable), but make extra sure.
232 * A memcpy() clone will wreak havoc on a ClassObject's "innards".
233 */
Dan Bornsteinc6d24702011-04-11 17:08:20 -0700234 assert(!dvmIsTheClassClass(clazz));
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800235
Carl Shapiro122dac52011-04-20 18:07:44 -0700236 size_t size;
Andy McFadden6af2ddd2011-02-16 16:50:40 -0800237 if (IS_CLASS_FLAG_SET(clazz, CLASS_ISARRAY)) {
Carl Shapirobfe4dcc2010-04-16 17:55:27 -0700238 size = dvmArrayObjectSize((ArrayObject *)obj);
239 } else {
Andy McFadden6af2ddd2011-02-16 16:50:40 -0800240 size = clazz->objectSize;
Carl Shapirobfe4dcc2010-04-16 17:55:27 -0700241 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800242
Carl Shapiro122dac52011-04-20 18:07:44 -0700243 Object* copy = (Object*)dvmMalloc(size, flags);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800244 if (copy == NULL)
245 return NULL;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800246
Carl Shapiro122dac52011-04-20 18:07:44 -0700247 DVM_OBJECT_INIT(copy, clazz);
248 size_t offset = sizeof(Object);
249 /* Copy instance data. We assume memcpy copies by words. */
250 memcpy((char*)copy + offset, (char*)obj + offset, size - offset);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800251
Carl Shapiro39721ef2011-02-22 16:51:27 -0800252 /* Mark the clone as finalizable if appropriate. */
Andy McFadden6af2ddd2011-02-16 16:50:40 -0800253 if (IS_CLASS_FLAG_SET(clazz, CLASS_ISFINALIZABLE)) {
254 dvmSetFinalizable(copy);
255 }
256
257 dvmTrackAllocation(clazz, size); /* notify DDMS */
258
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800259 return copy;
260}
261
262
263/*
264 * Track an object that was allocated internally and isn't yet part of the
265 * VM root set.
266 *
267 * We could do this per-thread or globally. If it's global we don't have
268 * to do the thread lookup but we do have to synchronize access to the list.
269 *
Andy McFaddenbd74b4b2010-09-22 12:37:49 -0700270 * "obj" must not be NULL.
271 *
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800272 * NOTE: "obj" is not a fully-formed object; in particular, obj->clazz will
273 * usually be NULL since we're being called from dvmMalloc().
274 */
275void dvmAddTrackedAlloc(Object* obj, Thread* self)
276{
277 if (self == NULL)
278 self = dvmThreadSelf();
279
Andy McFaddenbd74b4b2010-09-22 12:37:49 -0700280 assert(obj != NULL);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800281 assert(self != NULL);
282 if (!dvmAddToReferenceTable(&self->internalLocalRefTable, obj)) {
283 LOGE("threadid=%d: unable to add %p to internal ref table\n",
284 self->threadId, obj);
285 dvmDumpThread(self, false);
286 dvmAbort();
287 }
288}
289
290/*
291 * Stop tracking an object.
292 *
293 * We allow attempts to delete NULL "obj" so that callers don't have to wrap
294 * calls with "if != NULL".
295 */
296void dvmReleaseTrackedAlloc(Object* obj, Thread* self)
297{
298 if (obj == NULL)
299 return;
300
301 if (self == NULL)
302 self = dvmThreadSelf();
303 assert(self != NULL);
304
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800305 if (!dvmRemoveFromReferenceTable(&self->internalLocalRefTable,
306 self->internalLocalRefTable.table, obj))
307 {
308 LOGE("threadid=%d: failed to remove %p from internal ref table\n",
309 self->threadId, obj);
310 dvmAbort();
311 }
312}
313
314
315/*
316 * Explicitly initiate garbage collection.
317 */
Carl Shapiro1e1433e2011-04-20 16:51:38 -0700318void dvmCollectGarbage()
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800319{
Carl Shapiro821fd062011-01-19 12:56:14 -0800320 if (gDvm.disableExplicitGc) {
321 return;
322 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800323 dvmLockHeap();
Carl Shapiro039167e2010-12-20 18:33:24 -0800324 dvmWaitForConcurrentGcToComplete();
Carl Shapirocc6f5112011-01-26 17:25:27 -0800325 dvmCollectGarbageInternal(GC_EXPLICIT);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800326 dvmUnlockHeap();
327}
Carl Shapiro41eb6e92010-08-17 13:30:48 -0700328
329typedef struct {
330 const ClassObject *clazz;
331 size_t count;
Carl Shapirof331a602010-11-04 15:12:09 -0700332} CountContext;
Carl Shapiro41eb6e92010-08-17 13:30:48 -0700333
Carl Shapiro57ee2702010-08-27 13:06:48 -0700334static void countInstancesOfClassCallback(void *ptr, void *arg)
Carl Shapiro41eb6e92010-08-17 13:30:48 -0700335{
Carl Shapirofc75f3e2010-12-07 11:43:38 -0800336 CountContext *ctx = (CountContext *)arg;
337 const Object *obj = (const Object *)ptr;
Carl Shapiro41eb6e92010-08-17 13:30:48 -0700338
339 assert(ctx != NULL);
Carl Shapiro57ee2702010-08-27 13:06:48 -0700340 if (obj->clazz == ctx->clazz) {
341 ctx->count += 1;
Carl Shapiro41eb6e92010-08-17 13:30:48 -0700342 }
343}
344
345size_t dvmCountInstancesOfClass(const ClassObject *clazz)
346{
Carl Shapirof331a602010-11-04 15:12:09 -0700347 CountContext ctx = { clazz, 0 };
Carl Shapiro41eb6e92010-08-17 13:30:48 -0700348 dvmLockHeap();
Carl Shapiroa4313fe2011-01-24 12:31:09 -0800349 HeapBitmap *bitmap = dvmHeapSourceGetLiveBits();
Carl Shapiro41eb6e92010-08-17 13:30:48 -0700350 dvmHeapBitmapWalk(bitmap, countInstancesOfClassCallback, &ctx);
351 dvmUnlockHeap();
352 return ctx.count;
353}
Carl Shapirof331a602010-11-04 15:12:09 -0700354
355static void countAssignableInstancesOfClassCallback(void *ptr, void *arg)
356{
Carl Shapirofc75f3e2010-12-07 11:43:38 -0800357 CountContext *ctx = (CountContext *)arg;
358 const Object *obj = (const Object *)ptr;
Carl Shapirof331a602010-11-04 15:12:09 -0700359
360 assert(ctx != NULL);
Carl Shapiro2efc1262011-02-02 17:54:26 -0800361 if (obj->clazz != NULL && dvmInstanceof(obj->clazz, ctx->clazz)) {
Carl Shapirof331a602010-11-04 15:12:09 -0700362 ctx->count += 1;
363 }
364}
365
366size_t dvmCountAssignableInstancesOfClass(const ClassObject *clazz)
367{
368 CountContext ctx = { clazz, 0 };
Carl Shapirof331a602010-11-04 15:12:09 -0700369 dvmLockHeap();
Carl Shapiroa4313fe2011-01-24 12:31:09 -0800370 HeapBitmap *bitmap = dvmHeapSourceGetLiveBits();
Carl Shapirof331a602010-11-04 15:12:09 -0700371 dvmHeapBitmapWalk(bitmap, countAssignableInstancesOfClassCallback, &ctx);
372 dvmUnlockHeap();
373 return ctx.count;
374}
Carl Shapiro2494c502011-03-11 17:54:58 -0800375
376bool dvmIsHeapAddress(void *address)
377{
378 return dvmHeapSourceContainsAddress(address);
379}