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 "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