codegen_util.cc revision e3acd07f28d5625062b599c2817cb5f7a53f54a9
1/* 2 * Copyright (C) 2011 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 17namespace art { 18 19STATIC void pushWord(std::vector<uint16_t>&buf, int data) { 20 buf.push_back( data & 0xffff); 21 buf.push_back( (data >> 16) & 0xffff); 22} 23 24void alignBuffer(std::vector<uint16_t>&buf, size_t offset) { 25 while (buf.size() < (offset/2)) 26 buf.push_back(0); 27} 28 29/* Write the literal pool to the output stream */ 30STATIC void installLiteralPools(CompilationUnit* cUnit) 31{ 32 alignBuffer(cUnit->codeBuffer, cUnit->dataOffset); 33 TGT_LIR* dataLIR = (TGT_LIR*) cUnit->literalList; 34 while (dataLIR != NULL) { 35 pushWord(cUnit->codeBuffer, dataLIR->operands[0]); 36 dataLIR = NEXT_LIR(dataLIR); 37 } 38} 39 40/* Write the switch tables to the output stream */ 41STATIC void installSwitchTables(CompilationUnit* cUnit) 42{ 43 GrowableListIterator iterator; 44 oatGrowableListIteratorInit(&cUnit->switchTables, &iterator); 45 while (true) { 46 SwitchTable* tabRec = (SwitchTable *) oatGrowableListIteratorNext( 47 &iterator); 48 if (tabRec == NULL) break; 49 alignBuffer(cUnit->codeBuffer, tabRec->offset); 50 int bxOffset = tabRec->bxInst->generic.offset + 4; 51 if (cUnit->printMe) { 52 LOG(INFO) << "Switch table for offset 0x" << std::hex << bxOffset; 53 } 54 if (tabRec->table[0] == kSparseSwitchSignature) { 55 int* keys = (int*)&(tabRec->table[2]); 56 for (int elems = 0; elems < tabRec->table[1]; elems++) { 57 int disp = tabRec->targets[elems]->generic.offset - bxOffset; 58 if (cUnit->printMe) { 59 LOG(INFO) << " Case[" << elems << "] key: 0x" << 60 std::hex << keys[elems] << ", disp: 0x" << 61 std::hex << disp; 62 } 63 pushWord(cUnit->codeBuffer, keys[elems]); 64 pushWord(cUnit->codeBuffer, 65 tabRec->targets[elems]->generic.offset - bxOffset); 66 } 67 } else { 68 DCHECK_EQ(tabRec->table[0], kPackedSwitchSignature); 69 for (int elems = 0; elems < tabRec->table[1]; elems++) { 70 int disp = tabRec->targets[elems]->generic.offset - bxOffset; 71 if (cUnit->printMe) { 72 LOG(INFO) << " Case[" << elems << "] disp: 0x" << 73 std::hex << disp; 74 } 75 pushWord(cUnit->codeBuffer, 76 tabRec->targets[elems]->generic.offset - bxOffset); 77 } 78 } 79 } 80} 81 82/* Write the fill array dta to the output stream */ 83STATIC void installFillArrayData(CompilationUnit* cUnit) 84{ 85 GrowableListIterator iterator; 86 oatGrowableListIteratorInit(&cUnit->fillArrayData, &iterator); 87 while (true) { 88 FillArrayData *tabRec = (FillArrayData *) oatGrowableListIteratorNext( 89 &iterator); 90 if (tabRec == NULL) break; 91 alignBuffer(cUnit->codeBuffer, tabRec->offset); 92 for (int i = 0; i < ((tabRec->size + 1) / 2) ; i++) { 93 cUnit->codeBuffer.push_back( tabRec->table[i]); 94 } 95 } 96} 97 98STATIC int assignLiteralOffsetCommon(LIR* lir, int offset) 99{ 100 for (;lir != NULL; lir = lir->next) { 101 lir->offset = offset; 102 offset += 4; 103 } 104 return offset; 105} 106 107STATIC void createMappingTable(CompilationUnit* cUnit) 108{ 109 TGT_LIR* tgtLIR; 110 int currentDalvikOffset = -1; 111 112 for (tgtLIR = (TGT_LIR *) cUnit->firstLIRInsn; 113 tgtLIR; 114 tgtLIR = NEXT_LIR(tgtLIR)) { 115 if ((tgtLIR->opcode >= 0) && !tgtLIR->flags.isNop && 116 (currentDalvikOffset != tgtLIR->generic.dalvikOffset)) { 117 // Changed - need to emit a record 118 cUnit->mappingTable.push_back(tgtLIR->generic.offset); 119 cUnit->mappingTable.push_back(tgtLIR->generic.dalvikOffset); 120 currentDalvikOffset = tgtLIR->generic.dalvikOffset; 121 } 122 } 123} 124 125/* Determine the offset of each literal field */ 126STATIC int assignLiteralOffset(CompilationUnit* cUnit, int offset) 127{ 128 offset = assignLiteralOffsetCommon(cUnit->literalList, offset); 129 return offset; 130} 131 132STATIC int assignSwitchTablesOffset(CompilationUnit* cUnit, int offset) 133{ 134 GrowableListIterator iterator; 135 oatGrowableListIteratorInit(&cUnit->switchTables, &iterator); 136 while (true) { 137 SwitchTable *tabRec = (SwitchTable *) oatGrowableListIteratorNext( 138 &iterator); 139 if (tabRec == NULL) break; 140 tabRec->offset = offset; 141 if (tabRec->table[0] == kSparseSwitchSignature) { 142 offset += tabRec->table[1] * (sizeof(int) * 2); 143 } else { 144 DCHECK_EQ(tabRec->table[0], kPackedSwitchSignature); 145 offset += tabRec->table[1] * sizeof(int); 146 } 147 } 148 return offset; 149} 150 151STATIC int assignFillArrayDataOffset(CompilationUnit* cUnit, int offset) 152{ 153 GrowableListIterator iterator; 154 oatGrowableListIteratorInit(&cUnit->fillArrayData, &iterator); 155 while (true) { 156 FillArrayData *tabRec = (FillArrayData *) oatGrowableListIteratorNext( 157 &iterator); 158 if (tabRec == NULL) break; 159 tabRec->offset = offset; 160 offset += tabRec->size; 161 // word align 162 offset = (offset + 3) & ~3; 163 } 164 return offset; 165} 166 167/* 168 * Walk the compilation unit and assign offsets to instructions 169 * and literals and compute the total size of the compiled unit. 170 */ 171void oatAssignOffsets(CompilationUnit* cUnit) 172{ 173 int offset = oatAssignInsnOffsets(cUnit); 174 175 /* Const values have to be word aligned */ 176 offset = (offset + 3) & ~3; 177 178 /* Set up offsets for literals */ 179 cUnit->dataOffset = offset; 180 181 offset = assignLiteralOffset(cUnit, offset); 182 183 offset = assignSwitchTablesOffset(cUnit, offset); 184 185 offset = assignFillArrayDataOffset(cUnit, offset); 186 187 cUnit->totalSize = offset; 188} 189 190/* 191 * Go over each instruction in the list and calculate the offset from the top 192 * before sending them off to the assembler. If out-of-range branch distance is 193 * seen rearrange the instructions a bit to correct it. 194 */ 195void oatAssembleLIR(CompilationUnit* cUnit) 196{ 197 oatAssignOffsets(cUnit); 198 /* 199 * Assemble here. Note that we generate code with optimistic assumptions 200 * and if found now to work, we'll have to redo the sequence and retry. 201 */ 202 203 while (true) { 204 AssemblerStatus res = oatAssembleInstructions(cUnit, 0); 205 if (res == kSuccess) { 206 break; 207 } else { 208 cUnit->assemblerRetries++; 209 if (cUnit->assemblerRetries > MAX_ASSEMBLER_RETRIES) { 210 LOG(FATAL) << "Assembler error - too many retries"; 211 } 212 // Redo offsets and try again 213 oatAssignOffsets(cUnit); 214 cUnit->codeBuffer.clear(); 215 } 216 } 217 218 // Install literals 219 installLiteralPools(cUnit); 220 221 // Install switch tables 222 installSwitchTables(cUnit); 223 224 // Install fill array data 225 installFillArrayData(cUnit); 226 227 /* 228 * Create the mapping table 229 */ 230 createMappingTable(cUnit); 231} 232 233 234 235} // namespace art 236