Home | History | Annotate | Download | only in alloc
      1 /*
      2  * Copyright (C) 2010 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 #include "Dalvik.h"
     18 #include "alloc/HeapInternal.h"
     19 #include "alloc/Visit.h"
     20 #include "alloc/VisitInlines.h"
     21 
     22 /*
     23  * Visits all of the reference locations in an object.
     24  */
     25 void dvmVisitObject(Visitor *visitor, Object *obj, void *arg)
     26 {
     27     assert(visitor != NULL);
     28     assert(obj != NULL);
     29     assert(obj->clazz != NULL);
     30     visitObject(visitor, obj, arg);
     31 }
     32 
     33 /*
     34  * Applies a verification function to all present values in the hash table.
     35  */
     36 static void visitHashTable(RootVisitor *visitor, HashTable *table,
     37                            RootType type, void *arg)
     38 {
     39     assert(visitor != NULL);
     40     assert(table != NULL);
     41     dvmHashTableLock(table);
     42     for (int i = 0; i < table->tableSize; ++i) {
     43         HashEntry *entry = &table->pEntries[i];
     44         if (entry->data != NULL && entry->data != HASH_TOMBSTONE) {
     45             (*visitor)(&entry->data, 0, type, arg);
     46         }
     47     }
     48     dvmHashTableUnlock(table);
     49 }
     50 
     51 /*
     52  * Visits all entries in the reference table.
     53  */
     54 static void visitReferenceTable(RootVisitor *visitor, ReferenceTable *table,
     55                                 u4 threadId, RootType type, void *arg)
     56 {
     57     assert(visitor != NULL);
     58     assert(table != NULL);
     59     for (Object **entry = table->table; entry < table->nextEntry; ++entry) {
     60         assert(entry != NULL);
     61         (*visitor)(entry, threadId, type, arg);
     62     }
     63 }
     64 
     65 /*
     66  * Visits all entries in the indirect reference table.
     67  */
     68 static void visitIndirectRefTable(RootVisitor *visitor, IndirectRefTable *table,
     69                                   u4 threadId, RootType type, void *arg)
     70 {
     71     assert(visitor != NULL);
     72     assert(table != NULL);
     73     typedef IndirectRefTable::iterator It; // TODO: C++0x auto
     74     for (It it = table->begin(), end = table->end(); it != end; ++it) {
     75         (*visitor)(*it, threadId, type, arg);
     76     }
     77 }
     78 
     79 /*
     80  * Visits all stack slots except those belonging to native method
     81  * arguments.
     82  */
     83 static void visitThreadStack(RootVisitor *visitor, Thread *thread, void *arg)
     84 {
     85     assert(visitor != NULL);
     86     assert(thread != NULL);
     87     u4 threadId = thread->threadId;
     88     const StackSaveArea *saveArea;
     89     for (u4 *fp = (u4 *)thread->interpSave.curFrame;
     90          fp != NULL;
     91          fp = (u4 *)saveArea->prevFrame) {
     92         Method *method;
     93         saveArea = SAVEAREA_FROM_FP(fp);
     94         method = (Method *)saveArea->method;
     95         if (method != NULL && !dvmIsNativeMethod(method)) {
     96             const RegisterMap* pMap = dvmGetExpandedRegisterMap(method);
     97             const u1* regVector = NULL;
     98             if (pMap != NULL) {
     99                 /* found map, get registers for this address */
    100                 int addr = saveArea->xtra.currentPc - method->insns;
    101                 regVector = dvmRegisterMapGetLine(pMap, addr);
    102             }
    103             if (regVector == NULL) {
    104                 /*
    105                  * Either there was no register map or there is no
    106                  * info for the current PC.  Perform a conservative
    107                  * scan.
    108                  */
    109                 for (size_t i = 0; i < method->registersSize; ++i) {
    110                     if (dvmIsValidObject((Object *)fp[i])) {
    111                         (*visitor)(&fp[i], threadId, ROOT_JAVA_FRAME, arg);
    112                     }
    113                 }
    114             } else {
    115                 /*
    116                  * Precise scan.  v0 is at the lowest address on the
    117                  * interpreted stack, and is the first bit in the
    118                  * register vector, so we can walk through the
    119                  * register map and memory in the same direction.
    120                  *
    121                  * A '1' bit indicates a live reference.
    122                  */
    123                 u2 bits = 1 << 1;
    124                 for (size_t i = 0; i < method->registersSize; ++i) {
    125                     bits >>= 1;
    126                     if (bits == 1) {
    127                         /* set bit 9 so we can tell when we're empty */
    128                         bits = *regVector++ | 0x0100;
    129                     }
    130                     if ((bits & 0x1) != 0) {
    131                         /*
    132                          * Register is marked as live, it's a valid root.
    133                          */
    134 #if WITH_EXTRA_GC_CHECKS
    135                         if (fp[i] != 0 && !dvmIsValidObject((Object *)fp[i])) {
    136                             /* this is very bad */
    137                             ALOGE("PGC: invalid ref in reg %d: %#x",
    138                                  method->registersSize - 1 - i, fp[i]);
    139                             ALOGE("PGC: %s.%s addr %#x",
    140                                  method->clazz->descriptor, method->name,
    141                                  saveArea->xtra.currentPc - method->insns);
    142                             continue;
    143                         }
    144 #endif
    145                         (*visitor)(&fp[i], threadId, ROOT_JAVA_FRAME, arg);
    146                     }
    147                 }
    148                 dvmReleaseRegisterMapLine(pMap, regVector);
    149             }
    150         }
    151         /*
    152          * Don't fall into an infinite loop if things get corrupted.
    153          */
    154         assert((uintptr_t)saveArea->prevFrame > (uintptr_t)fp ||
    155                saveArea->prevFrame == NULL);
    156     }
    157 }
    158 
    159 /*
    160  * Visits all roots associated with a thread.
    161  */
    162 static void visitThread(RootVisitor *visitor, Thread *thread, void *arg)
    163 {
    164     u4 threadId;
    165 
    166     assert(visitor != NULL);
    167     assert(thread != NULL);
    168     threadId = thread->threadId;
    169     (*visitor)(&thread->threadObj, threadId, ROOT_THREAD_OBJECT, arg);
    170     (*visitor)(&thread->exception, threadId, ROOT_NATIVE_STACK, arg);
    171     visitReferenceTable(visitor, &thread->internalLocalRefTable, threadId, ROOT_NATIVE_STACK, arg);
    172     visitIndirectRefTable(visitor, &thread->jniLocalRefTable, threadId, ROOT_JNI_LOCAL, arg);
    173     if (thread->jniMonitorRefTable.table != NULL) {
    174         visitReferenceTable(visitor, &thread->jniMonitorRefTable, threadId, ROOT_JNI_MONITOR, arg);
    175     }
    176     visitThreadStack(visitor, thread, arg);
    177 }
    178 
    179 /*
    180  * Visits all threads on the thread list.
    181  */
    182 static void visitThreads(RootVisitor *visitor, void *arg)
    183 {
    184     Thread *thread;
    185 
    186     assert(visitor != NULL);
    187     dvmLockThreadList(dvmThreadSelf());
    188     thread = gDvm.threadList;
    189     while (thread) {
    190         visitThread(visitor, thread, arg);
    191         thread = thread->next;
    192     }
    193     dvmUnlockThreadList();
    194 }
    195 
    196 static void visitPrimitiveTypes(RootVisitor *visitor, void *arg)
    197 {
    198     (*visitor)(&gDvm.typeVoid, 0, ROOT_STICKY_CLASS, arg);
    199     (*visitor)(&gDvm.typeBoolean, 0, ROOT_STICKY_CLASS, arg);
    200     (*visitor)(&gDvm.typeByte, 0, ROOT_STICKY_CLASS, arg);
    201     (*visitor)(&gDvm.typeShort, 0, ROOT_STICKY_CLASS, arg);
    202     (*visitor)(&gDvm.typeChar, 0, ROOT_STICKY_CLASS, arg);
    203     (*visitor)(&gDvm.typeInt, 0, ROOT_STICKY_CLASS, arg);
    204     (*visitor)(&gDvm.typeLong, 0, ROOT_STICKY_CLASS, arg);
    205     (*visitor)(&gDvm.typeFloat, 0, ROOT_STICKY_CLASS, arg);
    206     (*visitor)(&gDvm.typeDouble, 0, ROOT_STICKY_CLASS, arg);
    207 }
    208 
    209 /*
    210  * Visits roots.  TODO: visit cached global references.
    211  */
    212 void dvmVisitRoots(RootVisitor *visitor, void *arg)
    213 {
    214     assert(visitor != NULL);
    215     visitHashTable(visitor, gDvm.loadedClasses, ROOT_STICKY_CLASS, arg);
    216     visitPrimitiveTypes(visitor, arg);
    217     if (gDvm.dbgRegistry != NULL) {
    218         visitHashTable(visitor, gDvm.dbgRegistry, ROOT_DEBUGGER, arg);
    219     }
    220     if (gDvm.literalStrings != NULL) {
    221         visitHashTable(visitor, gDvm.literalStrings, ROOT_INTERNED_STRING, arg);
    222     }
    223     dvmLockMutex(&gDvm.jniGlobalRefLock);
    224     visitIndirectRefTable(visitor, &gDvm.jniGlobalRefTable, 0, ROOT_JNI_GLOBAL, arg);
    225     dvmUnlockMutex(&gDvm.jniGlobalRefLock);
    226     dvmLockMutex(&gDvm.jniPinRefLock);
    227     visitReferenceTable(visitor, &gDvm.jniPinRefTable, 0, ROOT_VM_INTERNAL, arg);
    228     dvmUnlockMutex(&gDvm.jniPinRefLock);
    229     visitThreads(visitor, arg);
    230     (*visitor)(&gDvm.outOfMemoryObj, 0, ROOT_VM_INTERNAL, arg);
    231     (*visitor)(&gDvm.internalErrorObj, 0, ROOT_VM_INTERNAL, arg);
    232     (*visitor)(&gDvm.noClassDefFoundErrorObj, 0, ROOT_VM_INTERNAL, arg);
    233 }
    234