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 */ 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 */ 44 bool dvmGcStartupAfterZygote() 45 { 46 return dvmHeapStartupAfterZygote(); 47 } 48 49 /* 50 * Shutdown the threads internal to the garbage collector. 51 */ 52 void dvmGcThreadShutdown() 53 { 54 dvmHeapThreadShutdown(); 55 } 56 57 /* 58 * Shut the GC down. 59 */ 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 */ 69 bool dvmGcPreZygoteFork() 70 { 71 return dvmHeapSourceStartupBeforeFork(); 72 } 73 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 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 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 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 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 365 bool dvmIsHeapAddress(void *address) 366 { 367 return address != NULL && (((uintptr_t) address & (8-1)) == 0); 368 } 369 370 bool dvmIsNonMovingObject(const Object* object) 371 { 372 return true; 373 } 374