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 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 "verifier/method_verifier.h" 24 25 namespace art { 26 27 /* 28 * This source files contains "gen" codegen routines that should 29 * be applicable to most targets. Only mid-level support utilities 30 * and "op" calls may be used here. 31 */ 32 33 /* 34 * Generate an kPseudoBarrier marker to indicate the boundary of special 35 * blocks. 36 */ 37 void Mir2Lir::GenBarrier() { 38 LIR* barrier = NewLIR0(kPseudoBarrier); 39 /* Mark all resources as being clobbered */ 40 barrier->def_mask = -1; 41 } 42 43 // FIXME: need to do some work to split out targets with 44 // condition codes and those without 45 LIR* Mir2Lir::GenCheck(ConditionCode c_code, ThrowKind kind) { 46 DCHECK_NE(cu_->instruction_set, kMips); 47 LIR* tgt = RawLIR(0, kPseudoThrowTarget, kind, current_dalvik_offset_); 48 LIR* branch = OpCondBranch(c_code, tgt); 49 // Remember branch target - will process later 50 throw_launchpads_.Insert(tgt); 51 return branch; 52 } 53 54 LIR* Mir2Lir::GenImmedCheck(ConditionCode c_code, int reg, int imm_val, ThrowKind kind) { 55 LIR* tgt = RawLIR(0, kPseudoThrowTarget, kind, current_dalvik_offset_, reg, imm_val); 56 LIR* branch; 57 if (c_code == kCondAl) { 58 branch = OpUnconditionalBranch(tgt); 59 } else { 60 branch = OpCmpImmBranch(c_code, reg, imm_val, tgt); 61 } 62 // Remember branch target - will process later 63 throw_launchpads_.Insert(tgt); 64 return branch; 65 } 66 67 /* Perform null-check on a register. */ 68 LIR* Mir2Lir::GenNullCheck(int s_reg, int m_reg, int opt_flags) { 69 if (!(cu_->disable_opt & (1 << kNullCheckElimination)) && 70 opt_flags & MIR_IGNORE_NULL_CHECK) { 71 return NULL; 72 } 73 return GenImmedCheck(kCondEq, m_reg, 0, kThrowNullPointer); 74 } 75 76 /* Perform check on two registers */ 77 LIR* Mir2Lir::GenRegRegCheck(ConditionCode c_code, int reg1, int reg2, 78 ThrowKind kind) { 79 LIR* tgt = RawLIR(0, kPseudoThrowTarget, kind, current_dalvik_offset_, reg1, reg2); 80 LIR* branch = OpCmpBranch(c_code, reg1, reg2, tgt); 81 // Remember branch target - will process later 82 throw_launchpads_.Insert(tgt); 83 return branch; 84 } 85 86 void Mir2Lir::GenCompareAndBranch(Instruction::Code opcode, RegLocation rl_src1, 87 RegLocation rl_src2, LIR* taken, 88 LIR* fall_through) { 89 ConditionCode cond; 90 switch (opcode) { 91 case Instruction::IF_EQ: 92 cond = kCondEq; 93 break; 94 case Instruction::IF_NE: 95 cond = kCondNe; 96 break; 97 case Instruction::IF_LT: 98 cond = kCondLt; 99 break; 100 case Instruction::IF_GE: 101 cond = kCondGe; 102 break; 103 case Instruction::IF_GT: 104 cond = kCondGt; 105 break; 106 case Instruction::IF_LE: 107 cond = kCondLe; 108 break; 109 default: 110 cond = static_cast<ConditionCode>(0); 111 LOG(FATAL) << "Unexpected opcode " << opcode; 112 } 113 114 // Normalize such that if either operand is constant, src2 will be constant 115 if (rl_src1.is_const) { 116 RegLocation rl_temp = rl_src1; 117 rl_src1 = rl_src2; 118 rl_src2 = rl_temp; 119 cond = FlipComparisonOrder(cond); 120 } 121 122 rl_src1 = LoadValue(rl_src1, kCoreReg); 123 // Is this really an immediate comparison? 124 if (rl_src2.is_const) { 125 // If it's already live in a register or not easily materialized, just keep going 126 RegLocation rl_temp = UpdateLoc(rl_src2); 127 if ((rl_temp.location == kLocDalvikFrame) && 128 InexpensiveConstantInt(mir_graph_->ConstantValue(rl_src2))) { 129 // OK - convert this to a compare immediate and branch 130 OpCmpImmBranch(cond, rl_src1.low_reg, mir_graph_->ConstantValue(rl_src2), taken); 131 OpUnconditionalBranch(fall_through); 132 return; 133 } 134 } 135 rl_src2 = LoadValue(rl_src2, kCoreReg); 136 OpCmpBranch(cond, rl_src1.low_reg, rl_src2.low_reg, taken); 137 OpUnconditionalBranch(fall_through); 138 } 139 140 void Mir2Lir::GenCompareZeroAndBranch(Instruction::Code opcode, RegLocation rl_src, LIR* taken, 141 LIR* fall_through) { 142 ConditionCode cond; 143 rl_src = LoadValue(rl_src, kCoreReg); 144 switch (opcode) { 145 case Instruction::IF_EQZ: 146 cond = kCondEq; 147 break; 148 case Instruction::IF_NEZ: 149 cond = kCondNe; 150 break; 151 case Instruction::IF_LTZ: 152 cond = kCondLt; 153 break; 154 case Instruction::IF_GEZ: 155 cond = kCondGe; 156 break; 157 case Instruction::IF_GTZ: 158 cond = kCondGt; 159 break; 160 case Instruction::IF_LEZ: 161 cond = kCondLe; 162 break; 163 default: 164 cond = static_cast<ConditionCode>(0); 165 LOG(FATAL) << "Unexpected opcode " << opcode; 166 } 167 OpCmpImmBranch(cond, rl_src.low_reg, 0, taken); 168 OpUnconditionalBranch(fall_through); 169 } 170 171 void Mir2Lir::GenIntToLong(RegLocation rl_dest, RegLocation rl_src) { 172 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true); 173 if (rl_src.location == kLocPhysReg) { 174 OpRegCopy(rl_result.low_reg, rl_src.low_reg); 175 } else { 176 LoadValueDirect(rl_src, rl_result.low_reg); 177 } 178 OpRegRegImm(kOpAsr, rl_result.high_reg, rl_result.low_reg, 31); 179 StoreValueWide(rl_dest, rl_result); 180 } 181 182 void Mir2Lir::GenIntNarrowing(Instruction::Code opcode, RegLocation rl_dest, 183 RegLocation rl_src) { 184 rl_src = LoadValue(rl_src, kCoreReg); 185 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true); 186 OpKind op = kOpInvalid; 187 switch (opcode) { 188 case Instruction::INT_TO_BYTE: 189 op = kOp2Byte; 190 break; 191 case Instruction::INT_TO_SHORT: 192 op = kOp2Short; 193 break; 194 case Instruction::INT_TO_CHAR: 195 op = kOp2Char; 196 break; 197 default: 198 LOG(ERROR) << "Bad int conversion type"; 199 } 200 OpRegReg(op, rl_result.low_reg, rl_src.low_reg); 201 StoreValue(rl_dest, rl_result); 202 } 203 204 /* 205 * Let helper function take care of everything. Will call 206 * Array::AllocFromCode(type_idx, method, count); 207 * Note: AllocFromCode will handle checks for errNegativeArraySize. 208 */ 209 void Mir2Lir::GenNewArray(uint32_t type_idx, RegLocation rl_dest, 210 RegLocation rl_src) { 211 FlushAllRegs(); /* Everything to home location */ 212 ThreadOffset func_offset(-1); 213 if (cu_->compiler_driver->CanAccessTypeWithoutChecks(cu_->method_idx, *cu_->dex_file, 214 type_idx)) { 215 func_offset = QUICK_ENTRYPOINT_OFFSET(pAllocArray); 216 } else { 217 func_offset= QUICK_ENTRYPOINT_OFFSET(pAllocArrayWithAccessCheck); 218 } 219 CallRuntimeHelperImmMethodRegLocation(func_offset, type_idx, rl_src, true); 220 RegLocation rl_result = GetReturn(false); 221 StoreValue(rl_dest, rl_result); 222 } 223 224 /* 225 * Similar to GenNewArray, but with post-allocation initialization. 226 * Verifier guarantees we're dealing with an array class. Current 227 * code throws runtime exception "bad Filled array req" for 'D' and 'J'. 228 * Current code also throws internal unimp if not 'L', '[' or 'I'. 229 */ 230 void Mir2Lir::GenFilledNewArray(CallInfo* info) { 231 int elems = info->num_arg_words; 232 int type_idx = info->index; 233 FlushAllRegs(); /* Everything to home location */ 234 ThreadOffset func_offset(-1); 235 if (cu_->compiler_driver->CanAccessTypeWithoutChecks(cu_->method_idx, *cu_->dex_file, 236 type_idx)) { 237 func_offset = QUICK_ENTRYPOINT_OFFSET(pCheckAndAllocArray); 238 } else { 239 func_offset = QUICK_ENTRYPOINT_OFFSET(pCheckAndAllocArrayWithAccessCheck); 240 } 241 CallRuntimeHelperImmMethodImm(func_offset, type_idx, elems, true); 242 FreeTemp(TargetReg(kArg2)); 243 FreeTemp(TargetReg(kArg1)); 244 /* 245 * NOTE: the implicit target for Instruction::FILLED_NEW_ARRAY is the 246 * return region. Because AllocFromCode placed the new array 247 * in kRet0, we'll just lock it into place. When debugger support is 248 * added, it may be necessary to additionally copy all return 249 * values to a home location in thread-local storage 250 */ 251 LockTemp(TargetReg(kRet0)); 252 253 // TODO: use the correct component size, currently all supported types 254 // share array alignment with ints (see comment at head of function) 255 size_t component_size = sizeof(int32_t); 256 257 // Having a range of 0 is legal 258 if (info->is_range && (elems > 0)) { 259 /* 260 * Bit of ugliness here. We're going generate a mem copy loop 261 * on the register range, but it is possible that some regs 262 * in the range have been promoted. This is unlikely, but 263 * before generating the copy, we'll just force a flush 264 * of any regs in the source range that have been promoted to 265 * home location. 266 */ 267 for (int i = 0; i < elems; i++) { 268 RegLocation loc = UpdateLoc(info->args[i]); 269 if (loc.location == kLocPhysReg) { 270 StoreBaseDisp(TargetReg(kSp), SRegOffset(loc.s_reg_low), 271 loc.low_reg, kWord); 272 } 273 } 274 /* 275 * TUNING note: generated code here could be much improved, but 276 * this is an uncommon operation and isn't especially performance 277 * critical. 278 */ 279 int r_src = AllocTemp(); 280 int r_dst = AllocTemp(); 281 int r_idx = AllocTemp(); 282 int r_val = INVALID_REG; 283 switch (cu_->instruction_set) { 284 case kThumb2: 285 r_val = TargetReg(kLr); 286 break; 287 case kX86: 288 FreeTemp(TargetReg(kRet0)); 289 r_val = AllocTemp(); 290 break; 291 case kMips: 292 r_val = AllocTemp(); 293 break; 294 default: LOG(FATAL) << "Unexpected instruction set: " << cu_->instruction_set; 295 } 296 // Set up source pointer 297 RegLocation rl_first = info->args[0]; 298 OpRegRegImm(kOpAdd, r_src, TargetReg(kSp), SRegOffset(rl_first.s_reg_low)); 299 // Set up the target pointer 300 OpRegRegImm(kOpAdd, r_dst, TargetReg(kRet0), 301 mirror::Array::DataOffset(component_size).Int32Value()); 302 // Set up the loop counter (known to be > 0) 303 LoadConstant(r_idx, elems - 1); 304 // Generate the copy loop. Going backwards for convenience 305 LIR* target = NewLIR0(kPseudoTargetLabel); 306 // Copy next element 307 LoadBaseIndexed(r_src, r_idx, r_val, 2, kWord); 308 StoreBaseIndexed(r_dst, r_idx, r_val, 2, kWord); 309 FreeTemp(r_val); 310 OpDecAndBranch(kCondGe, r_idx, target); 311 if (cu_->instruction_set == kX86) { 312 // Restore the target pointer 313 OpRegRegImm(kOpAdd, TargetReg(kRet0), r_dst, 314 -mirror::Array::DataOffset(component_size).Int32Value()); 315 } 316 } else if (!info->is_range) { 317 // TUNING: interleave 318 for (int i = 0; i < elems; i++) { 319 RegLocation rl_arg = LoadValue(info->args[i], kCoreReg); 320 StoreBaseDisp(TargetReg(kRet0), 321 mirror::Array::DataOffset(component_size).Int32Value() + 322 i * 4, rl_arg.low_reg, kWord); 323 // If the LoadValue caused a temp to be allocated, free it 324 if (IsTemp(rl_arg.low_reg)) { 325 FreeTemp(rl_arg.low_reg); 326 } 327 } 328 } 329 if (info->result.location != kLocInvalid) { 330 StoreValue(info->result, GetReturn(false /* not fp */)); 331 } 332 } 333 334 void Mir2Lir::GenSput(uint32_t field_idx, RegLocation rl_src, bool is_long_or_double, 335 bool is_object) { 336 int field_offset; 337 int ssb_index; 338 bool is_volatile; 339 bool is_referrers_class; 340 bool fast_path = cu_->compiler_driver->ComputeStaticFieldInfo( 341 field_idx, mir_graph_->GetCurrentDexCompilationUnit(), field_offset, ssb_index, 342 is_referrers_class, is_volatile, true); 343 if (fast_path && !SLOW_FIELD_PATH) { 344 DCHECK_GE(field_offset, 0); 345 int rBase; 346 if (is_referrers_class) { 347 // Fast path, static storage base is this method's class 348 RegLocation rl_method = LoadCurrMethod(); 349 rBase = AllocTemp(); 350 LoadWordDisp(rl_method.low_reg, 351 mirror::ArtMethod::DeclaringClassOffset().Int32Value(), rBase); 352 if (IsTemp(rl_method.low_reg)) { 353 FreeTemp(rl_method.low_reg); 354 } 355 } else { 356 // Medium path, static storage base in a different class which requires checks that the other 357 // class is initialized. 358 // TODO: remove initialized check now that we are initializing classes in the compiler driver. 359 DCHECK_GE(ssb_index, 0); 360 // May do runtime call so everything to home locations. 361 FlushAllRegs(); 362 // Using fixed register to sync with possible call to runtime support. 363 int r_method = TargetReg(kArg1); 364 LockTemp(r_method); 365 LoadCurrMethodDirect(r_method); 366 rBase = TargetReg(kArg0); 367 LockTemp(rBase); 368 LoadWordDisp(r_method, 369 mirror::ArtMethod::DexCacheInitializedStaticStorageOffset().Int32Value(), 370 rBase); 371 LoadWordDisp(rBase, 372 mirror::Array::DataOffset(sizeof(mirror::Object*)).Int32Value() + 373 sizeof(int32_t*) * ssb_index, rBase); 374 // rBase now points at appropriate static storage base (Class*) 375 // or NULL if not initialized. Check for NULL and call helper if NULL. 376 // TUNING: fast path should fall through 377 LIR* branch_over = OpCmpImmBranch(kCondNe, rBase, 0, NULL); 378 LoadConstant(TargetReg(kArg0), ssb_index); 379 CallRuntimeHelperImm(QUICK_ENTRYPOINT_OFFSET(pInitializeStaticStorage), ssb_index, true); 380 if (cu_->instruction_set == kMips) { 381 // For Arm, kRet0 = kArg0 = rBase, for Mips, we need to copy 382 OpRegCopy(rBase, TargetReg(kRet0)); 383 } 384 LIR* skip_target = NewLIR0(kPseudoTargetLabel); 385 branch_over->target = skip_target; 386 FreeTemp(r_method); 387 } 388 // rBase now holds static storage base 389 if (is_long_or_double) { 390 rl_src = LoadValueWide(rl_src, kAnyReg); 391 } else { 392 rl_src = LoadValue(rl_src, kAnyReg); 393 } 394 if (is_volatile) { 395 GenMemBarrier(kStoreStore); 396 } 397 if (is_long_or_double) { 398 StoreBaseDispWide(rBase, field_offset, rl_src.low_reg, 399 rl_src.high_reg); 400 } else { 401 StoreWordDisp(rBase, field_offset, rl_src.low_reg); 402 } 403 if (is_volatile) { 404 GenMemBarrier(kStoreLoad); 405 } 406 if (is_object && !mir_graph_->IsConstantNullRef(rl_src)) { 407 MarkGCCard(rl_src.low_reg, rBase); 408 } 409 FreeTemp(rBase); 410 } else { 411 FlushAllRegs(); // Everything to home locations 412 ThreadOffset setter_offset = 413 is_long_or_double ? QUICK_ENTRYPOINT_OFFSET(pSet64Static) 414 : (is_object ? QUICK_ENTRYPOINT_OFFSET(pSetObjStatic) 415 : QUICK_ENTRYPOINT_OFFSET(pSet32Static)); 416 CallRuntimeHelperImmRegLocation(setter_offset, field_idx, rl_src, true); 417 } 418 } 419 420 void Mir2Lir::GenSget(uint32_t field_idx, RegLocation rl_dest, 421 bool is_long_or_double, bool is_object) { 422 int field_offset; 423 int ssb_index; 424 bool is_volatile; 425 bool is_referrers_class; 426 bool fast_path = cu_->compiler_driver->ComputeStaticFieldInfo( 427 field_idx, mir_graph_->GetCurrentDexCompilationUnit(), field_offset, ssb_index, 428 is_referrers_class, is_volatile, false); 429 if (fast_path && !SLOW_FIELD_PATH) { 430 DCHECK_GE(field_offset, 0); 431 int rBase; 432 if (is_referrers_class) { 433 // Fast path, static storage base is this method's class 434 RegLocation rl_method = LoadCurrMethod(); 435 rBase = AllocTemp(); 436 LoadWordDisp(rl_method.low_reg, 437 mirror::ArtMethod::DeclaringClassOffset().Int32Value(), rBase); 438 } else { 439 // Medium path, static storage base in a different class which requires checks that the other 440 // class is initialized 441 // TODO: remove initialized check now that we are initializing classes in the compiler driver. 442 DCHECK_GE(ssb_index, 0); 443 // May do runtime call so everything to home locations. 444 FlushAllRegs(); 445 // Using fixed register to sync with possible call to runtime support. 446 int r_method = TargetReg(kArg1); 447 LockTemp(r_method); 448 LoadCurrMethodDirect(r_method); 449 rBase = TargetReg(kArg0); 450 LockTemp(rBase); 451 LoadWordDisp(r_method, 452 mirror::ArtMethod::DexCacheInitializedStaticStorageOffset().Int32Value(), 453 rBase); 454 LoadWordDisp(rBase, mirror::Array::DataOffset(sizeof(mirror::Object*)).Int32Value() + 455 sizeof(int32_t*) * ssb_index, rBase); 456 // rBase now points at appropriate static storage base (Class*) 457 // or NULL if not initialized. Check for NULL and call helper if NULL. 458 // TUNING: fast path should fall through 459 LIR* branch_over = OpCmpImmBranch(kCondNe, rBase, 0, NULL); 460 CallRuntimeHelperImm(QUICK_ENTRYPOINT_OFFSET(pInitializeStaticStorage), ssb_index, true); 461 if (cu_->instruction_set == kMips) { 462 // For Arm, kRet0 = kArg0 = rBase, for Mips, we need to copy 463 OpRegCopy(rBase, TargetReg(kRet0)); 464 } 465 LIR* skip_target = NewLIR0(kPseudoTargetLabel); 466 branch_over->target = skip_target; 467 FreeTemp(r_method); 468 } 469 // rBase now holds static storage base 470 RegLocation rl_result = EvalLoc(rl_dest, kAnyReg, true); 471 if (is_volatile) { 472 GenMemBarrier(kLoadLoad); 473 } 474 if (is_long_or_double) { 475 LoadBaseDispWide(rBase, field_offset, rl_result.low_reg, 476 rl_result.high_reg, INVALID_SREG); 477 } else { 478 LoadWordDisp(rBase, field_offset, rl_result.low_reg); 479 } 480 FreeTemp(rBase); 481 if (is_long_or_double) { 482 StoreValueWide(rl_dest, rl_result); 483 } else { 484 StoreValue(rl_dest, rl_result); 485 } 486 } else { 487 FlushAllRegs(); // Everything to home locations 488 ThreadOffset getterOffset = 489 is_long_or_double ? QUICK_ENTRYPOINT_OFFSET(pGet64Static) 490 :(is_object ? QUICK_ENTRYPOINT_OFFSET(pGetObjStatic) 491 : QUICK_ENTRYPOINT_OFFSET(pGet32Static)); 492 CallRuntimeHelperImm(getterOffset, field_idx, true); 493 if (is_long_or_double) { 494 RegLocation rl_result = GetReturnWide(rl_dest.fp); 495 StoreValueWide(rl_dest, rl_result); 496 } else { 497 RegLocation rl_result = GetReturn(rl_dest.fp); 498 StoreValue(rl_dest, rl_result); 499 } 500 } 501 } 502 503 void Mir2Lir::HandleSuspendLaunchPads() { 504 int num_elems = suspend_launchpads_.Size(); 505 ThreadOffset helper_offset = QUICK_ENTRYPOINT_OFFSET(pTestSuspend); 506 for (int i = 0; i < num_elems; i++) { 507 ResetRegPool(); 508 ResetDefTracking(); 509 LIR* lab = suspend_launchpads_.Get(i); 510 LIR* resume_lab = reinterpret_cast<LIR*>(lab->operands[0]); 511 current_dalvik_offset_ = lab->operands[1]; 512 AppendLIR(lab); 513 int r_tgt = CallHelperSetup(helper_offset); 514 CallHelper(r_tgt, helper_offset, true /* MarkSafepointPC */); 515 OpUnconditionalBranch(resume_lab); 516 } 517 } 518 519 void Mir2Lir::HandleIntrinsicLaunchPads() { 520 int num_elems = intrinsic_launchpads_.Size(); 521 for (int i = 0; i < num_elems; i++) { 522 ResetRegPool(); 523 ResetDefTracking(); 524 LIR* lab = intrinsic_launchpads_.Get(i); 525 CallInfo* info = reinterpret_cast<CallInfo*>(lab->operands[0]); 526 current_dalvik_offset_ = info->offset; 527 AppendLIR(lab); 528 // NOTE: GenInvoke handles MarkSafepointPC 529 GenInvoke(info); 530 LIR* resume_lab = reinterpret_cast<LIR*>(lab->operands[2]); 531 if (resume_lab != NULL) { 532 OpUnconditionalBranch(resume_lab); 533 } 534 } 535 } 536 537 void Mir2Lir::HandleThrowLaunchPads() { 538 int num_elems = throw_launchpads_.Size(); 539 for (int i = 0; i < num_elems; i++) { 540 ResetRegPool(); 541 ResetDefTracking(); 542 LIR* lab = throw_launchpads_.Get(i); 543 current_dalvik_offset_ = lab->operands[1]; 544 AppendLIR(lab); 545 ThreadOffset func_offset(-1); 546 int v1 = lab->operands[2]; 547 int v2 = lab->operands[3]; 548 const bool target_x86 = cu_->instruction_set == kX86; 549 const bool target_arm = cu_->instruction_set == kArm || cu_->instruction_set == kThumb2; 550 const bool target_mips = cu_->instruction_set == kMips; 551 switch (lab->operands[0]) { 552 case kThrowNullPointer: 553 func_offset = QUICK_ENTRYPOINT_OFFSET(pThrowNullPointer); 554 break; 555 case kThrowConstantArrayBounds: // v1 is length reg (for Arm/Mips), v2 constant index 556 // v1 holds the constant array index. Mips/Arm uses v2 for length, x86 reloads. 557 if (target_x86) { 558 OpRegMem(kOpMov, TargetReg(kArg1), v1, mirror::Array::LengthOffset().Int32Value()); 559 } else { 560 OpRegCopy(TargetReg(kArg1), v1); 561 } 562 // Make sure the following LoadConstant doesn't mess with kArg1. 563 LockTemp(TargetReg(kArg1)); 564 LoadConstant(TargetReg(kArg0), v2); 565 func_offset = QUICK_ENTRYPOINT_OFFSET(pThrowArrayBounds); 566 break; 567 case kThrowArrayBounds: 568 // Move v1 (array index) to kArg0 and v2 (array length) to kArg1 569 if (v2 != TargetReg(kArg0)) { 570 OpRegCopy(TargetReg(kArg0), v1); 571 if (target_x86) { 572 // x86 leaves the array pointer in v2, so load the array length that the handler expects 573 OpRegMem(kOpMov, TargetReg(kArg1), v2, mirror::Array::LengthOffset().Int32Value()); 574 } else { 575 OpRegCopy(TargetReg(kArg1), v2); 576 } 577 } else { 578 if (v1 == TargetReg(kArg1)) { 579 // Swap v1 and v2, using kArg2 as a temp 580 OpRegCopy(TargetReg(kArg2), v1); 581 if (target_x86) { 582 // x86 leaves the array pointer in v2; load the array length that the handler expects 583 OpRegMem(kOpMov, TargetReg(kArg1), v2, mirror::Array::LengthOffset().Int32Value()); 584 } else { 585 OpRegCopy(TargetReg(kArg1), v2); 586 } 587 OpRegCopy(TargetReg(kArg0), TargetReg(kArg2)); 588 } else { 589 if (target_x86) { 590 // x86 leaves the array pointer in v2; load the array length that the handler expects 591 OpRegMem(kOpMov, TargetReg(kArg1), v2, mirror::Array::LengthOffset().Int32Value()); 592 } else { 593 OpRegCopy(TargetReg(kArg1), v2); 594 } 595 OpRegCopy(TargetReg(kArg0), v1); 596 } 597 } 598 func_offset = QUICK_ENTRYPOINT_OFFSET(pThrowArrayBounds); 599 break; 600 case kThrowDivZero: 601 func_offset = QUICK_ENTRYPOINT_OFFSET(pThrowDivZero); 602 break; 603 case kThrowNoSuchMethod: 604 OpRegCopy(TargetReg(kArg0), v1); 605 func_offset = 606 QUICK_ENTRYPOINT_OFFSET(pThrowNoSuchMethod); 607 break; 608 case kThrowStackOverflow: { 609 func_offset = QUICK_ENTRYPOINT_OFFSET(pThrowStackOverflow); 610 // Restore stack alignment 611 int r_tgt = 0; 612 const int spill_size = (num_core_spills_ + num_fp_spills_) * 4; 613 if (target_x86) { 614 // - 4 to leave link register on stack. 615 OpRegImm(kOpAdd, TargetReg(kSp), frame_size_ - 4); 616 ClobberCalleeSave(); 617 } else if (target_arm) { 618 r_tgt = r12; 619 LoadWordDisp(TargetReg(kSp), spill_size - 4, TargetReg(kLr)); 620 OpRegImm(kOpAdd, TargetReg(kSp), spill_size); 621 ClobberCalleeSave(); 622 LoadWordDisp(rARM_SELF, func_offset.Int32Value(), r_tgt); 623 } else { 624 DCHECK(target_mips); 625 DCHECK_EQ(num_fp_spills_, 0); // FP spills currently don't happen on mips. 626 // LR is offset 0 since we push in reverse order. 627 LoadWordDisp(TargetReg(kSp), 0, TargetReg(kLr)); 628 OpRegImm(kOpAdd, TargetReg(kSp), spill_size); 629 ClobberCalleeSave(); 630 r_tgt = CallHelperSetup(func_offset); // Doesn't clobber LR. 631 DCHECK_NE(r_tgt, TargetReg(kLr)); 632 } 633 CallHelper(r_tgt, func_offset, false /* MarkSafepointPC */, false /* UseLink */); 634 continue; 635 } 636 default: 637 LOG(FATAL) << "Unexpected throw kind: " << lab->operands[0]; 638 } 639 ClobberCalleeSave(); 640 int r_tgt = CallHelperSetup(func_offset); 641 CallHelper(r_tgt, func_offset, true /* MarkSafepointPC */, true /* UseLink */); 642 } 643 } 644 645 void Mir2Lir::GenIGet(uint32_t field_idx, int opt_flags, OpSize size, 646 RegLocation rl_dest, RegLocation rl_obj, bool is_long_or_double, 647 bool is_object) { 648 int field_offset; 649 bool is_volatile; 650 651 bool fast_path = FastInstance(field_idx, field_offset, is_volatile, false); 652 653 if (fast_path && !SLOW_FIELD_PATH) { 654 RegLocation rl_result; 655 RegisterClass reg_class = oat_reg_class_by_size(size); 656 DCHECK_GE(field_offset, 0); 657 rl_obj = LoadValue(rl_obj, kCoreReg); 658 if (is_long_or_double) { 659 DCHECK(rl_dest.wide); 660 GenNullCheck(rl_obj.s_reg_low, rl_obj.low_reg, opt_flags); 661 if (cu_->instruction_set == kX86) { 662 rl_result = EvalLoc(rl_dest, reg_class, true); 663 GenNullCheck(rl_obj.s_reg_low, rl_obj.low_reg, opt_flags); 664 LoadBaseDispWide(rl_obj.low_reg, field_offset, rl_result.low_reg, 665 rl_result.high_reg, rl_obj.s_reg_low); 666 if (is_volatile) { 667 GenMemBarrier(kLoadLoad); 668 } 669 } else { 670 int reg_ptr = AllocTemp(); 671 OpRegRegImm(kOpAdd, reg_ptr, rl_obj.low_reg, field_offset); 672 rl_result = EvalLoc(rl_dest, reg_class, true); 673 LoadBaseDispWide(reg_ptr, 0, rl_result.low_reg, rl_result.high_reg, INVALID_SREG); 674 if (is_volatile) { 675 GenMemBarrier(kLoadLoad); 676 } 677 FreeTemp(reg_ptr); 678 } 679 StoreValueWide(rl_dest, rl_result); 680 } else { 681 rl_result = EvalLoc(rl_dest, reg_class, true); 682 GenNullCheck(rl_obj.s_reg_low, rl_obj.low_reg, opt_flags); 683 LoadBaseDisp(rl_obj.low_reg, field_offset, rl_result.low_reg, 684 kWord, rl_obj.s_reg_low); 685 if (is_volatile) { 686 GenMemBarrier(kLoadLoad); 687 } 688 StoreValue(rl_dest, rl_result); 689 } 690 } else { 691 ThreadOffset getterOffset = 692 is_long_or_double ? QUICK_ENTRYPOINT_OFFSET(pGet64Instance) 693 : (is_object ? QUICK_ENTRYPOINT_OFFSET(pGetObjInstance) 694 : QUICK_ENTRYPOINT_OFFSET(pGet32Instance)); 695 CallRuntimeHelperImmRegLocation(getterOffset, field_idx, rl_obj, true); 696 if (is_long_or_double) { 697 RegLocation rl_result = GetReturnWide(rl_dest.fp); 698 StoreValueWide(rl_dest, rl_result); 699 } else { 700 RegLocation rl_result = GetReturn(rl_dest.fp); 701 StoreValue(rl_dest, rl_result); 702 } 703 } 704 } 705 706 void Mir2Lir::GenIPut(uint32_t field_idx, int opt_flags, OpSize size, 707 RegLocation rl_src, RegLocation rl_obj, bool is_long_or_double, 708 bool is_object) { 709 int field_offset; 710 bool is_volatile; 711 712 bool fast_path = FastInstance(field_idx, field_offset, is_volatile, 713 true); 714 if (fast_path && !SLOW_FIELD_PATH) { 715 RegisterClass reg_class = oat_reg_class_by_size(size); 716 DCHECK_GE(field_offset, 0); 717 rl_obj = LoadValue(rl_obj, kCoreReg); 718 if (is_long_or_double) { 719 int reg_ptr; 720 rl_src = LoadValueWide(rl_src, kAnyReg); 721 GenNullCheck(rl_obj.s_reg_low, rl_obj.low_reg, opt_flags); 722 reg_ptr = AllocTemp(); 723 OpRegRegImm(kOpAdd, reg_ptr, rl_obj.low_reg, field_offset); 724 if (is_volatile) { 725 GenMemBarrier(kStoreStore); 726 } 727 StoreBaseDispWide(reg_ptr, 0, rl_src.low_reg, rl_src.high_reg); 728 if (is_volatile) { 729 GenMemBarrier(kLoadLoad); 730 } 731 FreeTemp(reg_ptr); 732 } else { 733 rl_src = LoadValue(rl_src, reg_class); 734 GenNullCheck(rl_obj.s_reg_low, rl_obj.low_reg, opt_flags); 735 if (is_volatile) { 736 GenMemBarrier(kStoreStore); 737 } 738 StoreBaseDisp(rl_obj.low_reg, field_offset, rl_src.low_reg, kWord); 739 if (is_volatile) { 740 GenMemBarrier(kLoadLoad); 741 } 742 if (is_object && !mir_graph_->IsConstantNullRef(rl_src)) { 743 MarkGCCard(rl_src.low_reg, rl_obj.low_reg); 744 } 745 } 746 } else { 747 ThreadOffset setter_offset = 748 is_long_or_double ? QUICK_ENTRYPOINT_OFFSET(pSet64Instance) 749 : (is_object ? QUICK_ENTRYPOINT_OFFSET(pSetObjInstance) 750 : QUICK_ENTRYPOINT_OFFSET(pSet32Instance)); 751 CallRuntimeHelperImmRegLocationRegLocation(setter_offset, field_idx, rl_obj, rl_src, true); 752 } 753 } 754 755 void Mir2Lir::GenConstClass(uint32_t type_idx, RegLocation rl_dest) { 756 RegLocation rl_method = LoadCurrMethod(); 757 int res_reg = AllocTemp(); 758 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true); 759 if (!cu_->compiler_driver->CanAccessTypeWithoutChecks(cu_->method_idx, 760 *cu_->dex_file, 761 type_idx)) { 762 // Call out to helper which resolves type and verifies access. 763 // Resolved type returned in kRet0. 764 CallRuntimeHelperImmReg(QUICK_ENTRYPOINT_OFFSET(pInitializeTypeAndVerifyAccess), 765 type_idx, rl_method.low_reg, true); 766 RegLocation rl_result = GetReturn(false); 767 StoreValue(rl_dest, rl_result); 768 } else { 769 // We're don't need access checks, load type from dex cache 770 int32_t dex_cache_offset = 771 mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value(); 772 LoadWordDisp(rl_method.low_reg, dex_cache_offset, res_reg); 773 int32_t offset_of_type = 774 mirror::Array::DataOffset(sizeof(mirror::Class*)).Int32Value() + (sizeof(mirror::Class*) 775 * type_idx); 776 LoadWordDisp(res_reg, offset_of_type, rl_result.low_reg); 777 if (!cu_->compiler_driver->CanAssumeTypeIsPresentInDexCache(*cu_->dex_file, 778 type_idx) || SLOW_TYPE_PATH) { 779 // Slow path, at runtime test if type is null and if so initialize 780 FlushAllRegs(); 781 LIR* branch1 = OpCmpImmBranch(kCondEq, rl_result.low_reg, 0, NULL); 782 // Resolved, store and hop over following code 783 StoreValue(rl_dest, rl_result); 784 /* 785 * Because we have stores of the target value on two paths, 786 * clobber temp tracking for the destination using the ssa name 787 */ 788 ClobberSReg(rl_dest.s_reg_low); 789 LIR* branch2 = OpUnconditionalBranch(0); 790 // TUNING: move slow path to end & remove unconditional branch 791 LIR* target1 = NewLIR0(kPseudoTargetLabel); 792 // Call out to helper, which will return resolved type in kArg0 793 CallRuntimeHelperImmReg(QUICK_ENTRYPOINT_OFFSET(pInitializeType), type_idx, 794 rl_method.low_reg, true); 795 RegLocation rl_result = GetReturn(false); 796 StoreValue(rl_dest, rl_result); 797 /* 798 * Because we have stores of the target value on two paths, 799 * clobber temp tracking for the destination using the ssa name 800 */ 801 ClobberSReg(rl_dest.s_reg_low); 802 // Rejoin code paths 803 LIR* target2 = NewLIR0(kPseudoTargetLabel); 804 branch1->target = target1; 805 branch2->target = target2; 806 } else { 807 // Fast path, we're done - just store result 808 StoreValue(rl_dest, rl_result); 809 } 810 } 811 } 812 813 void Mir2Lir::GenConstString(uint32_t string_idx, RegLocation rl_dest) { 814 /* NOTE: Most strings should be available at compile time */ 815 int32_t offset_of_string = mirror::Array::DataOffset(sizeof(mirror::String*)).Int32Value() + 816 (sizeof(mirror::String*) * string_idx); 817 if (!cu_->compiler_driver->CanAssumeStringIsPresentInDexCache( 818 *cu_->dex_file, string_idx) || SLOW_STRING_PATH) { 819 // slow path, resolve string if not in dex cache 820 FlushAllRegs(); 821 LockCallTemps(); // Using explicit registers 822 LoadCurrMethodDirect(TargetReg(kArg2)); 823 LoadWordDisp(TargetReg(kArg2), 824 mirror::ArtMethod::DexCacheStringsOffset().Int32Value(), TargetReg(kArg0)); 825 // Might call out to helper, which will return resolved string in kRet0 826 int r_tgt = CallHelperSetup(QUICK_ENTRYPOINT_OFFSET(pResolveString)); 827 LoadWordDisp(TargetReg(kArg0), offset_of_string, TargetReg(kRet0)); 828 LoadConstant(TargetReg(kArg1), string_idx); 829 if (cu_->instruction_set == kThumb2) { 830 OpRegImm(kOpCmp, TargetReg(kRet0), 0); // Is resolved? 831 GenBarrier(); 832 // For testing, always force through helper 833 if (!EXERCISE_SLOWEST_STRING_PATH) { 834 OpIT(kCondEq, "T"); 835 } 836 OpRegCopy(TargetReg(kArg0), TargetReg(kArg2)); // .eq 837 LIR* call_inst = OpReg(kOpBlx, r_tgt); // .eq, helper(Method*, string_idx) 838 MarkSafepointPC(call_inst); 839 FreeTemp(r_tgt); 840 } else if (cu_->instruction_set == kMips) { 841 LIR* branch = OpCmpImmBranch(kCondNe, TargetReg(kRet0), 0, NULL); 842 OpRegCopy(TargetReg(kArg0), TargetReg(kArg2)); // .eq 843 LIR* call_inst = OpReg(kOpBlx, r_tgt); 844 MarkSafepointPC(call_inst); 845 FreeTemp(r_tgt); 846 LIR* target = NewLIR0(kPseudoTargetLabel); 847 branch->target = target; 848 } else { 849 DCHECK_EQ(cu_->instruction_set, kX86); 850 CallRuntimeHelperRegReg(QUICK_ENTRYPOINT_OFFSET(pResolveString), TargetReg(kArg2), 851 TargetReg(kArg1), true); 852 } 853 GenBarrier(); 854 StoreValue(rl_dest, GetReturn(false)); 855 } else { 856 RegLocation rl_method = LoadCurrMethod(); 857 int res_reg = AllocTemp(); 858 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true); 859 LoadWordDisp(rl_method.low_reg, 860 mirror::ArtMethod::DexCacheStringsOffset().Int32Value(), res_reg); 861 LoadWordDisp(res_reg, offset_of_string, rl_result.low_reg); 862 StoreValue(rl_dest, rl_result); 863 } 864 } 865 866 /* 867 * Let helper function take care of everything. Will 868 * call Class::NewInstanceFromCode(type_idx, method); 869 */ 870 void Mir2Lir::GenNewInstance(uint32_t type_idx, RegLocation rl_dest) { 871 FlushAllRegs(); /* Everything to home location */ 872 // alloc will always check for resolution, do we also need to verify 873 // access because the verifier was unable to? 874 ThreadOffset func_offset(-1); 875 if (cu_->compiler_driver->CanAccessInstantiableTypeWithoutChecks( 876 cu_->method_idx, *cu_->dex_file, type_idx)) { 877 func_offset = QUICK_ENTRYPOINT_OFFSET(pAllocObject); 878 } else { 879 func_offset = QUICK_ENTRYPOINT_OFFSET(pAllocObjectWithAccessCheck); 880 } 881 CallRuntimeHelperImmMethod(func_offset, type_idx, true); 882 RegLocation rl_result = GetReturn(false); 883 StoreValue(rl_dest, rl_result); 884 } 885 886 void Mir2Lir::GenThrow(RegLocation rl_src) { 887 FlushAllRegs(); 888 CallRuntimeHelperRegLocation(QUICK_ENTRYPOINT_OFFSET(pDeliverException), rl_src, true); 889 } 890 891 // For final classes there are no sub-classes to check and so we can answer the instance-of 892 // question with simple comparisons. 893 void Mir2Lir::GenInstanceofFinal(bool use_declaring_class, uint32_t type_idx, RegLocation rl_dest, 894 RegLocation rl_src) { 895 RegLocation object = LoadValue(rl_src, kCoreReg); 896 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true); 897 int result_reg = rl_result.low_reg; 898 if (result_reg == object.low_reg) { 899 result_reg = AllocTypedTemp(false, kCoreReg); 900 } 901 LoadConstant(result_reg, 0); // assume false 902 LIR* null_branchover = OpCmpImmBranch(kCondEq, object.low_reg, 0, NULL); 903 904 int check_class = AllocTypedTemp(false, kCoreReg); 905 int object_class = AllocTypedTemp(false, kCoreReg); 906 907 LoadCurrMethodDirect(check_class); 908 if (use_declaring_class) { 909 LoadWordDisp(check_class, mirror::ArtMethod::DeclaringClassOffset().Int32Value(), 910 check_class); 911 LoadWordDisp(object.low_reg, mirror::Object::ClassOffset().Int32Value(), object_class); 912 } else { 913 LoadWordDisp(check_class, mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value(), 914 check_class); 915 LoadWordDisp(object.low_reg, mirror::Object::ClassOffset().Int32Value(), object_class); 916 int32_t offset_of_type = 917 mirror::Array::DataOffset(sizeof(mirror::Class*)).Int32Value() + 918 (sizeof(mirror::Class*) * type_idx); 919 LoadWordDisp(check_class, offset_of_type, check_class); 920 } 921 922 LIR* ne_branchover = NULL; 923 if (cu_->instruction_set == kThumb2) { 924 OpRegReg(kOpCmp, check_class, object_class); // Same? 925 OpIT(kCondEq, ""); // if-convert the test 926 LoadConstant(result_reg, 1); // .eq case - load true 927 } else { 928 ne_branchover = OpCmpBranch(kCondNe, check_class, object_class, NULL); 929 LoadConstant(result_reg, 1); // eq case - load true 930 } 931 LIR* target = NewLIR0(kPseudoTargetLabel); 932 null_branchover->target = target; 933 if (ne_branchover != NULL) { 934 ne_branchover->target = target; 935 } 936 FreeTemp(object_class); 937 FreeTemp(check_class); 938 if (IsTemp(result_reg)) { 939 OpRegCopy(rl_result.low_reg, result_reg); 940 FreeTemp(result_reg); 941 } 942 StoreValue(rl_dest, rl_result); 943 } 944 945 void Mir2Lir::GenInstanceofCallingHelper(bool needs_access_check, bool type_known_final, 946 bool type_known_abstract, bool use_declaring_class, 947 bool can_assume_type_is_in_dex_cache, 948 uint32_t type_idx, RegLocation rl_dest, 949 RegLocation rl_src) { 950 FlushAllRegs(); 951 // May generate a call - use explicit registers 952 LockCallTemps(); 953 LoadCurrMethodDirect(TargetReg(kArg1)); // kArg1 <= current Method* 954 int class_reg = TargetReg(kArg2); // kArg2 will hold the Class* 955 if (needs_access_check) { 956 // Check we have access to type_idx and if not throw IllegalAccessError, 957 // returns Class* in kArg0 958 CallRuntimeHelperImm(QUICK_ENTRYPOINT_OFFSET(pInitializeTypeAndVerifyAccess), 959 type_idx, true); 960 OpRegCopy(class_reg, TargetReg(kRet0)); // Align usage with fast path 961 LoadValueDirectFixed(rl_src, TargetReg(kArg0)); // kArg0 <= ref 962 } else if (use_declaring_class) { 963 LoadValueDirectFixed(rl_src, TargetReg(kArg0)); // kArg0 <= ref 964 LoadWordDisp(TargetReg(kArg1), 965 mirror::ArtMethod::DeclaringClassOffset().Int32Value(), class_reg); 966 } else { 967 // Load dex cache entry into class_reg (kArg2) 968 LoadValueDirectFixed(rl_src, TargetReg(kArg0)); // kArg0 <= ref 969 LoadWordDisp(TargetReg(kArg1), 970 mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value(), class_reg); 971 int32_t offset_of_type = 972 mirror::Array::DataOffset(sizeof(mirror::Class*)).Int32Value() + (sizeof(mirror::Class*) 973 * type_idx); 974 LoadWordDisp(class_reg, offset_of_type, class_reg); 975 if (!can_assume_type_is_in_dex_cache) { 976 // Need to test presence of type in dex cache at runtime 977 LIR* hop_branch = OpCmpImmBranch(kCondNe, class_reg, 0, NULL); 978 // Not resolved 979 // Call out to helper, which will return resolved type in kRet0 980 CallRuntimeHelperImm(QUICK_ENTRYPOINT_OFFSET(pInitializeType), type_idx, true); 981 OpRegCopy(TargetReg(kArg2), TargetReg(kRet0)); // Align usage with fast path 982 LoadValueDirectFixed(rl_src, TargetReg(kArg0)); /* reload Ref */ 983 // Rejoin code paths 984 LIR* hop_target = NewLIR0(kPseudoTargetLabel); 985 hop_branch->target = hop_target; 986 } 987 } 988 /* kArg0 is ref, kArg2 is class. If ref==null, use directly as bool result */ 989 RegLocation rl_result = GetReturn(false); 990 if (cu_->instruction_set == kMips) { 991 // On MIPS rArg0 != rl_result, place false in result if branch is taken. 992 LoadConstant(rl_result.low_reg, 0); 993 } 994 LIR* branch1 = OpCmpImmBranch(kCondEq, TargetReg(kArg0), 0, NULL); 995 996 /* load object->klass_ */ 997 DCHECK_EQ(mirror::Object::ClassOffset().Int32Value(), 0); 998 LoadWordDisp(TargetReg(kArg0), mirror::Object::ClassOffset().Int32Value(), TargetReg(kArg1)); 999 /* kArg0 is ref, kArg1 is ref->klass_, kArg2 is class */ 1000 LIR* branchover = NULL; 1001 if (type_known_final) { 1002 // rl_result == ref == null == 0. 1003 if (cu_->instruction_set == kThumb2) { 1004 OpRegReg(kOpCmp, TargetReg(kArg1), TargetReg(kArg2)); // Same? 1005 OpIT(kCondEq, "E"); // if-convert the test 1006 LoadConstant(rl_result.low_reg, 1); // .eq case - load true 1007 LoadConstant(rl_result.low_reg, 0); // .ne case - load false 1008 } else { 1009 LoadConstant(rl_result.low_reg, 0); // ne case - load false 1010 branchover = OpCmpBranch(kCondNe, TargetReg(kArg1), TargetReg(kArg2), NULL); 1011 LoadConstant(rl_result.low_reg, 1); // eq case - load true 1012 } 1013 } else { 1014 if (cu_->instruction_set == kThumb2) { 1015 int r_tgt = LoadHelper(QUICK_ENTRYPOINT_OFFSET(pInstanceofNonTrivial)); 1016 if (!type_known_abstract) { 1017 /* Uses conditional nullification */ 1018 OpRegReg(kOpCmp, TargetReg(kArg1), TargetReg(kArg2)); // Same? 1019 OpIT(kCondEq, "EE"); // if-convert the test 1020 LoadConstant(TargetReg(kArg0), 1); // .eq case - load true 1021 } 1022 OpRegCopy(TargetReg(kArg0), TargetReg(kArg2)); // .ne case - arg0 <= class 1023 OpReg(kOpBlx, r_tgt); // .ne case: helper(class, ref->class) 1024 FreeTemp(r_tgt); 1025 } else { 1026 if (!type_known_abstract) { 1027 /* Uses branchovers */ 1028 LoadConstant(rl_result.low_reg, 1); // assume true 1029 branchover = OpCmpBranch(kCondEq, TargetReg(kArg1), TargetReg(kArg2), NULL); 1030 } 1031 if (cu_->instruction_set != kX86) { 1032 int r_tgt = LoadHelper(QUICK_ENTRYPOINT_OFFSET(pInstanceofNonTrivial)); 1033 OpRegCopy(TargetReg(kArg0), TargetReg(kArg2)); // .ne case - arg0 <= class 1034 OpReg(kOpBlx, r_tgt); // .ne case: helper(class, ref->class) 1035 FreeTemp(r_tgt); 1036 } else { 1037 OpRegCopy(TargetReg(kArg0), TargetReg(kArg2)); 1038 OpThreadMem(kOpBlx, QUICK_ENTRYPOINT_OFFSET(pInstanceofNonTrivial)); 1039 } 1040 } 1041 } 1042 // TODO: only clobber when type isn't final? 1043 ClobberCalleeSave(); 1044 /* branch targets here */ 1045 LIR* target = NewLIR0(kPseudoTargetLabel); 1046 StoreValue(rl_dest, rl_result); 1047 branch1->target = target; 1048 if (branchover != NULL) { 1049 branchover->target = target; 1050 } 1051 } 1052 1053 void Mir2Lir::GenInstanceof(uint32_t type_idx, RegLocation rl_dest, RegLocation rl_src) { 1054 bool type_known_final, type_known_abstract, use_declaring_class; 1055 bool needs_access_check = !cu_->compiler_driver->CanAccessTypeWithoutChecks(cu_->method_idx, 1056 *cu_->dex_file, 1057 type_idx, 1058 &type_known_final, 1059 &type_known_abstract, 1060 &use_declaring_class); 1061 bool can_assume_type_is_in_dex_cache = !needs_access_check && 1062 cu_->compiler_driver->CanAssumeTypeIsPresentInDexCache(*cu_->dex_file, type_idx); 1063 1064 if ((use_declaring_class || can_assume_type_is_in_dex_cache) && type_known_final) { 1065 GenInstanceofFinal(use_declaring_class, type_idx, rl_dest, rl_src); 1066 } else { 1067 GenInstanceofCallingHelper(needs_access_check, type_known_final, type_known_abstract, 1068 use_declaring_class, can_assume_type_is_in_dex_cache, 1069 type_idx, rl_dest, rl_src); 1070 } 1071 } 1072 1073 void Mir2Lir::GenCheckCast(uint32_t insn_idx, uint32_t type_idx, RegLocation rl_src) { 1074 bool type_known_final, type_known_abstract, use_declaring_class; 1075 bool needs_access_check = !cu_->compiler_driver->CanAccessTypeWithoutChecks(cu_->method_idx, 1076 *cu_->dex_file, 1077 type_idx, 1078 &type_known_final, 1079 &type_known_abstract, 1080 &use_declaring_class); 1081 // Note: currently type_known_final is unused, as optimizing will only improve the performance 1082 // of the exception throw path. 1083 DexCompilationUnit* cu = mir_graph_->GetCurrentDexCompilationUnit(); 1084 const MethodReference mr(cu->GetDexFile(), cu->GetDexMethodIndex()); 1085 if (!needs_access_check && cu_->compiler_driver->IsSafeCast(mr, insn_idx)) { 1086 // Verifier type analysis proved this check cast would never cause an exception. 1087 return; 1088 } 1089 FlushAllRegs(); 1090 // May generate a call - use explicit registers 1091 LockCallTemps(); 1092 LoadCurrMethodDirect(TargetReg(kArg1)); // kArg1 <= current Method* 1093 int class_reg = TargetReg(kArg2); // kArg2 will hold the Class* 1094 if (needs_access_check) { 1095 // Check we have access to type_idx and if not throw IllegalAccessError, 1096 // returns Class* in kRet0 1097 // InitializeTypeAndVerifyAccess(idx, method) 1098 CallRuntimeHelperImmReg(QUICK_ENTRYPOINT_OFFSET(pInitializeTypeAndVerifyAccess), 1099 type_idx, TargetReg(kArg1), true); 1100 OpRegCopy(class_reg, TargetReg(kRet0)); // Align usage with fast path 1101 } else if (use_declaring_class) { 1102 LoadWordDisp(TargetReg(kArg1), 1103 mirror::ArtMethod::DeclaringClassOffset().Int32Value(), class_reg); 1104 } else { 1105 // Load dex cache entry into class_reg (kArg2) 1106 LoadWordDisp(TargetReg(kArg1), 1107 mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value(), class_reg); 1108 int32_t offset_of_type = 1109 mirror::Array::DataOffset(sizeof(mirror::Class*)).Int32Value() + 1110 (sizeof(mirror::Class*) * type_idx); 1111 LoadWordDisp(class_reg, offset_of_type, class_reg); 1112 if (!cu_->compiler_driver->CanAssumeTypeIsPresentInDexCache(*cu_->dex_file, type_idx)) { 1113 // Need to test presence of type in dex cache at runtime 1114 LIR* hop_branch = OpCmpImmBranch(kCondNe, class_reg, 0, NULL); 1115 // Not resolved 1116 // Call out to helper, which will return resolved type in kArg0 1117 // InitializeTypeFromCode(idx, method) 1118 CallRuntimeHelperImmReg(QUICK_ENTRYPOINT_OFFSET(pInitializeType), type_idx, 1119 TargetReg(kArg1), true); 1120 OpRegCopy(class_reg, TargetReg(kRet0)); // Align usage with fast path 1121 // Rejoin code paths 1122 LIR* hop_target = NewLIR0(kPseudoTargetLabel); 1123 hop_branch->target = hop_target; 1124 } 1125 } 1126 // At this point, class_reg (kArg2) has class 1127 LoadValueDirectFixed(rl_src, TargetReg(kArg0)); // kArg0 <= ref 1128 /* Null is OK - continue */ 1129 LIR* branch1 = OpCmpImmBranch(kCondEq, TargetReg(kArg0), 0, NULL); 1130 /* load object->klass_ */ 1131 DCHECK_EQ(mirror::Object::ClassOffset().Int32Value(), 0); 1132 LoadWordDisp(TargetReg(kArg0), mirror::Object::ClassOffset().Int32Value(), TargetReg(kArg1)); 1133 /* kArg1 now contains object->klass_ */ 1134 LIR* branch2 = NULL; 1135 if (!type_known_abstract) { 1136 branch2 = OpCmpBranch(kCondEq, TargetReg(kArg1), class_reg, NULL); 1137 } 1138 CallRuntimeHelperRegReg(QUICK_ENTRYPOINT_OFFSET(pCheckCast), TargetReg(kArg1), 1139 TargetReg(kArg2), true); 1140 /* branch target here */ 1141 LIR* target = NewLIR0(kPseudoTargetLabel); 1142 branch1->target = target; 1143 if (branch2 != NULL) { 1144 branch2->target = target; 1145 } 1146 } 1147 1148 void Mir2Lir::GenLong3Addr(OpKind first_op, OpKind second_op, RegLocation rl_dest, 1149 RegLocation rl_src1, RegLocation rl_src2) { 1150 RegLocation rl_result; 1151 if (cu_->instruction_set == kThumb2) { 1152 /* 1153 * NOTE: This is the one place in the code in which we might have 1154 * as many as six live temporary registers. There are 5 in the normal 1155 * set for Arm. Until we have spill capabilities, temporarily add 1156 * lr to the temp set. It is safe to do this locally, but note that 1157 * lr is used explicitly elsewhere in the code generator and cannot 1158 * normally be used as a general temp register. 1159 */ 1160 MarkTemp(TargetReg(kLr)); // Add lr to the temp pool 1161 FreeTemp(TargetReg(kLr)); // and make it available 1162 } 1163 rl_src1 = LoadValueWide(rl_src1, kCoreReg); 1164 rl_src2 = LoadValueWide(rl_src2, kCoreReg); 1165 rl_result = EvalLoc(rl_dest, kCoreReg, true); 1166 // The longs may overlap - use intermediate temp if so 1167 if ((rl_result.low_reg == rl_src1.high_reg) || (rl_result.low_reg == rl_src2.high_reg)) { 1168 int t_reg = AllocTemp(); 1169 OpRegRegReg(first_op, t_reg, rl_src1.low_reg, rl_src2.low_reg); 1170 OpRegRegReg(second_op, rl_result.high_reg, rl_src1.high_reg, rl_src2.high_reg); 1171 OpRegCopy(rl_result.low_reg, t_reg); 1172 FreeTemp(t_reg); 1173 } else { 1174 OpRegRegReg(first_op, rl_result.low_reg, rl_src1.low_reg, rl_src2.low_reg); 1175 OpRegRegReg(second_op, rl_result.high_reg, rl_src1.high_reg, 1176 rl_src2.high_reg); 1177 } 1178 /* 1179 * NOTE: If rl_dest refers to a frame variable in a large frame, the 1180 * following StoreValueWide might need to allocate a temp register. 1181 * To further work around the lack of a spill capability, explicitly 1182 * free any temps from rl_src1 & rl_src2 that aren't still live in rl_result. 1183 * Remove when spill is functional. 1184 */ 1185 FreeRegLocTemps(rl_result, rl_src1); 1186 FreeRegLocTemps(rl_result, rl_src2); 1187 StoreValueWide(rl_dest, rl_result); 1188 if (cu_->instruction_set == kThumb2) { 1189 Clobber(TargetReg(kLr)); 1190 UnmarkTemp(TargetReg(kLr)); // Remove lr from the temp pool 1191 } 1192 } 1193 1194 1195 void Mir2Lir::GenShiftOpLong(Instruction::Code opcode, RegLocation rl_dest, 1196 RegLocation rl_src1, RegLocation rl_shift) { 1197 ThreadOffset func_offset(-1); 1198 1199 switch (opcode) { 1200 case Instruction::SHL_LONG: 1201 case Instruction::SHL_LONG_2ADDR: 1202 func_offset = QUICK_ENTRYPOINT_OFFSET(pShlLong); 1203 break; 1204 case Instruction::SHR_LONG: 1205 case Instruction::SHR_LONG_2ADDR: 1206 func_offset = QUICK_ENTRYPOINT_OFFSET(pShrLong); 1207 break; 1208 case Instruction::USHR_LONG: 1209 case Instruction::USHR_LONG_2ADDR: 1210 func_offset = QUICK_ENTRYPOINT_OFFSET(pUshrLong); 1211 break; 1212 default: 1213 LOG(FATAL) << "Unexpected case"; 1214 } 1215 FlushAllRegs(); /* Send everything to home location */ 1216 CallRuntimeHelperRegLocationRegLocation(func_offset, rl_src1, rl_shift, false); 1217 RegLocation rl_result = GetReturnWide(false); 1218 StoreValueWide(rl_dest, rl_result); 1219 } 1220 1221 1222 void Mir2Lir::GenArithOpInt(Instruction::Code opcode, RegLocation rl_dest, 1223 RegLocation rl_src1, RegLocation rl_src2) { 1224 OpKind op = kOpBkpt; 1225 bool is_div_rem = false; 1226 bool check_zero = false; 1227 bool unary = false; 1228 RegLocation rl_result; 1229 bool shift_op = false; 1230 switch (opcode) { 1231 case Instruction::NEG_INT: 1232 op = kOpNeg; 1233 unary = true; 1234 break; 1235 case Instruction::NOT_INT: 1236 op = kOpMvn; 1237 unary = true; 1238 break; 1239 case Instruction::ADD_INT: 1240 case Instruction::ADD_INT_2ADDR: 1241 op = kOpAdd; 1242 break; 1243 case Instruction::SUB_INT: 1244 case Instruction::SUB_INT_2ADDR: 1245 op = kOpSub; 1246 break; 1247 case Instruction::MUL_INT: 1248 case Instruction::MUL_INT_2ADDR: 1249 op = kOpMul; 1250 break; 1251 case Instruction::DIV_INT: 1252 case Instruction::DIV_INT_2ADDR: 1253 check_zero = true; 1254 op = kOpDiv; 1255 is_div_rem = true; 1256 break; 1257 /* NOTE: returns in kArg1 */ 1258 case Instruction::REM_INT: 1259 case Instruction::REM_INT_2ADDR: 1260 check_zero = true; 1261 op = kOpRem; 1262 is_div_rem = true; 1263 break; 1264 case Instruction::AND_INT: 1265 case Instruction::AND_INT_2ADDR: 1266 op = kOpAnd; 1267 break; 1268 case Instruction::OR_INT: 1269 case Instruction::OR_INT_2ADDR: 1270 op = kOpOr; 1271 break; 1272 case Instruction::XOR_INT: 1273 case Instruction::XOR_INT_2ADDR: 1274 op = kOpXor; 1275 break; 1276 case Instruction::SHL_INT: 1277 case Instruction::SHL_INT_2ADDR: 1278 shift_op = true; 1279 op = kOpLsl; 1280 break; 1281 case Instruction::SHR_INT: 1282 case Instruction::SHR_INT_2ADDR: 1283 shift_op = true; 1284 op = kOpAsr; 1285 break; 1286 case Instruction::USHR_INT: 1287 case Instruction::USHR_INT_2ADDR: 1288 shift_op = true; 1289 op = kOpLsr; 1290 break; 1291 default: 1292 LOG(FATAL) << "Invalid word arith op: " << opcode; 1293 } 1294 if (!is_div_rem) { 1295 if (unary) { 1296 rl_src1 = LoadValue(rl_src1, kCoreReg); 1297 rl_result = EvalLoc(rl_dest, kCoreReg, true); 1298 OpRegReg(op, rl_result.low_reg, rl_src1.low_reg); 1299 } else { 1300 if (shift_op) { 1301 int t_reg = INVALID_REG; 1302 if (cu_->instruction_set == kX86) { 1303 // X86 doesn't require masking and must use ECX 1304 t_reg = TargetReg(kCount); // rCX 1305 LoadValueDirectFixed(rl_src2, t_reg); 1306 } else { 1307 rl_src2 = LoadValue(rl_src2, kCoreReg); 1308 t_reg = AllocTemp(); 1309 OpRegRegImm(kOpAnd, t_reg, rl_src2.low_reg, 31); 1310 } 1311 rl_src1 = LoadValue(rl_src1, kCoreReg); 1312 rl_result = EvalLoc(rl_dest, kCoreReg, true); 1313 OpRegRegReg(op, rl_result.low_reg, rl_src1.low_reg, t_reg); 1314 FreeTemp(t_reg); 1315 } else { 1316 rl_src1 = LoadValue(rl_src1, kCoreReg); 1317 rl_src2 = LoadValue(rl_src2, kCoreReg); 1318 rl_result = EvalLoc(rl_dest, kCoreReg, true); 1319 OpRegRegReg(op, rl_result.low_reg, rl_src1.low_reg, rl_src2.low_reg); 1320 } 1321 } 1322 StoreValue(rl_dest, rl_result); 1323 } else { 1324 if (cu_->instruction_set == kMips) { 1325 rl_src1 = LoadValue(rl_src1, kCoreReg); 1326 rl_src2 = LoadValue(rl_src2, kCoreReg); 1327 if (check_zero) { 1328 GenImmedCheck(kCondEq, rl_src2.low_reg, 0, kThrowDivZero); 1329 } 1330 rl_result = GenDivRem(rl_dest, rl_src1.low_reg, rl_src2.low_reg, op == kOpDiv); 1331 } else { 1332 ThreadOffset func_offset = QUICK_ENTRYPOINT_OFFSET(pIdivmod); 1333 FlushAllRegs(); /* Send everything to home location */ 1334 LoadValueDirectFixed(rl_src2, TargetReg(kArg1)); 1335 int r_tgt = CallHelperSetup(func_offset); 1336 LoadValueDirectFixed(rl_src1, TargetReg(kArg0)); 1337 if (check_zero) { 1338 GenImmedCheck(kCondEq, TargetReg(kArg1), 0, kThrowDivZero); 1339 } 1340 // NOTE: callout here is not a safepoint 1341 CallHelper(r_tgt, func_offset, false /* not a safepoint */); 1342 if (op == kOpDiv) 1343 rl_result = GetReturn(false); 1344 else 1345 rl_result = GetReturnAlt(); 1346 } 1347 StoreValue(rl_dest, rl_result); 1348 } 1349 } 1350 1351 /* 1352 * The following are the first-level codegen routines that analyze the format 1353 * of each bytecode then either dispatch special purpose codegen routines 1354 * or produce corresponding Thumb instructions directly. 1355 */ 1356 1357 static bool IsPowerOfTwo(int x) { 1358 return (x & (x - 1)) == 0; 1359 } 1360 1361 // Returns true if no more than two bits are set in 'x'. 1362 static bool IsPopCountLE2(unsigned int x) { 1363 x &= x - 1; 1364 return (x & (x - 1)) == 0; 1365 } 1366 1367 // Returns the index of the lowest set bit in 'x'. 1368 static int LowestSetBit(unsigned int x) { 1369 int bit_posn = 0; 1370 while ((x & 0xf) == 0) { 1371 bit_posn += 4; 1372 x >>= 4; 1373 } 1374 while ((x & 1) == 0) { 1375 bit_posn++; 1376 x >>= 1; 1377 } 1378 return bit_posn; 1379 } 1380 1381 // Returns true if it added instructions to 'cu' to divide 'rl_src' by 'lit' 1382 // and store the result in 'rl_dest'. 1383 bool Mir2Lir::HandleEasyDivRem(Instruction::Code dalvik_opcode, bool is_div, 1384 RegLocation rl_src, RegLocation rl_dest, int lit) { 1385 if ((lit < 2) || ((cu_->instruction_set != kThumb2) && !IsPowerOfTwo(lit))) { 1386 return false; 1387 } 1388 // No divide instruction for Arm, so check for more special cases 1389 if ((cu_->instruction_set == kThumb2) && !IsPowerOfTwo(lit)) { 1390 return SmallLiteralDivRem(dalvik_opcode, is_div, rl_src, rl_dest, lit); 1391 } 1392 int k = LowestSetBit(lit); 1393 if (k >= 30) { 1394 // Avoid special cases. 1395 return false; 1396 } 1397 rl_src = LoadValue(rl_src, kCoreReg); 1398 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true); 1399 if (is_div) { 1400 int t_reg = AllocTemp(); 1401 if (lit == 2) { 1402 // Division by 2 is by far the most common division by constant. 1403 OpRegRegImm(kOpLsr, t_reg, rl_src.low_reg, 32 - k); 1404 OpRegRegReg(kOpAdd, t_reg, t_reg, rl_src.low_reg); 1405 OpRegRegImm(kOpAsr, rl_result.low_reg, t_reg, k); 1406 } else { 1407 OpRegRegImm(kOpAsr, t_reg, rl_src.low_reg, 31); 1408 OpRegRegImm(kOpLsr, t_reg, t_reg, 32 - k); 1409 OpRegRegReg(kOpAdd, t_reg, t_reg, rl_src.low_reg); 1410 OpRegRegImm(kOpAsr, rl_result.low_reg, t_reg, k); 1411 } 1412 } else { 1413 int t_reg1 = AllocTemp(); 1414 int t_reg2 = AllocTemp(); 1415 if (lit == 2) { 1416 OpRegRegImm(kOpLsr, t_reg1, rl_src.low_reg, 32 - k); 1417 OpRegRegReg(kOpAdd, t_reg2, t_reg1, rl_src.low_reg); 1418 OpRegRegImm(kOpAnd, t_reg2, t_reg2, lit -1); 1419 OpRegRegReg(kOpSub, rl_result.low_reg, t_reg2, t_reg1); 1420 } else { 1421 OpRegRegImm(kOpAsr, t_reg1, rl_src.low_reg, 31); 1422 OpRegRegImm(kOpLsr, t_reg1, t_reg1, 32 - k); 1423 OpRegRegReg(kOpAdd, t_reg2, t_reg1, rl_src.low_reg); 1424 OpRegRegImm(kOpAnd, t_reg2, t_reg2, lit - 1); 1425 OpRegRegReg(kOpSub, rl_result.low_reg, t_reg2, t_reg1); 1426 } 1427 } 1428 StoreValue(rl_dest, rl_result); 1429 return true; 1430 } 1431 1432 // Returns true if it added instructions to 'cu' to multiply 'rl_src' by 'lit' 1433 // and store the result in 'rl_dest'. 1434 bool Mir2Lir::HandleEasyMultiply(RegLocation rl_src, RegLocation rl_dest, int lit) { 1435 // Can we simplify this multiplication? 1436 bool power_of_two = false; 1437 bool pop_count_le2 = false; 1438 bool power_of_two_minus_one = false; 1439 if (lit < 2) { 1440 // Avoid special cases. 1441 return false; 1442 } else if (IsPowerOfTwo(lit)) { 1443 power_of_two = true; 1444 } else if (IsPopCountLE2(lit)) { 1445 pop_count_le2 = true; 1446 } else if (IsPowerOfTwo(lit + 1)) { 1447 power_of_two_minus_one = true; 1448 } else { 1449 return false; 1450 } 1451 rl_src = LoadValue(rl_src, kCoreReg); 1452 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true); 1453 if (power_of_two) { 1454 // Shift. 1455 OpRegRegImm(kOpLsl, rl_result.low_reg, rl_src.low_reg, LowestSetBit(lit)); 1456 } else if (pop_count_le2) { 1457 // Shift and add and shift. 1458 int first_bit = LowestSetBit(lit); 1459 int second_bit = LowestSetBit(lit ^ (1 << first_bit)); 1460 GenMultiplyByTwoBitMultiplier(rl_src, rl_result, lit, first_bit, second_bit); 1461 } else { 1462 // Reverse subtract: (src << (shift + 1)) - src. 1463 DCHECK(power_of_two_minus_one); 1464 // TUNING: rsb dst, src, src lsl#LowestSetBit(lit + 1) 1465 int t_reg = AllocTemp(); 1466 OpRegRegImm(kOpLsl, t_reg, rl_src.low_reg, LowestSetBit(lit + 1)); 1467 OpRegRegReg(kOpSub, rl_result.low_reg, t_reg, rl_src.low_reg); 1468 } 1469 StoreValue(rl_dest, rl_result); 1470 return true; 1471 } 1472 1473 void Mir2Lir::GenArithOpIntLit(Instruction::Code opcode, RegLocation rl_dest, RegLocation rl_src, 1474 int lit) { 1475 RegLocation rl_result; 1476 OpKind op = static_cast<OpKind>(0); /* Make gcc happy */ 1477 int shift_op = false; 1478 bool is_div = false; 1479 1480 switch (opcode) { 1481 case Instruction::RSUB_INT_LIT8: 1482 case Instruction::RSUB_INT: { 1483 rl_src = LoadValue(rl_src, kCoreReg); 1484 rl_result = EvalLoc(rl_dest, kCoreReg, true); 1485 if (cu_->instruction_set == kThumb2) { 1486 OpRegRegImm(kOpRsub, rl_result.low_reg, rl_src.low_reg, lit); 1487 } else { 1488 OpRegReg(kOpNeg, rl_result.low_reg, rl_src.low_reg); 1489 OpRegImm(kOpAdd, rl_result.low_reg, lit); 1490 } 1491 StoreValue(rl_dest, rl_result); 1492 return; 1493 } 1494 1495 case Instruction::SUB_INT: 1496 case Instruction::SUB_INT_2ADDR: 1497 lit = -lit; 1498 // Intended fallthrough 1499 case Instruction::ADD_INT: 1500 case Instruction::ADD_INT_2ADDR: 1501 case Instruction::ADD_INT_LIT8: 1502 case Instruction::ADD_INT_LIT16: 1503 op = kOpAdd; 1504 break; 1505 case Instruction::MUL_INT: 1506 case Instruction::MUL_INT_2ADDR: 1507 case Instruction::MUL_INT_LIT8: 1508 case Instruction::MUL_INT_LIT16: { 1509 if (HandleEasyMultiply(rl_src, rl_dest, lit)) { 1510 return; 1511 } 1512 op = kOpMul; 1513 break; 1514 } 1515 case Instruction::AND_INT: 1516 case Instruction::AND_INT_2ADDR: 1517 case Instruction::AND_INT_LIT8: 1518 case Instruction::AND_INT_LIT16: 1519 op = kOpAnd; 1520 break; 1521 case Instruction::OR_INT: 1522 case Instruction::OR_INT_2ADDR: 1523 case Instruction::OR_INT_LIT8: 1524 case Instruction::OR_INT_LIT16: 1525 op = kOpOr; 1526 break; 1527 case Instruction::XOR_INT: 1528 case Instruction::XOR_INT_2ADDR: 1529 case Instruction::XOR_INT_LIT8: 1530 case Instruction::XOR_INT_LIT16: 1531 op = kOpXor; 1532 break; 1533 case Instruction::SHL_INT_LIT8: 1534 case Instruction::SHL_INT: 1535 case Instruction::SHL_INT_2ADDR: 1536 lit &= 31; 1537 shift_op = true; 1538 op = kOpLsl; 1539 break; 1540 case Instruction::SHR_INT_LIT8: 1541 case Instruction::SHR_INT: 1542 case Instruction::SHR_INT_2ADDR: 1543 lit &= 31; 1544 shift_op = true; 1545 op = kOpAsr; 1546 break; 1547 case Instruction::USHR_INT_LIT8: 1548 case Instruction::USHR_INT: 1549 case Instruction::USHR_INT_2ADDR: 1550 lit &= 31; 1551 shift_op = true; 1552 op = kOpLsr; 1553 break; 1554 1555 case Instruction::DIV_INT: 1556 case Instruction::DIV_INT_2ADDR: 1557 case Instruction::DIV_INT_LIT8: 1558 case Instruction::DIV_INT_LIT16: 1559 case Instruction::REM_INT: 1560 case Instruction::REM_INT_2ADDR: 1561 case Instruction::REM_INT_LIT8: 1562 case Instruction::REM_INT_LIT16: { 1563 if (lit == 0) { 1564 GenImmedCheck(kCondAl, 0, 0, kThrowDivZero); 1565 return; 1566 } 1567 if ((opcode == Instruction::DIV_INT) || 1568 (opcode == Instruction::DIV_INT_2ADDR) || 1569 (opcode == Instruction::DIV_INT_LIT8) || 1570 (opcode == Instruction::DIV_INT_LIT16)) { 1571 is_div = true; 1572 } else { 1573 is_div = false; 1574 } 1575 if (HandleEasyDivRem(opcode, is_div, rl_src, rl_dest, lit)) { 1576 return; 1577 } 1578 if (cu_->instruction_set == kMips) { 1579 rl_src = LoadValue(rl_src, kCoreReg); 1580 rl_result = GenDivRemLit(rl_dest, rl_src.low_reg, lit, is_div); 1581 } else { 1582 FlushAllRegs(); /* Everything to home location */ 1583 LoadValueDirectFixed(rl_src, TargetReg(kArg0)); 1584 Clobber(TargetReg(kArg0)); 1585 ThreadOffset func_offset = QUICK_ENTRYPOINT_OFFSET(pIdivmod); 1586 CallRuntimeHelperRegImm(func_offset, TargetReg(kArg0), lit, false); 1587 if (is_div) 1588 rl_result = GetReturn(false); 1589 else 1590 rl_result = GetReturnAlt(); 1591 } 1592 StoreValue(rl_dest, rl_result); 1593 return; 1594 } 1595 default: 1596 LOG(FATAL) << "Unexpected opcode " << opcode; 1597 } 1598 rl_src = LoadValue(rl_src, kCoreReg); 1599 rl_result = EvalLoc(rl_dest, kCoreReg, true); 1600 // Avoid shifts by literal 0 - no support in Thumb. Change to copy 1601 if (shift_op && (lit == 0)) { 1602 OpRegCopy(rl_result.low_reg, rl_src.low_reg); 1603 } else { 1604 OpRegRegImm(op, rl_result.low_reg, rl_src.low_reg, lit); 1605 } 1606 StoreValue(rl_dest, rl_result); 1607 } 1608 1609 void Mir2Lir::GenArithOpLong(Instruction::Code opcode, RegLocation rl_dest, 1610 RegLocation rl_src1, RegLocation rl_src2) { 1611 RegLocation rl_result; 1612 OpKind first_op = kOpBkpt; 1613 OpKind second_op = kOpBkpt; 1614 bool call_out = false; 1615 bool check_zero = false; 1616 ThreadOffset func_offset(-1); 1617 int ret_reg = TargetReg(kRet0); 1618 1619 switch (opcode) { 1620 case Instruction::NOT_LONG: 1621 rl_src2 = LoadValueWide(rl_src2, kCoreReg); 1622 rl_result = EvalLoc(rl_dest, kCoreReg, true); 1623 // Check for destructive overlap 1624 if (rl_result.low_reg == rl_src2.high_reg) { 1625 int t_reg = AllocTemp(); 1626 OpRegCopy(t_reg, rl_src2.high_reg); 1627 OpRegReg(kOpMvn, rl_result.low_reg, rl_src2.low_reg); 1628 OpRegReg(kOpMvn, rl_result.high_reg, t_reg); 1629 FreeTemp(t_reg); 1630 } else { 1631 OpRegReg(kOpMvn, rl_result.low_reg, rl_src2.low_reg); 1632 OpRegReg(kOpMvn, rl_result.high_reg, rl_src2.high_reg); 1633 } 1634 StoreValueWide(rl_dest, rl_result); 1635 return; 1636 case Instruction::ADD_LONG: 1637 case Instruction::ADD_LONG_2ADDR: 1638 if (cu_->instruction_set != kThumb2) { 1639 GenAddLong(rl_dest, rl_src1, rl_src2); 1640 return; 1641 } 1642 first_op = kOpAdd; 1643 second_op = kOpAdc; 1644 break; 1645 case Instruction::SUB_LONG: 1646 case Instruction::SUB_LONG_2ADDR: 1647 if (cu_->instruction_set != kThumb2) { 1648 GenSubLong(rl_dest, rl_src1, rl_src2); 1649 return; 1650 } 1651 first_op = kOpSub; 1652 second_op = kOpSbc; 1653 break; 1654 case Instruction::MUL_LONG: 1655 case Instruction::MUL_LONG_2ADDR: 1656 if (cu_->instruction_set == kThumb2) { 1657 GenMulLong(rl_dest, rl_src1, rl_src2); 1658 return; 1659 } else { 1660 call_out = true; 1661 ret_reg = TargetReg(kRet0); 1662 func_offset = QUICK_ENTRYPOINT_OFFSET(pLmul); 1663 } 1664 break; 1665 case Instruction::DIV_LONG: 1666 case Instruction::DIV_LONG_2ADDR: 1667 call_out = true; 1668 check_zero = true; 1669 ret_reg = TargetReg(kRet0); 1670 func_offset = QUICK_ENTRYPOINT_OFFSET(pLdiv); 1671 break; 1672 case Instruction::REM_LONG: 1673 case Instruction::REM_LONG_2ADDR: 1674 call_out = true; 1675 check_zero = true; 1676 func_offset = QUICK_ENTRYPOINT_OFFSET(pLdivmod); 1677 /* NOTE - for Arm, result is in kArg2/kArg3 instead of kRet0/kRet1 */ 1678 ret_reg = (cu_->instruction_set == kThumb2) ? TargetReg(kArg2) : TargetReg(kRet0); 1679 break; 1680 case Instruction::AND_LONG_2ADDR: 1681 case Instruction::AND_LONG: 1682 if (cu_->instruction_set == kX86) { 1683 return GenAndLong(rl_dest, rl_src1, rl_src2); 1684 } 1685 first_op = kOpAnd; 1686 second_op = kOpAnd; 1687 break; 1688 case Instruction::OR_LONG: 1689 case Instruction::OR_LONG_2ADDR: 1690 if (cu_->instruction_set == kX86) { 1691 GenOrLong(rl_dest, rl_src1, rl_src2); 1692 return; 1693 } 1694 first_op = kOpOr; 1695 second_op = kOpOr; 1696 break; 1697 case Instruction::XOR_LONG: 1698 case Instruction::XOR_LONG_2ADDR: 1699 if (cu_->instruction_set == kX86) { 1700 GenXorLong(rl_dest, rl_src1, rl_src2); 1701 return; 1702 } 1703 first_op = kOpXor; 1704 second_op = kOpXor; 1705 break; 1706 case Instruction::NEG_LONG: { 1707 GenNegLong(rl_dest, rl_src2); 1708 return; 1709 } 1710 default: 1711 LOG(FATAL) << "Invalid long arith op"; 1712 } 1713 if (!call_out) { 1714 GenLong3Addr(first_op, second_op, rl_dest, rl_src1, rl_src2); 1715 } else { 1716 FlushAllRegs(); /* Send everything to home location */ 1717 if (check_zero) { 1718 LoadValueDirectWideFixed(rl_src2, TargetReg(kArg2), TargetReg(kArg3)); 1719 int r_tgt = CallHelperSetup(func_offset); 1720 GenDivZeroCheck(TargetReg(kArg2), TargetReg(kArg3)); 1721 LoadValueDirectWideFixed(rl_src1, TargetReg(kArg0), TargetReg(kArg1)); 1722 // NOTE: callout here is not a safepoint 1723 CallHelper(r_tgt, func_offset, false /* not safepoint */); 1724 } else { 1725 CallRuntimeHelperRegLocationRegLocation(func_offset, rl_src1, rl_src2, false); 1726 } 1727 // Adjust return regs in to handle case of rem returning kArg2/kArg3 1728 if (ret_reg == TargetReg(kRet0)) 1729 rl_result = GetReturnWide(false); 1730 else 1731 rl_result = GetReturnWideAlt(); 1732 StoreValueWide(rl_dest, rl_result); 1733 } 1734 } 1735 1736 void Mir2Lir::GenConversionCall(ThreadOffset func_offset, 1737 RegLocation rl_dest, RegLocation rl_src) { 1738 /* 1739 * Don't optimize the register usage since it calls out to support 1740 * functions 1741 */ 1742 FlushAllRegs(); /* Send everything to home location */ 1743 if (rl_src.wide) { 1744 LoadValueDirectWideFixed(rl_src, rl_src.fp ? TargetReg(kFArg0) : TargetReg(kArg0), 1745 rl_src.fp ? TargetReg(kFArg1) : TargetReg(kArg1)); 1746 } else { 1747 LoadValueDirectFixed(rl_src, rl_src.fp ? TargetReg(kFArg0) : TargetReg(kArg0)); 1748 } 1749 CallRuntimeHelperRegLocation(func_offset, rl_src, false); 1750 if (rl_dest.wide) { 1751 RegLocation rl_result; 1752 rl_result = GetReturnWide(rl_dest.fp); 1753 StoreValueWide(rl_dest, rl_result); 1754 } else { 1755 RegLocation rl_result; 1756 rl_result = GetReturn(rl_dest.fp); 1757 StoreValue(rl_dest, rl_result); 1758 } 1759 } 1760 1761 /* Check if we need to check for pending suspend request */ 1762 void Mir2Lir::GenSuspendTest(int opt_flags) { 1763 if (NO_SUSPEND || (opt_flags & MIR_IGNORE_SUSPEND_CHECK)) { 1764 return; 1765 } 1766 FlushAllRegs(); 1767 LIR* branch = OpTestSuspend(NULL); 1768 LIR* ret_lab = NewLIR0(kPseudoTargetLabel); 1769 LIR* target = RawLIR(current_dalvik_offset_, kPseudoSuspendTarget, 1770 reinterpret_cast<uintptr_t>(ret_lab), current_dalvik_offset_); 1771 branch->target = target; 1772 suspend_launchpads_.Insert(target); 1773 } 1774 1775 /* Check if we need to check for pending suspend request */ 1776 void Mir2Lir::GenSuspendTestAndBranch(int opt_flags, LIR* target) { 1777 if (NO_SUSPEND || (opt_flags & MIR_IGNORE_SUSPEND_CHECK)) { 1778 OpUnconditionalBranch(target); 1779 return; 1780 } 1781 OpTestSuspend(target); 1782 LIR* launch_pad = 1783 RawLIR(current_dalvik_offset_, kPseudoSuspendTarget, 1784 reinterpret_cast<uintptr_t>(target), current_dalvik_offset_); 1785 FlushAllRegs(); 1786 OpUnconditionalBranch(launch_pad); 1787 suspend_launchpads_.Insert(launch_pad); 1788 } 1789 1790 } // namespace art 1791