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 */ 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 */ 41 bool dvmGcStartupAfterZygote() 42 { 43 return dvmHeapStartupAfterZygote(); 44 } 45 46 /* 47 * Shutdown the threads internal to the garbage collector. 48 */ 49 void dvmGcThreadShutdown() 50 { 51 dvmHeapThreadShutdown(); 52 } 53 54 /* 55 * Shut the GC down. 56 */ 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 */ 66 bool dvmGcPreZygoteFork() 67 { 68 return dvmHeapSourceStartupBeforeFork(); 69 } 70 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 */ 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 LOGE("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 LOGE("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 LOGW("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 */ 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 LOGW("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 */ 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 */ 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 */ 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 LOGE("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 */ 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 LOGE("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 */ 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 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 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 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 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 351 bool dvmIsHeapAddress(void *address) 352 { 353 return address != NULL && (((uintptr_t) address & (8-1)) == 0); 354 } 355 356 bool dvmIsNonMovingObject(const Object* object) 357 { 358 return true; 359 } 360