• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 "Globals.h"
21 #include "alloc/Heap.h"
22 #include "alloc/HeapInternal.h"
23 #include "alloc/HeapSource.h"
24 #include "cutils/atomic.h"
25 #include "cutils/atomic-inline.h"
26 
27 /*
28  * Initialize the GC universe.
29  *
30  * We're currently using a memory-mapped arena to keep things off of the
31  * main heap.  This needs to be replaced with something real.
32  */
dvmGcStartup()33 bool dvmGcStartup()
34 {
35     dvmInitMutex(&gDvm.gcHeapLock);
36     pthread_cond_init(&gDvm.gcHeapCond, NULL);
37     return dvmHeapStartup();
38 }
39 
40 /*
41  * Post-zygote heap initialization, including starting
42  * the HeapWorker thread.
43  */
dvmGcStartupAfterZygote()44 bool dvmGcStartupAfterZygote()
45 {
46     return dvmHeapStartupAfterZygote();
47 }
48 
49 /*
50  * Shutdown the threads internal to the garbage collector.
51  */
dvmGcThreadShutdown()52 void dvmGcThreadShutdown()
53 {
54     dvmHeapThreadShutdown();
55 }
56 
57 /*
58  * Shut the GC down.
59  */
dvmGcShutdown()60 void dvmGcShutdown()
61 {
62     //TODO: grab and destroy the lock
63     dvmHeapShutdown();
64 }
65 
66 /*
67  * Do any last-minute preparation before we call fork() for the first time.
68  */
dvmGcPreZygoteFork()69 bool dvmGcPreZygoteFork()
70 {
71     return dvmHeapSourceStartupBeforeFork();
72 }
73 
dvmGcStartupClasses()74 bool dvmGcStartupClasses()
75 {
76     ClassObject *klass = dvmFindSystemClass("Ljava/lang/Daemons;");
77     if (klass == NULL) {
78         return false;
79     }
80     Method *method = dvmFindDirectMethodByDescriptor(klass, "start", "()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     return true;
89 }
90 
91 /*
92  * Create a "stock instance" of an exception class.
93  */
createStockException(const char * descriptor,const char * msg)94 static Object* createStockException(const char* descriptor, const char* msg)
95 {
96     Thread* self = dvmThreadSelf();
97     StringObject* msgStr = NULL;
98     ClassObject* clazz;
99     Method* init;
100     Object* obj;
101 
102     /* find class, initialize if necessary */
103     clazz = dvmFindSystemClass(descriptor);
104     if (clazz == NULL) {
105         ALOGE("Unable to find %s", descriptor);
106         return NULL;
107     }
108 
109     init = dvmFindDirectMethodByDescriptor(clazz, "<init>",
110             "(Ljava/lang/String;)V");
111     if (init == NULL) {
112         ALOGE("Unable to find String-arg constructor for %s", descriptor);
113         return NULL;
114     }
115 
116     obj = dvmAllocObject(clazz, ALLOC_DEFAULT);
117     if (obj == NULL)
118         return NULL;
119 
120     if (msg == NULL) {
121         msgStr = NULL;
122     } else {
123         msgStr = dvmCreateStringFromCstr(msg);
124         if (msgStr == NULL) {
125             ALOGW("Could not allocate message string \"%s\"", msg);
126             dvmReleaseTrackedAlloc(obj, self);
127             return NULL;
128         }
129     }
130 
131     JValue unused;
132     dvmCallMethod(self, init, obj, &unused, msgStr);
133     if (dvmCheckException(self)) {
134         dvmReleaseTrackedAlloc((Object*) msgStr, self);
135         dvmReleaseTrackedAlloc(obj, self);
136         return NULL;
137     }
138 
139     dvmReleaseTrackedAlloc((Object*) msgStr, self);     // okay if msgStr NULL
140     return obj;
141 }
142 
143 /*
144  * Create some "stock" exceptions.  These can be thrown when the system is
145  * too screwed up to allocate and initialize anything, or when we don't
146  * need a meaningful stack trace.
147  *
148  * We can't do this during the initial startup because we need to execute
149  * the constructors.
150  */
dvmCreateStockExceptions()151 bool dvmCreateStockExceptions()
152 {
153     /*
154      * Pre-allocate some throwables.  These need to be explicitly added
155      * to the GC's root set (see dvmHeapMarkRootSet()).
156      */
157     gDvm.outOfMemoryObj = createStockException("Ljava/lang/OutOfMemoryError;",
158         "[memory exhausted]");
159     dvmReleaseTrackedAlloc(gDvm.outOfMemoryObj, NULL);
160     gDvm.internalErrorObj = createStockException("Ljava/lang/InternalError;",
161         "[pre-allocated]");
162     dvmReleaseTrackedAlloc(gDvm.internalErrorObj, NULL);
163     gDvm.noClassDefFoundErrorObj =
164         createStockException("Ljava/lang/NoClassDefFoundError;",
165             "[generic]");
166     dvmReleaseTrackedAlloc(gDvm.noClassDefFoundErrorObj, NULL);
167 
168     if (gDvm.outOfMemoryObj == NULL || gDvm.internalErrorObj == NULL ||
169         gDvm.noClassDefFoundErrorObj == NULL)
170     {
171         ALOGW("Unable to create stock exceptions");
172         return false;
173     }
174 
175     return true;
176 }
177 
178 
179 /*
180  * Create an instance of the specified class.
181  *
182  * Returns NULL and throws an exception on failure.
183  */
dvmAllocObject(ClassObject * clazz,int flags)184 Object* dvmAllocObject(ClassObject* clazz, int flags)
185 {
186     Object* newObj;
187 
188     assert(clazz != NULL);
189     assert(dvmIsClassInitialized(clazz) || dvmIsClassInitializing(clazz));
190 
191     /* allocate on GC heap; memory is zeroed out */
192     newObj = (Object*)dvmMalloc(clazz->objectSize, flags);
193     if (newObj != NULL) {
194         DVM_OBJECT_INIT(newObj, clazz);
195         dvmTrackAllocation(clazz, clazz->objectSize);   /* notify DDMS */
196     }
197 
198     return newObj;
199 }
200 
201 /*
202  * Create a copy of an object, for Object.clone().
203  *
204  * We use the size actually allocated, rather than obj->clazz->objectSize,
205  * because the latter doesn't work for array objects.
206  */
dvmCloneObject(Object * obj,int flags)207 Object* dvmCloneObject(Object* obj, int flags)
208 {
209     assert(dvmIsValidObject(obj));
210     ClassObject* clazz = obj->clazz;
211 
212     /* Class.java shouldn't let us get here (java.lang.Class is final
213      * and does not implement Clonable), but make extra sure.
214      * A memcpy() clone will wreak havoc on a ClassObject's "innards".
215      */
216     assert(!dvmIsTheClassClass(clazz));
217 
218     size_t size;
219     if (IS_CLASS_FLAG_SET(clazz, CLASS_ISARRAY)) {
220         size = dvmArrayObjectSize((ArrayObject *)obj);
221     } else {
222         size = clazz->objectSize;
223     }
224 
225     Object* copy = (Object*)dvmMalloc(size, flags);
226     if (copy == NULL)
227         return NULL;
228 
229     DVM_OBJECT_INIT(copy, clazz);
230     size_t offset = sizeof(Object);
231     /* Copy instance data.  We assume memcpy copies by words. */
232     memcpy((char*)copy + offset, (char*)obj + offset, size - offset);
233 
234     /* Mark the clone as finalizable if appropriate. */
235     if (IS_CLASS_FLAG_SET(clazz, CLASS_ISFINALIZABLE)) {
236         dvmSetFinalizable(copy);
237     }
238 
239     dvmTrackAllocation(clazz, size);    /* notify DDMS */
240 
241     return copy;
242 }
243 
244 
245 /*
246  * Track an object that was allocated internally and isn't yet part of the
247  * VM root set.
248  *
249  * We could do this per-thread or globally.  If it's global we don't have
250  * to do the thread lookup but we do have to synchronize access to the list.
251  *
252  * "obj" must not be NULL.
253  *
254  * NOTE: "obj" is not a fully-formed object; in particular, obj->clazz will
255  * usually be NULL since we're being called from dvmMalloc().
256  */
dvmAddTrackedAlloc(Object * obj,Thread * self)257 void dvmAddTrackedAlloc(Object* obj, Thread* self)
258 {
259     if (self == NULL)
260         self = dvmThreadSelf();
261 
262     assert(obj != NULL);
263     assert(self != NULL);
264     if (!dvmAddToReferenceTable(&self->internalLocalRefTable, obj)) {
265         ALOGE("threadid=%d: unable to add %p to internal ref table",
266             self->threadId, obj);
267         dvmDumpThread(self, false);
268         dvmAbort();
269     }
270 }
271 
272 /*
273  * Stop tracking an object.
274  *
275  * We allow attempts to delete NULL "obj" so that callers don't have to wrap
276  * calls with "if != NULL".
277  */
dvmReleaseTrackedAlloc(Object * obj,Thread * self)278 void dvmReleaseTrackedAlloc(Object* obj, Thread* self)
279 {
280     if (obj == NULL)
281         return;
282 
283     if (self == NULL)
284         self = dvmThreadSelf();
285     assert(self != NULL);
286 
287     if (!dvmRemoveFromReferenceTable(&self->internalLocalRefTable,
288             self->internalLocalRefTable.table, obj))
289     {
290         ALOGE("threadid=%d: failed to remove %p from internal ref table",
291             self->threadId, obj);
292         dvmAbort();
293     }
294 }
295 
296 
297 /*
298  * Explicitly initiate garbage collection.
299  */
dvmCollectGarbage()300 void dvmCollectGarbage()
301 {
302     if (gDvm.disableExplicitGc) {
303         return;
304     }
305     dvmLockHeap();
306     dvmWaitForConcurrentGcToComplete();
307     dvmCollectGarbageInternal(GC_EXPLICIT);
308     dvmUnlockHeap();
309 }
310 
311 /*
312  * Run finalization.
313  */
dvmRunFinalization()314 void dvmRunFinalization() {
315   Thread *self = dvmThreadSelf();
316   assert(self != NULL);
317   JValue unusedResult;
318   assert(gDvm.methJavaLangSystem_runFinalization != NULL);
319   dvmCallMethod(self, gDvm.methJavaLangSystem_runFinalization, NULL, &unusedResult);
320 }
321 
322 struct CountContext {
323     const ClassObject *clazz;
324     size_t count;
325 };
326 
countInstancesOfClassCallback(Object * obj,void * arg)327 static void countInstancesOfClassCallback(Object *obj, void *arg)
328 {
329     CountContext *ctx = (CountContext *)arg;
330     assert(ctx != NULL);
331     if (obj->clazz == ctx->clazz) {
332         ctx->count += 1;
333     }
334 }
335 
dvmCountInstancesOfClass(const ClassObject * clazz)336 size_t dvmCountInstancesOfClass(const ClassObject *clazz)
337 {
338     CountContext ctx = { clazz, 0 };
339     dvmLockHeap();
340     HeapBitmap *bitmap = dvmHeapSourceGetLiveBits();
341     dvmHeapBitmapWalk(bitmap, countInstancesOfClassCallback, &ctx);
342     dvmUnlockHeap();
343     return ctx.count;
344 }
345 
countAssignableInstancesOfClassCallback(Object * obj,void * arg)346 static void countAssignableInstancesOfClassCallback(Object *obj, void *arg)
347 {
348     CountContext *ctx = (CountContext *)arg;
349     assert(ctx != NULL);
350     if (obj->clazz != NULL && dvmInstanceof(obj->clazz, ctx->clazz)) {
351         ctx->count += 1;
352     }
353 }
354 
dvmCountAssignableInstancesOfClass(const ClassObject * clazz)355 size_t dvmCountAssignableInstancesOfClass(const ClassObject *clazz)
356 {
357     CountContext ctx = { clazz, 0 };
358     dvmLockHeap();
359     HeapBitmap *bitmap = dvmHeapSourceGetLiveBits();
360     dvmHeapBitmapWalk(bitmap, countAssignableInstancesOfClassCallback, &ctx);
361     dvmUnlockHeap();
362     return ctx.count;
363 }
364 
dvmIsHeapAddress(void * address)365 bool dvmIsHeapAddress(void *address)
366 {
367     return address != NULL && (((uintptr_t) address & (8-1)) == 0);
368 }
369 
dvmIsNonMovingObject(const Object * object)370 bool dvmIsNonMovingObject(const Object* object)
371 {
372     return true;
373 }
374