blob: 47dfb503419cc7a3eabcb20171b3f6058da987d7 [file] [log] [blame]
/*
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "compiler_internals.h"
namespace art {
const char* extendedMIROpNames[kMirOpLast - kMirOpFirst] = {
"kMirOpPhi",
"kMirOpCopy",
"kMirFusedCmplFloat",
"kMirFusedCmpgFloat",
"kMirFusedCmplDouble",
"kMirFusedCmpgDouble",
"kMirFusedCmpLong",
"kMirNop",
"kMirOpNullCheck",
"kMirOpRangeCheck",
"kMirOpDivZeroCheck",
"kMirOpCheck",
};
#ifdef WITH_MEMSTATS
struct Memstats {
uint32_t allocStats[kNumAllocKinds];
int listSizes[kNumListKinds];
int listWasted[kNumListKinds];
int listGrows[kNumListKinds];
int listMaxElems[kNumListKinds];
int bitMapSizes[kNumBitMapKinds];
int bitMapWasted[kNumBitMapKinds];
int bitMapGrows[kNumBitMapKinds];
};
const char* allocNames[kNumAllocKinds] = {
"Misc ",
"BasicBlock ",
"LIR ",
"MIR ",
"DataFlow ",
"GrowList ",
"GrowBitMap ",
"Dalvik2SSA ",
"DebugInfo ",
"Successor ",
"RegAlloc ",
"Data ",
"Preds ",
};
const char* listNames[kNumListKinds] = {
"Misc ",
"blockList ",
"SSAtoDalvik ",
"dfsOrder ",
"dfsPostOrder ",
"domPostOrderTraversal ",
"throwLaunchPads ",
"suspendLaunchPads ",
"switchTables ",
"fillArrayData ",
"SuccessorBlocks ",
"Predecessors ",
};
const char* bitMapNames[kNumBitMapKinds] = {
"Misc ",
"Use ",
"Def ",
"LiveIn ",
"BlockMatrix ",
"Dominators ",
"IDominated ",
"DomFrontier ",
"Phi ",
"TmpBlocks ",
"InputBlocks ",
"RegisterV ",
"TempSSARegisterV ",
"Null Check ",
"TmpBlockV ",
"Predecessors ",
};
#endif
#define kArenaBitVectorGrowth 4 /* increase by 4 uint32_ts when limit hit */
/* Allocate the initial memory block for arena-based allocation */
bool HeapInit(CompilationUnit* cUnit)
{
DCHECK(cUnit->arenaHead == NULL);
cUnit->arenaHead =
static_cast<ArenaMemBlock*>(malloc(sizeof(ArenaMemBlock) + ARENA_DEFAULT_SIZE));
if (cUnit->arenaHead == NULL) {
LOG(FATAL) << "No memory left to create compiler heap memory";
}
cUnit->arenaHead->blockSize = ARENA_DEFAULT_SIZE;
cUnit->currentArena = cUnit->arenaHead;
cUnit->currentArena->bytesAllocated = 0;
cUnit->currentArena->next = NULL;
cUnit->numArenaBlocks = 1;
#ifdef WITH_MEMSTATS
cUnit->mstats = (Memstats*) NewMem(cUnit, sizeof(Memstats), true,
kAllocDebugInfo);
#endif
return true;
}
/* Arena-based malloc for compilation tasks */
void* NewMem(CompilationUnit* cUnit, size_t size, bool zero, oatAllocKind kind)
{
size = (size + 3) & ~3;
#ifdef WITH_MEMSTATS
if (cUnit->mstats != NULL) {
cUnit->mstats->allocStats[kind] += size;
}
#endif
retry:
/* Normal case - space is available in the current page */
if (size + cUnit->currentArena->bytesAllocated <=
cUnit->currentArena->blockSize) {
void *ptr;
ptr = &cUnit->currentArena->ptr[cUnit->currentArena->bytesAllocated];
cUnit->currentArena->bytesAllocated += size;
if (zero) {
memset(ptr, 0, size);
}
return ptr;
} else {
/*
* See if there are previously allocated arena blocks before the last
* reset
*/
if (cUnit->currentArena->next) {
cUnit->currentArena = cUnit->currentArena->next;
cUnit->currentArena->bytesAllocated = 0;
goto retry;
}
size_t blockSize = (size < ARENA_DEFAULT_SIZE) ? ARENA_DEFAULT_SIZE : size;
/* Time to allocate a new arena */
ArenaMemBlock *newArena =
static_cast<ArenaMemBlock*>(malloc(sizeof(ArenaMemBlock) + blockSize));
if (newArena == NULL) {
LOG(FATAL) << "Arena allocation failure";
}
newArena->blockSize = blockSize;
newArena->bytesAllocated = 0;
newArena->next = NULL;
cUnit->currentArena->next = newArena;
cUnit->currentArena = newArena;
cUnit->numArenaBlocks++;
if (cUnit->numArenaBlocks > 20000) {
LOG(INFO) << "Total arena pages: " << cUnit->numArenaBlocks;
}
goto retry;
}
}
/* Reclaim all the arena blocks allocated so far */
void ArenaReset(CompilationUnit* cUnit)
{
ArenaMemBlock* head = cUnit->arenaHead;
while (head != NULL) {
ArenaMemBlock* p = head;
head = head->next;
free(p);
}
cUnit->arenaHead = NULL;
cUnit->currentArena = NULL;
}
/* Growable List initialization */
void CompilerInitGrowableList(CompilationUnit* cUnit, GrowableList* gList,
size_t initLength, oatListKind kind)
{
gList->numAllocated = initLength;
gList->numUsed = 0;
gList->elemList = static_cast<uintptr_t *>(NewMem(cUnit, sizeof(intptr_t) * initLength,
true, kAllocGrowableList));
#ifdef WITH_MEMSTATS
cUnit->mstats->listSizes[kind] += sizeof(uintptr_t) * initLength;
gList->kind = kind;
if (static_cast<int>(initLength) > cUnit->mstats->listMaxElems[kind]) {
cUnit->mstats->listMaxElems[kind] = initLength;
}
#endif
}
/* Expand the capacity of a growable list */
static void ExpandGrowableList(CompilationUnit* cUnit, GrowableList* gList)
{
int newLength = gList->numAllocated;
if (newLength < 128) {
newLength <<= 1;
} else {
newLength += 128;
}
uintptr_t *newArray =
static_cast<uintptr_t*>(NewMem(cUnit, sizeof(uintptr_t) * newLength, true,
kAllocGrowableList));
memcpy(newArray, gList->elemList, sizeof(uintptr_t) * gList->numAllocated);
#ifdef WITH_MEMSTATS
cUnit->mstats->listSizes[gList->kind] += sizeof(uintptr_t) * newLength;
cUnit->mstats->listWasted[gList->kind] +=
sizeof(uintptr_t) * gList->numAllocated;
cUnit->mstats->listGrows[gList->kind]++;
if (newLength > cUnit->mstats->listMaxElems[gList->kind]) {
cUnit->mstats->listMaxElems[gList->kind] = newLength;
}
#endif
gList->numAllocated = newLength;
gList->elemList = newArray;
}
/* Insert a new element into the growable list */
void InsertGrowableList(CompilationUnit* cUnit, GrowableList* gList,
uintptr_t elem)
{
DCHECK_NE(gList->numAllocated, 0U);
if (gList->numUsed == gList->numAllocated) {
ExpandGrowableList(cUnit, gList);
}
gList->elemList[gList->numUsed++] = elem;
}
/* Delete an element from a growable list. Element must be present */
void DeleteGrowableList(GrowableList* gList, uintptr_t elem)
{
bool found = false;
for (unsigned int i = 0; i < gList->numUsed; i++) {
if (!found && gList->elemList[i] == elem) {
found = true;
}
if (found) {
gList->elemList[i] = gList->elemList[i+1];
}
}
DCHECK_EQ(found, true);
gList->numUsed--;
}
void GrowableListIteratorInit(GrowableList* gList,
GrowableListIterator* iterator)
{
iterator->list = gList;
iterator->idx = 0;
iterator->size = gList->numUsed;
}
uintptr_t GrowableListIteratorNext(GrowableListIterator* iterator)
{
DCHECK_EQ(iterator->size, iterator->list->numUsed);
if (iterator->idx == iterator->size) return 0;
return iterator->list->elemList[iterator->idx++];
}
uintptr_t GrowableListGetElement(const GrowableList* gList, size_t idx)
{
DCHECK_LT(idx, gList->numUsed);
return gList->elemList[idx];
}
#ifdef WITH_MEMSTATS
/* Dump memory usage stats */
void DumpMemStats(CompilationUnit* cUnit)
{
uint32_t total = 0;
for (int i = 0; i < kNumAllocKinds; i++) {
total += cUnit->mstats->allocStats[i];
}
if (total > (10 * 1024 * 1024)) {
LOG(INFO) << "MEMUSAGE: " << total << " : "
<< PrettyMethod(cUnit->method_idx, *cUnit->dex_file);
LOG(INFO) << "insnsSize: " << cUnit->insnsSize;
if (cUnit->disableDataflow) {
LOG(INFO) << " ** Dataflow disabled ** ";
}
LOG(INFO) << "===== Overall allocations";
for (int i = 0; i < kNumAllocKinds; i++) {
LOG(INFO) << allocNames[i] << std::setw(10) <<
cUnit->mstats->allocStats[i];
}
LOG(INFO) << "===== GrowableList allocations";
for (int i = 0; i < kNumListKinds; i++) {
LOG(INFO) << listNames[i]
<< " S:" << cUnit->mstats->listSizes[i]
<< ", W:" << cUnit->mstats->listWasted[i]
<< ", G:" << cUnit->mstats->listGrows[i]
<< ", E:" << cUnit->mstats->listMaxElems[i];
}
LOG(INFO) << "===== GrowableBitMap allocations";
for (int i = 0; i < kNumBitMapKinds; i++) {
LOG(INFO) << bitMapNames[i]
<< " S:" << cUnit->mstats->bitMapSizes[i]
<< ", W:" << cUnit->mstats->bitMapWasted[i]
<< ", G:" << cUnit->mstats->bitMapGrows[i];
}
}
}
#endif
/* Debug Utility - dump a compilation unit */
void DumpCompilationUnit(CompilationUnit* cUnit)
{
BasicBlock* bb;
const char* blockTypeNames[] = {
"Entry Block",
"Code Block",
"Exit Block",
"Exception Handling",
"Catch Block"
};
LOG(INFO) << "Compiling " << PrettyMethod(cUnit->method_idx, *cUnit->dex_file);
LOG(INFO) << cUnit->insns << " insns";
LOG(INFO) << cUnit->numBlocks << " blocks in total";
GrowableListIterator iterator;
GrowableListIteratorInit(&cUnit->blockList, &iterator);
while (true) {
bb = reinterpret_cast<BasicBlock*>(GrowableListIteratorNext(&iterator));
if (bb == NULL) break;
LOG(INFO) << StringPrintf("Block %d (%s) (insn %04x - %04x%s)",
bb->id,
blockTypeNames[bb->blockType],
bb->startOffset,
bb->lastMIRInsn ? bb->lastMIRInsn->offset : bb->startOffset,
bb->lastMIRInsn ? "" : " empty");
if (bb->taken) {
LOG(INFO) << " Taken branch: block " << bb->taken->id
<< "(0x" << std::hex << bb->taken->startOffset << ")";
}
if (bb->fallThrough) {
LOG(INFO) << " Fallthrough : block " << bb->fallThrough->id
<< " (0x" << std::hex << bb->fallThrough->startOffset << ")";
}
}
}
static uint32_t checkMasks[32] = {
0x00000001, 0x00000002, 0x00000004, 0x00000008, 0x00000010,
0x00000020, 0x00000040, 0x00000080, 0x00000100, 0x00000200,
0x00000400, 0x00000800, 0x00001000, 0x00002000, 0x00004000,
0x00008000, 0x00010000, 0x00020000, 0x00040000, 0x00080000,
0x00100000, 0x00200000, 0x00400000, 0x00800000, 0x01000000,
0x02000000, 0x04000000, 0x08000000, 0x10000000, 0x20000000,
0x40000000, 0x80000000 };
/*
* Allocate a bit vector with enough space to hold at least the specified
* number of bits.
*
* NOTE: memory is allocated from the compiler arena.
*/
ArenaBitVector* AllocBitVector(CompilationUnit* cUnit,
unsigned int startBits, bool expandable,
oatBitMapKind kind)
{
ArenaBitVector* bv;
unsigned int count;
DCHECK_EQ(sizeof(bv->storage[0]), 4U); /* assuming 32-bit units */
bv = static_cast<ArenaBitVector*>(NewMem(cUnit, sizeof(ArenaBitVector), false,
kAllocGrowableBitMap));
count = (startBits + 31) >> 5;
bv->storageSize = count;
bv->expandable = expandable;
bv->storage = static_cast<uint32_t*>(NewMem(cUnit, count * sizeof(uint32_t), true,
kAllocGrowableBitMap));
#ifdef WITH_MEMSTATS
bv->kind = kind;
cUnit->mstats->bitMapSizes[kind] += count * sizeof(uint32_t);
#endif
return bv;
}
/*
* Determine whether or not the specified bit is set.
*/
bool IsBitSet(const ArenaBitVector* pBits, unsigned int num)
{
DCHECK_LT(num, pBits->storageSize * sizeof(uint32_t) * 8);
unsigned int val = pBits->storage[num >> 5] & checkMasks[num & 0x1f];
return (val != 0);
}
/*
* Mark all bits bit as "clear".
*/
void ClearAllBits(ArenaBitVector* pBits)
{
unsigned int count = pBits->storageSize;
memset(pBits->storage, 0, count * sizeof(uint32_t));
}
/*
* Mark the specified bit as "set".
*
* Returns "false" if the bit is outside the range of the vector and we're
* not allowed to expand.
*
* NOTE: memory is allocated from the compiler arena.
*/
bool SetBit(CompilationUnit* cUnit, ArenaBitVector* pBits, unsigned int num)
{
if (num >= pBits->storageSize * sizeof(uint32_t) * 8) {
if (!pBits->expandable) {
LOG(FATAL) << "Can't expand";
}
/* Round up to word boundaries for "num+1" bits */
unsigned int newSize = (num + 1 + 31) >> 5;
DCHECK_GT(newSize, pBits->storageSize);
uint32_t *newStorage = static_cast<uint32_t*>(NewMem(cUnit, newSize * sizeof(uint32_t), false,
kAllocGrowableBitMap));
memcpy(newStorage, pBits->storage, pBits->storageSize * sizeof(uint32_t));
memset(&newStorage[pBits->storageSize], 0,
(newSize - pBits->storageSize) * sizeof(uint32_t));
#ifdef WITH_MEMSTATS
cUnit->mstats->bitMapWasted[pBits->kind] +=
pBits->storageSize * sizeof(uint32_t);
cUnit->mstats->bitMapSizes[pBits->kind] += newSize * sizeof(uint32_t);
cUnit->mstats->bitMapGrows[pBits->kind]++;
#endif
pBits->storage = newStorage;
pBits->storageSize = newSize;
}
pBits->storage[num >> 5] |= checkMasks[num & 0x1f];
return true;
}
/*
* Mark the specified bit as "unset".
*
* Returns "false" if the bit is outside the range of the vector and we're
* not allowed to expand.
*
* NOTE: memory is allocated from the compiler arena.
*/
bool ClearBit(ArenaBitVector* pBits, unsigned int num)
{
if (num >= pBits->storageSize * sizeof(uint32_t) * 8) {
LOG(FATAL) << "Attempt to clear a bit not set in the vector yet";;
}
pBits->storage[num >> 5] &= ~checkMasks[num & 0x1f];
return true;
}
/* Initialize the iterator structure */
void BitVectorIteratorInit(ArenaBitVector* pBits,
ArenaBitVectorIterator* iterator)
{
iterator->pBits = pBits;
iterator->bitSize = pBits->storageSize * sizeof(uint32_t) * 8;
iterator->idx = 0;
}
/*
* If the vector sizes don't match, log an error and abort.
*/
static void CheckSizes(const ArenaBitVector* bv1, const ArenaBitVector* bv2)
{
if (bv1->storageSize != bv2->storageSize) {
LOG(FATAL) << "Mismatched vector sizes (" << bv1->storageSize
<< ", " << bv2->storageSize << ")";
}
}
/*
* Copy a whole vector to the other. Only do that when the both vectors have
* the same size.
*/
void CopyBitVector(ArenaBitVector* dest, const ArenaBitVector* src)
{
/* if dest is expandable and < src, we could expand dest to match */
CheckSizes(dest, src);
memcpy(dest->storage, src->storage, sizeof(uint32_t) * dest->storageSize);
}
/*
* Intersect two bit vectors and store the result to the dest vector.
*/
bool IntersectBitVectors(ArenaBitVector* dest, const ArenaBitVector* src1,
const ArenaBitVector* src2)
{
DCHECK(src1 != NULL);
DCHECK(src2 != NULL);
if (dest->storageSize != src1->storageSize ||
dest->storageSize != src2->storageSize ||
dest->expandable != src1->expandable ||
dest->expandable != src2->expandable)
return false;
unsigned int idx;
for (idx = 0; idx < dest->storageSize; idx++) {
dest->storage[idx] = src1->storage[idx] & src2->storage[idx];
}
return true;
}
/*
* Unify two bit vectors and store the result to the dest vector.
*/
bool UnifyBitVetors(ArenaBitVector* dest, const ArenaBitVector* src1,
const ArenaBitVector* src2)
{
DCHECK(src1 != NULL);
DCHECK(src2 != NULL);
if (dest->storageSize != src1->storageSize ||
dest->storageSize != src2->storageSize ||
dest->expandable != src1->expandable ||
dest->expandable != src2->expandable)
return false;
unsigned int idx;
for (idx = 0; idx < dest->storageSize; idx++) {
dest->storage[idx] = src1->storage[idx] | src2->storage[idx];
}
return true;
}
/*
* Return true if any bits collide. Vectors must be same size.
*/
bool TestBitVectors(const ArenaBitVector* src1,
const ArenaBitVector* src2)
{
DCHECK_EQ(src1->storageSize, src2->storageSize);
for (uint32_t idx = 0; idx < src1->storageSize; idx++) {
if (src1->storage[idx] & src2->storage[idx]) return true;
}
return false;
}
/*
* Compare two bit vectors and return true if difference is seen.
*/
bool CompareBitVectors(const ArenaBitVector* src1,
const ArenaBitVector* src2)
{
if (src1->storageSize != src2->storageSize ||
src1->expandable != src2->expandable)
return true;
unsigned int idx;
for (idx = 0; idx < src1->storageSize; idx++) {
if (src1->storage[idx] != src2->storage[idx]) return true;
}
return false;
}
/*
* Count the number of bits that are set.
*/
int CountSetBits(const ArenaBitVector* pBits)
{
unsigned int word;
unsigned int count = 0;
for (word = 0; word < pBits->storageSize; word++) {
uint32_t val = pBits->storage[word];
if (val != 0) {
if (val == 0xffffffff) {
count += 32;
} else {
/* count the number of '1' bits */
while (val != 0) {
val &= val - 1;
count++;
}
}
}
}
return count;
}
/* Return the next position set to 1. -1 means end-of-element reached */
int BitVectorIteratorNext(ArenaBitVectorIterator* iterator)
{
ArenaBitVector* pBits = iterator->pBits;
uint32_t bitIndex = iterator->idx;
uint32_t bitSize = iterator->bitSize;
DCHECK_EQ(bitSize, pBits->storageSize * sizeof(uint32_t) * 8);
if (bitIndex >= bitSize) return -1;
uint32_t wordIndex = bitIndex >> 5;
uint32_t endWordIndex = bitSize >> 5;
uint32_t* storage = pBits->storage;
uint32_t word = storage[wordIndex++];
// Mask out any bits in the first word we've already considered
word &= ~((1 << (bitIndex & 0x1f))-1);
for (; wordIndex <= endWordIndex;) {
uint32_t bitPos = bitIndex & 0x1f;
if (word == 0) {
bitIndex += (32 - bitPos);
word = storage[wordIndex++];
continue;
}
for (; bitPos < 32; bitPos++) {
if (word & (1 << bitPos)) {
iterator->idx = bitIndex + 1;
return bitIndex;
}
bitIndex++;
}
word = storage[wordIndex++];
}
iterator->idx = iterator->bitSize;
return -1;
}
/*
* Mark specified number of bits as "set". Cannot set all bits like ClearAll
* since there might be unused bits - setting those to one will confuse the
* iterator.
*/
void SetInitialBits(ArenaBitVector* pBits, unsigned int numBits)
{
unsigned int idx;
DCHECK_LE(((numBits + 31) >> 5), pBits->storageSize);
for (idx = 0; idx < (numBits >> 5); idx++) {
pBits->storage[idx] = -1;
}
unsigned int remNumBits = numBits & 0x1f;
if (remNumBits) {
pBits->storage[idx] = (1 << remNumBits) - 1;
}
}
void GetBlockName(BasicBlock* bb, char* name)
{
switch (bb->blockType) {
case kEntryBlock:
snprintf(name, BLOCK_NAME_LEN, "entry_%d", bb->id);
break;
case kExitBlock:
snprintf(name, BLOCK_NAME_LEN, "exit_%d", bb->id);
break;
case kDalvikByteCode:
snprintf(name, BLOCK_NAME_LEN, "block%04x_%d", bb->startOffset, bb->id);
break;
case kExceptionHandling:
snprintf(name, BLOCK_NAME_LEN, "exception%04x_%d", bb->startOffset,
bb->id);
break;
default:
snprintf(name, BLOCK_NAME_LEN, "??_%d", bb->id);
break;
}
}
const char* GetShortyFromTargetIdx(CompilationUnit *cUnit, int targetIdx)
{
const DexFile::MethodId& methodId = cUnit->dex_file->GetMethodId(targetIdx);
return cUnit->dex_file->GetShorty(methodId.proto_idx_);
}
} // namespace art