1 /* 2 * Copyright (C) 2012 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 #include "dex/compiler_ir.h" 17 #include "dex/compiler_internals.h" 18 #include "dex/quick/arm/arm_lir.h" 19 #include "dex/quick/mir_to_lir-inl.h" 20 #include "entrypoints/quick/quick_entrypoints.h" 21 #include "mirror/array.h" 22 #include "mirror/object_array-inl.h" 23 #include "mirror/object-inl.h" 24 #include "mirror/object_reference.h" 25 #include "verifier/method_verifier.h" 26 #include <functional> 27 28 namespace art { 29 30 // Shortcuts to repeatedly used long types. 31 typedef mirror::ObjectArray<mirror::Object> ObjArray; 32 typedef mirror::ObjectArray<mirror::Class> ClassArray; 33 34 /* 35 * This source files contains "gen" codegen routines that should 36 * be applicable to most targets. Only mid-level support utilities 37 * and "op" calls may be used here. 38 */ 39 40 /* 41 * Generate a kPseudoBarrier marker to indicate the boundary of special 42 * blocks. 43 */ 44 void Mir2Lir::GenBarrier() { 45 LIR* barrier = NewLIR0(kPseudoBarrier); 46 /* Mark all resources as being clobbered */ 47 DCHECK(!barrier->flags.use_def_invalid); 48 barrier->u.m.def_mask = &kEncodeAll; 49 } 50 51 void Mir2Lir::GenDivZeroException() { 52 LIR* branch = OpUnconditionalBranch(nullptr); 53 AddDivZeroCheckSlowPath(branch); 54 } 55 56 void Mir2Lir::GenDivZeroCheck(ConditionCode c_code) { 57 LIR* branch = OpCondBranch(c_code, nullptr); 58 AddDivZeroCheckSlowPath(branch); 59 } 60 61 void Mir2Lir::GenDivZeroCheck(RegStorage reg) { 62 LIR* branch = OpCmpImmBranch(kCondEq, reg, 0, nullptr); 63 AddDivZeroCheckSlowPath(branch); 64 } 65 66 void Mir2Lir::AddDivZeroCheckSlowPath(LIR* branch) { 67 class DivZeroCheckSlowPath : public Mir2Lir::LIRSlowPath { 68 public: 69 DivZeroCheckSlowPath(Mir2Lir* m2l, LIR* branch) 70 : LIRSlowPath(m2l, m2l->GetCurrentDexPc(), branch) { 71 } 72 73 void Compile() OVERRIDE { 74 m2l_->ResetRegPool(); 75 m2l_->ResetDefTracking(); 76 GenerateTargetLabel(kPseudoThrowTarget); 77 m2l_->CallRuntimeHelper(kQuickThrowDivZero, true); 78 } 79 }; 80 81 AddSlowPath(new (arena_) DivZeroCheckSlowPath(this, branch)); 82 } 83 84 void Mir2Lir::GenArrayBoundsCheck(RegStorage index, RegStorage length) { 85 class ArrayBoundsCheckSlowPath : public Mir2Lir::LIRSlowPath { 86 public: 87 ArrayBoundsCheckSlowPath(Mir2Lir* m2l, LIR* branch, RegStorage index, RegStorage length) 88 : LIRSlowPath(m2l, m2l->GetCurrentDexPc(), branch), 89 index_(index), length_(length) { 90 } 91 92 void Compile() OVERRIDE { 93 m2l_->ResetRegPool(); 94 m2l_->ResetDefTracking(); 95 GenerateTargetLabel(kPseudoThrowTarget); 96 m2l_->CallRuntimeHelperRegReg(kQuickThrowArrayBounds, index_, length_, true); 97 } 98 99 private: 100 const RegStorage index_; 101 const RegStorage length_; 102 }; 103 104 LIR* branch = OpCmpBranch(kCondUge, index, length, nullptr); 105 AddSlowPath(new (arena_) ArrayBoundsCheckSlowPath(this, branch, index, length)); 106 } 107 108 void Mir2Lir::GenArrayBoundsCheck(int index, RegStorage length) { 109 class ArrayBoundsCheckSlowPath : public Mir2Lir::LIRSlowPath { 110 public: 111 ArrayBoundsCheckSlowPath(Mir2Lir* m2l, LIR* branch, int index, RegStorage length) 112 : LIRSlowPath(m2l, m2l->GetCurrentDexPc(), branch), 113 index_(index), length_(length) { 114 } 115 116 void Compile() OVERRIDE { 117 m2l_->ResetRegPool(); 118 m2l_->ResetDefTracking(); 119 GenerateTargetLabel(kPseudoThrowTarget); 120 121 RegStorage arg1_32 = m2l_->TargetReg(kArg1, kNotWide); 122 RegStorage arg0_32 = m2l_->TargetReg(kArg0, kNotWide); 123 124 m2l_->OpRegCopy(arg1_32, length_); 125 m2l_->LoadConstant(arg0_32, index_); 126 m2l_->CallRuntimeHelperRegReg(kQuickThrowArrayBounds, arg0_32, arg1_32, true); 127 } 128 129 private: 130 const int32_t index_; 131 const RegStorage length_; 132 }; 133 134 LIR* branch = OpCmpImmBranch(kCondLs, length, index, nullptr); 135 AddSlowPath(new (arena_) ArrayBoundsCheckSlowPath(this, branch, index, length)); 136 } 137 138 LIR* Mir2Lir::GenNullCheck(RegStorage reg) { 139 class NullCheckSlowPath : public Mir2Lir::LIRSlowPath { 140 public: 141 NullCheckSlowPath(Mir2Lir* m2l, LIR* branch) 142 : LIRSlowPath(m2l, m2l->GetCurrentDexPc(), branch) { 143 } 144 145 void Compile() OVERRIDE { 146 m2l_->ResetRegPool(); 147 m2l_->ResetDefTracking(); 148 GenerateTargetLabel(kPseudoThrowTarget); 149 m2l_->CallRuntimeHelper(kQuickThrowNullPointer, true); 150 } 151 }; 152 153 LIR* branch = OpCmpImmBranch(kCondEq, reg, 0, nullptr); 154 AddSlowPath(new (arena_) NullCheckSlowPath(this, branch)); 155 return branch; 156 } 157 158 /* Perform null-check on a register. */ 159 LIR* Mir2Lir::GenNullCheck(RegStorage m_reg, int opt_flags) { 160 if (!cu_->compiler_driver->GetCompilerOptions().GetImplicitNullChecks()) { 161 return GenExplicitNullCheck(m_reg, opt_flags); 162 } 163 // If null check has not been eliminated, reset redundant store tracking. 164 if ((opt_flags & MIR_IGNORE_NULL_CHECK) == 0) { 165 ResetDefTracking(); 166 } 167 return nullptr; 168 } 169 170 /* Perform an explicit null-check on a register. */ 171 LIR* Mir2Lir::GenExplicitNullCheck(RegStorage m_reg, int opt_flags) { 172 if (!(cu_->disable_opt & (1 << kNullCheckElimination)) && (opt_flags & MIR_IGNORE_NULL_CHECK)) { 173 return NULL; 174 } 175 return GenNullCheck(m_reg); 176 } 177 178 void Mir2Lir::MarkPossibleNullPointerException(int opt_flags) { 179 if (cu_->compiler_driver->GetCompilerOptions().GetImplicitNullChecks()) { 180 if (!(cu_->disable_opt & (1 << kNullCheckElimination)) && (opt_flags & MIR_IGNORE_NULL_CHECK)) { 181 return; 182 } 183 // Insert after last instruction. 184 MarkSafepointPC(last_lir_insn_); 185 } 186 } 187 188 void Mir2Lir::MarkPossibleNullPointerExceptionAfter(int opt_flags, LIR* after) { 189 if (cu_->compiler_driver->GetCompilerOptions().GetImplicitNullChecks()) { 190 if (!(cu_->disable_opt & (1 << kNullCheckElimination)) && (opt_flags & MIR_IGNORE_NULL_CHECK)) { 191 return; 192 } 193 MarkSafepointPCAfter(after); 194 } 195 } 196 197 void Mir2Lir::MarkPossibleStackOverflowException() { 198 if (cu_->compiler_driver->GetCompilerOptions().GetImplicitStackOverflowChecks()) { 199 MarkSafepointPC(last_lir_insn_); 200 } 201 } 202 203 void Mir2Lir::ForceImplicitNullCheck(RegStorage reg, int opt_flags) { 204 if (cu_->compiler_driver->GetCompilerOptions().GetImplicitNullChecks()) { 205 if (!(cu_->disable_opt & (1 << kNullCheckElimination)) && (opt_flags & MIR_IGNORE_NULL_CHECK)) { 206 return; 207 } 208 // Force an implicit null check by performing a memory operation (load) from the given 209 // register with offset 0. This will cause a signal if the register contains 0 (null). 210 RegStorage tmp = AllocTemp(); 211 // TODO: for Mips, would be best to use rZERO as the bogus register target. 212 LIR* load = Load32Disp(reg, 0, tmp); 213 FreeTemp(tmp); 214 MarkSafepointPC(load); 215 } 216 } 217 218 void Mir2Lir::GenCompareAndBranch(Instruction::Code opcode, RegLocation rl_src1, 219 RegLocation rl_src2, LIR* taken, 220 LIR* fall_through) { 221 DCHECK(!rl_src1.fp); 222 DCHECK(!rl_src2.fp); 223 ConditionCode cond; 224 switch (opcode) { 225 case Instruction::IF_EQ: 226 cond = kCondEq; 227 break; 228 case Instruction::IF_NE: 229 cond = kCondNe; 230 break; 231 case Instruction::IF_LT: 232 cond = kCondLt; 233 break; 234 case Instruction::IF_GE: 235 cond = kCondGe; 236 break; 237 case Instruction::IF_GT: 238 cond = kCondGt; 239 break; 240 case Instruction::IF_LE: 241 cond = kCondLe; 242 break; 243 default: 244 cond = static_cast<ConditionCode>(0); 245 LOG(FATAL) << "Unexpected opcode " << opcode; 246 } 247 248 // Normalize such that if either operand is constant, src2 will be constant 249 if (rl_src1.is_const) { 250 RegLocation rl_temp = rl_src1; 251 rl_src1 = rl_src2; 252 rl_src2 = rl_temp; 253 cond = FlipComparisonOrder(cond); 254 } 255 256 rl_src1 = LoadValue(rl_src1); 257 // Is this really an immediate comparison? 258 if (rl_src2.is_const) { 259 // If it's already live in a register or not easily materialized, just keep going 260 RegLocation rl_temp = UpdateLoc(rl_src2); 261 int32_t constant_value = mir_graph_->ConstantValue(rl_src2); 262 if ((rl_temp.location == kLocDalvikFrame) && 263 InexpensiveConstantInt(constant_value, opcode)) { 264 // OK - convert this to a compare immediate and branch 265 OpCmpImmBranch(cond, rl_src1.reg, mir_graph_->ConstantValue(rl_src2), taken); 266 return; 267 } 268 269 // It's also commonly more efficient to have a test against zero with Eq/Ne. This is not worse 270 // for x86, and allows a cbz/cbnz for Arm and Mips. At the same time, it works around a register 271 // mismatch for 64b systems, where a reference is compared against null, as dex bytecode uses 272 // the 32b literal 0 for null. 273 if (constant_value == 0 && (cond == kCondEq || cond == kCondNe)) { 274 // Use the OpCmpImmBranch and ignore the value in the register. 275 OpCmpImmBranch(cond, rl_src1.reg, 0, taken); 276 return; 277 } 278 } 279 280 rl_src2 = LoadValue(rl_src2); 281 OpCmpBranch(cond, rl_src1.reg, rl_src2.reg, taken); 282 } 283 284 void Mir2Lir::GenCompareZeroAndBranch(Instruction::Code opcode, RegLocation rl_src, LIR* taken, 285 LIR* fall_through) { 286 ConditionCode cond; 287 DCHECK(!rl_src.fp); 288 rl_src = LoadValue(rl_src); 289 switch (opcode) { 290 case Instruction::IF_EQZ: 291 cond = kCondEq; 292 break; 293 case Instruction::IF_NEZ: 294 cond = kCondNe; 295 break; 296 case Instruction::IF_LTZ: 297 cond = kCondLt; 298 break; 299 case Instruction::IF_GEZ: 300 cond = kCondGe; 301 break; 302 case Instruction::IF_GTZ: 303 cond = kCondGt; 304 break; 305 case Instruction::IF_LEZ: 306 cond = kCondLe; 307 break; 308 default: 309 cond = static_cast<ConditionCode>(0); 310 LOG(FATAL) << "Unexpected opcode " << opcode; 311 } 312 OpCmpImmBranch(cond, rl_src.reg, 0, taken); 313 } 314 315 void Mir2Lir::GenIntToLong(RegLocation rl_dest, RegLocation rl_src) { 316 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true); 317 if (rl_src.location == kLocPhysReg) { 318 OpRegCopy(rl_result.reg, rl_src.reg); 319 } else { 320 LoadValueDirect(rl_src, rl_result.reg.GetLow()); 321 } 322 OpRegRegImm(kOpAsr, rl_result.reg.GetHigh(), rl_result.reg.GetLow(), 31); 323 StoreValueWide(rl_dest, rl_result); 324 } 325 326 void Mir2Lir::GenIntNarrowing(Instruction::Code opcode, RegLocation rl_dest, 327 RegLocation rl_src) { 328 rl_src = LoadValue(rl_src, kCoreReg); 329 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true); 330 OpKind op = kOpInvalid; 331 switch (opcode) { 332 case Instruction::INT_TO_BYTE: 333 op = kOp2Byte; 334 break; 335 case Instruction::INT_TO_SHORT: 336 op = kOp2Short; 337 break; 338 case Instruction::INT_TO_CHAR: 339 op = kOp2Char; 340 break; 341 default: 342 LOG(ERROR) << "Bad int conversion type"; 343 } 344 OpRegReg(op, rl_result.reg, rl_src.reg); 345 StoreValue(rl_dest, rl_result); 346 } 347 348 /* 349 * Let helper function take care of everything. Will call 350 * Array::AllocFromCode(type_idx, method, count); 351 * Note: AllocFromCode will handle checks for errNegativeArraySize. 352 */ 353 void Mir2Lir::GenNewArray(uint32_t type_idx, RegLocation rl_dest, 354 RegLocation rl_src) { 355 FlushAllRegs(); /* Everything to home location */ 356 const DexFile* dex_file = cu_->dex_file; 357 CompilerDriver* driver = cu_->compiler_driver; 358 if (cu_->compiler_driver->CanAccessTypeWithoutChecks(cu_->method_idx, *dex_file, type_idx)) { 359 bool is_type_initialized; // Ignored as an array does not have an initializer. 360 bool use_direct_type_ptr; 361 uintptr_t direct_type_ptr; 362 bool is_finalizable; 363 if (kEmbedClassInCode && 364 driver->CanEmbedTypeInCode(*dex_file, type_idx, &is_type_initialized, &use_direct_type_ptr, 365 &direct_type_ptr, &is_finalizable)) { 366 // The fast path. 367 if (!use_direct_type_ptr) { 368 LoadClassType(type_idx, kArg0); 369 CallRuntimeHelperRegMethodRegLocation(kQuickAllocArrayResolved, TargetReg(kArg0, kNotWide), 370 rl_src, true); 371 } else { 372 // Use the direct pointer. 373 CallRuntimeHelperImmMethodRegLocation(kQuickAllocArrayResolved, direct_type_ptr, rl_src, 374 true); 375 } 376 } else { 377 // The slow path. 378 CallRuntimeHelperImmMethodRegLocation(kQuickAllocArray, type_idx, rl_src, true); 379 } 380 } else { 381 CallRuntimeHelperImmMethodRegLocation(kQuickAllocArrayWithAccessCheck, type_idx, rl_src, true); 382 } 383 StoreValue(rl_dest, GetReturn(kRefReg)); 384 } 385 386 /* 387 * Similar to GenNewArray, but with post-allocation initialization. 388 * Verifier guarantees we're dealing with an array class. Current 389 * code throws runtime exception "bad Filled array req" for 'D' and 'J'. 390 * Current code also throws internal unimp if not 'L', '[' or 'I'. 391 */ 392 void Mir2Lir::GenFilledNewArray(CallInfo* info) { 393 int elems = info->num_arg_words; 394 int type_idx = info->index; 395 FlushAllRegs(); /* Everything to home location */ 396 QuickEntrypointEnum target; 397 if (cu_->compiler_driver->CanAccessTypeWithoutChecks(cu_->method_idx, *cu_->dex_file, 398 type_idx)) { 399 target = kQuickCheckAndAllocArray; 400 } else { 401 target = kQuickCheckAndAllocArrayWithAccessCheck; 402 } 403 CallRuntimeHelperImmMethodImm(target, type_idx, elems, true); 404 FreeTemp(TargetReg(kArg2, kNotWide)); 405 FreeTemp(TargetReg(kArg1, kNotWide)); 406 /* 407 * NOTE: the implicit target for Instruction::FILLED_NEW_ARRAY is the 408 * return region. Because AllocFromCode placed the new array 409 * in kRet0, we'll just lock it into place. When debugger support is 410 * added, it may be necessary to additionally copy all return 411 * values to a home location in thread-local storage 412 */ 413 RegStorage ref_reg = TargetReg(kRet0, kRef); 414 LockTemp(ref_reg); 415 416 // TODO: use the correct component size, currently all supported types 417 // share array alignment with ints (see comment at head of function) 418 size_t component_size = sizeof(int32_t); 419 420 // Having a range of 0 is legal 421 if (info->is_range && (elems > 0)) { 422 /* 423 * Bit of ugliness here. We're going generate a mem copy loop 424 * on the register range, but it is possible that some regs 425 * in the range have been promoted. This is unlikely, but 426 * before generating the copy, we'll just force a flush 427 * of any regs in the source range that have been promoted to 428 * home location. 429 */ 430 for (int i = 0; i < elems; i++) { 431 RegLocation loc = UpdateLoc(info->args[i]); 432 if (loc.location == kLocPhysReg) { 433 ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg); 434 Store32Disp(TargetPtrReg(kSp), SRegOffset(loc.s_reg_low), loc.reg); 435 } 436 } 437 /* 438 * TUNING note: generated code here could be much improved, but 439 * this is an uncommon operation and isn't especially performance 440 * critical. 441 */ 442 // This is addressing the stack, which may be out of the 4G area. 443 RegStorage r_src = AllocTempRef(); 444 RegStorage r_dst = AllocTempRef(); 445 RegStorage r_idx = AllocTempRef(); // Not really a reference, but match src/dst. 446 RegStorage r_val; 447 switch (cu_->instruction_set) { 448 case kThumb2: 449 case kArm64: 450 r_val = TargetReg(kLr, kNotWide); 451 break; 452 case kX86: 453 case kX86_64: 454 FreeTemp(ref_reg); 455 r_val = AllocTemp(); 456 break; 457 case kMips: 458 r_val = AllocTemp(); 459 break; 460 default: LOG(FATAL) << "Unexpected instruction set: " << cu_->instruction_set; 461 } 462 // Set up source pointer 463 RegLocation rl_first = info->args[0]; 464 OpRegRegImm(kOpAdd, r_src, TargetPtrReg(kSp), SRegOffset(rl_first.s_reg_low)); 465 // Set up the target pointer 466 OpRegRegImm(kOpAdd, r_dst, ref_reg, 467 mirror::Array::DataOffset(component_size).Int32Value()); 468 // Set up the loop counter (known to be > 0) 469 LoadConstant(r_idx, elems - 1); 470 // Generate the copy loop. Going backwards for convenience 471 LIR* target = NewLIR0(kPseudoTargetLabel); 472 // Copy next element 473 { 474 ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg); 475 LoadBaseIndexed(r_src, r_idx, r_val, 2, k32); 476 // NOTE: No dalvik register annotation, local optimizations will be stopped 477 // by the loop boundaries. 478 } 479 StoreBaseIndexed(r_dst, r_idx, r_val, 2, k32); 480 FreeTemp(r_val); 481 OpDecAndBranch(kCondGe, r_idx, target); 482 if (cu_->instruction_set == kX86 || cu_->instruction_set == kX86_64) { 483 // Restore the target pointer 484 OpRegRegImm(kOpAdd, ref_reg, r_dst, 485 -mirror::Array::DataOffset(component_size).Int32Value()); 486 } 487 } else if (!info->is_range) { 488 // TUNING: interleave 489 for (int i = 0; i < elems; i++) { 490 RegLocation rl_arg = LoadValue(info->args[i], kCoreReg); 491 Store32Disp(ref_reg, 492 mirror::Array::DataOffset(component_size).Int32Value() + i * 4, rl_arg.reg); 493 // If the LoadValue caused a temp to be allocated, free it 494 if (IsTemp(rl_arg.reg)) { 495 FreeTemp(rl_arg.reg); 496 } 497 } 498 } 499 if (info->result.location != kLocInvalid) { 500 StoreValue(info->result, GetReturn(kRefReg)); 501 } 502 } 503 504 // 505 // Slow path to ensure a class is initialized for sget/sput. 506 // 507 class StaticFieldSlowPath : public Mir2Lir::LIRSlowPath { 508 public: 509 StaticFieldSlowPath(Mir2Lir* m2l, LIR* unresolved, LIR* uninit, LIR* cont, int storage_index, 510 RegStorage r_base) : 511 LIRSlowPath(m2l, m2l->GetCurrentDexPc(), unresolved, cont), uninit_(uninit), 512 storage_index_(storage_index), r_base_(r_base) { 513 } 514 515 void Compile() { 516 LIR* unresolved_target = GenerateTargetLabel(); 517 uninit_->target = unresolved_target; 518 m2l_->CallRuntimeHelperImm(kQuickInitializeStaticStorage, storage_index_, true); 519 // Copy helper's result into r_base, a no-op on all but MIPS. 520 m2l_->OpRegCopy(r_base_, m2l_->TargetReg(kRet0, kRef)); 521 522 m2l_->OpUnconditionalBranch(cont_); 523 } 524 525 private: 526 LIR* const uninit_; 527 const int storage_index_; 528 const RegStorage r_base_; 529 }; 530 531 void Mir2Lir::GenSput(MIR* mir, RegLocation rl_src, bool is_long_or_double, 532 bool is_object) { 533 const MirSFieldLoweringInfo& field_info = mir_graph_->GetSFieldLoweringInfo(mir); 534 cu_->compiler_driver->ProcessedStaticField(field_info.FastPut(), field_info.IsReferrersClass()); 535 OpSize store_size = LoadStoreOpSize(is_long_or_double, is_object); 536 if (!SLOW_FIELD_PATH && field_info.FastPut()) { 537 DCHECK_GE(field_info.FieldOffset().Int32Value(), 0); 538 RegStorage r_base; 539 if (field_info.IsReferrersClass()) { 540 // Fast path, static storage base is this method's class 541 RegLocation rl_method = LoadCurrMethod(); 542 r_base = AllocTempRef(); 543 LoadRefDisp(rl_method.reg, mirror::ArtMethod::DeclaringClassOffset().Int32Value(), r_base, 544 kNotVolatile); 545 if (IsTemp(rl_method.reg)) { 546 FreeTemp(rl_method.reg); 547 } 548 } else { 549 // Medium path, static storage base in a different class which requires checks that the other 550 // class is initialized. 551 // TODO: remove initialized check now that we are initializing classes in the compiler driver. 552 DCHECK_NE(field_info.StorageIndex(), DexFile::kDexNoIndex); 553 // May do runtime call so everything to home locations. 554 FlushAllRegs(); 555 // Using fixed register to sync with possible call to runtime support. 556 RegStorage r_method = TargetReg(kArg1, kRef); 557 LockTemp(r_method); 558 LoadCurrMethodDirect(r_method); 559 r_base = TargetReg(kArg0, kRef); 560 LockTemp(r_base); 561 LoadRefDisp(r_method, mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value(), r_base, 562 kNotVolatile); 563 int32_t offset_of_field = ObjArray::OffsetOfElement(field_info.StorageIndex()).Int32Value(); 564 LoadRefDisp(r_base, offset_of_field, r_base, kNotVolatile); 565 // r_base now points at static storage (Class*) or NULL if the type is not yet resolved. 566 if (!field_info.IsInitialized() && 567 (mir->optimization_flags & MIR_IGNORE_CLINIT_CHECK) == 0) { 568 // Check if r_base is NULL or a not yet initialized class. 569 570 // The slow path is invoked if the r_base is NULL or the class pointed 571 // to by it is not initialized. 572 LIR* unresolved_branch = OpCmpImmBranch(kCondEq, r_base, 0, NULL); 573 RegStorage r_tmp = TargetReg(kArg2, kNotWide); 574 LockTemp(r_tmp); 575 LIR* uninit_branch = OpCmpMemImmBranch(kCondLt, r_tmp, r_base, 576 mirror::Class::StatusOffset().Int32Value(), 577 mirror::Class::kStatusInitialized, nullptr, nullptr); 578 LIR* cont = NewLIR0(kPseudoTargetLabel); 579 580 AddSlowPath(new (arena_) StaticFieldSlowPath(this, unresolved_branch, uninit_branch, cont, 581 field_info.StorageIndex(), r_base)); 582 583 FreeTemp(r_tmp); 584 // Ensure load of status and store of value don't re-order. 585 // TODO: Presumably the actual value store is control-dependent on the status load, 586 // and will thus not be reordered in any case, since stores are never speculated. 587 // Does later code "know" that the class is now initialized? If so, we still 588 // need the barrier to guard later static loads. 589 GenMemBarrier(kLoadAny); 590 } 591 FreeTemp(r_method); 592 } 593 // rBase now holds static storage base 594 RegisterClass reg_class = RegClassForFieldLoadStore(store_size, field_info.IsVolatile()); 595 if (is_long_or_double) { 596 rl_src = LoadValueWide(rl_src, reg_class); 597 } else { 598 rl_src = LoadValue(rl_src, reg_class); 599 } 600 if (is_object) { 601 StoreRefDisp(r_base, field_info.FieldOffset().Int32Value(), rl_src.reg, 602 field_info.IsVolatile() ? kVolatile : kNotVolatile); 603 } else { 604 StoreBaseDisp(r_base, field_info.FieldOffset().Int32Value(), rl_src.reg, store_size, 605 field_info.IsVolatile() ? kVolatile : kNotVolatile); 606 } 607 if (is_object && !mir_graph_->IsConstantNullRef(rl_src)) { 608 MarkGCCard(rl_src.reg, r_base); 609 } 610 FreeTemp(r_base); 611 } else { 612 FlushAllRegs(); // Everything to home locations 613 QuickEntrypointEnum target = 614 is_long_or_double ? kQuickSet64Static 615 : (is_object ? kQuickSetObjStatic : kQuickSet32Static); 616 CallRuntimeHelperImmRegLocation(target, field_info.FieldIndex(), rl_src, true); 617 } 618 } 619 620 void Mir2Lir::GenSget(MIR* mir, RegLocation rl_dest, 621 bool is_long_or_double, bool is_object) { 622 const MirSFieldLoweringInfo& field_info = mir_graph_->GetSFieldLoweringInfo(mir); 623 cu_->compiler_driver->ProcessedStaticField(field_info.FastGet(), field_info.IsReferrersClass()); 624 OpSize load_size = LoadStoreOpSize(is_long_or_double, is_object); 625 if (!SLOW_FIELD_PATH && field_info.FastGet()) { 626 DCHECK_GE(field_info.FieldOffset().Int32Value(), 0); 627 RegStorage r_base; 628 if (field_info.IsReferrersClass()) { 629 // Fast path, static storage base is this method's class 630 RegLocation rl_method = LoadCurrMethod(); 631 r_base = AllocTempRef(); 632 LoadRefDisp(rl_method.reg, mirror::ArtMethod::DeclaringClassOffset().Int32Value(), r_base, 633 kNotVolatile); 634 } else { 635 // Medium path, static storage base in a different class which requires checks that the other 636 // class is initialized 637 DCHECK_NE(field_info.StorageIndex(), DexFile::kDexNoIndex); 638 // May do runtime call so everything to home locations. 639 FlushAllRegs(); 640 // Using fixed register to sync with possible call to runtime support. 641 RegStorage r_method = TargetReg(kArg1, kRef); 642 LockTemp(r_method); 643 LoadCurrMethodDirect(r_method); 644 r_base = TargetReg(kArg0, kRef); 645 LockTemp(r_base); 646 LoadRefDisp(r_method, mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value(), r_base, 647 kNotVolatile); 648 int32_t offset_of_field = ObjArray::OffsetOfElement(field_info.StorageIndex()).Int32Value(); 649 LoadRefDisp(r_base, offset_of_field, r_base, kNotVolatile); 650 // r_base now points at static storage (Class*) or NULL if the type is not yet resolved. 651 if (!field_info.IsInitialized() && 652 (mir->optimization_flags & MIR_IGNORE_CLINIT_CHECK) == 0) { 653 // Check if r_base is NULL or a not yet initialized class. 654 655 // The slow path is invoked if the r_base is NULL or the class pointed 656 // to by it is not initialized. 657 LIR* unresolved_branch = OpCmpImmBranch(kCondEq, r_base, 0, NULL); 658 RegStorage r_tmp = TargetReg(kArg2, kNotWide); 659 LockTemp(r_tmp); 660 LIR* uninit_branch = OpCmpMemImmBranch(kCondLt, r_tmp, r_base, 661 mirror::Class::StatusOffset().Int32Value(), 662 mirror::Class::kStatusInitialized, nullptr, nullptr); 663 LIR* cont = NewLIR0(kPseudoTargetLabel); 664 665 AddSlowPath(new (arena_) StaticFieldSlowPath(this, unresolved_branch, uninit_branch, cont, 666 field_info.StorageIndex(), r_base)); 667 668 FreeTemp(r_tmp); 669 // Ensure load of status and load of value don't re-order. 670 GenMemBarrier(kLoadAny); 671 } 672 FreeTemp(r_method); 673 } 674 // r_base now holds static storage base 675 RegisterClass reg_class = RegClassForFieldLoadStore(load_size, field_info.IsVolatile()); 676 RegLocation rl_result = EvalLoc(rl_dest, reg_class, true); 677 678 int field_offset = field_info.FieldOffset().Int32Value(); 679 if (is_object) { 680 LoadRefDisp(r_base, field_offset, rl_result.reg, field_info.IsVolatile() ? kVolatile : 681 kNotVolatile); 682 } else { 683 LoadBaseDisp(r_base, field_offset, rl_result.reg, load_size, field_info.IsVolatile() ? 684 kVolatile : kNotVolatile); 685 } 686 FreeTemp(r_base); 687 688 if (is_long_or_double) { 689 StoreValueWide(rl_dest, rl_result); 690 } else { 691 StoreValue(rl_dest, rl_result); 692 } 693 } else { 694 FlushAllRegs(); // Everything to home locations 695 QuickEntrypointEnum target = 696 is_long_or_double ? kQuickGet64Static 697 : (is_object ? kQuickGetObjStatic : kQuickGet32Static); 698 CallRuntimeHelperImm(target, field_info.FieldIndex(), true); 699 700 // FIXME: pGetXXStatic always return an int or int64 regardless of rl_dest.fp. 701 if (is_long_or_double) { 702 RegLocation rl_result = GetReturnWide(kCoreReg); 703 StoreValueWide(rl_dest, rl_result); 704 } else { 705 RegLocation rl_result = GetReturn(rl_dest.ref ? kRefReg : kCoreReg); 706 StoreValue(rl_dest, rl_result); 707 } 708 } 709 } 710 711 // Generate code for all slow paths. 712 void Mir2Lir::HandleSlowPaths() { 713 // We should check slow_paths_.Size() every time, because a new slow path 714 // may be created during slowpath->Compile(). 715 for (size_t i = 0; i < slow_paths_.Size(); ++i) { 716 LIRSlowPath* slowpath = slow_paths_.Get(i); 717 slowpath->Compile(); 718 } 719 slow_paths_.Reset(); 720 } 721 722 void Mir2Lir::GenIGet(MIR* mir, int opt_flags, OpSize size, 723 RegLocation rl_dest, RegLocation rl_obj, bool is_long_or_double, 724 bool is_object) { 725 const MirIFieldLoweringInfo& field_info = mir_graph_->GetIFieldLoweringInfo(mir); 726 cu_->compiler_driver->ProcessedInstanceField(field_info.FastGet()); 727 OpSize load_size = LoadStoreOpSize(is_long_or_double, is_object); 728 if (!SLOW_FIELD_PATH && field_info.FastGet()) { 729 RegisterClass reg_class = RegClassForFieldLoadStore(load_size, field_info.IsVolatile()); 730 // A load of the class will lead to an iget with offset 0. 731 DCHECK_GE(field_info.FieldOffset().Int32Value(), 0); 732 rl_obj = LoadValue(rl_obj, kRefReg); 733 GenNullCheck(rl_obj.reg, opt_flags); 734 RegLocation rl_result = EvalLoc(rl_dest, reg_class, true); 735 int field_offset = field_info.FieldOffset().Int32Value(); 736 LIR* load_lir; 737 if (is_object) { 738 load_lir = LoadRefDisp(rl_obj.reg, field_offset, rl_result.reg, field_info.IsVolatile() ? 739 kVolatile : kNotVolatile); 740 } else { 741 load_lir = LoadBaseDisp(rl_obj.reg, field_offset, rl_result.reg, load_size, 742 field_info.IsVolatile() ? kVolatile : kNotVolatile); 743 } 744 MarkPossibleNullPointerExceptionAfter(opt_flags, load_lir); 745 if (is_long_or_double) { 746 StoreValueWide(rl_dest, rl_result); 747 } else { 748 StoreValue(rl_dest, rl_result); 749 } 750 } else { 751 QuickEntrypointEnum target = 752 is_long_or_double ? kQuickGet64Instance 753 : (is_object ? kQuickGetObjInstance : kQuickGet32Instance); 754 // Second argument of pGetXXInstance is always a reference. 755 DCHECK_EQ(static_cast<unsigned int>(rl_obj.wide), 0U); 756 CallRuntimeHelperImmRegLocation(target, field_info.FieldIndex(), rl_obj, true); 757 758 // FIXME: pGetXXInstance always return an int or int64 regardless of rl_dest.fp. 759 if (is_long_or_double) { 760 RegLocation rl_result = GetReturnWide(kCoreReg); 761 StoreValueWide(rl_dest, rl_result); 762 } else { 763 RegLocation rl_result = GetReturn(rl_dest.ref ? kRefReg : kCoreReg); 764 StoreValue(rl_dest, rl_result); 765 } 766 } 767 } 768 769 void Mir2Lir::GenIPut(MIR* mir, int opt_flags, OpSize size, 770 RegLocation rl_src, RegLocation rl_obj, bool is_long_or_double, 771 bool is_object) { 772 const MirIFieldLoweringInfo& field_info = mir_graph_->GetIFieldLoweringInfo(mir); 773 cu_->compiler_driver->ProcessedInstanceField(field_info.FastPut()); 774 OpSize store_size = LoadStoreOpSize(is_long_or_double, is_object); 775 if (!SLOW_FIELD_PATH && field_info.FastPut()) { 776 RegisterClass reg_class = RegClassForFieldLoadStore(store_size, field_info.IsVolatile()); 777 // Dex code never writes to the class field. 778 DCHECK_GE(static_cast<uint32_t>(field_info.FieldOffset().Int32Value()), 779 sizeof(mirror::HeapReference<mirror::Class>)); 780 rl_obj = LoadValue(rl_obj, kRefReg); 781 if (is_long_or_double) { 782 rl_src = LoadValueWide(rl_src, reg_class); 783 } else { 784 rl_src = LoadValue(rl_src, reg_class); 785 } 786 GenNullCheck(rl_obj.reg, opt_flags); 787 int field_offset = field_info.FieldOffset().Int32Value(); 788 LIR* null_ck_insn; 789 if (is_object) { 790 null_ck_insn = StoreRefDisp(rl_obj.reg, field_offset, rl_src.reg, field_info.IsVolatile() ? 791 kVolatile : kNotVolatile); 792 } else { 793 null_ck_insn = StoreBaseDisp(rl_obj.reg, field_offset, rl_src.reg, store_size, 794 field_info.IsVolatile() ? kVolatile : kNotVolatile); 795 } 796 MarkPossibleNullPointerExceptionAfter(opt_flags, null_ck_insn); 797 if (is_object && !mir_graph_->IsConstantNullRef(rl_src)) { 798 MarkGCCard(rl_src.reg, rl_obj.reg); 799 } 800 } else { 801 QuickEntrypointEnum target = 802 is_long_or_double ? kQuickSet64Instance 803 : (is_object ? kQuickSetObjInstance : kQuickSet32Instance); 804 CallRuntimeHelperImmRegLocationRegLocation(target, field_info.FieldIndex(), rl_obj, rl_src, 805 true); 806 } 807 } 808 809 void Mir2Lir::GenArrayObjPut(int opt_flags, RegLocation rl_array, RegLocation rl_index, 810 RegLocation rl_src) { 811 bool needs_range_check = !(opt_flags & MIR_IGNORE_RANGE_CHECK); 812 bool needs_null_check = !((cu_->disable_opt & (1 << kNullCheckElimination)) && 813 (opt_flags & MIR_IGNORE_NULL_CHECK)); 814 QuickEntrypointEnum target = needs_range_check 815 ? (needs_null_check ? kQuickAputObjectWithNullAndBoundCheck 816 : kQuickAputObjectWithBoundCheck) 817 : kQuickAputObject; 818 CallRuntimeHelperRegLocationRegLocationRegLocation(target, rl_array, rl_index, rl_src, true); 819 } 820 821 void Mir2Lir::GenConstClass(uint32_t type_idx, RegLocation rl_dest) { 822 RegLocation rl_method = LoadCurrMethod(); 823 CheckRegLocation(rl_method); 824 RegStorage res_reg = AllocTempRef(); 825 RegLocation rl_result = EvalLoc(rl_dest, kRefReg, true); 826 if (!cu_->compiler_driver->CanAccessTypeWithoutChecks(cu_->method_idx, 827 *cu_->dex_file, 828 type_idx)) { 829 // Call out to helper which resolves type and verifies access. 830 // Resolved type returned in kRet0. 831 CallRuntimeHelperImmReg(kQuickInitializeTypeAndVerifyAccess, type_idx, rl_method.reg, true); 832 RegLocation rl_result = GetReturn(kRefReg); 833 StoreValue(rl_dest, rl_result); 834 } else { 835 // We're don't need access checks, load type from dex cache 836 int32_t dex_cache_offset = 837 mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value(); 838 LoadRefDisp(rl_method.reg, dex_cache_offset, res_reg, kNotVolatile); 839 int32_t offset_of_type = ClassArray::OffsetOfElement(type_idx).Int32Value(); 840 LoadRefDisp(res_reg, offset_of_type, rl_result.reg, kNotVolatile); 841 if (!cu_->compiler_driver->CanAssumeTypeIsPresentInDexCache(*cu_->dex_file, 842 type_idx) || SLOW_TYPE_PATH) { 843 // Slow path, at runtime test if type is null and if so initialize 844 FlushAllRegs(); 845 LIR* branch = OpCmpImmBranch(kCondEq, rl_result.reg, 0, NULL); 846 LIR* cont = NewLIR0(kPseudoTargetLabel); 847 848 // Object to generate the slow path for class resolution. 849 class SlowPath : public LIRSlowPath { 850 public: 851 SlowPath(Mir2Lir* m2l, LIR* fromfast, LIR* cont, const int type_idx, 852 const RegLocation& rl_method, const RegLocation& rl_result) : 853 LIRSlowPath(m2l, m2l->GetCurrentDexPc(), fromfast, cont), type_idx_(type_idx), 854 rl_method_(rl_method), rl_result_(rl_result) { 855 } 856 857 void Compile() { 858 GenerateTargetLabel(); 859 860 m2l_->CallRuntimeHelperImmReg(kQuickInitializeType, type_idx_, rl_method_.reg, true); 861 m2l_->OpRegCopy(rl_result_.reg, m2l_->TargetReg(kRet0, kRef)); 862 m2l_->OpUnconditionalBranch(cont_); 863 } 864 865 private: 866 const int type_idx_; 867 const RegLocation rl_method_; 868 const RegLocation rl_result_; 869 }; 870 871 // Add to list for future. 872 AddSlowPath(new (arena_) SlowPath(this, branch, cont, type_idx, rl_method, rl_result)); 873 874 StoreValue(rl_dest, rl_result); 875 } else { 876 // Fast path, we're done - just store result 877 StoreValue(rl_dest, rl_result); 878 } 879 } 880 } 881 882 void Mir2Lir::GenConstString(uint32_t string_idx, RegLocation rl_dest) { 883 /* NOTE: Most strings should be available at compile time */ 884 const int32_t offset_of_string = 885 mirror::ObjectArray<mirror::String>::OffsetOfElement(string_idx).Int32Value(); 886 if (!cu_->compiler_driver->CanAssumeStringIsPresentInDexCache( 887 *cu_->dex_file, string_idx) || SLOW_STRING_PATH) { 888 // slow path, resolve string if not in dex cache 889 FlushAllRegs(); 890 LockCallTemps(); // Using explicit registers 891 892 // If the Method* is already in a register, we can save a copy. 893 RegLocation rl_method = mir_graph_->GetMethodLoc(); 894 RegStorage r_method; 895 if (rl_method.location == kLocPhysReg) { 896 // A temp would conflict with register use below. 897 DCHECK(!IsTemp(rl_method.reg)); 898 r_method = rl_method.reg; 899 } else { 900 r_method = TargetReg(kArg2, kRef); 901 LoadCurrMethodDirect(r_method); 902 } 903 // Method to declaring class. 904 LoadRefDisp(r_method, mirror::ArtMethod::DeclaringClassOffset().Int32Value(), 905 TargetReg(kArg0, kRef), kNotVolatile); 906 // Declaring class to dex cache strings. 907 LoadRefDisp(TargetReg(kArg0, kRef), mirror::Class::DexCacheStringsOffset().Int32Value(), 908 TargetReg(kArg0, kRef), kNotVolatile); 909 910 // Might call out to helper, which will return resolved string in kRet0 911 LoadRefDisp(TargetReg(kArg0, kRef), offset_of_string, TargetReg(kRet0, kRef), kNotVolatile); 912 LIR* fromfast = OpCmpImmBranch(kCondEq, TargetReg(kRet0, kRef), 0, NULL); 913 LIR* cont = NewLIR0(kPseudoTargetLabel); 914 915 { 916 // Object to generate the slow path for string resolution. 917 class SlowPath : public LIRSlowPath { 918 public: 919 SlowPath(Mir2Lir* m2l, LIR* fromfast, LIR* cont, RegStorage r_method, int32_t string_idx) : 920 LIRSlowPath(m2l, m2l->GetCurrentDexPc(), fromfast, cont), 921 r_method_(r_method), string_idx_(string_idx) { 922 } 923 924 void Compile() { 925 GenerateTargetLabel(); 926 m2l_->CallRuntimeHelperRegImm(kQuickResolveString, r_method_, string_idx_, true); 927 m2l_->OpUnconditionalBranch(cont_); 928 } 929 930 private: 931 const RegStorage r_method_; 932 const int32_t string_idx_; 933 }; 934 935 AddSlowPath(new (arena_) SlowPath(this, fromfast, cont, r_method, string_idx)); 936 } 937 938 GenBarrier(); 939 StoreValue(rl_dest, GetReturn(kRefReg)); 940 } else { 941 // Try to see if we can embed a direct pointer. 942 bool use_direct_ptr = false; 943 size_t direct_ptr = 0; 944 bool embed_string = false; 945 // TODO: Implement for X86. 946 if (cu_->instruction_set != kX86 && cu_->instruction_set != kX86_64) { 947 embed_string = cu_->compiler_driver->CanEmbedStringInCode(*cu_->dex_file, string_idx, 948 &use_direct_ptr, &direct_ptr); 949 } 950 if (embed_string) { 951 RegLocation rl_result = EvalLoc(rl_dest, kRefReg, true); 952 if (!use_direct_ptr) { 953 LoadString(string_idx, rl_result.reg); 954 } else { 955 LoadConstant(rl_result.reg, static_cast<int32_t>(direct_ptr)); 956 } 957 StoreValue(rl_dest, rl_result); 958 } else { 959 RegLocation rl_method = LoadCurrMethod(); 960 RegStorage res_reg = AllocTempRef(); 961 RegLocation rl_result = EvalLoc(rl_dest, kRefReg, true); 962 963 // Method to declaring class. 964 LoadRefDisp(rl_method.reg, mirror::ArtMethod::DeclaringClassOffset().Int32Value(), 965 res_reg, kNotVolatile); 966 // Declaring class to dex cache strings. 967 LoadRefDisp(res_reg, mirror::Class::DexCacheStringsOffset().Int32Value(), res_reg, 968 kNotVolatile); 969 970 LoadRefDisp(res_reg, offset_of_string, rl_result.reg, kNotVolatile); 971 StoreValue(rl_dest, rl_result); 972 } 973 } 974 } 975 976 /* 977 * Let helper function take care of everything. Will 978 * call Class::NewInstanceFromCode(type_idx, method); 979 */ 980 void Mir2Lir::GenNewInstance(uint32_t type_idx, RegLocation rl_dest) { 981 FlushAllRegs(); /* Everything to home location */ 982 // alloc will always check for resolution, do we also need to verify 983 // access because the verifier was unable to? 984 const DexFile* dex_file = cu_->dex_file; 985 CompilerDriver* driver = cu_->compiler_driver; 986 if (driver->CanAccessInstantiableTypeWithoutChecks(cu_->method_idx, *dex_file, type_idx)) { 987 bool is_type_initialized; 988 bool use_direct_type_ptr; 989 uintptr_t direct_type_ptr; 990 bool is_finalizable; 991 if (kEmbedClassInCode && 992 driver->CanEmbedTypeInCode(*dex_file, type_idx, &is_type_initialized, &use_direct_type_ptr, 993 &direct_type_ptr, &is_finalizable) && 994 !is_finalizable) { 995 // The fast path. 996 if (!use_direct_type_ptr) { 997 LoadClassType(type_idx, kArg0); 998 if (!is_type_initialized) { 999 CallRuntimeHelperRegMethod(kQuickAllocObjectResolved, TargetReg(kArg0, kRef), true); 1000 } else { 1001 CallRuntimeHelperRegMethod(kQuickAllocObjectInitialized, TargetReg(kArg0, kRef), true); 1002 } 1003 } else { 1004 // Use the direct pointer. 1005 if (!is_type_initialized) { 1006 CallRuntimeHelperImmMethod(kQuickAllocObjectResolved, direct_type_ptr, true); 1007 } else { 1008 CallRuntimeHelperImmMethod(kQuickAllocObjectInitialized, direct_type_ptr, true); 1009 } 1010 } 1011 } else { 1012 // The slow path. 1013 CallRuntimeHelperImmMethod(kQuickAllocObject, type_idx, true); 1014 } 1015 } else { 1016 CallRuntimeHelperImmMethod(kQuickAllocObjectWithAccessCheck, type_idx, true); 1017 } 1018 StoreValue(rl_dest, GetReturn(kRefReg)); 1019 } 1020 1021 void Mir2Lir::GenThrow(RegLocation rl_src) { 1022 FlushAllRegs(); 1023 CallRuntimeHelperRegLocation(kQuickDeliverException, rl_src, true); 1024 } 1025 1026 // For final classes there are no sub-classes to check and so we can answer the instance-of 1027 // question with simple comparisons. 1028 void Mir2Lir::GenInstanceofFinal(bool use_declaring_class, uint32_t type_idx, RegLocation rl_dest, 1029 RegLocation rl_src) { 1030 // X86 has its own implementation. 1031 DCHECK(cu_->instruction_set != kX86 && cu_->instruction_set != kX86_64); 1032 1033 RegLocation object = LoadValue(rl_src, kRefReg); 1034 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true); 1035 RegStorage result_reg = rl_result.reg; 1036 if (IsSameReg(result_reg, object.reg)) { 1037 result_reg = AllocTypedTemp(false, kCoreReg); 1038 DCHECK(!IsSameReg(result_reg, object.reg)); 1039 } 1040 LoadConstant(result_reg, 0); // assume false 1041 LIR* null_branchover = OpCmpImmBranch(kCondEq, object.reg, 0, NULL); 1042 1043 RegStorage check_class = AllocTypedTemp(false, kRefReg); 1044 RegStorage object_class = AllocTypedTemp(false, kRefReg); 1045 1046 LoadCurrMethodDirect(check_class); 1047 if (use_declaring_class) { 1048 LoadRefDisp(check_class, mirror::ArtMethod::DeclaringClassOffset().Int32Value(), check_class, 1049 kNotVolatile); 1050 LoadRefDisp(object.reg, mirror::Object::ClassOffset().Int32Value(), object_class, 1051 kNotVolatile); 1052 } else { 1053 LoadRefDisp(check_class, mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value(), 1054 check_class, kNotVolatile); 1055 LoadRefDisp(object.reg, mirror::Object::ClassOffset().Int32Value(), object_class, 1056 kNotVolatile); 1057 int32_t offset_of_type = ClassArray::OffsetOfElement(type_idx).Int32Value(); 1058 LoadRefDisp(check_class, offset_of_type, check_class, kNotVolatile); 1059 } 1060 1061 // FIXME: what should we be comparing here? compressed or decompressed references? 1062 if (cu_->instruction_set == kThumb2) { 1063 OpRegReg(kOpCmp, check_class, object_class); // Same? 1064 LIR* it = OpIT(kCondEq, ""); // if-convert the test 1065 LoadConstant(result_reg, 1); // .eq case - load true 1066 OpEndIT(it); 1067 } else { 1068 GenSelectConst32(check_class, object_class, kCondEq, 1, 0, result_reg, kCoreReg); 1069 } 1070 LIR* target = NewLIR0(kPseudoTargetLabel); 1071 null_branchover->target = target; 1072 FreeTemp(object_class); 1073 FreeTemp(check_class); 1074 if (IsTemp(result_reg)) { 1075 OpRegCopy(rl_result.reg, result_reg); 1076 FreeTemp(result_reg); 1077 } 1078 StoreValue(rl_dest, rl_result); 1079 } 1080 1081 void Mir2Lir::GenInstanceofCallingHelper(bool needs_access_check, bool type_known_final, 1082 bool type_known_abstract, bool use_declaring_class, 1083 bool can_assume_type_is_in_dex_cache, 1084 uint32_t type_idx, RegLocation rl_dest, 1085 RegLocation rl_src) { 1086 FlushAllRegs(); 1087 // May generate a call - use explicit registers 1088 LockCallTemps(); 1089 RegStorage method_reg = TargetReg(kArg1, kRef); 1090 LoadCurrMethodDirect(method_reg); // kArg1 <= current Method* 1091 RegStorage class_reg = TargetReg(kArg2, kRef); // kArg2 will hold the Class* 1092 RegStorage ref_reg = TargetReg(kArg0, kRef); // kArg0 will hold the ref. 1093 RegStorage ret_reg = GetReturn(kRefReg).reg; 1094 if (needs_access_check) { 1095 // Check we have access to type_idx and if not throw IllegalAccessError, 1096 // returns Class* in kArg0 1097 CallRuntimeHelperImm(kQuickInitializeTypeAndVerifyAccess, type_idx, true); 1098 OpRegCopy(class_reg, ret_reg); // Align usage with fast path 1099 LoadValueDirectFixed(rl_src, ref_reg); // kArg0 <= ref 1100 } else if (use_declaring_class) { 1101 LoadValueDirectFixed(rl_src, ref_reg); // kArg0 <= ref 1102 LoadRefDisp(method_reg, mirror::ArtMethod::DeclaringClassOffset().Int32Value(), 1103 class_reg, kNotVolatile); 1104 } else { 1105 if (can_assume_type_is_in_dex_cache) { 1106 // Conditionally, as in the other case we will also load it. 1107 LoadValueDirectFixed(rl_src, ref_reg); // kArg0 <= ref 1108 } 1109 1110 // Load dex cache entry into class_reg (kArg2) 1111 LoadRefDisp(method_reg, mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value(), 1112 class_reg, kNotVolatile); 1113 int32_t offset_of_type = ClassArray::OffsetOfElement(type_idx).Int32Value(); 1114 LoadRefDisp(class_reg, offset_of_type, class_reg, kNotVolatile); 1115 if (!can_assume_type_is_in_dex_cache) { 1116 LIR* slow_path_branch = OpCmpImmBranch(kCondEq, class_reg, 0, NULL); 1117 LIR* slow_path_target = NewLIR0(kPseudoTargetLabel); 1118 1119 // Should load value here. 1120 LoadValueDirectFixed(rl_src, ref_reg); // kArg0 <= ref 1121 1122 class InitTypeSlowPath : public Mir2Lir::LIRSlowPath { 1123 public: 1124 InitTypeSlowPath(Mir2Lir* m2l, LIR* branch, LIR* cont, uint32_t type_idx, 1125 RegLocation rl_src) 1126 : LIRSlowPath(m2l, m2l->GetCurrentDexPc(), branch, cont), type_idx_(type_idx), 1127 rl_src_(rl_src) { 1128 } 1129 1130 void Compile() OVERRIDE { 1131 GenerateTargetLabel(); 1132 1133 m2l_->CallRuntimeHelperImm(kQuickInitializeType, type_idx_, true); 1134 m2l_->OpRegCopy(m2l_->TargetReg(kArg2, kRef), 1135 m2l_->TargetReg(kRet0, kRef)); // Align usage with fast path 1136 m2l_->OpUnconditionalBranch(cont_); 1137 } 1138 1139 private: 1140 uint32_t type_idx_; 1141 RegLocation rl_src_; 1142 }; 1143 1144 AddSlowPath(new (arena_) InitTypeSlowPath(this, slow_path_branch, slow_path_target, 1145 type_idx, rl_src)); 1146 } 1147 } 1148 /* kArg0 is ref, kArg2 is class. If ref==null, use directly as bool result */ 1149 RegLocation rl_result = GetReturn(kCoreReg); 1150 if (!IsSameReg(rl_result.reg, ref_reg)) { 1151 // On MIPS and x86_64 rArg0 != rl_result, place false in result if branch is taken. 1152 LoadConstant(rl_result.reg, 0); 1153 } 1154 LIR* branch1 = OpCmpImmBranch(kCondEq, ref_reg, 0, NULL); 1155 1156 /* load object->klass_ */ 1157 RegStorage ref_class_reg = TargetReg(kArg1, kRef); // kArg1 will hold the Class* of ref. 1158 DCHECK_EQ(mirror::Object::ClassOffset().Int32Value(), 0); 1159 LoadRefDisp(ref_reg, mirror::Object::ClassOffset().Int32Value(), 1160 ref_class_reg, kNotVolatile); 1161 /* kArg0 is ref, kArg1 is ref->klass_, kArg2 is class */ 1162 LIR* branchover = NULL; 1163 if (type_known_final) { 1164 // rl_result == ref == class. 1165 GenSelectConst32(ref_class_reg, class_reg, kCondEq, 1, 0, rl_result.reg, 1166 kCoreReg); 1167 } else { 1168 if (cu_->instruction_set == kThumb2) { 1169 RegStorage r_tgt = LoadHelper(kQuickInstanceofNonTrivial); 1170 LIR* it = nullptr; 1171 if (!type_known_abstract) { 1172 /* Uses conditional nullification */ 1173 OpRegReg(kOpCmp, ref_class_reg, class_reg); // Same? 1174 it = OpIT(kCondEq, "EE"); // if-convert the test 1175 LoadConstant(rl_result.reg, 1); // .eq case - load true 1176 } 1177 OpRegCopy(ref_reg, class_reg); // .ne case - arg0 <= class 1178 OpReg(kOpBlx, r_tgt); // .ne case: helper(class, ref->class) 1179 if (it != nullptr) { 1180 OpEndIT(it); 1181 } 1182 FreeTemp(r_tgt); 1183 } else { 1184 if (!type_known_abstract) { 1185 /* Uses branchovers */ 1186 LoadConstant(rl_result.reg, 1); // assume true 1187 branchover = OpCmpBranch(kCondEq, TargetReg(kArg1, kRef), TargetReg(kArg2, kRef), NULL); 1188 } 1189 1190 OpRegCopy(TargetReg(kArg0, kRef), class_reg); // .ne case - arg0 <= class 1191 CallRuntimeHelper(kQuickInstanceofNonTrivial, false); 1192 } 1193 } 1194 // TODO: only clobber when type isn't final? 1195 ClobberCallerSave(); 1196 /* branch targets here */ 1197 LIR* target = NewLIR0(kPseudoTargetLabel); 1198 StoreValue(rl_dest, rl_result); 1199 branch1->target = target; 1200 if (branchover != nullptr) { 1201 branchover->target = target; 1202 } 1203 } 1204 1205 void Mir2Lir::GenInstanceof(uint32_t type_idx, RegLocation rl_dest, RegLocation rl_src) { 1206 bool type_known_final, type_known_abstract, use_declaring_class; 1207 bool needs_access_check = !cu_->compiler_driver->CanAccessTypeWithoutChecks(cu_->method_idx, 1208 *cu_->dex_file, 1209 type_idx, 1210 &type_known_final, 1211 &type_known_abstract, 1212 &use_declaring_class); 1213 bool can_assume_type_is_in_dex_cache = !needs_access_check && 1214 cu_->compiler_driver->CanAssumeTypeIsPresentInDexCache(*cu_->dex_file, type_idx); 1215 1216 if ((use_declaring_class || can_assume_type_is_in_dex_cache) && type_known_final) { 1217 GenInstanceofFinal(use_declaring_class, type_idx, rl_dest, rl_src); 1218 } else { 1219 GenInstanceofCallingHelper(needs_access_check, type_known_final, type_known_abstract, 1220 use_declaring_class, can_assume_type_is_in_dex_cache, 1221 type_idx, rl_dest, rl_src); 1222 } 1223 } 1224 1225 void Mir2Lir::GenCheckCast(uint32_t insn_idx, uint32_t type_idx, RegLocation rl_src) { 1226 bool type_known_final, type_known_abstract, use_declaring_class; 1227 bool needs_access_check = !cu_->compiler_driver->CanAccessTypeWithoutChecks(cu_->method_idx, 1228 *cu_->dex_file, 1229 type_idx, 1230 &type_known_final, 1231 &type_known_abstract, 1232 &use_declaring_class); 1233 // Note: currently type_known_final is unused, as optimizing will only improve the performance 1234 // of the exception throw path. 1235 DexCompilationUnit* cu = mir_graph_->GetCurrentDexCompilationUnit(); 1236 if (!needs_access_check && cu_->compiler_driver->IsSafeCast(cu, insn_idx)) { 1237 // Verifier type analysis proved this check cast would never cause an exception. 1238 return; 1239 } 1240 FlushAllRegs(); 1241 // May generate a call - use explicit registers 1242 LockCallTemps(); 1243 RegStorage method_reg = TargetReg(kArg1, kRef); 1244 LoadCurrMethodDirect(method_reg); // kArg1 <= current Method* 1245 RegStorage class_reg = TargetReg(kArg2, kRef); // kArg2 will hold the Class* 1246 if (needs_access_check) { 1247 // Check we have access to type_idx and if not throw IllegalAccessError, 1248 // returns Class* in kRet0 1249 // InitializeTypeAndVerifyAccess(idx, method) 1250 CallRuntimeHelperImm(kQuickInitializeTypeAndVerifyAccess, type_idx, true); 1251 OpRegCopy(class_reg, TargetReg(kRet0, kRef)); // Align usage with fast path 1252 } else if (use_declaring_class) { 1253 LoadRefDisp(method_reg, mirror::ArtMethod::DeclaringClassOffset().Int32Value(), 1254 class_reg, kNotVolatile); 1255 } else { 1256 // Load dex cache entry into class_reg (kArg2) 1257 LoadRefDisp(method_reg, mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value(), 1258 class_reg, kNotVolatile); 1259 int32_t offset_of_type = ClassArray::OffsetOfElement(type_idx).Int32Value(); 1260 LoadRefDisp(class_reg, offset_of_type, class_reg, kNotVolatile); 1261 if (!cu_->compiler_driver->CanAssumeTypeIsPresentInDexCache(*cu_->dex_file, type_idx)) { 1262 // Need to test presence of type in dex cache at runtime 1263 LIR* hop_branch = OpCmpImmBranch(kCondEq, class_reg, 0, NULL); 1264 LIR* cont = NewLIR0(kPseudoTargetLabel); 1265 1266 // Slow path to initialize the type. Executed if the type is NULL. 1267 class SlowPath : public LIRSlowPath { 1268 public: 1269 SlowPath(Mir2Lir* m2l, LIR* fromfast, LIR* cont, const int type_idx, 1270 const RegStorage class_reg) : 1271 LIRSlowPath(m2l, m2l->GetCurrentDexPc(), fromfast, cont), type_idx_(type_idx), 1272 class_reg_(class_reg) { 1273 } 1274 1275 void Compile() { 1276 GenerateTargetLabel(); 1277 1278 // Call out to helper, which will return resolved type in kArg0 1279 // InitializeTypeFromCode(idx, method) 1280 m2l_->CallRuntimeHelperImmReg(kQuickInitializeType, type_idx_, 1281 m2l_->TargetReg(kArg1, kRef), true); 1282 m2l_->OpRegCopy(class_reg_, m2l_->TargetReg(kRet0, kRef)); // Align usage with fast path 1283 m2l_->OpUnconditionalBranch(cont_); 1284 } 1285 1286 public: 1287 const int type_idx_; 1288 const RegStorage class_reg_; 1289 }; 1290 1291 AddSlowPath(new (arena_) SlowPath(this, hop_branch, cont, type_idx, class_reg)); 1292 } 1293 } 1294 // At this point, class_reg (kArg2) has class 1295 LoadValueDirectFixed(rl_src, TargetReg(kArg0, kRef)); // kArg0 <= ref 1296 1297 // Slow path for the case where the classes are not equal. In this case we need 1298 // to call a helper function to do the check. 1299 class SlowPath : public LIRSlowPath { 1300 public: 1301 SlowPath(Mir2Lir* m2l, LIR* fromfast, LIR* cont, bool load): 1302 LIRSlowPath(m2l, m2l->GetCurrentDexPc(), fromfast, cont), load_(load) { 1303 } 1304 1305 void Compile() { 1306 GenerateTargetLabel(); 1307 1308 if (load_) { 1309 m2l_->LoadRefDisp(m2l_->TargetReg(kArg0, kRef), mirror::Object::ClassOffset().Int32Value(), 1310 m2l_->TargetReg(kArg1, kRef), kNotVolatile); 1311 } 1312 m2l_->CallRuntimeHelperRegReg(kQuickCheckCast, m2l_->TargetReg(kArg2, kRef), 1313 m2l_->TargetReg(kArg1, kRef), true); 1314 m2l_->OpUnconditionalBranch(cont_); 1315 } 1316 1317 private: 1318 const bool load_; 1319 }; 1320 1321 if (type_known_abstract) { 1322 // Easier case, run slow path if target is non-null (slow path will load from target) 1323 LIR* branch = OpCmpImmBranch(kCondNe, TargetReg(kArg0, kRef), 0, nullptr); 1324 LIR* cont = NewLIR0(kPseudoTargetLabel); 1325 AddSlowPath(new (arena_) SlowPath(this, branch, cont, true)); 1326 } else { 1327 // Harder, more common case. We need to generate a forward branch over the load 1328 // if the target is null. If it's non-null we perform the load and branch to the 1329 // slow path if the classes are not equal. 1330 1331 /* Null is OK - continue */ 1332 LIR* branch1 = OpCmpImmBranch(kCondEq, TargetReg(kArg0, kRef), 0, nullptr); 1333 /* load object->klass_ */ 1334 DCHECK_EQ(mirror::Object::ClassOffset().Int32Value(), 0); 1335 LoadRefDisp(TargetReg(kArg0, kRef), mirror::Object::ClassOffset().Int32Value(), 1336 TargetReg(kArg1, kRef), kNotVolatile); 1337 1338 LIR* branch2 = OpCmpBranch(kCondNe, TargetReg(kArg1, kRef), class_reg, nullptr); 1339 LIR* cont = NewLIR0(kPseudoTargetLabel); 1340 1341 // Add the slow path that will not perform load since this is already done. 1342 AddSlowPath(new (arena_) SlowPath(this, branch2, cont, false)); 1343 1344 // Set the null check to branch to the continuation. 1345 branch1->target = cont; 1346 } 1347 } 1348 1349 void Mir2Lir::GenLong3Addr(OpKind first_op, OpKind second_op, RegLocation rl_dest, 1350 RegLocation rl_src1, RegLocation rl_src2) { 1351 RegLocation rl_result; 1352 if (cu_->instruction_set == kThumb2) { 1353 /* 1354 * NOTE: This is the one place in the code in which we might have 1355 * as many as six live temporary registers. There are 5 in the normal 1356 * set for Arm. Until we have spill capabilities, temporarily add 1357 * lr to the temp set. It is safe to do this locally, but note that 1358 * lr is used explicitly elsewhere in the code generator and cannot 1359 * normally be used as a general temp register. 1360 */ 1361 MarkTemp(TargetReg(kLr, kNotWide)); // Add lr to the temp pool 1362 FreeTemp(TargetReg(kLr, kNotWide)); // and make it available 1363 } 1364 rl_src1 = LoadValueWide(rl_src1, kCoreReg); 1365 rl_src2 = LoadValueWide(rl_src2, kCoreReg); 1366 rl_result = EvalLoc(rl_dest, kCoreReg, true); 1367 // The longs may overlap - use intermediate temp if so 1368 if ((rl_result.reg.GetLowReg() == rl_src1.reg.GetHighReg()) || (rl_result.reg.GetLowReg() == rl_src2.reg.GetHighReg())) { 1369 RegStorage t_reg = AllocTemp(); 1370 OpRegRegReg(first_op, t_reg, rl_src1.reg.GetLow(), rl_src2.reg.GetLow()); 1371 OpRegRegReg(second_op, rl_result.reg.GetHigh(), rl_src1.reg.GetHigh(), rl_src2.reg.GetHigh()); 1372 OpRegCopy(rl_result.reg.GetLow(), t_reg); 1373 FreeTemp(t_reg); 1374 } else { 1375 OpRegRegReg(first_op, rl_result.reg.GetLow(), rl_src1.reg.GetLow(), rl_src2.reg.GetLow()); 1376 OpRegRegReg(second_op, rl_result.reg.GetHigh(), rl_src1.reg.GetHigh(), rl_src2.reg.GetHigh()); 1377 } 1378 /* 1379 * NOTE: If rl_dest refers to a frame variable in a large frame, the 1380 * following StoreValueWide might need to allocate a temp register. 1381 * To further work around the lack of a spill capability, explicitly 1382 * free any temps from rl_src1 & rl_src2 that aren't still live in rl_result. 1383 * Remove when spill is functional. 1384 */ 1385 FreeRegLocTemps(rl_result, rl_src1); 1386 FreeRegLocTemps(rl_result, rl_src2); 1387 StoreValueWide(rl_dest, rl_result); 1388 if (cu_->instruction_set == kThumb2) { 1389 Clobber(TargetReg(kLr, kNotWide)); 1390 UnmarkTemp(TargetReg(kLr, kNotWide)); // Remove lr from the temp pool 1391 } 1392 } 1393 1394 void Mir2Lir::GenShiftOpLong(Instruction::Code opcode, RegLocation rl_dest, 1395 RegLocation rl_src1, RegLocation rl_shift) { 1396 QuickEntrypointEnum target; 1397 switch (opcode) { 1398 case Instruction::SHL_LONG: 1399 case Instruction::SHL_LONG_2ADDR: 1400 target = kQuickShlLong; 1401 break; 1402 case Instruction::SHR_LONG: 1403 case Instruction::SHR_LONG_2ADDR: 1404 target = kQuickShrLong; 1405 break; 1406 case Instruction::USHR_LONG: 1407 case Instruction::USHR_LONG_2ADDR: 1408 target = kQuickUshrLong; 1409 break; 1410 default: 1411 LOG(FATAL) << "Unexpected case"; 1412 target = kQuickShlLong; 1413 } 1414 FlushAllRegs(); /* Send everything to home location */ 1415 CallRuntimeHelperRegLocationRegLocation(target, rl_src1, rl_shift, false); 1416 RegLocation rl_result = GetReturnWide(kCoreReg); 1417 StoreValueWide(rl_dest, rl_result); 1418 } 1419 1420 1421 void Mir2Lir::GenArithOpInt(Instruction::Code opcode, RegLocation rl_dest, 1422 RegLocation rl_src1, RegLocation rl_src2) { 1423 DCHECK(cu_->instruction_set != kX86 && cu_->instruction_set != kX86_64); 1424 OpKind op = kOpBkpt; 1425 bool is_div_rem = false; 1426 bool check_zero = false; 1427 bool unary = false; 1428 RegLocation rl_result; 1429 bool shift_op = false; 1430 switch (opcode) { 1431 case Instruction::NEG_INT: 1432 op = kOpNeg; 1433 unary = true; 1434 break; 1435 case Instruction::NOT_INT: 1436 op = kOpMvn; 1437 unary = true; 1438 break; 1439 case Instruction::ADD_INT: 1440 case Instruction::ADD_INT_2ADDR: 1441 op = kOpAdd; 1442 break; 1443 case Instruction::SUB_INT: 1444 case Instruction::SUB_INT_2ADDR: 1445 op = kOpSub; 1446 break; 1447 case Instruction::MUL_INT: 1448 case Instruction::MUL_INT_2ADDR: 1449 op = kOpMul; 1450 break; 1451 case Instruction::DIV_INT: 1452 case Instruction::DIV_INT_2ADDR: 1453 check_zero = true; 1454 op = kOpDiv; 1455 is_div_rem = true; 1456 break; 1457 /* NOTE: returns in kArg1 */ 1458 case Instruction::REM_INT: 1459 case Instruction::REM_INT_2ADDR: 1460 check_zero = true; 1461 op = kOpRem; 1462 is_div_rem = true; 1463 break; 1464 case Instruction::AND_INT: 1465 case Instruction::AND_INT_2ADDR: 1466 op = kOpAnd; 1467 break; 1468 case Instruction::OR_INT: 1469 case Instruction::OR_INT_2ADDR: 1470 op = kOpOr; 1471 break; 1472 case Instruction::XOR_INT: 1473 case Instruction::XOR_INT_2ADDR: 1474 op = kOpXor; 1475 break; 1476 case Instruction::SHL_INT: 1477 case Instruction::SHL_INT_2ADDR: 1478 shift_op = true; 1479 op = kOpLsl; 1480 break; 1481 case Instruction::SHR_INT: 1482 case Instruction::SHR_INT_2ADDR: 1483 shift_op = true; 1484 op = kOpAsr; 1485 break; 1486 case Instruction::USHR_INT: 1487 case Instruction::USHR_INT_2ADDR: 1488 shift_op = true; 1489 op = kOpLsr; 1490 break; 1491 default: 1492 LOG(FATAL) << "Invalid word arith op: " << opcode; 1493 } 1494 if (!is_div_rem) { 1495 if (unary) { 1496 rl_src1 = LoadValue(rl_src1, kCoreReg); 1497 rl_result = EvalLoc(rl_dest, kCoreReg, true); 1498 OpRegReg(op, rl_result.reg, rl_src1.reg); 1499 } else { 1500 if ((shift_op) && (cu_->instruction_set != kArm64)) { 1501 rl_src2 = LoadValue(rl_src2, kCoreReg); 1502 RegStorage t_reg = AllocTemp(); 1503 OpRegRegImm(kOpAnd, t_reg, rl_src2.reg, 31); 1504 rl_src1 = LoadValue(rl_src1, kCoreReg); 1505 rl_result = EvalLoc(rl_dest, kCoreReg, true); 1506 OpRegRegReg(op, rl_result.reg, rl_src1.reg, t_reg); 1507 FreeTemp(t_reg); 1508 } else { 1509 rl_src1 = LoadValue(rl_src1, kCoreReg); 1510 rl_src2 = LoadValue(rl_src2, kCoreReg); 1511 rl_result = EvalLoc(rl_dest, kCoreReg, true); 1512 OpRegRegReg(op, rl_result.reg, rl_src1.reg, rl_src2.reg); 1513 } 1514 } 1515 StoreValue(rl_dest, rl_result); 1516 } else { 1517 bool done = false; // Set to true if we happen to find a way to use a real instruction. 1518 if (cu_->instruction_set == kMips || cu_->instruction_set == kArm64) { 1519 rl_src1 = LoadValue(rl_src1, kCoreReg); 1520 rl_src2 = LoadValue(rl_src2, kCoreReg); 1521 if (check_zero) { 1522 GenDivZeroCheck(rl_src2.reg); 1523 } 1524 rl_result = GenDivRem(rl_dest, rl_src1.reg, rl_src2.reg, op == kOpDiv); 1525 done = true; 1526 } else if (cu_->instruction_set == kThumb2) { 1527 if (cu_->GetInstructionSetFeatures().HasDivideInstruction()) { 1528 // Use ARM SDIV instruction for division. For remainder we also need to 1529 // calculate using a MUL and subtract. 1530 rl_src1 = LoadValue(rl_src1, kCoreReg); 1531 rl_src2 = LoadValue(rl_src2, kCoreReg); 1532 if (check_zero) { 1533 GenDivZeroCheck(rl_src2.reg); 1534 } 1535 rl_result = GenDivRem(rl_dest, rl_src1.reg, rl_src2.reg, op == kOpDiv); 1536 done = true; 1537 } 1538 } 1539 1540 // If we haven't already generated the code use the callout function. 1541 if (!done) { 1542 FlushAllRegs(); /* Send everything to home location */ 1543 LoadValueDirectFixed(rl_src2, TargetReg(kArg1, kNotWide)); 1544 RegStorage r_tgt = CallHelperSetup(kQuickIdivmod); 1545 LoadValueDirectFixed(rl_src1, TargetReg(kArg0, kNotWide)); 1546 if (check_zero) { 1547 GenDivZeroCheck(TargetReg(kArg1, kNotWide)); 1548 } 1549 // NOTE: callout here is not a safepoint. 1550 CallHelper(r_tgt, kQuickIdivmod, false /* not a safepoint */); 1551 if (op == kOpDiv) 1552 rl_result = GetReturn(kCoreReg); 1553 else 1554 rl_result = GetReturnAlt(); 1555 } 1556 StoreValue(rl_dest, rl_result); 1557 } 1558 } 1559 1560 /* 1561 * The following are the first-level codegen routines that analyze the format 1562 * of each bytecode then either dispatch special purpose codegen routines 1563 * or produce corresponding Thumb instructions directly. 1564 */ 1565 1566 // Returns true if no more than two bits are set in 'x'. 1567 static bool IsPopCountLE2(unsigned int x) { 1568 x &= x - 1; 1569 return (x & (x - 1)) == 0; 1570 } 1571 1572 // Returns true if it added instructions to 'cu' to divide 'rl_src' by 'lit' 1573 // and store the result in 'rl_dest'. 1574 bool Mir2Lir::HandleEasyDivRem(Instruction::Code dalvik_opcode, bool is_div, 1575 RegLocation rl_src, RegLocation rl_dest, int lit) { 1576 if ((lit < 2) || ((cu_->instruction_set != kThumb2) && !IsPowerOfTwo(lit))) { 1577 return false; 1578 } 1579 // No divide instruction for Arm, so check for more special cases 1580 if ((cu_->instruction_set == kThumb2) && !IsPowerOfTwo(lit)) { 1581 return SmallLiteralDivRem(dalvik_opcode, is_div, rl_src, rl_dest, lit); 1582 } 1583 int k = LowestSetBit(lit); 1584 if (k >= 30) { 1585 // Avoid special cases. 1586 return false; 1587 } 1588 rl_src = LoadValue(rl_src, kCoreReg); 1589 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true); 1590 if (is_div) { 1591 RegStorage t_reg = AllocTemp(); 1592 if (lit == 2) { 1593 // Division by 2 is by far the most common division by constant. 1594 OpRegRegImm(kOpLsr, t_reg, rl_src.reg, 32 - k); 1595 OpRegRegReg(kOpAdd, t_reg, t_reg, rl_src.reg); 1596 OpRegRegImm(kOpAsr, rl_result.reg, t_reg, k); 1597 } else { 1598 OpRegRegImm(kOpAsr, t_reg, rl_src.reg, 31); 1599 OpRegRegImm(kOpLsr, t_reg, t_reg, 32 - k); 1600 OpRegRegReg(kOpAdd, t_reg, t_reg, rl_src.reg); 1601 OpRegRegImm(kOpAsr, rl_result.reg, t_reg, k); 1602 } 1603 } else { 1604 RegStorage t_reg1 = AllocTemp(); 1605 RegStorage t_reg2 = AllocTemp(); 1606 if (lit == 2) { 1607 OpRegRegImm(kOpLsr, t_reg1, rl_src.reg, 32 - k); 1608 OpRegRegReg(kOpAdd, t_reg2, t_reg1, rl_src.reg); 1609 OpRegRegImm(kOpAnd, t_reg2, t_reg2, lit -1); 1610 OpRegRegReg(kOpSub, rl_result.reg, t_reg2, t_reg1); 1611 } else { 1612 OpRegRegImm(kOpAsr, t_reg1, rl_src.reg, 31); 1613 OpRegRegImm(kOpLsr, t_reg1, t_reg1, 32 - k); 1614 OpRegRegReg(kOpAdd, t_reg2, t_reg1, rl_src.reg); 1615 OpRegRegImm(kOpAnd, t_reg2, t_reg2, lit - 1); 1616 OpRegRegReg(kOpSub, rl_result.reg, t_reg2, t_reg1); 1617 } 1618 } 1619 StoreValue(rl_dest, rl_result); 1620 return true; 1621 } 1622 1623 // Returns true if it added instructions to 'cu' to multiply 'rl_src' by 'lit' 1624 // and store the result in 'rl_dest'. 1625 bool Mir2Lir::HandleEasyMultiply(RegLocation rl_src, RegLocation rl_dest, int lit) { 1626 if (lit < 0) { 1627 return false; 1628 } 1629 if (lit == 0) { 1630 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true); 1631 LoadConstant(rl_result.reg, 0); 1632 StoreValue(rl_dest, rl_result); 1633 return true; 1634 } 1635 if (lit == 1) { 1636 rl_src = LoadValue(rl_src, kCoreReg); 1637 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true); 1638 OpRegCopy(rl_result.reg, rl_src.reg); 1639 StoreValue(rl_dest, rl_result); 1640 return true; 1641 } 1642 // There is RegRegRegShift on Arm, so check for more special cases 1643 if (cu_->instruction_set == kThumb2) { 1644 return EasyMultiply(rl_src, rl_dest, lit); 1645 } 1646 // Can we simplify this multiplication? 1647 bool power_of_two = false; 1648 bool pop_count_le2 = false; 1649 bool power_of_two_minus_one = false; 1650 if (IsPowerOfTwo(lit)) { 1651 power_of_two = true; 1652 } else if (IsPopCountLE2(lit)) { 1653 pop_count_le2 = true; 1654 } else if (IsPowerOfTwo(lit + 1)) { 1655 power_of_two_minus_one = true; 1656 } else { 1657 return false; 1658 } 1659 rl_src = LoadValue(rl_src, kCoreReg); 1660 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true); 1661 if (power_of_two) { 1662 // Shift. 1663 OpRegRegImm(kOpLsl, rl_result.reg, rl_src.reg, LowestSetBit(lit)); 1664 } else if (pop_count_le2) { 1665 // Shift and add and shift. 1666 int first_bit = LowestSetBit(lit); 1667 int second_bit = LowestSetBit(lit ^ (1 << first_bit)); 1668 GenMultiplyByTwoBitMultiplier(rl_src, rl_result, lit, first_bit, second_bit); 1669 } else { 1670 // Reverse subtract: (src << (shift + 1)) - src. 1671 DCHECK(power_of_two_minus_one); 1672 // TUNING: rsb dst, src, src lsl#LowestSetBit(lit + 1) 1673 RegStorage t_reg = AllocTemp(); 1674 OpRegRegImm(kOpLsl, t_reg, rl_src.reg, LowestSetBit(lit + 1)); 1675 OpRegRegReg(kOpSub, rl_result.reg, t_reg, rl_src.reg); 1676 } 1677 StoreValue(rl_dest, rl_result); 1678 return true; 1679 } 1680 1681 void Mir2Lir::GenArithOpIntLit(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src, 1682 int lit) { 1683 RegLocation rl_result; 1684 OpKind op = static_cast<OpKind>(0); /* Make gcc happy */ 1685 int shift_op = false; 1686 bool is_div = false; 1687 1688 switch (opcode) { 1689 case Instruction::RSUB_INT_LIT8: 1690 case Instruction::RSUB_INT: { 1691 rl_src = LoadValue(rl_src, kCoreReg); 1692 rl_result = EvalLoc(rl_dest, kCoreReg, true); 1693 if (cu_->instruction_set == kThumb2) { 1694 OpRegRegImm(kOpRsub, rl_result.reg, rl_src.reg, lit); 1695 } else { 1696 OpRegReg(kOpNeg, rl_result.reg, rl_src.reg); 1697 OpRegImm(kOpAdd, rl_result.reg, lit); 1698 } 1699 StoreValue(rl_dest, rl_result); 1700 return; 1701 } 1702 1703 case Instruction::SUB_INT: 1704 case Instruction::SUB_INT_2ADDR: 1705 lit = -lit; 1706 // Intended fallthrough 1707 case Instruction::ADD_INT: 1708 case Instruction::ADD_INT_2ADDR: 1709 case Instruction::ADD_INT_LIT8: 1710 case Instruction::ADD_INT_LIT16: 1711 op = kOpAdd; 1712 break; 1713 case Instruction::MUL_INT: 1714 case Instruction::MUL_INT_2ADDR: 1715 case Instruction::MUL_INT_LIT8: 1716 case Instruction::MUL_INT_LIT16: { 1717 if (HandleEasyMultiply(rl_src, rl_dest, lit)) { 1718 return; 1719 } 1720 op = kOpMul; 1721 break; 1722 } 1723 case Instruction::AND_INT: 1724 case Instruction::AND_INT_2ADDR: 1725 case Instruction::AND_INT_LIT8: 1726 case Instruction::AND_INT_LIT16: 1727 op = kOpAnd; 1728 break; 1729 case Instruction::OR_INT: 1730 case Instruction::OR_INT_2ADDR: 1731 case Instruction::OR_INT_LIT8: 1732 case Instruction::OR_INT_LIT16: 1733 op = kOpOr; 1734 break; 1735 case Instruction::XOR_INT: 1736 case Instruction::XOR_INT_2ADDR: 1737 case Instruction::XOR_INT_LIT8: 1738 case Instruction::XOR_INT_LIT16: 1739 op = kOpXor; 1740 break; 1741 case Instruction::SHL_INT_LIT8: 1742 case Instruction::SHL_INT: 1743 case Instruction::SHL_INT_2ADDR: 1744 lit &= 31; 1745 shift_op = true; 1746 op = kOpLsl; 1747 break; 1748 case Instruction::SHR_INT_LIT8: 1749 case Instruction::SHR_INT: 1750 case Instruction::SHR_INT_2ADDR: 1751 lit &= 31; 1752 shift_op = true; 1753 op = kOpAsr; 1754 break; 1755 case Instruction::USHR_INT_LIT8: 1756 case Instruction::USHR_INT: 1757 case Instruction::USHR_INT_2ADDR: 1758 lit &= 31; 1759 shift_op = true; 1760 op = kOpLsr; 1761 break; 1762 1763 case Instruction::DIV_INT: 1764 case Instruction::DIV_INT_2ADDR: 1765 case Instruction::DIV_INT_LIT8: 1766 case Instruction::DIV_INT_LIT16: 1767 case Instruction::REM_INT: 1768 case Instruction::REM_INT_2ADDR: 1769 case Instruction::REM_INT_LIT8: 1770 case Instruction::REM_INT_LIT16: { 1771 if (lit == 0) { 1772 GenDivZeroException(); 1773 return; 1774 } 1775 if ((opcode == Instruction::DIV_INT) || 1776 (opcode == Instruction::DIV_INT_2ADDR) || 1777 (opcode == Instruction::DIV_INT_LIT8) || 1778 (opcode == Instruction::DIV_INT_LIT16)) { 1779 is_div = true; 1780 } else { 1781 is_div = false; 1782 } 1783 if (HandleEasyDivRem(opcode, is_div, rl_src, rl_dest, lit)) { 1784 return; 1785 } 1786 1787 bool done = false; 1788 if (cu_->instruction_set == kMips || cu_->instruction_set == kArm64) { 1789 rl_src = LoadValue(rl_src, kCoreReg); 1790 rl_result = GenDivRemLit(rl_dest, rl_src.reg, lit, is_div); 1791 done = true; 1792 } else if (cu_->instruction_set == kX86 || cu_->instruction_set == kX86_64) { 1793 rl_result = GenDivRemLit(rl_dest, rl_src, lit, is_div); 1794 done = true; 1795 } else if (cu_->instruction_set == kThumb2) { 1796 if (cu_->GetInstructionSetFeatures().HasDivideInstruction()) { 1797 // Use ARM SDIV instruction for division. For remainder we also need to 1798 // calculate using a MUL and subtract. 1799 rl_src = LoadValue(rl_src, kCoreReg); 1800 rl_result = GenDivRemLit(rl_dest, rl_src.reg, lit, is_div); 1801 done = true; 1802 } 1803 } 1804 1805 if (!done) { 1806 FlushAllRegs(); /* Everything to home location. */ 1807 LoadValueDirectFixed(rl_src, TargetReg(kArg0, kNotWide)); 1808 Clobber(TargetReg(kArg0, kNotWide)); 1809 CallRuntimeHelperRegImm(kQuickIdivmod, TargetReg(kArg0, kNotWide), lit, false); 1810 if (is_div) 1811 rl_result = GetReturn(kCoreReg); 1812 else 1813 rl_result = GetReturnAlt(); 1814 } 1815 StoreValue(rl_dest, rl_result); 1816 return; 1817 } 1818 default: 1819 LOG(FATAL) << "Unexpected opcode " << opcode; 1820 } 1821 rl_src = LoadValue(rl_src, kCoreReg); 1822 rl_result = EvalLoc(rl_dest, kCoreReg, true); 1823 // Avoid shifts by literal 0 - no support in Thumb. Change to copy. 1824 if (shift_op && (lit == 0)) { 1825 OpRegCopy(rl_result.reg, rl_src.reg); 1826 } else { 1827 OpRegRegImm(op, rl_result.reg, rl_src.reg, lit); 1828 } 1829 StoreValue(rl_dest, rl_result); 1830 } 1831 1832 void Mir2Lir::GenArithOpLong(Instruction::Code opcode, RegLocation rl_dest, 1833 RegLocation rl_src1, RegLocation rl_src2) { 1834 RegLocation rl_result; 1835 OpKind first_op = kOpBkpt; 1836 OpKind second_op = kOpBkpt; 1837 bool call_out = false; 1838 bool check_zero = false; 1839 int ret_reg = TargetReg(kRet0, kNotWide).GetReg(); 1840 QuickEntrypointEnum target; 1841 1842 switch (opcode) { 1843 case Instruction::NOT_LONG: 1844 rl_src2 = LoadValueWide(rl_src2, kCoreReg); 1845 rl_result = EvalLoc(rl_dest, kCoreReg, true); 1846 // Check for destructive overlap 1847 if (rl_result.reg.GetLowReg() == rl_src2.reg.GetHighReg()) { 1848 RegStorage t_reg = AllocTemp(); 1849 OpRegCopy(t_reg, rl_src2.reg.GetHigh()); 1850 OpRegReg(kOpMvn, rl_result.reg.GetLow(), rl_src2.reg.GetLow()); 1851 OpRegReg(kOpMvn, rl_result.reg.GetHigh(), t_reg); 1852 FreeTemp(t_reg); 1853 } else { 1854 OpRegReg(kOpMvn, rl_result.reg.GetLow(), rl_src2.reg.GetLow()); 1855 OpRegReg(kOpMvn, rl_result.reg.GetHigh(), rl_src2.reg.GetHigh()); 1856 } 1857 StoreValueWide(rl_dest, rl_result); 1858 return; 1859 case Instruction::ADD_LONG: 1860 case Instruction::ADD_LONG_2ADDR: 1861 first_op = kOpAdd; 1862 second_op = kOpAdc; 1863 break; 1864 case Instruction::SUB_LONG: 1865 case Instruction::SUB_LONG_2ADDR: 1866 first_op = kOpSub; 1867 second_op = kOpSbc; 1868 break; 1869 case Instruction::MUL_LONG: 1870 case Instruction::MUL_LONG_2ADDR: 1871 call_out = true; 1872 ret_reg = TargetReg(kRet0, kNotWide).GetReg(); 1873 target = kQuickLmul; 1874 break; 1875 case Instruction::DIV_LONG: 1876 case Instruction::DIV_LONG_2ADDR: 1877 call_out = true; 1878 check_zero = true; 1879 ret_reg = TargetReg(kRet0, kNotWide).GetReg(); 1880 target = kQuickLdiv; 1881 break; 1882 case Instruction::REM_LONG: 1883 case Instruction::REM_LONG_2ADDR: 1884 call_out = true; 1885 check_zero = true; 1886 target = kQuickLmod; 1887 /* NOTE - for Arm, result is in kArg2/kArg3 instead of kRet0/kRet1 */ 1888 ret_reg = (cu_->instruction_set == kThumb2) ? TargetReg(kArg2, kNotWide).GetReg() : 1889 TargetReg(kRet0, kNotWide).GetReg(); 1890 break; 1891 case Instruction::AND_LONG_2ADDR: 1892 case Instruction::AND_LONG: 1893 first_op = kOpAnd; 1894 second_op = kOpAnd; 1895 break; 1896 case Instruction::OR_LONG: 1897 case Instruction::OR_LONG_2ADDR: 1898 first_op = kOpOr; 1899 second_op = kOpOr; 1900 break; 1901 case Instruction::XOR_LONG: 1902 case Instruction::XOR_LONG_2ADDR: 1903 first_op = kOpXor; 1904 second_op = kOpXor; 1905 break; 1906 default: 1907 LOG(FATAL) << "Invalid long arith op"; 1908 } 1909 if (!call_out) { 1910 GenLong3Addr(first_op, second_op, rl_dest, rl_src1, rl_src2); 1911 } else { 1912 FlushAllRegs(); /* Send everything to home location */ 1913 if (check_zero) { 1914 RegStorage r_tmp1 = TargetReg(kArg0, kWide); 1915 RegStorage r_tmp2 = TargetReg(kArg2, kWide); 1916 LoadValueDirectWideFixed(rl_src2, r_tmp2); 1917 RegStorage r_tgt = CallHelperSetup(target); 1918 GenDivZeroCheckWide(r_tmp2); 1919 LoadValueDirectWideFixed(rl_src1, r_tmp1); 1920 // NOTE: callout here is not a safepoint 1921 CallHelper(r_tgt, target, false /* not safepoint */); 1922 } else { 1923 CallRuntimeHelperRegLocationRegLocation(target, rl_src1, rl_src2, false); 1924 } 1925 // Adjust return regs in to handle case of rem returning kArg2/kArg3 1926 if (ret_reg == TargetReg(kRet0, kNotWide).GetReg()) 1927 rl_result = GetReturnWide(kCoreReg); 1928 else 1929 rl_result = GetReturnWideAlt(); 1930 StoreValueWide(rl_dest, rl_result); 1931 } 1932 } 1933 1934 void Mir2Lir::GenConst(RegLocation rl_dest, int value) { 1935 RegLocation rl_result = EvalLoc(rl_dest, kAnyReg, true); 1936 LoadConstantNoClobber(rl_result.reg, value); 1937 StoreValue(rl_dest, rl_result); 1938 if (value == 0) { 1939 Workaround7250540(rl_dest, rl_result.reg); 1940 } 1941 } 1942 1943 void Mir2Lir::GenConversionCall(QuickEntrypointEnum trampoline, RegLocation rl_dest, 1944 RegLocation rl_src) { 1945 /* 1946 * Don't optimize the register usage since it calls out to support 1947 * functions 1948 */ 1949 1950 FlushAllRegs(); /* Send everything to home location */ 1951 CallRuntimeHelperRegLocation(trampoline, rl_src, false); 1952 if (rl_dest.wide) { 1953 RegLocation rl_result; 1954 rl_result = GetReturnWide(LocToRegClass(rl_dest)); 1955 StoreValueWide(rl_dest, rl_result); 1956 } else { 1957 RegLocation rl_result; 1958 rl_result = GetReturn(LocToRegClass(rl_dest)); 1959 StoreValue(rl_dest, rl_result); 1960 } 1961 } 1962 1963 class SuspendCheckSlowPath : public Mir2Lir::LIRSlowPath { 1964 public: 1965 SuspendCheckSlowPath(Mir2Lir* m2l, LIR* branch, LIR* cont) 1966 : LIRSlowPath(m2l, m2l->GetCurrentDexPc(), branch, cont) { 1967 } 1968 1969 void Compile() OVERRIDE { 1970 m2l_->ResetRegPool(); 1971 m2l_->ResetDefTracking(); 1972 GenerateTargetLabel(kPseudoSuspendTarget); 1973 m2l_->CallRuntimeHelper(kQuickTestSuspend, true); 1974 if (cont_ != nullptr) { 1975 m2l_->OpUnconditionalBranch(cont_); 1976 } 1977 } 1978 }; 1979 1980 /* Check if we need to check for pending suspend request */ 1981 void Mir2Lir::GenSuspendTest(int opt_flags) { 1982 if (!cu_->compiler_driver->GetCompilerOptions().GetImplicitSuspendChecks()) { 1983 if (NO_SUSPEND || (opt_flags & MIR_IGNORE_SUSPEND_CHECK)) { 1984 return; 1985 } 1986 FlushAllRegs(); 1987 LIR* branch = OpTestSuspend(NULL); 1988 LIR* cont = NewLIR0(kPseudoTargetLabel); 1989 AddSlowPath(new (arena_) SuspendCheckSlowPath(this, branch, cont)); 1990 } else { 1991 if (NO_SUSPEND || (opt_flags & MIR_IGNORE_SUSPEND_CHECK)) { 1992 return; 1993 } 1994 FlushAllRegs(); // TODO: needed? 1995 LIR* inst = CheckSuspendUsingLoad(); 1996 MarkSafepointPC(inst); 1997 } 1998 } 1999 2000 /* Check if we need to check for pending suspend request */ 2001 void Mir2Lir::GenSuspendTestAndBranch(int opt_flags, LIR* target) { 2002 if (!cu_->compiler_driver->GetCompilerOptions().GetImplicitSuspendChecks()) { 2003 if (NO_SUSPEND || (opt_flags & MIR_IGNORE_SUSPEND_CHECK)) { 2004 OpUnconditionalBranch(target); 2005 return; 2006 } 2007 OpTestSuspend(target); 2008 FlushAllRegs(); 2009 LIR* branch = OpUnconditionalBranch(nullptr); 2010 AddSlowPath(new (arena_) SuspendCheckSlowPath(this, branch, target)); 2011 } else { 2012 // For the implicit suspend check, just perform the trigger 2013 // load and branch to the target. 2014 if (NO_SUSPEND || (opt_flags & MIR_IGNORE_SUSPEND_CHECK)) { 2015 OpUnconditionalBranch(target); 2016 return; 2017 } 2018 FlushAllRegs(); 2019 LIR* inst = CheckSuspendUsingLoad(); 2020 MarkSafepointPC(inst); 2021 OpUnconditionalBranch(target); 2022 } 2023 } 2024 2025 /* Call out to helper assembly routine that will null check obj and then lock it. */ 2026 void Mir2Lir::GenMonitorEnter(int opt_flags, RegLocation rl_src) { 2027 FlushAllRegs(); 2028 CallRuntimeHelperRegLocation(kQuickLockObject, rl_src, true); 2029 } 2030 2031 /* Call out to helper assembly routine that will null check obj and then unlock it. */ 2032 void Mir2Lir::GenMonitorExit(int opt_flags, RegLocation rl_src) { 2033 FlushAllRegs(); 2034 CallRuntimeHelperRegLocation(kQuickUnlockObject, rl_src, true); 2035 } 2036 2037 /* Generic code for generating a wide constant into a VR. */ 2038 void Mir2Lir::GenConstWide(RegLocation rl_dest, int64_t value) { 2039 RegLocation rl_result = EvalLoc(rl_dest, kAnyReg, true); 2040 LoadConstantWide(rl_result.reg, value); 2041 StoreValueWide(rl_dest, rl_result); 2042 } 2043 2044 void Mir2Lir::GenSmallPackedSwitch(MIR* mir, DexOffset table_offset, RegLocation rl_src) { 2045 const uint16_t* table = cu_->insns + current_dalvik_offset_ + table_offset; 2046 const uint16_t entries = table[1]; 2047 // Chained cmp-and-branch. 2048 const int32_t* as_int32 = reinterpret_cast<const int32_t*>(&table[2]); 2049 int32_t current_key = as_int32[0]; 2050 const int32_t* targets = &as_int32[1]; 2051 rl_src = LoadValue(rl_src, kCoreReg); 2052 int i = 0; 2053 for (; i < entries; i++, current_key++) { 2054 if (!InexpensiveConstantInt(current_key, Instruction::Code::IF_EQ)) { 2055 // Switch to using a temp and add. 2056 break; 2057 } 2058 BasicBlock* case_block = 2059 mir_graph_->FindBlock(current_dalvik_offset_ + targets[i]); 2060 OpCmpImmBranch(kCondEq, rl_src.reg, current_key, &block_label_list_[case_block->id]); 2061 } 2062 if (i < entries) { 2063 // The rest do not seem to be inexpensive. Try to allocate a temp and use add. 2064 RegStorage key_temp = AllocTypedTemp(false, kCoreReg, false); 2065 if (key_temp.Valid()) { 2066 LoadConstantNoClobber(key_temp, current_key); 2067 for (; i < entries - 1; i++, current_key++) { 2068 BasicBlock* case_block = 2069 mir_graph_->FindBlock(current_dalvik_offset_ + targets[i]); 2070 OpCmpBranch(kCondEq, rl_src.reg, key_temp, &block_label_list_[case_block->id]); 2071 OpRegImm(kOpAdd, key_temp, 1); // Increment key. 2072 } 2073 BasicBlock* case_block = 2074 mir_graph_->FindBlock(current_dalvik_offset_ + targets[i]); 2075 OpCmpBranch(kCondEq, rl_src.reg, key_temp, &block_label_list_[case_block->id]); 2076 } else { 2077 // No free temp, just finish the old loop. 2078 for (; i < entries; i++, current_key++) { 2079 BasicBlock* case_block = 2080 mir_graph_->FindBlock(current_dalvik_offset_ + targets[i]); 2081 OpCmpImmBranch(kCondEq, rl_src.reg, current_key, &block_label_list_[case_block->id]); 2082 } 2083 } 2084 } 2085 } 2086 2087 void Mir2Lir::GenPackedSwitch(MIR* mir, DexOffset table_offset, RegLocation rl_src) { 2088 const uint16_t* table = cu_->insns + current_dalvik_offset_ + table_offset; 2089 if (cu_->verbose) { 2090 DumpSparseSwitchTable(table); 2091 } 2092 2093 const uint16_t entries = table[1]; 2094 if (entries <= kSmallSwitchThreshold) { 2095 GenSmallPackedSwitch(mir, table_offset, rl_src); 2096 } else { 2097 // Use the backend-specific implementation. 2098 GenLargePackedSwitch(mir, table_offset, rl_src); 2099 } 2100 } 2101 2102 void Mir2Lir::GenSmallSparseSwitch(MIR* mir, DexOffset table_offset, RegLocation rl_src) { 2103 const uint16_t* table = cu_->insns + current_dalvik_offset_ + table_offset; 2104 const uint16_t entries = table[1]; 2105 // Chained cmp-and-branch. 2106 const int32_t* keys = reinterpret_cast<const int32_t*>(&table[2]); 2107 const int32_t* targets = &keys[entries]; 2108 rl_src = LoadValue(rl_src, kCoreReg); 2109 for (int i = 0; i < entries; i++) { 2110 int key = keys[i]; 2111 BasicBlock* case_block = 2112 mir_graph_->FindBlock(current_dalvik_offset_ + targets[i]); 2113 OpCmpImmBranch(kCondEq, rl_src.reg, key, &block_label_list_[case_block->id]); 2114 } 2115 } 2116 2117 void Mir2Lir::GenSparseSwitch(MIR* mir, DexOffset table_offset, RegLocation rl_src) { 2118 const uint16_t* table = cu_->insns + current_dalvik_offset_ + table_offset; 2119 if (cu_->verbose) { 2120 DumpSparseSwitchTable(table); 2121 } 2122 2123 const uint16_t entries = table[1]; 2124 if (entries <= kSmallSwitchThreshold) { 2125 GenSmallSparseSwitch(mir, table_offset, rl_src); 2126 } else { 2127 // Use the backend-specific implementation. 2128 GenLargeSparseSwitch(mir, table_offset, rl_src); 2129 } 2130 } 2131 2132 } // namespace art 2133