codegen_util.cc revision fa57c47f1b72916371a9c2d5c1389219bce655b4
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 17#include "../compiler_internals.h" 18#include "gc_map.h" 19#include "verifier/dex_gc_map.h" 20#include "verifier/method_verifier.h" 21#include "ralloc_util.h" 22#include "codegen_util.h" 23 24namespace art { 25 26/* Convert an instruction to a NOP */ 27void NopLIR( LIR* lir) 28{ 29 lir->flags.is_nop = true; 30} 31 32void SetMemRefType(LIR* lir, bool is_load, int mem_type) 33{ 34 uint64_t *mask_ptr; 35 uint64_t mask = ENCODE_MEM;; 36 DCHECK(GetTargetInstFlags(lir->opcode) & (IS_LOAD | IS_STORE)); 37 if (is_load) { 38 mask_ptr = &lir->use_mask; 39 } else { 40 mask_ptr = &lir->def_mask; 41 } 42 /* Clear out the memref flags */ 43 *mask_ptr &= ~mask; 44 /* ..and then add back the one we need */ 45 switch (mem_type) { 46 case kLiteral: 47 DCHECK(is_load); 48 *mask_ptr |= ENCODE_LITERAL; 49 break; 50 case kDalvikReg: 51 *mask_ptr |= ENCODE_DALVIK_REG; 52 break; 53 case kHeapRef: 54 *mask_ptr |= ENCODE_HEAP_REF; 55 break; 56 case kMustNotAlias: 57 /* Currently only loads can be marked as kMustNotAlias */ 58 DCHECK(!(GetTargetInstFlags(lir->opcode) & IS_STORE)); 59 *mask_ptr |= ENCODE_MUST_NOT_ALIAS; 60 break; 61 default: 62 LOG(FATAL) << "Oat: invalid memref kind - " << mem_type; 63 } 64} 65 66/* 67 * Mark load/store instructions that access Dalvik registers through the stack. 68 */ 69void AnnotateDalvikRegAccess(LIR* lir, int reg_id, bool is_load, bool is64bit) 70{ 71 SetMemRefType(lir, is_load, kDalvikReg); 72 73 /* 74 * Store the Dalvik register id in alias_info. Mark the MSB if it is a 64-bit 75 * access. 76 */ 77 lir->alias_info = ENCODE_ALIAS_INFO(reg_id, is64bit); 78} 79 80/* 81 * Mark the corresponding bit(s). 82 */ 83void SetupRegMask(CompilationUnit* cu, uint64_t* mask, int reg) 84{ 85 *mask |= GetRegMaskCommon(cu, reg); 86} 87 88/* 89 * Set up the proper fields in the resource mask 90 */ 91void SetupResourceMasks(CompilationUnit* cu, LIR* lir) 92{ 93 int opcode = lir->opcode; 94 95 if (opcode <= 0) { 96 lir->use_mask = lir->def_mask = 0; 97 return; 98 } 99 100 uint64_t flags = GetTargetInstFlags(opcode); 101 102 if (flags & NEEDS_FIXUP) { 103 lir->flags.pcRelFixup = true; 104 } 105 106 /* Get the starting size of the instruction's template */ 107 lir->flags.size = GetInsnSize(lir); 108 109 /* Set up the mask for resources that are updated */ 110 if (flags & (IS_LOAD | IS_STORE)) { 111 /* Default to heap - will catch specialized classes later */ 112 SetMemRefType(lir, flags & IS_LOAD, kHeapRef); 113 } 114 115 /* 116 * Conservatively assume the branch here will call out a function that in 117 * turn will trash everything. 118 */ 119 if (flags & IS_BRANCH) { 120 lir->def_mask = lir->use_mask = ENCODE_ALL; 121 return; 122 } 123 124 if (flags & REG_DEF0) { 125 SetupRegMask(cu, &lir->def_mask, lir->operands[0]); 126 } 127 128 if (flags & REG_DEF1) { 129 SetupRegMask(cu, &lir->def_mask, lir->operands[1]); 130 } 131 132 133 if (flags & SETS_CCODES) { 134 lir->def_mask |= ENCODE_CCODE; 135 } 136 137 if (flags & (REG_USE0 | REG_USE1 | REG_USE2 | REG_USE3)) { 138 int i; 139 140 for (i = 0; i < 4; i++) { 141 if (flags & (1 << (kRegUse0 + i))) { 142 SetupRegMask(cu, &lir->use_mask, lir->operands[i]); 143 } 144 } 145 } 146 147 if (flags & USES_CCODES) { 148 lir->use_mask |= ENCODE_CCODE; 149 } 150 151 // Handle target-specific actions 152 SetupTargetResourceMasks(cu, lir); 153} 154 155/* 156 * Debugging macros 157 */ 158#define DUMP_RESOURCE_MASK(X) 159#define DUMP_SSA_REP(X) 160 161/* Pretty-print a LIR instruction */ 162void DumpLIRInsn(CompilationUnit* cu, LIR* lir, unsigned char* base_addr) 163{ 164 int offset = lir->offset; 165 int dest = lir->operands[0]; 166 const bool dump_nop = (cu->enable_debug & (1 << kDebugShowNops)); 167 168 /* Handle pseudo-ops individually, and all regular insns as a group */ 169 switch (lir->opcode) { 170 case kPseudoMethodEntry: 171 LOG(INFO) << "-------- method entry " 172 << PrettyMethod(cu->method_idx, *cu->dex_file); 173 break; 174 case kPseudoMethodExit: 175 LOG(INFO) << "-------- Method_Exit"; 176 break; 177 case kPseudoBarrier: 178 LOG(INFO) << "-------- BARRIER"; 179 break; 180 case kPseudoExtended: 181 LOG(INFO) << "-------- " << reinterpret_cast<char*>(dest); 182 break; 183 case kPseudoSSARep: 184 DUMP_SSA_REP(LOG(INFO) << "-------- kMirOpPhi: " << reinterpret_cast<char*>(dest)); 185 break; 186 case kPseudoEntryBlock: 187 LOG(INFO) << "-------- entry offset: 0x" << std::hex << dest; 188 break; 189 case kPseudoDalvikByteCodeBoundary: 190 LOG(INFO) << "-------- dalvik offset: 0x" << std::hex 191 << lir->dalvik_offset << " @ " << reinterpret_cast<char*>(lir->operands[0]); 192 break; 193 case kPseudoExitBlock: 194 LOG(INFO) << "-------- exit offset: 0x" << std::hex << dest; 195 break; 196 case kPseudoPseudoAlign4: 197 LOG(INFO) << reinterpret_cast<uintptr_t>(base_addr) + offset << " (0x" << std::hex 198 << offset << "): .align4"; 199 break; 200 case kPseudoEHBlockLabel: 201 LOG(INFO) << "Exception_Handling:"; 202 break; 203 case kPseudoTargetLabel: 204 case kPseudoNormalBlockLabel: 205 LOG(INFO) << "L" << reinterpret_cast<void*>(lir) << ":"; 206 break; 207 case kPseudoThrowTarget: 208 LOG(INFO) << "LT" << reinterpret_cast<void*>(lir) << ":"; 209 break; 210 case kPseudoIntrinsicRetry: 211 LOG(INFO) << "IR" << reinterpret_cast<void*>(lir) << ":"; 212 break; 213 case kPseudoSuspendTarget: 214 LOG(INFO) << "LS" << reinterpret_cast<void*>(lir) << ":"; 215 break; 216 case kPseudoSafepointPC: 217 LOG(INFO) << "LsafepointPC_0x" << std::hex << lir->offset << "_" << lir->dalvik_offset << ":"; 218 break; 219 case kPseudoExportedPC: 220 LOG(INFO) << "LexportedPC_0x" << std::hex << lir->offset << "_" << lir->dalvik_offset << ":"; 221 break; 222 case kPseudoCaseLabel: 223 LOG(INFO) << "LC" << reinterpret_cast<void*>(lir) << ": Case target 0x" 224 << std::hex << lir->operands[0] << "|" << std::dec << 225 lir->operands[0]; 226 break; 227 default: 228 if (lir->flags.is_nop && !dump_nop) { 229 break; 230 } else { 231 std::string op_name(BuildInsnString(GetTargetInstName(lir->opcode), 232 lir, base_addr)); 233 std::string op_operands(BuildInsnString(GetTargetInstFmt(lir->opcode), 234 lir, base_addr)); 235 LOG(INFO) << StringPrintf("%05x: %-9s%s%s", 236 reinterpret_cast<unsigned int>(base_addr + offset), 237 op_name.c_str(), op_operands.c_str(), 238 lir->flags.is_nop ? "(nop)" : ""); 239 } 240 break; 241 } 242 243 if (lir->use_mask && (!lir->flags.is_nop || dump_nop)) { 244 DUMP_RESOURCE_MASK(DumpResourceMask((LIR* ) lir, lir->use_mask, "use")); 245 } 246 if (lir->def_mask && (!lir->flags.is_nop || dump_nop)) { 247 DUMP_RESOURCE_MASK(DumpResourceMask((LIR* ) lir, lir->def_mask, "def")); 248 } 249} 250 251void DumpPromotionMap(CompilationUnit *cu) 252{ 253 int num_regs = cu->num_dalvik_registers + cu->num_compiler_temps + 1; 254 for (int i = 0; i < num_regs; i++) { 255 PromotionMap v_reg_map = cu->promotion_map[i]; 256 std::string buf; 257 if (v_reg_map.fp_location == kLocPhysReg) { 258 StringAppendF(&buf, " : s%d", v_reg_map.FpReg & FpRegMask()); 259 } 260 261 std::string buf3; 262 if (i < cu->num_dalvik_registers) { 263 StringAppendF(&buf3, "%02d", i); 264 } else if (i == cu->method_sreg) { 265 buf3 = "Method*"; 266 } else { 267 StringAppendF(&buf3, "ct%d", i - cu->num_dalvik_registers); 268 } 269 270 LOG(INFO) << StringPrintf("V[%s] -> %s%d%s", buf3.c_str(), 271 v_reg_map.core_location == kLocPhysReg ? 272 "r" : "SP+", v_reg_map.core_location == kLocPhysReg ? 273 v_reg_map.core_reg : SRegOffset(cu, i), 274 buf.c_str()); 275 } 276} 277 278/* Dump a mapping table */ 279static void DumpMappingTable(const char* table_name, const std::string& descriptor, 280 const std::string& name, const std::string& signature, 281 const std::vector<uint32_t>& v) { 282 if (v.size() > 0) { 283 std::string line(StringPrintf("\n %s %s%s_%s_table[%zu] = {", table_name, 284 descriptor.c_str(), name.c_str(), signature.c_str(), v.size())); 285 std::replace(line.begin(), line.end(), ';', '_'); 286 LOG(INFO) << line; 287 for (uint32_t i = 0; i < v.size(); i+=2) { 288 line = StringPrintf(" {0x%05x, 0x%04x},", v[i], v[i+1]); 289 LOG(INFO) << line; 290 } 291 LOG(INFO) <<" };\n\n"; 292 } 293} 294 295/* Dump instructions and constant pool contents */ 296void CodegenDump(CompilationUnit* cu) 297{ 298 LOG(INFO) << "Dumping LIR insns for " 299 << PrettyMethod(cu->method_idx, *cu->dex_file); 300 LIR* lir_insn; 301 int insns_size = cu->insns_size; 302 303 LOG(INFO) << "Regs (excluding ins) : " << cu->num_regs; 304 LOG(INFO) << "Ins : " << cu->num_ins; 305 LOG(INFO) << "Outs : " << cu->num_outs; 306 LOG(INFO) << "CoreSpills : " << cu->num_core_spills; 307 LOG(INFO) << "FPSpills : " << cu->num_fp_spills; 308 LOG(INFO) << "CompilerTemps : " << cu->num_compiler_temps; 309 LOG(INFO) << "Frame size : " << cu->frame_size; 310 LOG(INFO) << "code size is " << cu->total_size << 311 " bytes, Dalvik size is " << insns_size * 2; 312 LOG(INFO) << "expansion factor: " 313 << static_cast<float>(cu->total_size) / static_cast<float>(insns_size * 2); 314 DumpPromotionMap(cu); 315 for (lir_insn = cu->first_lir_insn; lir_insn; lir_insn = lir_insn->next) { 316 DumpLIRInsn(cu, lir_insn, 0); 317 } 318 for (lir_insn = cu->literal_list; lir_insn; lir_insn = lir_insn->next) { 319 LOG(INFO) << StringPrintf("%x (%04x): .word (%#x)", lir_insn->offset, lir_insn->offset, 320 lir_insn->operands[0]); 321 } 322 323 const DexFile::MethodId& method_id = 324 cu->dex_file->GetMethodId(cu->method_idx); 325 std::string signature(cu->dex_file->GetMethodSignature(method_id)); 326 std::string name(cu->dex_file->GetMethodName(method_id)); 327 std::string descriptor(cu->dex_file->GetMethodDeclaringClassDescriptor(method_id)); 328 329 // Dump mapping tables 330 DumpMappingTable("PC2Dex_MappingTable", descriptor, name, signature, cu->pc2dexMappingTable); 331 DumpMappingTable("Dex2PC_MappingTable", descriptor, name, signature, cu->dex2pcMappingTable); 332} 333 334 335LIR* RawLIR(CompilationUnit* cu, int dalvik_offset, int opcode, int op0, 336 int op1, int op2, int op3, int op4, LIR* target) 337{ 338 LIR* insn = static_cast<LIR*>(NewMem(cu, sizeof(LIR), true, kAllocLIR)); 339 insn->dalvik_offset = dalvik_offset; 340 insn->opcode = opcode; 341 insn->operands[0] = op0; 342 insn->operands[1] = op1; 343 insn->operands[2] = op2; 344 insn->operands[3] = op3; 345 insn->operands[4] = op4; 346 insn->target = target; 347 SetupResourceMasks(cu, insn); 348 if ((opcode == kPseudoTargetLabel) || (opcode == kPseudoSafepointPC) || 349 (opcode == kPseudoExportedPC)) { 350 // Always make labels scheduling barriers 351 insn->use_mask = insn->def_mask = ENCODE_ALL; 352 } 353 return insn; 354} 355 356/* 357 * The following are building blocks to construct low-level IRs with 0 - 4 358 * operands. 359 */ 360LIR* NewLIR0(CompilationUnit* cu, int opcode) 361{ 362 DCHECK(is_pseudo_opcode(opcode) || (GetTargetInstFlags(opcode) & NO_OPERAND)) 363 << GetTargetInstName(opcode) << " " << opcode << " " 364 << PrettyMethod(cu->method_idx, *cu->dex_file) << " " 365 << cu->current_dalvik_offset; 366 LIR* insn = RawLIR(cu, cu->current_dalvik_offset, opcode); 367 AppendLIR(cu, insn); 368 return insn; 369} 370 371LIR* NewLIR1(CompilationUnit* cu, int opcode, 372 int dest) 373{ 374 DCHECK(is_pseudo_opcode(opcode) || (GetTargetInstFlags(opcode) & IS_UNARY_OP)) 375 << GetTargetInstName(opcode) << " " << opcode << " " 376 << PrettyMethod(cu->method_idx, *cu->dex_file) << " " 377 << cu->current_dalvik_offset; 378 LIR* insn = RawLIR(cu, cu->current_dalvik_offset, opcode, dest); 379 AppendLIR(cu, insn); 380 return insn; 381} 382 383LIR* NewLIR2(CompilationUnit* cu, int opcode, 384 int dest, int src1) 385{ 386 DCHECK(is_pseudo_opcode(opcode) || (GetTargetInstFlags(opcode) & IS_BINARY_OP)) 387 << GetTargetInstName(opcode) << " " << opcode << " " 388 << PrettyMethod(cu->method_idx, *cu->dex_file) << " " 389 << cu->current_dalvik_offset; 390 LIR* insn = RawLIR(cu, cu->current_dalvik_offset, opcode, dest, src1); 391 AppendLIR(cu, insn); 392 return insn; 393} 394 395LIR* NewLIR3(CompilationUnit* cu, int opcode, 396 int dest, int src1, int src2) 397{ 398 DCHECK(is_pseudo_opcode(opcode) || (GetTargetInstFlags(opcode) & IS_TERTIARY_OP)) 399 << GetTargetInstName(opcode) << " " << opcode << " " 400 << PrettyMethod(cu->method_idx, *cu->dex_file) << " " 401 << cu->current_dalvik_offset; 402 LIR* insn = RawLIR(cu, cu->current_dalvik_offset, opcode, dest, src1, src2); 403 AppendLIR(cu, insn); 404 return insn; 405} 406 407LIR* NewLIR4(CompilationUnit* cu, int opcode, 408 int dest, int src1, int src2, int info) 409{ 410 DCHECK(is_pseudo_opcode(opcode) || (GetTargetInstFlags(opcode) & IS_QUAD_OP)) 411 << GetTargetInstName(opcode) << " " << opcode << " " 412 << PrettyMethod(cu->method_idx, *cu->dex_file) << " " 413 << cu->current_dalvik_offset; 414 LIR* insn = RawLIR(cu, cu->current_dalvik_offset, opcode, dest, src1, src2, info); 415 AppendLIR(cu, insn); 416 return insn; 417} 418 419LIR* NewLIR5(CompilationUnit* cu, int opcode, 420 int dest, int src1, int src2, int info1, int info2) 421{ 422 DCHECK(is_pseudo_opcode(opcode) || (GetTargetInstFlags(opcode) & IS_QUIN_OP)) 423 << GetTargetInstName(opcode) << " " << opcode << " " 424 << PrettyMethod(cu->method_idx, *cu->dex_file) << " " 425 << cu->current_dalvik_offset; 426 LIR* insn = RawLIR(cu, cu->current_dalvik_offset, opcode, dest, src1, src2, info1, info2); 427 AppendLIR(cu, insn); 428 return insn; 429} 430 431/* 432 * Search the existing constants in the literal pool for an exact or close match 433 * within specified delta (greater or equal to 0). 434 */ 435LIR* ScanLiteralPool(LIR* data_target, int value, unsigned int delta) 436{ 437 while (data_target) { 438 if ((static_cast<unsigned>(value - data_target->operands[0])) <= delta) 439 return data_target; 440 data_target = data_target->next; 441 } 442 return NULL; 443} 444 445/* Search the existing constants in the literal pool for an exact wide match */ 446LIR* ScanLiteralPoolWide(LIR* data_target, int val_lo, int val_hi) 447{ 448 bool lo_match = false; 449 LIR* lo_target = NULL; 450 while (data_target) { 451 if (lo_match && (data_target->operands[0] == val_hi)) { 452 return lo_target; 453 } 454 lo_match = false; 455 if (data_target->operands[0] == val_lo) { 456 lo_match = true; 457 lo_target = data_target; 458 } 459 data_target = data_target->next; 460 } 461 return NULL; 462} 463 464/* 465 * The following are building blocks to insert constants into the pool or 466 * instruction streams. 467 */ 468 469/* Add a 32-bit constant either in the constant pool */ 470LIR* AddWordData(CompilationUnit* cu, LIR* *constant_list_p, int value) 471{ 472 /* Add the constant to the literal pool */ 473 if (constant_list_p) { 474 LIR* new_value = static_cast<LIR*>(NewMem(cu, sizeof(LIR), true, kAllocData)); 475 new_value->operands[0] = value; 476 new_value->next = *constant_list_p; 477 *constant_list_p = new_value; 478 return new_value; 479 } 480 return NULL; 481} 482 483/* Add a 64-bit constant to the constant pool or mixed with code */ 484LIR* AddWideData(CompilationUnit* cu, LIR* *constant_list_p, 485 int val_lo, int val_hi) 486{ 487 AddWordData(cu, constant_list_p, val_hi); 488 return AddWordData(cu, constant_list_p, val_lo); 489} 490 491static void PushWord(std::vector<uint8_t>&buf, int data) { 492 buf.push_back( data & 0xff); 493 buf.push_back( (data >> 8) & 0xff); 494 buf.push_back( (data >> 16) & 0xff); 495 buf.push_back( (data >> 24) & 0xff); 496} 497 498static void AlignBuffer(std::vector<uint8_t>&buf, size_t offset) { 499 while (buf.size() < offset) { 500 buf.push_back(0); 501 } 502} 503 504/* Write the literal pool to the output stream */ 505static void InstallLiteralPools(CompilationUnit* cu) 506{ 507 AlignBuffer(cu->code_buffer, cu->data_offset); 508 LIR* data_lir = cu->literal_list; 509 while (data_lir != NULL) { 510 PushWord(cu->code_buffer, data_lir->operands[0]); 511 data_lir = NEXT_LIR(data_lir); 512 } 513 // Push code and method literals, record offsets for the compiler to patch. 514 data_lir = cu->code_literal_list; 515 while (data_lir != NULL) { 516 uint32_t target = data_lir->operands[0]; 517 cu->compiler->AddCodePatch(cu->dex_file, 518 cu->method_idx, 519 cu->invoke_type, 520 target, 521 static_cast<InvokeType>(data_lir->operands[1]), 522 cu->code_buffer.size()); 523 const DexFile::MethodId& id = cu->dex_file->GetMethodId(target); 524 // unique based on target to ensure code deduplication works 525 uint32_t unique_patch_value = reinterpret_cast<uint32_t>(&id); 526 PushWord(cu->code_buffer, unique_patch_value); 527 data_lir = NEXT_LIR(data_lir); 528 } 529 data_lir = cu->method_literal_list; 530 while (data_lir != NULL) { 531 uint32_t target = data_lir->operands[0]; 532 cu->compiler->AddMethodPatch(cu->dex_file, 533 cu->method_idx, 534 cu->invoke_type, 535 target, 536 static_cast<InvokeType>(data_lir->operands[1]), 537 cu->code_buffer.size()); 538 const DexFile::MethodId& id = cu->dex_file->GetMethodId(target); 539 // unique based on target to ensure code deduplication works 540 uint32_t unique_patch_value = reinterpret_cast<uint32_t>(&id); 541 PushWord(cu->code_buffer, unique_patch_value); 542 data_lir = NEXT_LIR(data_lir); 543 } 544} 545 546/* Write the switch tables to the output stream */ 547static void InstallSwitchTables(CompilationUnit* cu) 548{ 549 GrowableListIterator iterator; 550 GrowableListIteratorInit(&cu->switch_tables, &iterator); 551 while (true) { 552 SwitchTable* tab_rec = reinterpret_cast<SwitchTable*>(GrowableListIteratorNext( &iterator)); 553 if (tab_rec == NULL) break; 554 AlignBuffer(cu->code_buffer, tab_rec->offset); 555 /* 556 * For Arm, our reference point is the address of the bx 557 * instruction that does the launch, so we have to subtract 558 * the auto pc-advance. For other targets the reference point 559 * is a label, so we can use the offset as-is. 560 */ 561 int bx_offset = INVALID_OFFSET; 562 switch (cu->instruction_set) { 563 case kThumb2: 564 bx_offset = tab_rec->anchor->offset + 4; 565 break; 566 case kX86: 567 bx_offset = 0; 568 break; 569 case kMips: 570 bx_offset = tab_rec->anchor->offset; 571 break; 572 default: LOG(FATAL) << "Unexpected instruction set: " << cu->instruction_set; 573 } 574 if (cu->verbose) { 575 LOG(INFO) << "Switch table for offset 0x" << std::hex << bx_offset; 576 } 577 if (tab_rec->table[0] == Instruction::kSparseSwitchSignature) { 578 const int* keys = reinterpret_cast<const int*>(&(tab_rec->table[2])); 579 for (int elems = 0; elems < tab_rec->table[1]; elems++) { 580 int disp = tab_rec->targets[elems]->offset - bx_offset; 581 if (cu->verbose) { 582 LOG(INFO) << " Case[" << elems << "] key: 0x" 583 << std::hex << keys[elems] << ", disp: 0x" 584 << std::hex << disp; 585 } 586 PushWord(cu->code_buffer, keys[elems]); 587 PushWord(cu->code_buffer, 588 tab_rec->targets[elems]->offset - bx_offset); 589 } 590 } else { 591 DCHECK_EQ(static_cast<int>(tab_rec->table[0]), 592 static_cast<int>(Instruction::kPackedSwitchSignature)); 593 for (int elems = 0; elems < tab_rec->table[1]; elems++) { 594 int disp = tab_rec->targets[elems]->offset - bx_offset; 595 if (cu->verbose) { 596 LOG(INFO) << " Case[" << elems << "] disp: 0x" 597 << std::hex << disp; 598 } 599 PushWord(cu->code_buffer, tab_rec->targets[elems]->offset - bx_offset); 600 } 601 } 602 } 603} 604 605/* Write the fill array dta to the output stream */ 606static void InstallFillArrayData(CompilationUnit* cu) 607{ 608 GrowableListIterator iterator; 609 GrowableListIteratorInit(&cu->fill_array_data, &iterator); 610 while (true) { 611 FillArrayData *tab_rec = 612 reinterpret_cast<FillArrayData*>(GrowableListIteratorNext( &iterator)); 613 if (tab_rec == NULL) break; 614 AlignBuffer(cu->code_buffer, tab_rec->offset); 615 for (int i = 0; i < (tab_rec->size + 1) / 2; i++) { 616 cu->code_buffer.push_back( tab_rec->table[i] & 0xFF); 617 cu->code_buffer.push_back( (tab_rec->table[i] >> 8) & 0xFF); 618 } 619 } 620} 621 622static int AssignLiteralOffsetCommon(LIR* lir, int offset) 623{ 624 for (;lir != NULL; lir = lir->next) { 625 lir->offset = offset; 626 offset += 4; 627 } 628 return offset; 629} 630 631// Make sure we have a code address for every declared catch entry 632static bool VerifyCatchEntries(CompilationUnit* cu) 633{ 634 bool success = true; 635 for (std::set<uint32_t>::const_iterator it = cu->catches.begin(); it != cu->catches.end(); ++it) { 636 uint32_t dex_pc = *it; 637 bool found = false; 638 for (size_t i = 0; i < cu->dex2pcMappingTable.size(); i += 2) { 639 if (dex_pc == cu->dex2pcMappingTable[i+1]) { 640 found = true; 641 break; 642 } 643 } 644 if (!found) { 645 LOG(INFO) << "Missing native PC for catch entry @ 0x" << std::hex << dex_pc; 646 success = false; 647 } 648 } 649 // Now, try in the other direction 650 for (size_t i = 0; i < cu->dex2pcMappingTable.size(); i += 2) { 651 uint32_t dex_pc = cu->dex2pcMappingTable[i+1]; 652 if (cu->catches.find(dex_pc) == cu->catches.end()) { 653 LOG(INFO) << "Unexpected catch entry @ dex pc 0x" << std::hex << dex_pc; 654 success = false; 655 } 656 } 657 if (!success) { 658 LOG(INFO) << "Bad dex2pcMapping table in " << PrettyMethod(cu->method_idx, *cu->dex_file); 659 LOG(INFO) << "Entries @ decode: " << cu->catches.size() << ", Entries in table: " 660 << cu->dex2pcMappingTable.size()/2; 661 } 662 return success; 663} 664 665static void CreateMappingTables(CompilationUnit* cu) 666{ 667 for (LIR* tgt_lir = cu->first_lir_insn; tgt_lir != NULL; tgt_lir = NEXT_LIR(tgt_lir)) { 668 if (!tgt_lir->flags.is_nop && (tgt_lir->opcode == kPseudoSafepointPC)) { 669 cu->pc2dexMappingTable.push_back(tgt_lir->offset); 670 cu->pc2dexMappingTable.push_back(tgt_lir->dalvik_offset); 671 } 672 if (!tgt_lir->flags.is_nop && (tgt_lir->opcode == kPseudoExportedPC)) { 673 cu->dex2pcMappingTable.push_back(tgt_lir->offset); 674 cu->dex2pcMappingTable.push_back(tgt_lir->dalvik_offset); 675 } 676 } 677 DCHECK(VerifyCatchEntries(cu)); 678 cu->combined_mapping_table.push_back(cu->pc2dexMappingTable.size() + 679 cu->dex2pcMappingTable.size()); 680 cu->combined_mapping_table.push_back(cu->pc2dexMappingTable.size()); 681 cu->combined_mapping_table.insert(cu->combined_mapping_table.end(), 682 cu->pc2dexMappingTable.begin(), 683 cu->pc2dexMappingTable.end()); 684 cu->combined_mapping_table.insert(cu->combined_mapping_table.end(), 685 cu->dex2pcMappingTable.begin(), 686 cu->dex2pcMappingTable.end()); 687} 688 689class NativePcToReferenceMapBuilder { 690 public: 691 NativePcToReferenceMapBuilder(std::vector<uint8_t>* table, 692 size_t entries, uint32_t max_native_offset, 693 size_t references_width) : entries_(entries), 694 references_width_(references_width), in_use_(entries), 695 table_(table) { 696 // Compute width in bytes needed to hold max_native_offset. 697 native_offset_width_ = 0; 698 while (max_native_offset != 0) { 699 native_offset_width_++; 700 max_native_offset >>= 8; 701 } 702 // Resize table and set up header. 703 table->resize((EntryWidth() * entries) + sizeof(uint32_t)); 704 CHECK_LT(native_offset_width_, 1U << 3); 705 (*table)[0] = native_offset_width_ & 7; 706 CHECK_LT(references_width_, 1U << 13); 707 (*table)[0] |= (references_width_ << 3) & 0xFF; 708 (*table)[1] = (references_width_ >> 5) & 0xFF; 709 CHECK_LT(entries, 1U << 16); 710 (*table)[2] = entries & 0xFF; 711 (*table)[3] = (entries >> 8) & 0xFF; 712 } 713 714 void AddEntry(uint32_t native_offset, const uint8_t* references) { 715 size_t table_index = TableIndex(native_offset); 716 while (in_use_[table_index]) { 717 table_index = (table_index + 1) % entries_; 718 } 719 in_use_[table_index] = true; 720 SetNativeOffset(table_index, native_offset); 721 DCHECK_EQ(native_offset, GetNativeOffset(table_index)); 722 SetReferences(table_index, references); 723 } 724 725 private: 726 size_t TableIndex(uint32_t native_offset) { 727 return NativePcOffsetToReferenceMap::Hash(native_offset) % entries_; 728 } 729 730 uint32_t GetNativeOffset(size_t table_index) { 731 uint32_t native_offset = 0; 732 size_t table_offset = (table_index * EntryWidth()) + sizeof(uint32_t); 733 for (size_t i = 0; i < native_offset_width_; i++) { 734 native_offset |= (*table_)[table_offset + i] << (i * 8); 735 } 736 return native_offset; 737 } 738 739 void SetNativeOffset(size_t table_index, uint32_t native_offset) { 740 size_t table_offset = (table_index * EntryWidth()) + sizeof(uint32_t); 741 for (size_t i = 0; i < native_offset_width_; i++) { 742 (*table_)[table_offset + i] = (native_offset >> (i * 8)) & 0xFF; 743 } 744 } 745 746 void SetReferences(size_t table_index, const uint8_t* references) { 747 size_t table_offset = (table_index * EntryWidth()) + sizeof(uint32_t); 748 memcpy(&(*table_)[table_offset + native_offset_width_], references, references_width_); 749 } 750 751 size_t EntryWidth() const { 752 return native_offset_width_ + references_width_; 753 } 754 755 // Number of entries in the table. 756 const size_t entries_; 757 // Number of bytes used to encode the reference bitmap. 758 const size_t references_width_; 759 // Number of bytes used to encode a native offset. 760 size_t native_offset_width_; 761 // Entries that are in use. 762 std::vector<bool> in_use_; 763 // The table we're building. 764 std::vector<uint8_t>* const table_; 765}; 766 767static void CreateNativeGcMap(CompilationUnit* cu) { 768 const std::vector<uint32_t>& mapping_table = cu->pc2dexMappingTable; 769 uint32_t max_native_offset = 0; 770 for (size_t i = 0; i < mapping_table.size(); i += 2) { 771 uint32_t native_offset = mapping_table[i + 0]; 772 if (native_offset > max_native_offset) { 773 max_native_offset = native_offset; 774 } 775 } 776 Compiler::MethodReference method_ref(cu->dex_file, cu->method_idx); 777 const std::vector<uint8_t>* gc_map_raw = verifier::MethodVerifier::GetDexGcMap(method_ref); 778 verifier::DexPcToReferenceMap dex_gc_map(&(*gc_map_raw)[4], gc_map_raw->size() - 4); 779 // Compute native offset to references size. 780 NativePcToReferenceMapBuilder native_gc_map_builder(&cu->native_gc_map, 781 mapping_table.size() / 2, max_native_offset, 782 dex_gc_map.RegWidth()); 783 784 for (size_t i = 0; i < mapping_table.size(); i += 2) { 785 uint32_t native_offset = mapping_table[i + 0]; 786 uint32_t dex_pc = mapping_table[i + 1]; 787 const uint8_t* references = dex_gc_map.FindBitMap(dex_pc, false); 788 CHECK(references != NULL) << "Missing ref for dex pc 0x" << std::hex << dex_pc; 789 native_gc_map_builder.AddEntry(native_offset, references); 790 } 791} 792 793/* Determine the offset of each literal field */ 794static int AssignLiteralOffset(CompilationUnit* cu, int offset) 795{ 796 offset = AssignLiteralOffsetCommon(cu->literal_list, offset); 797 offset = AssignLiteralOffsetCommon(cu->code_literal_list, offset); 798 offset = AssignLiteralOffsetCommon(cu->method_literal_list, offset); 799 return offset; 800} 801 802static int AssignSwitchTablesOffset(CompilationUnit* cu, int offset) 803{ 804 GrowableListIterator iterator; 805 GrowableListIteratorInit(&cu->switch_tables, &iterator); 806 while (true) { 807 SwitchTable *tab_rec = reinterpret_cast<SwitchTable*>(GrowableListIteratorNext(&iterator)); 808 if (tab_rec == NULL) break; 809 tab_rec->offset = offset; 810 if (tab_rec->table[0] == Instruction::kSparseSwitchSignature) { 811 offset += tab_rec->table[1] * (sizeof(int) * 2); 812 } else { 813 DCHECK_EQ(static_cast<int>(tab_rec->table[0]), 814 static_cast<int>(Instruction::kPackedSwitchSignature)); 815 offset += tab_rec->table[1] * sizeof(int); 816 } 817 } 818 return offset; 819} 820 821static int AssignFillArrayDataOffset(CompilationUnit* cu, int offset) 822{ 823 GrowableListIterator iterator; 824 GrowableListIteratorInit(&cu->fill_array_data, &iterator); 825 while (true) { 826 FillArrayData *tab_rec = 827 reinterpret_cast<FillArrayData*>(GrowableListIteratorNext(&iterator)); 828 if (tab_rec == NULL) break; 829 tab_rec->offset = offset; 830 offset += tab_rec->size; 831 // word align 832 offset = (offset + 3) & ~3; 833 } 834 return offset; 835} 836 837/* 838 * Walk the compilation unit and assign offsets to instructions 839 * and literals and compute the total size of the compiled unit. 840 */ 841static void AssignOffsets(CompilationUnit* cu) 842{ 843 int offset = AssignInsnOffsets(cu); 844 845 /* Const values have to be word aligned */ 846 offset = (offset + 3) & ~3; 847 848 /* Set up offsets for literals */ 849 cu->data_offset = offset; 850 851 offset = AssignLiteralOffset(cu, offset); 852 853 offset = AssignSwitchTablesOffset(cu, offset); 854 855 offset = AssignFillArrayDataOffset(cu, offset); 856 857 cu->total_size = offset; 858} 859 860/* 861 * Go over each instruction in the list and calculate the offset from the top 862 * before sending them off to the assembler. If out-of-range branch distance is 863 * seen rearrange the instructions a bit to correct it. 864 */ 865void AssembleLIR(CompilationUnit* cu) 866{ 867 AssignOffsets(cu); 868 /* 869 * Assemble here. Note that we generate code with optimistic assumptions 870 * and if found now to work, we'll have to redo the sequence and retry. 871 */ 872 873 while (true) { 874 AssemblerStatus res = AssembleInstructions(cu, 0); 875 if (res == kSuccess) { 876 break; 877 } else { 878 cu->assembler_retries++; 879 if (cu->assembler_retries > MAX_ASSEMBLER_RETRIES) { 880 CodegenDump(cu); 881 LOG(FATAL) << "Assembler error - too many retries"; 882 } 883 // Redo offsets and try again 884 AssignOffsets(cu); 885 cu->code_buffer.clear(); 886 } 887 } 888 889 // Install literals 890 InstallLiteralPools(cu); 891 892 // Install switch tables 893 InstallSwitchTables(cu); 894 895 // Install fill array data 896 InstallFillArrayData(cu); 897 898 // Create the mapping table and native offset to reference map. 899 CreateMappingTables(cu); 900 901 CreateNativeGcMap(cu); 902} 903 904/* 905 * Insert a kPseudoCaseLabel at the beginning of the Dalvik 906 * offset vaddr. This label will be used to fix up the case 907 * branch table during the assembly phase. Be sure to set 908 * all resource flags on this to prevent code motion across 909 * target boundaries. KeyVal is just there for debugging. 910 */ 911static LIR* InsertCaseLabel(CompilationUnit* cu, int vaddr, int keyVal) 912{ 913 SafeMap<unsigned int, LIR*>::iterator it; 914 it = cu->boundary_map.find(vaddr); 915 if (it == cu->boundary_map.end()) { 916 LOG(FATAL) << "Error: didn't find vaddr 0x" << std::hex << vaddr; 917 } 918 LIR* new_label = static_cast<LIR*>(NewMem(cu, sizeof(LIR), true, kAllocLIR)); 919 new_label->dalvik_offset = vaddr; 920 new_label->opcode = kPseudoCaseLabel; 921 new_label->operands[0] = keyVal; 922 InsertLIRAfter(it->second, new_label); 923 return new_label; 924} 925 926static void MarkPackedCaseLabels(CompilationUnit* cu, SwitchTable *tab_rec) 927{ 928 const uint16_t* table = tab_rec->table; 929 int base_vaddr = tab_rec->vaddr; 930 const int *targets = reinterpret_cast<const int*>(&table[4]); 931 int entries = table[1]; 932 int low_key = s4FromSwitchData(&table[2]); 933 for (int i = 0; i < entries; i++) { 934 tab_rec->targets[i] = InsertCaseLabel(cu, base_vaddr + targets[i], i + low_key); 935 } 936} 937 938static void MarkSparseCaseLabels(CompilationUnit* cu, SwitchTable *tab_rec) 939{ 940 const uint16_t* table = tab_rec->table; 941 int base_vaddr = tab_rec->vaddr; 942 int entries = table[1]; 943 const int* keys = reinterpret_cast<const int*>(&table[2]); 944 const int* targets = &keys[entries]; 945 for (int i = 0; i < entries; i++) { 946 tab_rec->targets[i] = InsertCaseLabel(cu, base_vaddr + targets[i], keys[i]); 947 } 948} 949 950void ProcessSwitchTables(CompilationUnit* cu) 951{ 952 GrowableListIterator iterator; 953 GrowableListIteratorInit(&cu->switch_tables, &iterator); 954 while (true) { 955 SwitchTable *tab_rec = 956 reinterpret_cast<SwitchTable*>(GrowableListIteratorNext(&iterator)); 957 if (tab_rec == NULL) break; 958 if (tab_rec->table[0] == Instruction::kPackedSwitchSignature) { 959 MarkPackedCaseLabels(cu, tab_rec); 960 } else if (tab_rec->table[0] == Instruction::kSparseSwitchSignature) { 961 MarkSparseCaseLabels(cu, tab_rec); 962 } else { 963 LOG(FATAL) << "Invalid switch table"; 964 } 965 } 966} 967 968void DumpSparseSwitchTable(const uint16_t* table) 969 /* 970 * Sparse switch data format: 971 * ushort ident = 0x0200 magic value 972 * ushort size number of entries in the table; > 0 973 * int keys[size] keys, sorted low-to-high; 32-bit aligned 974 * int targets[size] branch targets, relative to switch opcode 975 * 976 * Total size is (2+size*4) 16-bit code units. 977 */ 978{ 979 uint16_t ident = table[0]; 980 int entries = table[1]; 981 const int* keys = reinterpret_cast<const int*>(&table[2]); 982 const int* targets = &keys[entries]; 983 LOG(INFO) << "Sparse switch table - ident:0x" << std::hex << ident 984 << ", entries: " << std::dec << entries; 985 for (int i = 0; i < entries; i++) { 986 LOG(INFO) << " Key[" << keys[i] << "] -> 0x" << std::hex << targets[i]; 987 } 988} 989 990void DumpPackedSwitchTable(const uint16_t* table) 991 /* 992 * Packed switch data format: 993 * ushort ident = 0x0100 magic value 994 * ushort size number of entries in the table 995 * int first_key first (and lowest) switch case value 996 * int targets[size] branch targets, relative to switch opcode 997 * 998 * Total size is (4+size*2) 16-bit code units. 999 */ 1000{ 1001 uint16_t ident = table[0]; 1002 const int* targets = reinterpret_cast<const int*>(&table[4]); 1003 int entries = table[1]; 1004 int low_key = s4FromSwitchData(&table[2]); 1005 LOG(INFO) << "Packed switch table - ident:0x" << std::hex << ident 1006 << ", entries: " << std::dec << entries << ", low_key: " << low_key; 1007 for (int i = 0; i < entries; i++) { 1008 LOG(INFO) << " Key[" << (i + low_key) << "] -> 0x" << std::hex 1009 << targets[i]; 1010 } 1011} 1012 1013/* 1014 * Set up special LIR to mark a Dalvik byte-code instruction start and 1015 * record it in the boundary_map. NOTE: in cases such as kMirOpCheck in 1016 * which we split a single Dalvik instruction, only the first MIR op 1017 * associated with a Dalvik PC should be entered into the map. 1018 */ 1019LIR* MarkBoundary(CompilationUnit* cu, int offset, const char* inst_str) 1020{ 1021 LIR* res = NewLIR1(cu, kPseudoDalvikByteCodeBoundary, reinterpret_cast<uintptr_t>(inst_str)); 1022 if (cu->boundary_map.find(offset) == cu->boundary_map.end()) { 1023 cu->boundary_map.Put(offset, res); 1024 } 1025 return res; 1026} 1027 1028} 1029 // namespace art 1030