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