blob: 8269290a3b3f744dd4dff92fb0bd8cf13461830e [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 */
30bool dvmGcStartup(void)
31{
32 dvmInitMutex(&gDvm.gcHeapLock);
33
34 return dvmHeapStartup();
35}
36
37/*
38 * Post-zygote heap initialization, including starting
39 * the HeapWorker thread.
40 */
41bool dvmGcStartupAfterZygote(void)
42{
43 if (!dvmHeapWorkerStartup()) {
44 return false;
45 }
Carl Shapiroec805ea2010-06-28 16:28:26 -070046 return dvmHeapStartupAfterZygote();
47}
48
49/*
50 * Shutdown the threads internal to the garbage collector.
51 */
52void dvmGcThreadShutdown(void)
53{
54 dvmHeapWorkerShutdown();
55 dvmHeapThreadShutdown();
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080056}
57
58/*
59 * Shut the GC down.
60 */
61void dvmGcShutdown(void)
62{
63 //TODO: grab and destroy the lock
64 dvmHeapShutdown();
65}
66
67/*
68 * Do any last-minute preparation before we call fork() for the first time.
69 */
70bool dvmGcPreZygoteFork(void)
71{
72 return dvmHeapSourceStartupBeforeFork();
73}
74
75/*
Andy McFadden7fc3ce82009-07-14 15:57:23 -070076 * Create a "stock instance" of an exception class.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080077 */
Andy McFadden7fc3ce82009-07-14 15:57:23 -070078static Object* createStockException(const char* descriptor, const char* msg)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080079{
Andy McFadden7fc3ce82009-07-14 15:57:23 -070080 Thread* self = dvmThreadSelf();
81 StringObject* msgStr = NULL;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080082 ClassObject* clazz;
83 Method* init;
84 Object* obj;
85
Andy McFadden7fc3ce82009-07-14 15:57:23 -070086 /* find class, initialize if necessary */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080087 clazz = dvmFindSystemClass(descriptor);
88 if (clazz == NULL) {
89 LOGE("Unable to find %s\n", descriptor);
90 return NULL;
91 }
92
Andy McFadden7fc3ce82009-07-14 15:57:23 -070093 init = dvmFindDirectMethodByDescriptor(clazz, "<init>",
94 "(Ljava/lang/String;)V");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080095 if (init == NULL) {
Andy McFadden7fc3ce82009-07-14 15:57:23 -070096 LOGE("Unable to find String-arg constructor for %s\n", descriptor);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080097 return NULL;
98 }
99
100 obj = dvmAllocObject(clazz, ALLOC_DEFAULT);
101 if (obj == NULL)
102 return NULL;
103
Andy McFadden7fc3ce82009-07-14 15:57:23 -0700104 if (msg == NULL) {
105 msgStr = NULL;
106 } else {
Barry Hayes81f3ebe2010-06-15 16:17:37 -0700107 msgStr = dvmCreateStringFromCstr(msg);
Andy McFadden7fc3ce82009-07-14 15:57:23 -0700108 if (msgStr == NULL) {
109 LOGW("Could not allocate message string \"%s\"\n", msg);
110 dvmReleaseTrackedAlloc(obj, self);
111 return NULL;
112 }
113 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800114
Andy McFadden7fc3ce82009-07-14 15:57:23 -0700115 JValue unused;
116 dvmCallMethod(self, init, obj, &unused, msgStr);
117 if (dvmCheckException(self)) {
118 dvmReleaseTrackedAlloc((Object*) msgStr, self);
119 dvmReleaseTrackedAlloc(obj, self);
120 return NULL;
121 }
122
123 dvmReleaseTrackedAlloc((Object*) msgStr, self); // okay if msgStr NULL
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800124 return obj;
125}
126
127/*
Andy McFadden7fc3ce82009-07-14 15:57:23 -0700128 * Create some "stock" exceptions. These can be thrown when the system is
129 * too screwed up to allocate and initialize anything, or when we don't
130 * need a meaningful stack trace.
131 *
132 * We can't do this during the initial startup because we need to execute
133 * the constructors.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800134 */
Andy McFadden7fc3ce82009-07-14 15:57:23 -0700135bool dvmCreateStockExceptions(void)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800136{
137 /*
138 * Pre-allocate some throwables. These need to be explicitly added
Andy McFadden7fc3ce82009-07-14 15:57:23 -0700139 * to the GC's root set (see dvmHeapMarkRootSet()).
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800140 */
Andy McFadden7fc3ce82009-07-14 15:57:23 -0700141 gDvm.outOfMemoryObj = createStockException("Ljava/lang/OutOfMemoryError;",
142 "[memory exhausted]");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800143 dvmReleaseTrackedAlloc(gDvm.outOfMemoryObj, NULL);
Andy McFadden7fc3ce82009-07-14 15:57:23 -0700144 gDvm.internalErrorObj = createStockException("Ljava/lang/InternalError;",
145 "[pre-allocated]");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800146 dvmReleaseTrackedAlloc(gDvm.internalErrorObj, NULL);
Andy McFadden7fc3ce82009-07-14 15:57:23 -0700147 gDvm.noClassDefFoundErrorObj =
Andy McFadden4c691d12009-12-10 15:11:18 -0800148 createStockException("Ljava/lang/NoClassDefFoundError;",
149 "[generic]");
Andy McFadden7fc3ce82009-07-14 15:57:23 -0700150 dvmReleaseTrackedAlloc(gDvm.noClassDefFoundErrorObj, NULL);
151
152 if (gDvm.outOfMemoryObj == NULL || gDvm.internalErrorObj == NULL ||
153 gDvm.noClassDefFoundErrorObj == NULL)
154 {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800155 LOGW("Unable to create stock exceptions\n");
156 return false;
157 }
158
159 return true;
160}
161
162
163/*
164 * Create an instance of the specified class.
165 *
166 * Returns NULL and throws an exception on failure.
167 */
168Object* dvmAllocObject(ClassObject* clazz, int flags)
169{
170 Object* newObj;
171
172 assert(dvmIsClassInitialized(clazz) || dvmIsClassInitializing(clazz));
173
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800174 /* allocate on GC heap; memory is zeroed out */
Carl Shapirofc75f3e2010-12-07 11:43:38 -0800175 newObj = (Object*)dvmMalloc(clazz->objectSize, flags);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800176 if (newObj != NULL) {
177 DVM_OBJECT_INIT(newObj, clazz);
Andy McFadden6af2ddd2011-02-16 16:50:40 -0800178 dvmTrackAllocation(clazz, clazz->objectSize); /* notify DDMS */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800179 }
180
181 return newObj;
182}
183
184/*
185 * Create a copy of an object, for Object.clone().
186 *
187 * We use the size actually allocated, rather than obj->clazz->objectSize,
188 * because the latter doesn't work for array objects.
189 */
Andy McFadden0f27ad72011-02-22 13:56:47 -0800190Object* dvmCloneObject(Object* obj, int flags)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800191{
Andy McFadden6af2ddd2011-02-16 16:50:40 -0800192 ClassObject* clazz;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800193 Object* copy;
Andy McFadden6af2ddd2011-02-16 16:50:40 -0800194 size_t size;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800195
196 assert(dvmIsValidObject(obj));
Andy McFadden6af2ddd2011-02-16 16:50:40 -0800197 clazz = obj->clazz;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800198
199 /* Class.java shouldn't let us get here (java.lang.Class is final
200 * and does not implement Clonable), but make extra sure.
201 * A memcpy() clone will wreak havoc on a ClassObject's "innards".
202 */
Andy McFadden6af2ddd2011-02-16 16:50:40 -0800203 assert(clazz != gDvm.classJavaLangClass);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800204
Andy McFadden6af2ddd2011-02-16 16:50:40 -0800205 if (IS_CLASS_FLAG_SET(clazz, CLASS_ISARRAY)) {
Carl Shapirobfe4dcc2010-04-16 17:55:27 -0700206 size = dvmArrayObjectSize((ArrayObject *)obj);
207 } else {
Andy McFadden6af2ddd2011-02-16 16:50:40 -0800208 size = clazz->objectSize;
Carl Shapirobfe4dcc2010-04-16 17:55:27 -0700209 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800210
Andy McFadden0f27ad72011-02-22 13:56:47 -0800211 copy = (Object*)dvmMalloc(size, flags);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800212 if (copy == NULL)
213 return NULL;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800214
Andy McFadden6af2ddd2011-02-16 16:50:40 -0800215 /* We assume that memcpy will copy obj by words. */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800216 memcpy(copy, obj, size);
217 DVM_LOCK_INIT(&copy->lock);
Barry Hayes364f9d92010-06-11 16:12:47 -0700218 dvmWriteBarrierObject(copy);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800219
Carl Shapiro39721ef2011-02-22 16:51:27 -0800220 /* Mark the clone as finalizable if appropriate. */
Andy McFadden6af2ddd2011-02-16 16:50:40 -0800221 if (IS_CLASS_FLAG_SET(clazz, CLASS_ISFINALIZABLE)) {
222 dvmSetFinalizable(copy);
223 }
224
225 dvmTrackAllocation(clazz, size); /* notify DDMS */
226
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800227 return copy;
228}
229
230
231/*
232 * Track an object that was allocated internally and isn't yet part of the
233 * VM root set.
234 *
235 * We could do this per-thread or globally. If it's global we don't have
236 * to do the thread lookup but we do have to synchronize access to the list.
237 *
Andy McFaddenbd74b4b2010-09-22 12:37:49 -0700238 * "obj" must not be NULL.
239 *
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800240 * NOTE: "obj" is not a fully-formed object; in particular, obj->clazz will
241 * usually be NULL since we're being called from dvmMalloc().
242 */
243void dvmAddTrackedAlloc(Object* obj, Thread* self)
244{
245 if (self == NULL)
246 self = dvmThreadSelf();
247
Andy McFaddenbd74b4b2010-09-22 12:37:49 -0700248 assert(obj != NULL);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800249 assert(self != NULL);
250 if (!dvmAddToReferenceTable(&self->internalLocalRefTable, obj)) {
251 LOGE("threadid=%d: unable to add %p to internal ref table\n",
252 self->threadId, obj);
253 dvmDumpThread(self, false);
254 dvmAbort();
255 }
256}
257
258/*
259 * Stop tracking an object.
260 *
261 * We allow attempts to delete NULL "obj" so that callers don't have to wrap
262 * calls with "if != NULL".
263 */
264void dvmReleaseTrackedAlloc(Object* obj, Thread* self)
265{
266 if (obj == NULL)
267 return;
268
269 if (self == NULL)
270 self = dvmThreadSelf();
271 assert(self != NULL);
272
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800273 if (!dvmRemoveFromReferenceTable(&self->internalLocalRefTable,
274 self->internalLocalRefTable.table, obj))
275 {
276 LOGE("threadid=%d: failed to remove %p from internal ref table\n",
277 self->threadId, obj);
278 dvmAbort();
279 }
280}
281
282
283/*
284 * Explicitly initiate garbage collection.
285 */
Carl Shapirobc3ba012011-02-09 14:20:14 -0800286void dvmCollectGarbage(void)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800287{
Carl Shapiro821fd062011-01-19 12:56:14 -0800288 if (gDvm.disableExplicitGc) {
289 return;
290 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800291 dvmLockHeap();
Carl Shapiro039167e2010-12-20 18:33:24 -0800292 dvmWaitForConcurrentGcToComplete();
Carl Shapirocc6f5112011-01-26 17:25:27 -0800293 dvmCollectGarbageInternal(GC_EXPLICIT);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800294 dvmUnlockHeap();
295}
Carl Shapiro41eb6e92010-08-17 13:30:48 -0700296
297typedef struct {
298 const ClassObject *clazz;
299 size_t count;
Carl Shapirof331a602010-11-04 15:12:09 -0700300} CountContext;
Carl Shapiro41eb6e92010-08-17 13:30:48 -0700301
Carl Shapiro57ee2702010-08-27 13:06:48 -0700302static void countInstancesOfClassCallback(void *ptr, void *arg)
Carl Shapiro41eb6e92010-08-17 13:30:48 -0700303{
Carl Shapirofc75f3e2010-12-07 11:43:38 -0800304 CountContext *ctx = (CountContext *)arg;
305 const Object *obj = (const Object *)ptr;
Carl Shapiro41eb6e92010-08-17 13:30:48 -0700306
307 assert(ctx != NULL);
Carl Shapiro57ee2702010-08-27 13:06:48 -0700308 if (obj->clazz == ctx->clazz) {
309 ctx->count += 1;
Carl Shapiro41eb6e92010-08-17 13:30:48 -0700310 }
311}
312
313size_t dvmCountInstancesOfClass(const ClassObject *clazz)
314{
Carl Shapirof331a602010-11-04 15:12:09 -0700315 CountContext ctx = { clazz, 0 };
Carl Shapiro41eb6e92010-08-17 13:30:48 -0700316 dvmLockHeap();
Carl Shapiroa4313fe2011-01-24 12:31:09 -0800317 HeapBitmap *bitmap = dvmHeapSourceGetLiveBits();
Carl Shapiro41eb6e92010-08-17 13:30:48 -0700318 dvmHeapBitmapWalk(bitmap, countInstancesOfClassCallback, &ctx);
319 dvmUnlockHeap();
320 return ctx.count;
321}
Carl Shapirof331a602010-11-04 15:12:09 -0700322
323static void countAssignableInstancesOfClassCallback(void *ptr, void *arg)
324{
Carl Shapirofc75f3e2010-12-07 11:43:38 -0800325 CountContext *ctx = (CountContext *)arg;
326 const Object *obj = (const Object *)ptr;
Carl Shapirof331a602010-11-04 15:12:09 -0700327
328 assert(ctx != NULL);
Carl Shapiro2efc1262011-02-02 17:54:26 -0800329 if (obj->clazz != NULL && dvmInstanceof(obj->clazz, ctx->clazz)) {
Carl Shapirof331a602010-11-04 15:12:09 -0700330 ctx->count += 1;
331 }
332}
333
334size_t dvmCountAssignableInstancesOfClass(const ClassObject *clazz)
335{
336 CountContext ctx = { clazz, 0 };
Carl Shapirof331a602010-11-04 15:12:09 -0700337 dvmLockHeap();
Carl Shapiroa4313fe2011-01-24 12:31:09 -0800338 HeapBitmap *bitmap = dvmHeapSourceGetLiveBits();
Carl Shapirof331a602010-11-04 15:12:09 -0700339 dvmHeapBitmapWalk(bitmap, countAssignableInstancesOfClassCallback, &ctx);
340 dvmUnlockHeap();
341 return ctx.count;
342}
Carl Shapiro2494c502011-03-11 17:54:58 -0800343
344bool dvmIsHeapAddress(void *address)
345{
346 return dvmHeapSourceContainsAddress(address);
347}