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