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