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