blob: 1f05a17a65404ada5435fea5452213e4536ec15f [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.
*/
namespace art {
STATIC void pushWord(std::vector<uint16_t>&buf, int data) {
buf.push_back( data & 0xffff);
buf.push_back( (data >> 16) & 0xffff);
}
void alignBuffer(std::vector<uint16_t>&buf, size_t offset) {
while (buf.size() < (offset/2))
buf.push_back(0);
}
/* Write the literal pool to the output stream */
STATIC void installLiteralPools(CompilationUnit* cUnit)
{
alignBuffer(cUnit->codeBuffer, cUnit->dataOffset);
TGT_LIR* dataLIR = (TGT_LIR*) cUnit->literalList;
while (dataLIR != NULL) {
pushWord(cUnit->codeBuffer, dataLIR->operands[0]);
dataLIR = NEXT_LIR(dataLIR);
}
}
/* Write the switch tables to the output stream */
STATIC void installSwitchTables(CompilationUnit* cUnit)
{
GrowableListIterator iterator;
oatGrowableListIteratorInit(&cUnit->switchTables, &iterator);
while (true) {
SwitchTable* tabRec = (SwitchTable *) oatGrowableListIteratorNext(
&iterator);
if (tabRec == NULL) break;
alignBuffer(cUnit->codeBuffer, tabRec->offset);
int bxOffset = tabRec->bxInst->generic.offset + 4;
if (cUnit->printMe) {
LOG(INFO) << "Switch table for offset 0x" << std::hex << bxOffset;
}
if (tabRec->table[0] == kSparseSwitchSignature) {
int* keys = (int*)&(tabRec->table[2]);
for (int elems = 0; elems < tabRec->table[1]; elems++) {
int disp = tabRec->targets[elems]->generic.offset - bxOffset;
if (cUnit->printMe) {
LOG(INFO) << " Case[" << elems << "] key: 0x" <<
std::hex << keys[elems] << ", disp: 0x" <<
std::hex << disp;
}
pushWord(cUnit->codeBuffer, keys[elems]);
pushWord(cUnit->codeBuffer,
tabRec->targets[elems]->generic.offset - bxOffset);
}
} else {
DCHECK_EQ(tabRec->table[0], kPackedSwitchSignature);
for (int elems = 0; elems < tabRec->table[1]; elems++) {
int disp = tabRec->targets[elems]->generic.offset - bxOffset;
if (cUnit->printMe) {
LOG(INFO) << " Case[" << elems << "] disp: 0x" <<
std::hex << disp;
}
pushWord(cUnit->codeBuffer,
tabRec->targets[elems]->generic.offset - bxOffset);
}
}
}
}
/* Write the fill array dta to the output stream */
STATIC void installFillArrayData(CompilationUnit* cUnit)
{
GrowableListIterator iterator;
oatGrowableListIteratorInit(&cUnit->fillArrayData, &iterator);
while (true) {
FillArrayData *tabRec = (FillArrayData *) oatGrowableListIteratorNext(
&iterator);
if (tabRec == NULL) break;
alignBuffer(cUnit->codeBuffer, tabRec->offset);
for (int i = 0; i < ((tabRec->size + 1) / 2) ; i++) {
cUnit->codeBuffer.push_back( tabRec->table[i]);
}
}
}
STATIC int assignLiteralOffsetCommon(LIR* lir, int offset)
{
for (;lir != NULL; lir = lir->next) {
lir->offset = offset;
offset += 4;
}
return offset;
}
STATIC void createMappingTable(CompilationUnit* cUnit)
{
TGT_LIR* tgtLIR;
int currentDalvikOffset = -1;
for (tgtLIR = (TGT_LIR *) cUnit->firstLIRInsn;
tgtLIR;
tgtLIR = NEXT_LIR(tgtLIR)) {
if ((tgtLIR->opcode >= 0) && !tgtLIR->flags.isNop &&
(currentDalvikOffset != tgtLIR->generic.dalvikOffset)) {
// Changed - need to emit a record
cUnit->mappingTable.push_back(tgtLIR->generic.offset);
cUnit->mappingTable.push_back(tgtLIR->generic.dalvikOffset);
currentDalvikOffset = tgtLIR->generic.dalvikOffset;
}
}
}
/* Determine the offset of each literal field */
STATIC int assignLiteralOffset(CompilationUnit* cUnit, int offset)
{
offset = assignLiteralOffsetCommon(cUnit->literalList, offset);
return offset;
}
STATIC int assignSwitchTablesOffset(CompilationUnit* cUnit, int offset)
{
GrowableListIterator iterator;
oatGrowableListIteratorInit(&cUnit->switchTables, &iterator);
while (true) {
SwitchTable *tabRec = (SwitchTable *) oatGrowableListIteratorNext(
&iterator);
if (tabRec == NULL) break;
tabRec->offset = offset;
if (tabRec->table[0] == kSparseSwitchSignature) {
offset += tabRec->table[1] * (sizeof(int) * 2);
} else {
DCHECK_EQ(tabRec->table[0], kPackedSwitchSignature);
offset += tabRec->table[1] * sizeof(int);
}
}
return offset;
}
STATIC int assignFillArrayDataOffset(CompilationUnit* cUnit, int offset)
{
GrowableListIterator iterator;
oatGrowableListIteratorInit(&cUnit->fillArrayData, &iterator);
while (true) {
FillArrayData *tabRec = (FillArrayData *) oatGrowableListIteratorNext(
&iterator);
if (tabRec == NULL) break;
tabRec->offset = offset;
offset += tabRec->size;
// word align
offset = (offset + 3) & ~3;
}
return offset;
}
/*
* Walk the compilation unit and assign offsets to instructions
* and literals and compute the total size of the compiled unit.
*/
void oatAssignOffsets(CompilationUnit* cUnit)
{
int offset = oatAssignInsnOffsets(cUnit);
/* Const values have to be word aligned */
offset = (offset + 3) & ~3;
/* Set up offsets for literals */
cUnit->dataOffset = offset;
offset = assignLiteralOffset(cUnit, offset);
offset = assignSwitchTablesOffset(cUnit, offset);
offset = assignFillArrayDataOffset(cUnit, offset);
cUnit->totalSize = offset;
}
/*
* Go over each instruction in the list and calculate the offset from the top
* before sending them off to the assembler. If out-of-range branch distance is
* seen rearrange the instructions a bit to correct it.
*/
void oatAssembleLIR(CompilationUnit* cUnit)
{
oatAssignOffsets(cUnit);
/*
* Assemble here. Note that we generate code with optimistic assumptions
* and if found now to work, we'll have to redo the sequence and retry.
*/
while (true) {
AssemblerStatus res = oatAssembleInstructions(cUnit, 0);
if (res == kSuccess) {
break;
} else {
cUnit->assemblerRetries++;
if (cUnit->assemblerRetries > MAX_ASSEMBLER_RETRIES) {
LOG(FATAL) << "Assembler error - too many retries";
}
// Redo offsets and try again
oatAssignOffsets(cUnit);
cUnit->codeBuffer.clear();
}
}
// Install literals
installLiteralPools(cUnit);
// Install switch tables
installSwitchTables(cUnit);
// Install fill array data
installFillArrayData(cUnit);
/*
* Create the mapping table
*/
createMappingTable(cUnit);
}
} // namespace art