Home | History | Annotate | Download | only in alloc
      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         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  */
    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  */
    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         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  */
    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  */
    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