Home | History | Annotate | Download | only in compiler
      1 /*
      2  * Copyright (C) 2009 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 "CompilerInternals.h"
     19 
     20 static ArenaMemBlock *arenaHead, *currentArena;
     21 static int numArenaBlocks;
     22 
     23 /* Allocate the initial memory block for arena-based allocation */
     24 bool dvmCompilerHeapInit(void)
     25 {
     26     assert(arenaHead == NULL);
     27     arenaHead =
     28         (ArenaMemBlock *) malloc(sizeof(ArenaMemBlock) + ARENA_DEFAULT_SIZE);
     29     if (arenaHead == NULL) {
     30         LOGE("No memory left to create compiler heap memory\n");
     31         return false;
     32     }
     33     currentArena = arenaHead;
     34     currentArena->bytesAllocated = 0;
     35     currentArena->next = NULL;
     36     numArenaBlocks = 1;
     37 
     38     return true;
     39 }
     40 
     41 /* Arena-based malloc for compilation tasks */
     42 void * dvmCompilerNew(size_t size, bool zero)
     43 {
     44     size = (size + 3) & ~3;
     45 retry:
     46     /* Normal case - space is available in the current page */
     47     if (size + currentArena->bytesAllocated <= ARENA_DEFAULT_SIZE) {
     48         void *ptr;
     49         ptr = &currentArena->ptr[currentArena->bytesAllocated];
     50         currentArena->bytesAllocated += size;
     51         if (zero) {
     52             memset(ptr, 0, size);
     53         }
     54         return ptr;
     55     } else {
     56         /*
     57          * See if there are previously allocated arena blocks before the last
     58          * reset
     59          */
     60         if (currentArena->next) {
     61             currentArena = currentArena->next;
     62             goto retry;
     63         }
     64         /*
     65          * If we allocate really large variable-sized data structures that
     66          * could go above the limit we need to enhance the allocation
     67          * mechanism.
     68          */
     69         assert(size <= ARENA_DEFAULT_SIZE);
     70         /* Time to allocate a new arena */
     71         ArenaMemBlock *newArena = (ArenaMemBlock *)
     72             malloc(sizeof(ArenaMemBlock) + ARENA_DEFAULT_SIZE);
     73         newArena->bytesAllocated = 0;
     74         newArena->next = NULL;
     75         currentArena->next = newArena;
     76         currentArena = newArena;
     77         numArenaBlocks++;
     78         if (numArenaBlocks > 10)
     79             LOGI("Total arena pages for JIT: %d", numArenaBlocks);
     80         goto retry;
     81     }
     82     return NULL;
     83 }
     84 
     85 /* Reclaim all the arena blocks allocated so far */
     86 void dvmCompilerArenaReset(void)
     87 {
     88     ArenaMemBlock *block;
     89 
     90     for (block = arenaHead; block; block = block->next) {
     91         block->bytesAllocated = 0;
     92     }
     93     currentArena = arenaHead;
     94 }
     95 
     96 /* Growable List initialization */
     97 void dvmInitGrowableList(GrowableList *gList, size_t initLength)
     98 {
     99     gList->numAllocated = initLength;
    100     gList->numUsed = 0;
    101     gList->elemList = (void **) dvmCompilerNew(sizeof(void *) * initLength,
    102                                                true);
    103 }
    104 
    105 /* Expand the capacity of a growable list */
    106 static void expandGrowableList(GrowableList *gList)
    107 {
    108     int newLength = gList->numAllocated;
    109     if (newLength < 128) {
    110         newLength <<= 1;
    111     } else {
    112         newLength += 128;
    113     }
    114     void *newArray = dvmCompilerNew(sizeof(void *) * newLength, true);
    115     memcpy(newArray, gList->elemList, sizeof(void *) * gList->numAllocated);
    116     gList->numAllocated = newLength;
    117     gList->elemList = newArray;
    118 }
    119 
    120 /* Insert a new element into the growable list */
    121 void dvmInsertGrowableList(GrowableList *gList, void *elem)
    122 {
    123     if (gList->numUsed == gList->numAllocated) {
    124         expandGrowableList(gList);
    125     }
    126     gList->elemList[gList->numUsed++] = elem;
    127 }
    128 
    129 /* Debug Utility - dump a compilation unit */
    130 void dvmCompilerDumpCompilationUnit(CompilationUnit *cUnit)
    131 {
    132     int i;
    133     BasicBlock *bb;
    134     LOGD("%d blocks in total\n", cUnit->numBlocks);
    135 
    136     for (i = 0; i < cUnit->numBlocks; i++) {
    137         bb = cUnit->blockList[i];
    138         LOGD("Block %d (insn %04x - %04x%s)\n",
    139              bb->id, bb->startOffset,
    140              bb->lastMIRInsn ? bb->lastMIRInsn->offset : bb->startOffset,
    141              bb->lastMIRInsn ? "" : " empty");
    142         if (bb->taken) {
    143             LOGD("  Taken branch: block %d (%04x)\n",
    144                  bb->taken->id, bb->taken->startOffset);
    145         }
    146         if (bb->fallThrough) {
    147             LOGD("  Fallthrough : block %d (%04x)\n",
    148                  bb->fallThrough->id, bb->fallThrough->startOffset);
    149         }
    150     }
    151 }
    152 
    153 /*
    154  * dvmHashForeach callback.
    155  */
    156 static int dumpMethodStats(void *compilerMethodStats, void *totalMethodStats)
    157 {
    158     CompilerMethodStats *methodStats =
    159         (CompilerMethodStats *) compilerMethodStats;
    160     CompilerMethodStats *totalStats =
    161         (CompilerMethodStats *) totalMethodStats;
    162     const Method *method = methodStats->method;
    163 
    164     totalStats->dalvikSize += methodStats->dalvikSize;
    165     totalStats->compiledDalvikSize += methodStats->compiledDalvikSize;
    166     totalStats->nativeSize += methodStats->nativeSize;
    167 
    168     /* Enable the following when fine-tuning the JIT performance */
    169 #if 0
    170     int limit = (methodStats->dalvikSize >> 2) * 3;
    171 
    172     /* If over 3/4 of the Dalvik code is compiled, print something */
    173     if (methodStats->compiledDalvikSize >= limit) {
    174         LOGD("Method stats: %s%s, %d/%d (compiled/total Dalvik), %d (native)",
    175              method->clazz->descriptor, method->name,
    176              methodStats->compiledDalvikSize,
    177              methodStats->dalvikSize,
    178              methodStats->nativeSize);
    179     }
    180 #endif
    181     return 0;
    182 }
    183 
    184 /*
    185  * Dump the current stats of the compiler, including number of bytes used in
    186  * the code cache, arena size, and work queue length, and various JIT stats.
    187  */
    188 void dvmCompilerDumpStats(void)
    189 {
    190     CompilerMethodStats totalMethodStats;
    191 
    192     memset(&totalMethodStats, 0, sizeof(CompilerMethodStats));
    193     LOGD("%d compilations using %d + %d bytes",
    194          gDvmJit.numCompilations,
    195          gDvmJit.templateSize,
    196          gDvmJit.codeCacheByteUsed - gDvmJit.templateSize);
    197     LOGD("Compiler arena uses %d blocks (%d bytes each)",
    198          numArenaBlocks, ARENA_DEFAULT_SIZE);
    199     LOGD("Compiler work queue length is %d/%d", gDvmJit.compilerQueueLength,
    200          gDvmJit.compilerMaxQueued);
    201     dvmJitStats();
    202     dvmCompilerArchDump();
    203     if (gDvmJit.methodStatsTable) {
    204         dvmHashForeach(gDvmJit.methodStatsTable, dumpMethodStats,
    205                        &totalMethodStats);
    206     }
    207     LOGD("Code size stats: %d/%d (compiled/total Dalvik), %d (native)",
    208          totalMethodStats.compiledDalvikSize,
    209          totalMethodStats.dalvikSize,
    210          totalMethodStats.nativeSize);
    211 }
    212 
    213 /*
    214  * Allocate a bit vector with enough space to hold at least the specified
    215  * number of bits.
    216  *
    217  * NOTE: this is the sister implementation of dvmAllocBitVector. In this version
    218  * memory is allocated from the compiler arena.
    219  */
    220 BitVector* dvmCompilerAllocBitVector(int startBits, bool expandable)
    221 {
    222     BitVector* bv;
    223     int count;
    224 
    225     assert(sizeof(bv->storage[0]) == 4);        /* assuming 32-bit units */
    226     assert(startBits >= 0);
    227 
    228     bv = (BitVector*) dvmCompilerNew(sizeof(BitVector), false);
    229 
    230     count = (startBits + 31) >> 5;
    231 
    232     bv->storageSize = count;
    233     bv->expandable = expandable;
    234     bv->storage = (u4*) dvmCompilerNew(count * sizeof(u4), true);
    235     return bv;
    236 }
    237 
    238 /*
    239  * Mark the specified bit as "set".
    240  *
    241  * Returns "false" if the bit is outside the range of the vector and we're
    242  * not allowed to expand.
    243  *
    244  * NOTE: this is the sister implementation of dvmSetBit. In this version
    245  * memory is allocated from the compiler arena.
    246  */
    247 bool dvmCompilerSetBit(BitVector *pBits, int num)
    248 {
    249     assert(num >= 0);
    250     if (num >= pBits->storageSize * (int)sizeof(u4) * 8) {
    251         if (!pBits->expandable)
    252             return false;
    253 
    254         int newSize = (num + 31) >> 5;
    255         assert(newSize > pBits->storageSize);
    256         u4 *newStorage = dvmCompilerNew(newSize * sizeof(u4), false);
    257         memcpy(newStorage, pBits->storage, pBits->storageSize * sizeof(u4));
    258         memset(&newStorage[pBits->storageSize], 0,
    259                (newSize - pBits->storageSize) * sizeof(u4));
    260         pBits->storage = newStorage;
    261         pBits->storageSize = newSize;
    262     }
    263 
    264     pBits->storage[num >> 5] |= 1 << (num & 0x1f);
    265     return true;
    266 }
    267 
    268 void dvmDebugBitVector(char *msg, const BitVector *bv, int length)
    269 {
    270     int i;
    271 
    272     LOGE("%s", msg);
    273     for (i = 0; i < length; i++) {
    274         if (dvmIsBitSet(bv, i)) {
    275             LOGE("Bit %d is set", i);
    276         }
    277     }
    278 }
    279 
    280 void dvmCompilerAbort(CompilationUnit *cUnit)
    281 {
    282     LOGE("Jit: aborting trace compilation, reverting to interpreter");
    283     /* Force a traceback in debug builds */
    284     assert(0);
    285     /*
    286      * Abort translation and force to interpret-only for this trace
    287      * Matching setjmp in compiler thread work loop in Compiler.c.
    288      */
    289     longjmp(*cUnit->bailPtr, 1);
    290 }
    291