gen_invoke.cc revision 2d7210188805292e463be4bcf7a133b654d7e0ea
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 "arm/codegen_arm.h" 18#include "dex/compiler_ir.h" 19#include "dex/frontend.h" 20#include "dex/quick/dex_file_method_inliner.h" 21#include "dex/quick/dex_file_to_method_inliner_map.h" 22#include "dex_file-inl.h" 23#include "entrypoints/quick/quick_entrypoints.h" 24#include "invoke_type.h" 25#include "mirror/array.h" 26#include "mirror/class-inl.h" 27#include "mirror/dex_cache.h" 28#include "mirror/object_array-inl.h" 29#include "mirror/string.h" 30#include "mir_to_lir-inl.h" 31#include "scoped_thread_state_change.h" 32 33namespace art { 34 35// Shortcuts to repeatedly used long types. 36typedef mirror::ObjectArray<mirror::Object> ObjArray; 37 38/* 39 * This source files contains "gen" codegen routines that should 40 * be applicable to most targets. Only mid-level support utilities 41 * and "op" calls may be used here. 42 */ 43 44void Mir2Lir::AddIntrinsicSlowPath(CallInfo* info, LIR* branch, LIR* resume) { 45 class IntrinsicSlowPathPath : public Mir2Lir::LIRSlowPath { 46 public: 47 IntrinsicSlowPathPath(Mir2Lir* m2l, CallInfo* info_in, LIR* branch_in, LIR* resume_in) 48 : LIRSlowPath(m2l, info_in->offset, branch_in, resume_in), info_(info_in) { 49 } 50 51 void Compile() { 52 m2l_->ResetRegPool(); 53 m2l_->ResetDefTracking(); 54 GenerateTargetLabel(kPseudoIntrinsicRetry); 55 // NOTE: GenInvokeNoInline() handles MarkSafepointPC. 56 m2l_->GenInvokeNoInline(info_); 57 if (cont_ != nullptr) { 58 m2l_->OpUnconditionalBranch(cont_); 59 } 60 } 61 62 private: 63 CallInfo* const info_; 64 }; 65 66 AddSlowPath(new (arena_) IntrinsicSlowPathPath(this, info, branch, resume)); 67} 68 69/* 70 * To save scheduling time, helper calls are broken into two parts: generation of 71 * the helper target address, and the actual call to the helper. Because x86 72 * has a memory call operation, part 1 is a NOP for x86. For other targets, 73 * load arguments between the two parts. 74 */ 75// template <size_t pointer_size> 76RegStorage Mir2Lir::CallHelperSetup(QuickEntrypointEnum trampoline) { 77 if (cu_->instruction_set == kX86 || cu_->instruction_set == kX86_64) { 78 return RegStorage::InvalidReg(); 79 } else { 80 return LoadHelper(trampoline); 81 } 82} 83 84LIR* Mir2Lir::CallHelper(RegStorage r_tgt, QuickEntrypointEnum trampoline, bool safepoint_pc, 85 bool use_link) { 86 LIR* call_inst = InvokeTrampoline(use_link ? kOpBlx : kOpBx, r_tgt, trampoline); 87 88 if (r_tgt.Valid()) { 89 FreeTemp(r_tgt); 90 } 91 92 if (safepoint_pc) { 93 MarkSafepointPC(call_inst); 94 } 95 return call_inst; 96} 97 98void Mir2Lir::CallRuntimeHelper(QuickEntrypointEnum trampoline, bool safepoint_pc) { 99 RegStorage r_tgt = CallHelperSetup(trampoline); 100 ClobberCallerSave(); 101 CallHelper(r_tgt, trampoline, safepoint_pc); 102} 103 104void Mir2Lir::CallRuntimeHelperImm(QuickEntrypointEnum trampoline, int arg0, bool safepoint_pc) { 105 RegStorage r_tgt = CallHelperSetup(trampoline); 106 LoadConstant(TargetReg(kArg0, kNotWide), arg0); 107 ClobberCallerSave(); 108 CallHelper(r_tgt, trampoline, safepoint_pc); 109} 110 111void Mir2Lir::CallRuntimeHelperReg(QuickEntrypointEnum trampoline, RegStorage arg0, 112 bool safepoint_pc) { 113 RegStorage r_tgt = CallHelperSetup(trampoline); 114 OpRegCopy(TargetReg(kArg0, arg0.GetWideKind()), arg0); 115 ClobberCallerSave(); 116 CallHelper(r_tgt, trampoline, safepoint_pc); 117} 118 119void Mir2Lir::CallRuntimeHelperRegLocation(QuickEntrypointEnum trampoline, RegLocation arg0, 120 bool safepoint_pc) { 121 RegStorage r_tgt = CallHelperSetup(trampoline); 122 if (arg0.wide == 0) { 123 LoadValueDirectFixed(arg0, TargetReg(arg0.fp ? kFArg0 : kArg0, arg0)); 124 } else { 125 LoadValueDirectWideFixed(arg0, TargetReg(arg0.fp ? kFArg0 : kArg0, kWide)); 126 } 127 ClobberCallerSave(); 128 CallHelper(r_tgt, trampoline, safepoint_pc); 129} 130 131void Mir2Lir::CallRuntimeHelperImmImm(QuickEntrypointEnum trampoline, int arg0, int arg1, 132 bool safepoint_pc) { 133 RegStorage r_tgt = CallHelperSetup(trampoline); 134 LoadConstant(TargetReg(kArg0, kNotWide), arg0); 135 LoadConstant(TargetReg(kArg1, kNotWide), arg1); 136 ClobberCallerSave(); 137 CallHelper(r_tgt, trampoline, safepoint_pc); 138} 139 140void Mir2Lir::CallRuntimeHelperImmRegLocation(QuickEntrypointEnum trampoline, int arg0, 141 RegLocation arg1, bool safepoint_pc) { 142 RegStorage r_tgt = CallHelperSetup(trampoline); 143 if (arg1.wide == 0) { 144 LoadValueDirectFixed(arg1, TargetReg(kArg1, arg1)); 145 } else { 146 RegStorage r_tmp = TargetReg(cu_->instruction_set == kMips ? kArg2 : kArg1, kWide); 147 LoadValueDirectWideFixed(arg1, r_tmp); 148 } 149 LoadConstant(TargetReg(kArg0, kNotWide), arg0); 150 ClobberCallerSave(); 151 CallHelper(r_tgt, trampoline, safepoint_pc); 152} 153 154void Mir2Lir::CallRuntimeHelperRegLocationImm(QuickEntrypointEnum trampoline, RegLocation arg0, 155 int arg1, bool safepoint_pc) { 156 RegStorage r_tgt = CallHelperSetup(trampoline); 157 DCHECK(!arg0.wide); 158 LoadValueDirectFixed(arg0, TargetReg(kArg0, arg0)); 159 LoadConstant(TargetReg(kArg1, kNotWide), arg1); 160 ClobberCallerSave(); 161 CallHelper(r_tgt, trampoline, safepoint_pc); 162} 163 164void Mir2Lir::CallRuntimeHelperImmReg(QuickEntrypointEnum trampoline, int arg0, RegStorage arg1, 165 bool safepoint_pc) { 166 RegStorage r_tgt = CallHelperSetup(trampoline); 167 OpRegCopy(TargetReg(kArg1, arg1.GetWideKind()), arg1); 168 LoadConstant(TargetReg(kArg0, kNotWide), arg0); 169 ClobberCallerSave(); 170 CallHelper(r_tgt, trampoline, safepoint_pc); 171} 172 173void Mir2Lir::CallRuntimeHelperRegImm(QuickEntrypointEnum trampoline, RegStorage arg0, int arg1, 174 bool safepoint_pc) { 175 RegStorage r_tgt = CallHelperSetup(trampoline); 176 OpRegCopy(TargetReg(kArg0, arg0.GetWideKind()), arg0); 177 LoadConstant(TargetReg(kArg1, kNotWide), arg1); 178 ClobberCallerSave(); 179 CallHelper(r_tgt, trampoline, safepoint_pc); 180} 181 182void Mir2Lir::CallRuntimeHelperImmMethod(QuickEntrypointEnum trampoline, int arg0, 183 bool safepoint_pc) { 184 RegStorage r_tgt = CallHelperSetup(trampoline); 185 LoadCurrMethodDirect(TargetReg(kArg1, kRef)); 186 LoadConstant(TargetReg(kArg0, kNotWide), arg0); 187 ClobberCallerSave(); 188 CallHelper(r_tgt, trampoline, safepoint_pc); 189} 190 191void Mir2Lir::CallRuntimeHelperRegMethod(QuickEntrypointEnum trampoline, RegStorage arg0, 192 bool safepoint_pc) { 193 RegStorage r_tgt = CallHelperSetup(trampoline); 194 DCHECK(!IsSameReg(TargetReg(kArg1, arg0.GetWideKind()), arg0)); 195 RegStorage r_tmp = TargetReg(kArg0, arg0.GetWideKind()); 196 if (r_tmp.NotExactlyEquals(arg0)) { 197 OpRegCopy(r_tmp, arg0); 198 } 199 LoadCurrMethodDirect(TargetReg(kArg1, kRef)); 200 ClobberCallerSave(); 201 CallHelper(r_tgt, trampoline, safepoint_pc); 202} 203 204void Mir2Lir::CallRuntimeHelperRegMethodRegLocation(QuickEntrypointEnum trampoline, RegStorage arg0, 205 RegLocation arg2, bool safepoint_pc) { 206 RegStorage r_tgt = CallHelperSetup(trampoline); 207 DCHECK(!IsSameReg(TargetReg(kArg1, arg0.GetWideKind()), arg0)); 208 RegStorage r_tmp = TargetReg(kArg0, arg0.GetWideKind()); 209 if (r_tmp.NotExactlyEquals(arg0)) { 210 OpRegCopy(r_tmp, arg0); 211 } 212 LoadCurrMethodDirect(TargetReg(kArg1, kRef)); 213 LoadValueDirectFixed(arg2, TargetReg(kArg2, arg2)); 214 ClobberCallerSave(); 215 CallHelper(r_tgt, trampoline, safepoint_pc); 216} 217 218void Mir2Lir::CallRuntimeHelperRegLocationRegLocation(QuickEntrypointEnum trampoline, 219 RegLocation arg0, RegLocation arg1, 220 bool safepoint_pc) { 221 RegStorage r_tgt = CallHelperSetup(trampoline); 222 if (cu_->instruction_set == kArm64 || cu_->instruction_set == kX86_64) { 223 RegStorage arg0_reg = TargetReg((arg0.fp) ? kFArg0 : kArg0, arg0); 224 225 RegStorage arg1_reg; 226 if (arg1.fp == arg0.fp) { 227 arg1_reg = TargetReg((arg1.fp) ? kFArg1 : kArg1, arg1); 228 } else { 229 arg1_reg = TargetReg((arg1.fp) ? kFArg0 : kArg0, arg1); 230 } 231 232 if (arg0.wide == 0) { 233 LoadValueDirectFixed(arg0, arg0_reg); 234 } else { 235 LoadValueDirectWideFixed(arg0, arg0_reg); 236 } 237 238 if (arg1.wide == 0) { 239 LoadValueDirectFixed(arg1, arg1_reg); 240 } else { 241 LoadValueDirectWideFixed(arg1, arg1_reg); 242 } 243 } else { 244 DCHECK(!cu_->target64); 245 if (arg0.wide == 0) { 246 LoadValueDirectFixed(arg0, TargetReg(arg0.fp ? kFArg0 : kArg0, kNotWide)); 247 if (arg1.wide == 0) { 248 if (cu_->instruction_set == kMips) { 249 LoadValueDirectFixed(arg1, TargetReg(arg1.fp ? kFArg2 : kArg1, kNotWide)); 250 } else { 251 LoadValueDirectFixed(arg1, TargetReg(arg1.fp ? kFArg1 : kArg1, kNotWide)); 252 } 253 } else { 254 if (cu_->instruction_set == kMips) { 255 LoadValueDirectWideFixed(arg1, TargetReg(arg1.fp ? kFArg2 : kArg2, kWide)); 256 } else { 257 LoadValueDirectWideFixed(arg1, TargetReg(arg1.fp ? kFArg1 : kArg1, kWide)); 258 } 259 } 260 } else { 261 LoadValueDirectWideFixed(arg0, TargetReg(arg0.fp ? kFArg0 : kArg0, kWide)); 262 if (arg1.wide == 0) { 263 LoadValueDirectFixed(arg1, TargetReg(arg1.fp ? kFArg2 : kArg2, kNotWide)); 264 } else { 265 LoadValueDirectWideFixed(arg1, TargetReg(arg1.fp ? kFArg2 : kArg2, kWide)); 266 } 267 } 268 } 269 ClobberCallerSave(); 270 CallHelper(r_tgt, trampoline, safepoint_pc); 271} 272 273void Mir2Lir::CopyToArgumentRegs(RegStorage arg0, RegStorage arg1) { 274 WideKind arg0_kind = arg0.GetWideKind(); 275 WideKind arg1_kind = arg1.GetWideKind(); 276 if (IsSameReg(arg1, TargetReg(kArg0, arg1_kind))) { 277 if (IsSameReg(arg0, TargetReg(kArg1, arg0_kind))) { 278 // Swap kArg0 and kArg1 with kArg2 as temp. 279 OpRegCopy(TargetReg(kArg2, arg1_kind), arg1); 280 OpRegCopy(TargetReg(kArg0, arg0_kind), arg0); 281 OpRegCopy(TargetReg(kArg1, arg1_kind), TargetReg(kArg2, arg1_kind)); 282 } else { 283 OpRegCopy(TargetReg(kArg1, arg1_kind), arg1); 284 OpRegCopy(TargetReg(kArg0, arg0_kind), arg0); 285 } 286 } else { 287 OpRegCopy(TargetReg(kArg0, arg0_kind), arg0); 288 OpRegCopy(TargetReg(kArg1, arg1_kind), arg1); 289 } 290} 291 292void Mir2Lir::CallRuntimeHelperRegReg(QuickEntrypointEnum trampoline, RegStorage arg0, 293 RegStorage arg1, bool safepoint_pc) { 294 RegStorage r_tgt = CallHelperSetup(trampoline); 295 CopyToArgumentRegs(arg0, arg1); 296 ClobberCallerSave(); 297 CallHelper(r_tgt, trampoline, safepoint_pc); 298} 299 300void Mir2Lir::CallRuntimeHelperRegRegImm(QuickEntrypointEnum trampoline, RegStorage arg0, 301 RegStorage arg1, int arg2, bool safepoint_pc) { 302 RegStorage r_tgt = CallHelperSetup(trampoline); 303 CopyToArgumentRegs(arg0, arg1); 304 LoadConstant(TargetReg(kArg2, kNotWide), arg2); 305 ClobberCallerSave(); 306 CallHelper(r_tgt, trampoline, safepoint_pc); 307} 308 309void Mir2Lir::CallRuntimeHelperImmMethodRegLocation(QuickEntrypointEnum trampoline, int arg0, 310 RegLocation arg2, bool safepoint_pc) { 311 RegStorage r_tgt = CallHelperSetup(trampoline); 312 LoadValueDirectFixed(arg2, TargetReg(kArg2, arg2)); 313 LoadCurrMethodDirect(TargetReg(kArg1, kRef)); 314 LoadConstant(TargetReg(kArg0, kNotWide), arg0); 315 ClobberCallerSave(); 316 CallHelper(r_tgt, trampoline, safepoint_pc); 317} 318 319void Mir2Lir::CallRuntimeHelperImmMethodImm(QuickEntrypointEnum trampoline, int arg0, int arg2, 320 bool safepoint_pc) { 321 RegStorage r_tgt = CallHelperSetup(trampoline); 322 LoadCurrMethodDirect(TargetReg(kArg1, kRef)); 323 LoadConstant(TargetReg(kArg2, kNotWide), arg2); 324 LoadConstant(TargetReg(kArg0, kNotWide), arg0); 325 ClobberCallerSave(); 326 CallHelper(r_tgt, trampoline, safepoint_pc); 327} 328 329void Mir2Lir::CallRuntimeHelperImmRegLocationRegLocation(QuickEntrypointEnum trampoline, int arg0, 330 RegLocation arg1, 331 RegLocation arg2, bool safepoint_pc) { 332 RegStorage r_tgt = CallHelperSetup(trampoline); 333 DCHECK_EQ(static_cast<unsigned int>(arg1.wide), 0U); // The static_cast works around an 334 // instantiation bug in GCC. 335 LoadValueDirectFixed(arg1, TargetReg(kArg1, arg1)); 336 if (arg2.wide == 0) { 337 LoadValueDirectFixed(arg2, TargetReg(kArg2, arg2)); 338 } else { 339 LoadValueDirectWideFixed(arg2, TargetReg(kArg2, kWide)); 340 } 341 LoadConstant(TargetReg(kArg0, kNotWide), arg0); 342 ClobberCallerSave(); 343 CallHelper(r_tgt, trampoline, safepoint_pc); 344} 345 346void Mir2Lir::CallRuntimeHelperRegLocationRegLocationRegLocation( 347 QuickEntrypointEnum trampoline, 348 RegLocation arg0, 349 RegLocation arg1, 350 RegLocation arg2, 351 bool safepoint_pc) { 352 RegStorage r_tgt = CallHelperSetup(trampoline); 353 LoadValueDirectFixed(arg0, TargetReg(kArg0, arg0)); 354 LoadValueDirectFixed(arg1, TargetReg(kArg1, arg1)); 355 LoadValueDirectFixed(arg2, TargetReg(kArg2, arg2)); 356 ClobberCallerSave(); 357 CallHelper(r_tgt, trampoline, safepoint_pc); 358} 359 360/* 361 * If there are any ins passed in registers that have not been promoted 362 * to a callee-save register, flush them to the frame. Perform initial 363 * assignment of promoted arguments. 364 * 365 * ArgLocs is an array of location records describing the incoming arguments 366 * with one location record per word of argument. 367 */ 368// TODO: Support 64-bit argument registers. 369void Mir2Lir::FlushIns(RegLocation* ArgLocs, RegLocation rl_method) { 370 /* 371 * Dummy up a RegLocation for the incoming StackReference<mirror::ArtMethod> 372 * It will attempt to keep kArg0 live (or copy it to home location 373 * if promoted). 374 */ 375 RegLocation rl_src = rl_method; 376 rl_src.location = kLocPhysReg; 377 rl_src.reg = TargetReg(kArg0, kRef); 378 rl_src.home = false; 379 MarkLive(rl_src); 380 StoreValue(rl_method, rl_src); 381 // If Method* has been promoted, explicitly flush 382 if (rl_method.location == kLocPhysReg) { 383 StoreRefDisp(TargetPtrReg(kSp), 0, rl_src.reg, kNotVolatile); 384 } 385 386 if (mir_graph_->GetNumOfInVRs() == 0) { 387 return; 388 } 389 390 int start_vreg = mir_graph_->GetFirstInVR(); 391 /* 392 * Copy incoming arguments to their proper home locations. 393 * NOTE: an older version of dx had an issue in which 394 * it would reuse static method argument registers. 395 * This could result in the same Dalvik virtual register 396 * being promoted to both core and fp regs. To account for this, 397 * we only copy to the corresponding promoted physical register 398 * if it matches the type of the SSA name for the incoming 399 * argument. It is also possible that long and double arguments 400 * end up half-promoted. In those cases, we must flush the promoted 401 * half to memory as well. 402 */ 403 ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg); 404 for (uint32_t i = 0; i < mir_graph_->GetNumOfInVRs(); i++) { 405 PromotionMap* v_map = &promotion_map_[start_vreg + i]; 406 RegStorage reg = GetArgMappingToPhysicalReg(i); 407 408 if (reg.Valid()) { 409 // If arriving in register 410 bool need_flush = true; 411 RegLocation* t_loc = &ArgLocs[i]; 412 if ((v_map->core_location == kLocPhysReg) && !t_loc->fp) { 413 OpRegCopy(RegStorage::Solo32(v_map->core_reg), reg); 414 need_flush = false; 415 } else if ((v_map->fp_location == kLocPhysReg) && t_loc->fp) { 416 OpRegCopy(RegStorage::Solo32(v_map->fp_reg), reg); 417 need_flush = false; 418 } else { 419 need_flush = true; 420 } 421 422 // For wide args, force flush if not fully promoted 423 if (t_loc->wide) { 424 PromotionMap* p_map = v_map + (t_loc->high_word ? -1 : +1); 425 // Is only half promoted? 426 need_flush |= (p_map->core_location != v_map->core_location) || 427 (p_map->fp_location != v_map->fp_location); 428 if ((cu_->instruction_set == kThumb2) && t_loc->fp && !need_flush) { 429 /* 430 * In Arm, a double is represented as a pair of consecutive single float 431 * registers starting at an even number. It's possible that both Dalvik vRegs 432 * representing the incoming double were independently promoted as singles - but 433 * not in a form usable as a double. If so, we need to flush - even though the 434 * incoming arg appears fully in register. At this point in the code, both 435 * halves of the double are promoted. Make sure they are in a usable form. 436 */ 437 int lowreg_index = start_vreg + i + (t_loc->high_word ? -1 : 0); 438 int low_reg = promotion_map_[lowreg_index].fp_reg; 439 int high_reg = promotion_map_[lowreg_index + 1].fp_reg; 440 if (((low_reg & 0x1) != 0) || (high_reg != (low_reg + 1))) { 441 need_flush = true; 442 } 443 } 444 } 445 if (need_flush) { 446 Store32Disp(TargetPtrReg(kSp), SRegOffset(start_vreg + i), reg); 447 } 448 } else { 449 // If arriving in frame & promoted 450 if (v_map->core_location == kLocPhysReg) { 451 Load32Disp(TargetPtrReg(kSp), SRegOffset(start_vreg + i), 452 RegStorage::Solo32(v_map->core_reg)); 453 } 454 if (v_map->fp_location == kLocPhysReg) { 455 Load32Disp(TargetPtrReg(kSp), SRegOffset(start_vreg + i), 456 RegStorage::Solo32(v_map->fp_reg)); 457 } 458 } 459 } 460} 461 462static void CommonCallCodeLoadThisIntoArg1(const CallInfo* info, Mir2Lir* cg) { 463 RegLocation rl_arg = info->args[0]; 464 cg->LoadValueDirectFixed(rl_arg, cg->TargetReg(kArg1, kRef)); 465} 466 467static void CommonCallCodeLoadClassIntoArg0(const CallInfo* info, Mir2Lir* cg) { 468 cg->GenNullCheck(cg->TargetReg(kArg1, kRef), info->opt_flags); 469 // get this->klass_ [use kArg1, set kArg0] 470 cg->LoadRefDisp(cg->TargetReg(kArg1, kRef), mirror::Object::ClassOffset().Int32Value(), 471 cg->TargetReg(kArg0, kRef), 472 kNotVolatile); 473 cg->MarkPossibleNullPointerException(info->opt_flags); 474} 475 476static bool CommonCallCodeLoadCodePointerIntoInvokeTgt(const RegStorage* alt_from, 477 const CompilationUnit* cu, Mir2Lir* cg) { 478 if (cu->instruction_set != kX86 && cu->instruction_set != kX86_64) { 479 int32_t offset = mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset( 480 InstructionSetPointerSize(cu->instruction_set)).Int32Value(); 481 // Get the compiled code address [use *alt_from or kArg0, set kInvokeTgt] 482 cg->LoadWordDisp(alt_from == nullptr ? cg->TargetReg(kArg0, kRef) : *alt_from, offset, 483 cg->TargetPtrReg(kInvokeTgt)); 484 return true; 485 } 486 return false; 487} 488 489/* 490 * Bit of a hack here - in the absence of a real scheduling pass, 491 * emit the next instruction in static & direct invoke sequences. 492 */ 493static int NextSDCallInsn(CompilationUnit* cu, CallInfo* info, 494 int state, const MethodReference& target_method, 495 uint32_t, 496 uintptr_t direct_code, uintptr_t direct_method, 497 InvokeType type) { 498 UNUSED(info); 499 DCHECK(cu->instruction_set != kX86 && cu->instruction_set != kX86_64 && 500 cu->instruction_set != kThumb2 && cu->instruction_set != kArm && 501 cu->instruction_set != kArm64); 502 Mir2Lir* cg = static_cast<Mir2Lir*>(cu->cg.get()); 503 if (direct_code != 0 && direct_method != 0) { 504 switch (state) { 505 case 0: // Get the current Method* [sets kArg0] 506 if (direct_code != static_cast<uintptr_t>(-1)) { 507 cg->LoadConstant(cg->TargetPtrReg(kInvokeTgt), direct_code); 508 } else { 509 cg->LoadCodeAddress(target_method, type, kInvokeTgt); 510 } 511 if (direct_method != static_cast<uintptr_t>(-1)) { 512 cg->LoadConstant(cg->TargetReg(kArg0, kRef), direct_method); 513 } else { 514 cg->LoadMethodAddress(target_method, type, kArg0); 515 } 516 break; 517 default: 518 return -1; 519 } 520 } else { 521 RegStorage arg0_ref = cg->TargetReg(kArg0, kRef); 522 switch (state) { 523 case 0: // Get the current Method* [sets kArg0] 524 // TUNING: we can save a reg copy if Method* has been promoted. 525 cg->LoadCurrMethodDirect(arg0_ref); 526 break; 527 case 1: // Get method->dex_cache_resolved_methods_ 528 cg->LoadRefDisp(arg0_ref, 529 mirror::ArtMethod::DexCacheResolvedMethodsOffset().Int32Value(), 530 arg0_ref, 531 kNotVolatile); 532 // Set up direct code if known. 533 if (direct_code != 0) { 534 if (direct_code != static_cast<uintptr_t>(-1)) { 535 cg->LoadConstant(cg->TargetPtrReg(kInvokeTgt), direct_code); 536 } else { 537 CHECK_LT(target_method.dex_method_index, target_method.dex_file->NumMethodIds()); 538 cg->LoadCodeAddress(target_method, type, kInvokeTgt); 539 } 540 } 541 break; 542 case 2: // Grab target method* 543 CHECK_EQ(cu->dex_file, target_method.dex_file); 544 cg->LoadRefDisp(arg0_ref, 545 ObjArray::OffsetOfElement(target_method.dex_method_index).Int32Value(), 546 arg0_ref, 547 kNotVolatile); 548 break; 549 case 3: // Grab the code from the method* 550 if (direct_code == 0) { 551 if (CommonCallCodeLoadCodePointerIntoInvokeTgt(&arg0_ref, cu, cg)) { 552 break; // kInvokeTgt := arg0_ref->entrypoint 553 } 554 } else { 555 break; 556 } 557 DCHECK(cu->instruction_set == kX86 || cu->instruction_set == kX86_64); 558 FALLTHROUGH_INTENDED; 559 default: 560 return -1; 561 } 562 } 563 return state + 1; 564} 565 566/* 567 * Bit of a hack here - in the absence of a real scheduling pass, 568 * emit the next instruction in a virtual invoke sequence. 569 * We can use kLr as a temp prior to target address loading 570 * Note also that we'll load the first argument ("this") into 571 * kArg1 here rather than the standard LoadArgRegs. 572 */ 573static int NextVCallInsn(CompilationUnit* cu, CallInfo* info, 574 int state, const MethodReference& target_method, 575 uint32_t method_idx, uintptr_t, uintptr_t, 576 InvokeType) { 577 UNUSED(target_method); 578 Mir2Lir* cg = static_cast<Mir2Lir*>(cu->cg.get()); 579 /* 580 * This is the fast path in which the target virtual method is 581 * fully resolved at compile time. 582 */ 583 switch (state) { 584 case 0: 585 CommonCallCodeLoadThisIntoArg1(info, cg); // kArg1 := this 586 break; 587 case 1: 588 CommonCallCodeLoadClassIntoArg0(info, cg); // kArg0 := kArg1->class 589 // Includes a null-check. 590 break; 591 case 2: { 592 // Get this->klass_.embedded_vtable[method_idx] [usr kArg0, set kArg0] 593 int32_t offset = mirror::Class::EmbeddedVTableOffset().Uint32Value() + 594 method_idx * sizeof(mirror::Class::VTableEntry); 595 // Load target method from embedded vtable to kArg0 [use kArg0, set kArg0] 596 cg->LoadRefDisp(cg->TargetReg(kArg0, kRef), offset, cg->TargetReg(kArg0, kRef), kNotVolatile); 597 break; 598 } 599 case 3: 600 if (CommonCallCodeLoadCodePointerIntoInvokeTgt(nullptr, cu, cg)) { 601 break; // kInvokeTgt := kArg0->entrypoint 602 } 603 DCHECK(cu->instruction_set == kX86 || cu->instruction_set == kX86_64); 604 FALLTHROUGH_INTENDED; 605 default: 606 return -1; 607 } 608 return state + 1; 609} 610 611/* 612 * Emit the next instruction in an invoke interface sequence. This will do a lookup in the 613 * class's IMT, calling either the actual method or art_quick_imt_conflict_trampoline if 614 * more than one interface method map to the same index. Note also that we'll load the first 615 * argument ("this") into kArg1 here rather than the standard LoadArgRegs. 616 */ 617static int NextInterfaceCallInsn(CompilationUnit* cu, CallInfo* info, int state, 618 const MethodReference& target_method, 619 uint32_t method_idx, uintptr_t, uintptr_t, InvokeType) { 620 Mir2Lir* cg = static_cast<Mir2Lir*>(cu->cg.get()); 621 622 switch (state) { 623 case 0: // Set target method index in case of conflict [set kHiddenArg, kHiddenFpArg (x86)] 624 CHECK_LT(target_method.dex_method_index, target_method.dex_file->NumMethodIds()); 625 cg->LoadConstant(cg->TargetReg(kHiddenArg, kNotWide), target_method.dex_method_index); 626 if (cu->instruction_set == kX86) { 627 cg->OpRegCopy(cg->TargetReg(kHiddenFpArg, kNotWide), cg->TargetReg(kHiddenArg, kNotWide)); 628 } 629 break; 630 case 1: 631 CommonCallCodeLoadThisIntoArg1(info, cg); // kArg1 := this 632 break; 633 case 2: 634 CommonCallCodeLoadClassIntoArg0(info, cg); // kArg0 := kArg1->class 635 // Includes a null-check. 636 break; 637 case 3: { // Get target method [use kInvokeTgt, set kArg0] 638 int32_t offset = mirror::Class::EmbeddedImTableOffset().Uint32Value() + 639 (method_idx % mirror::Class::kImtSize) * sizeof(mirror::Class::ImTableEntry); 640 // Load target method from embedded imtable to kArg0 [use kArg0, set kArg0] 641 cg->LoadRefDisp(cg->TargetReg(kArg0, kRef), offset, cg->TargetReg(kArg0, kRef), kNotVolatile); 642 break; 643 } 644 case 4: 645 if (CommonCallCodeLoadCodePointerIntoInvokeTgt(nullptr, cu, cg)) { 646 break; // kInvokeTgt := kArg0->entrypoint 647 } 648 DCHECK(cu->instruction_set == kX86 || cu->instruction_set == kX86_64); 649 FALLTHROUGH_INTENDED; 650 default: 651 return -1; 652 } 653 return state + 1; 654} 655 656static int NextInvokeInsnSP(CompilationUnit* cu, CallInfo* info, 657 QuickEntrypointEnum trampoline, int state, 658 const MethodReference& target_method, uint32_t method_idx) { 659 UNUSED(info, method_idx); 660 Mir2Lir* cg = static_cast<Mir2Lir*>(cu->cg.get()); 661 662 /* 663 * This handles the case in which the base method is not fully 664 * resolved at compile time, we bail to a runtime helper. 665 */ 666 if (state == 0) { 667 if (cu->instruction_set != kX86 && cu->instruction_set != kX86_64) { 668 // Load trampoline target 669 int32_t disp; 670 if (cu->target64) { 671 disp = GetThreadOffset<8>(trampoline).Int32Value(); 672 } else { 673 disp = GetThreadOffset<4>(trampoline).Int32Value(); 674 } 675 cg->LoadWordDisp(cg->TargetPtrReg(kSelf), disp, cg->TargetPtrReg(kInvokeTgt)); 676 } 677 // Load kArg0 with method index 678 CHECK_EQ(cu->dex_file, target_method.dex_file); 679 cg->LoadConstant(cg->TargetReg(kArg0, kNotWide), target_method.dex_method_index); 680 return 1; 681 } 682 return -1; 683} 684 685static int NextStaticCallInsnSP(CompilationUnit* cu, CallInfo* info, 686 int state, 687 const MethodReference& target_method, 688 uint32_t, uintptr_t, uintptr_t, InvokeType) { 689 return NextInvokeInsnSP(cu, info, kQuickInvokeStaticTrampolineWithAccessCheck, state, 690 target_method, 0); 691} 692 693static int NextDirectCallInsnSP(CompilationUnit* cu, CallInfo* info, int state, 694 const MethodReference& target_method, 695 uint32_t, uintptr_t, uintptr_t, InvokeType) { 696 return NextInvokeInsnSP(cu, info, kQuickInvokeDirectTrampolineWithAccessCheck, state, 697 target_method, 0); 698} 699 700static int NextSuperCallInsnSP(CompilationUnit* cu, CallInfo* info, int state, 701 const MethodReference& target_method, 702 uint32_t, uintptr_t, uintptr_t, InvokeType) { 703 return NextInvokeInsnSP(cu, info, kQuickInvokeSuperTrampolineWithAccessCheck, state, 704 target_method, 0); 705} 706 707static int NextVCallInsnSP(CompilationUnit* cu, CallInfo* info, int state, 708 const MethodReference& target_method, 709 uint32_t, uintptr_t, uintptr_t, InvokeType) { 710 return NextInvokeInsnSP(cu, info, kQuickInvokeVirtualTrampolineWithAccessCheck, state, 711 target_method, 0); 712} 713 714static int NextInterfaceCallInsnWithAccessCheck(CompilationUnit* cu, 715 CallInfo* info, int state, 716 const MethodReference& target_method, 717 uint32_t, uintptr_t, uintptr_t, InvokeType) { 718 return NextInvokeInsnSP(cu, info, kQuickInvokeInterfaceTrampolineWithAccessCheck, state, 719 target_method, 0); 720} 721 722int Mir2Lir::LoadArgRegs(CallInfo* info, int call_state, 723 NextCallInsn next_call_insn, 724 const MethodReference& target_method, 725 uint32_t vtable_idx, uintptr_t direct_code, 726 uintptr_t direct_method, InvokeType type, bool skip_this) { 727 int last_arg_reg = 3 - 1; 728 int arg_regs[3] = {TargetReg(kArg1, kNotWide).GetReg(), TargetReg(kArg2, kNotWide).GetReg(), 729 TargetReg(kArg3, kNotWide).GetReg()}; 730 731 int next_reg = 0; 732 int next_arg = 0; 733 if (skip_this) { 734 next_reg++; 735 next_arg++; 736 } 737 for (; (next_reg <= last_arg_reg) && (next_arg < info->num_arg_words); next_reg++) { 738 RegLocation rl_arg = info->args[next_arg++]; 739 rl_arg = UpdateRawLoc(rl_arg); 740 if (rl_arg.wide && (next_reg <= last_arg_reg - 1)) { 741 RegStorage r_tmp(RegStorage::k64BitPair, arg_regs[next_reg], arg_regs[next_reg + 1]); 742 LoadValueDirectWideFixed(rl_arg, r_tmp); 743 next_reg++; 744 next_arg++; 745 } else { 746 if (rl_arg.wide) { 747 rl_arg = NarrowRegLoc(rl_arg); 748 rl_arg.is_const = false; 749 } 750 LoadValueDirectFixed(rl_arg, RegStorage::Solo32(arg_regs[next_reg])); 751 } 752 call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx, 753 direct_code, direct_method, type); 754 } 755 return call_state; 756} 757 758/* 759 * Load up to 5 arguments, the first three of which will be in 760 * kArg1 .. kArg3. On entry kArg0 contains the current method pointer, 761 * and as part of the load sequence, it must be replaced with 762 * the target method pointer. Note, this may also be called 763 * for "range" variants if the number of arguments is 5 or fewer. 764 */ 765int Mir2Lir::GenDalvikArgsNoRange(CallInfo* info, 766 int call_state, LIR** pcrLabel, NextCallInsn next_call_insn, 767 const MethodReference& target_method, 768 uint32_t vtable_idx, uintptr_t direct_code, 769 uintptr_t direct_method, InvokeType type, bool skip_this) { 770 RegLocation rl_arg; 771 772 /* If no arguments, just return */ 773 if (info->num_arg_words == 0) 774 return call_state; 775 776 call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx, 777 direct_code, direct_method, type); 778 779 DCHECK_LE(info->num_arg_words, 5); 780 if (info->num_arg_words > 3) { 781 int32_t next_use = 3; 782 // Detect special case of wide arg spanning arg3/arg4 783 RegLocation rl_use0 = info->args[0]; 784 RegLocation rl_use1 = info->args[1]; 785 RegLocation rl_use2 = info->args[2]; 786 if (((!rl_use0.wide && !rl_use1.wide) || rl_use0.wide) && rl_use2.wide) { 787 RegStorage reg; 788 // Wide spans, we need the 2nd half of uses[2]. 789 rl_arg = UpdateLocWide(rl_use2); 790 if (rl_arg.location == kLocPhysReg) { 791 if (rl_arg.reg.IsPair()) { 792 reg = rl_arg.reg.GetHigh(); 793 } else { 794 RegisterInfo* reg_info = GetRegInfo(rl_arg.reg); 795 reg_info = reg_info->FindMatchingView(RegisterInfo::kHighSingleStorageMask); 796 if (reg_info == nullptr) { 797 // NOTE: For hard float convention we won't split arguments across reg/mem. 798 UNIMPLEMENTED(FATAL) << "Needs hard float api."; 799 } 800 reg = reg_info->GetReg(); 801 } 802 } else { 803 // kArg2 & rArg3 can safely be used here 804 reg = TargetReg(kArg3, kNotWide); 805 { 806 ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg); 807 Load32Disp(TargetPtrReg(kSp), SRegOffset(rl_arg.s_reg_low) + 4, reg); 808 } 809 call_state = next_call_insn(cu_, info, call_state, target_method, 810 vtable_idx, direct_code, direct_method, type); 811 } 812 { 813 ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg); 814 Store32Disp(TargetPtrReg(kSp), (next_use + 1) * 4, reg); 815 } 816 call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx, 817 direct_code, direct_method, type); 818 next_use++; 819 } 820 // Loop through the rest 821 while (next_use < info->num_arg_words) { 822 RegStorage arg_reg; 823 rl_arg = info->args[next_use]; 824 rl_arg = UpdateRawLoc(rl_arg); 825 if (rl_arg.location == kLocPhysReg) { 826 arg_reg = rl_arg.reg; 827 } else { 828 arg_reg = TargetReg(kArg2, rl_arg.wide ? kWide : kNotWide); 829 if (rl_arg.wide) { 830 LoadValueDirectWideFixed(rl_arg, arg_reg); 831 } else { 832 LoadValueDirectFixed(rl_arg, arg_reg); 833 } 834 call_state = next_call_insn(cu_, info, call_state, target_method, 835 vtable_idx, direct_code, direct_method, type); 836 } 837 int outs_offset = (next_use + 1) * 4; 838 { 839 ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg); 840 if (rl_arg.wide) { 841 StoreBaseDisp(TargetPtrReg(kSp), outs_offset, arg_reg, k64, kNotVolatile); 842 next_use += 2; 843 } else { 844 Store32Disp(TargetPtrReg(kSp), outs_offset, arg_reg); 845 next_use++; 846 } 847 } 848 call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx, 849 direct_code, direct_method, type); 850 } 851 } 852 853 call_state = LoadArgRegs(info, call_state, next_call_insn, 854 target_method, vtable_idx, direct_code, direct_method, 855 type, skip_this); 856 857 if (pcrLabel) { 858 if (!cu_->compiler_driver->GetCompilerOptions().GetImplicitNullChecks()) { 859 *pcrLabel = GenExplicitNullCheck(TargetReg(kArg1, kRef), info->opt_flags); 860 } else { 861 *pcrLabel = nullptr; 862 if (!(cu_->disable_opt & (1 << kNullCheckElimination)) && 863 (info->opt_flags & MIR_IGNORE_NULL_CHECK)) { 864 return call_state; 865 } 866 // In lieu of generating a check for kArg1 being null, we need to 867 // perform a load when doing implicit checks. 868 GenImplicitNullCheck(TargetReg(kArg1, kRef), info->opt_flags); 869 } 870 } 871 return call_state; 872} 873 874// Default implementation of implicit null pointer check. 875// Overridden by arch specific as necessary. 876void Mir2Lir::GenImplicitNullCheck(RegStorage reg, int opt_flags) { 877 if (!(cu_->disable_opt & (1 << kNullCheckElimination)) && (opt_flags & MIR_IGNORE_NULL_CHECK)) { 878 return; 879 } 880 RegStorage tmp = AllocTemp(); 881 Load32Disp(reg, 0, tmp); 882 MarkPossibleNullPointerException(opt_flags); 883 FreeTemp(tmp); 884} 885 886 887/* 888 * May have 0+ arguments (also used for jumbo). Note that 889 * source virtual registers may be in physical registers, so may 890 * need to be flushed to home location before copying. This 891 * applies to arg3 and above (see below). 892 * 893 * Two general strategies: 894 * If < 20 arguments 895 * Pass args 3-18 using vldm/vstm block copy 896 * Pass arg0, arg1 & arg2 in kArg1-kArg3 897 * If 20+ arguments 898 * Pass args arg19+ using memcpy block copy 899 * Pass arg0, arg1 & arg2 in kArg1-kArg3 900 * 901 */ 902int Mir2Lir::GenDalvikArgsRange(CallInfo* info, int call_state, 903 LIR** pcrLabel, NextCallInsn next_call_insn, 904 const MethodReference& target_method, 905 uint32_t vtable_idx, uintptr_t direct_code, uintptr_t direct_method, 906 InvokeType type, bool skip_this) { 907 // If we can treat it as non-range (Jumbo ops will use range form) 908 if (info->num_arg_words <= 5) 909 return GenDalvikArgsNoRange(info, call_state, pcrLabel, 910 next_call_insn, target_method, vtable_idx, 911 direct_code, direct_method, type, skip_this); 912 /* 913 * First load the non-register arguments. Both forms expect all 914 * of the source arguments to be in their home frame location, so 915 * scan the s_reg names and flush any that have been promoted to 916 * frame backing storage. 917 */ 918 // Scan the rest of the args - if in phys_reg flush to memory 919 for (int next_arg = 0; next_arg < info->num_arg_words;) { 920 RegLocation loc = info->args[next_arg]; 921 if (loc.wide) { 922 loc = UpdateLocWide(loc); 923 if ((next_arg >= 2) && (loc.location == kLocPhysReg)) { 924 ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg); 925 StoreBaseDisp(TargetPtrReg(kSp), SRegOffset(loc.s_reg_low), loc.reg, k64, kNotVolatile); 926 } 927 next_arg += 2; 928 } else { 929 loc = UpdateLoc(loc); 930 if ((next_arg >= 3) && (loc.location == kLocPhysReg)) { 931 ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg); 932 Store32Disp(TargetPtrReg(kSp), SRegOffset(loc.s_reg_low), loc.reg); 933 } 934 next_arg++; 935 } 936 } 937 938 // The first 3 arguments are passed via registers. 939 // TODO: For 64-bit, instead of hardcoding 4 for Method* size, we should either 940 // get size of uintptr_t or size of object reference according to model being used. 941 int outs_offset = 4 /* Method* */ + (3 * sizeof(uint32_t)); 942 int start_offset = SRegOffset(info->args[3].s_reg_low); 943 int regs_left_to_pass_via_stack = info->num_arg_words - 3; 944 DCHECK_GT(regs_left_to_pass_via_stack, 0); 945 946 if (cu_->instruction_set == kThumb2 && regs_left_to_pass_via_stack <= 16) { 947 // Use vldm/vstm pair using kArg3 as a temp 948 call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx, 949 direct_code, direct_method, type); 950 OpRegRegImm(kOpAdd, TargetReg(kArg3, kRef), TargetPtrReg(kSp), start_offset); 951 LIR* ld = nullptr; 952 { 953 ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg); 954 ld = OpVldm(TargetReg(kArg3, kRef), regs_left_to_pass_via_stack); 955 } 956 // TUNING: loosen barrier 957 ld->u.m.def_mask = &kEncodeAll; 958 call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx, 959 direct_code, direct_method, type); 960 OpRegRegImm(kOpAdd, TargetReg(kArg3, kRef), TargetPtrReg(kSp), 4 /* Method* */ + (3 * 4)); 961 call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx, 962 direct_code, direct_method, type); 963 LIR* st = nullptr; 964 { 965 ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg); 966 st = OpVstm(TargetReg(kArg3, kRef), regs_left_to_pass_via_stack); 967 } 968 st->u.m.def_mask = &kEncodeAll; 969 call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx, 970 direct_code, direct_method, type); 971 } else if (cu_->instruction_set == kX86 || cu_->instruction_set == kX86_64) { 972 int current_src_offset = start_offset; 973 int current_dest_offset = outs_offset; 974 975 // Only davik regs are accessed in this loop; no next_call_insn() calls. 976 ScopedMemRefType mem_ref_type(this, ResourceMask::kDalvikReg); 977 while (regs_left_to_pass_via_stack > 0) { 978 // This is based on the knowledge that the stack itself is 16-byte aligned. 979 bool src_is_16b_aligned = (current_src_offset & 0xF) == 0; 980 bool dest_is_16b_aligned = (current_dest_offset & 0xF) == 0; 981 size_t bytes_to_move; 982 983 /* 984 * The amount to move defaults to 32-bit. If there are 4 registers left to move, then do a 985 * a 128-bit move because we won't get the chance to try to aligned. If there are more than 986 * 4 registers left to move, consider doing a 128-bit only if either src or dest are aligned. 987 * We do this because we could potentially do a smaller move to align. 988 */ 989 if (regs_left_to_pass_via_stack == 4 || 990 (regs_left_to_pass_via_stack > 4 && (src_is_16b_aligned || dest_is_16b_aligned))) { 991 // Moving 128-bits via xmm register. 992 bytes_to_move = sizeof(uint32_t) * 4; 993 994 // Allocate a free xmm temp. Since we are working through the calling sequence, 995 // we expect to have an xmm temporary available. AllocTempDouble will abort if 996 // there are no free registers. 997 RegStorage temp = AllocTempDouble(); 998 999 LIR* ld1 = nullptr; 1000 LIR* ld2 = nullptr; 1001 LIR* st1 = nullptr; 1002 LIR* st2 = nullptr; 1003 1004 /* 1005 * The logic is similar for both loads and stores. If we have 16-byte alignment, 1006 * do an aligned move. If we have 8-byte alignment, then do the move in two 1007 * parts. This approach prevents possible cache line splits. Finally, fall back 1008 * to doing an unaligned move. In most cases we likely won't split the cache 1009 * line but we cannot prove it and thus take a conservative approach. 1010 */ 1011 bool src_is_8b_aligned = (current_src_offset & 0x7) == 0; 1012 bool dest_is_8b_aligned = (current_dest_offset & 0x7) == 0; 1013 1014 if (src_is_16b_aligned) { 1015 ld1 = OpMovRegMem(temp, TargetPtrReg(kSp), current_src_offset, kMovA128FP); 1016 } else if (src_is_8b_aligned) { 1017 ld1 = OpMovRegMem(temp, TargetPtrReg(kSp), current_src_offset, kMovLo128FP); 1018 ld2 = OpMovRegMem(temp, TargetPtrReg(kSp), current_src_offset + (bytes_to_move >> 1), 1019 kMovHi128FP); 1020 } else { 1021 ld1 = OpMovRegMem(temp, TargetPtrReg(kSp), current_src_offset, kMovU128FP); 1022 } 1023 1024 if (dest_is_16b_aligned) { 1025 st1 = OpMovMemReg(TargetPtrReg(kSp), current_dest_offset, temp, kMovA128FP); 1026 } else if (dest_is_8b_aligned) { 1027 st1 = OpMovMemReg(TargetPtrReg(kSp), current_dest_offset, temp, kMovLo128FP); 1028 st2 = OpMovMemReg(TargetPtrReg(kSp), current_dest_offset + (bytes_to_move >> 1), 1029 temp, kMovHi128FP); 1030 } else { 1031 st1 = OpMovMemReg(TargetPtrReg(kSp), current_dest_offset, temp, kMovU128FP); 1032 } 1033 1034 // TODO If we could keep track of aliasing information for memory accesses that are wider 1035 // than 64-bit, we wouldn't need to set up a barrier. 1036 if (ld1 != nullptr) { 1037 if (ld2 != nullptr) { 1038 // For 64-bit load we can actually set up the aliasing information. 1039 AnnotateDalvikRegAccess(ld1, current_src_offset >> 2, true, true); 1040 AnnotateDalvikRegAccess(ld2, (current_src_offset + (bytes_to_move >> 1)) >> 2, true, 1041 true); 1042 } else { 1043 // Set barrier for 128-bit load. 1044 ld1->u.m.def_mask = &kEncodeAll; 1045 } 1046 } 1047 if (st1 != nullptr) { 1048 if (st2 != nullptr) { 1049 // For 64-bit store we can actually set up the aliasing information. 1050 AnnotateDalvikRegAccess(st1, current_dest_offset >> 2, false, true); 1051 AnnotateDalvikRegAccess(st2, (current_dest_offset + (bytes_to_move >> 1)) >> 2, false, 1052 true); 1053 } else { 1054 // Set barrier for 128-bit store. 1055 st1->u.m.def_mask = &kEncodeAll; 1056 } 1057 } 1058 1059 // Free the temporary used for the data movement. 1060 FreeTemp(temp); 1061 } else { 1062 // Moving 32-bits via general purpose register. 1063 bytes_to_move = sizeof(uint32_t); 1064 1065 // Instead of allocating a new temp, simply reuse one of the registers being used 1066 // for argument passing. 1067 RegStorage temp = TargetReg(kArg3, kNotWide); 1068 1069 // Now load the argument VR and store to the outs. 1070 Load32Disp(TargetPtrReg(kSp), current_src_offset, temp); 1071 Store32Disp(TargetPtrReg(kSp), current_dest_offset, temp); 1072 } 1073 1074 current_src_offset += bytes_to_move; 1075 current_dest_offset += bytes_to_move; 1076 regs_left_to_pass_via_stack -= (bytes_to_move >> 2); 1077 } 1078 } else { 1079 // Generate memcpy 1080 OpRegRegImm(kOpAdd, TargetReg(kArg0, kRef), TargetPtrReg(kSp), outs_offset); 1081 OpRegRegImm(kOpAdd, TargetReg(kArg1, kRef), TargetPtrReg(kSp), start_offset); 1082 CallRuntimeHelperRegRegImm(kQuickMemcpy, TargetReg(kArg0, kRef), TargetReg(kArg1, kRef), 1083 (info->num_arg_words - 3) * 4, false); 1084 } 1085 1086 call_state = LoadArgRegs(info, call_state, next_call_insn, 1087 target_method, vtable_idx, direct_code, direct_method, 1088 type, skip_this); 1089 1090 call_state = next_call_insn(cu_, info, call_state, target_method, vtable_idx, 1091 direct_code, direct_method, type); 1092 if (pcrLabel) { 1093 if (!cu_->compiler_driver->GetCompilerOptions().GetImplicitNullChecks()) { 1094 *pcrLabel = GenExplicitNullCheck(TargetReg(kArg1, kRef), info->opt_flags); 1095 } else { 1096 *pcrLabel = nullptr; 1097 if (!(cu_->disable_opt & (1 << kNullCheckElimination)) && 1098 (info->opt_flags & MIR_IGNORE_NULL_CHECK)) { 1099 return call_state; 1100 } 1101 // In lieu of generating a check for kArg1 being null, we need to 1102 // perform a load when doing implicit checks. 1103 GenImplicitNullCheck(TargetReg(kArg1, kRef), info->opt_flags); 1104 } 1105 } 1106 return call_state; 1107} 1108 1109RegLocation Mir2Lir::InlineTarget(CallInfo* info) { 1110 RegLocation res; 1111 if (info->result.location == kLocInvalid) { 1112 // If result is unused, return a sink target based on type of invoke target. 1113 res = GetReturn(ShortyToRegClass(mir_graph_->GetShortyFromTargetIdx(info->index)[0])); 1114 } else { 1115 res = info->result; 1116 DCHECK_EQ(LocToRegClass(res), 1117 ShortyToRegClass(mir_graph_->GetShortyFromTargetIdx(info->index)[0])); 1118 } 1119 return res; 1120} 1121 1122RegLocation Mir2Lir::InlineTargetWide(CallInfo* info) { 1123 RegLocation res; 1124 if (info->result.location == kLocInvalid) { 1125 // If result is unused, return a sink target based on type of invoke target. 1126 res = GetReturnWide(ShortyToRegClass(mir_graph_->GetShortyFromTargetIdx(info->index)[0])); 1127 } else { 1128 res = info->result; 1129 DCHECK_EQ(LocToRegClass(res), 1130 ShortyToRegClass(mir_graph_->GetShortyFromTargetIdx(info->index)[0])); 1131 } 1132 return res; 1133} 1134 1135bool Mir2Lir::GenInlinedReferenceGetReferent(CallInfo* info) { 1136 if (cu_->instruction_set == kMips) { 1137 // TODO - add Mips implementation 1138 return false; 1139 } 1140 1141 bool use_direct_type_ptr; 1142 uintptr_t direct_type_ptr; 1143 ClassReference ref; 1144 if (!cu_->compiler_driver->CanEmbedReferenceTypeInCode(&ref, 1145 &use_direct_type_ptr, &direct_type_ptr)) { 1146 return false; 1147 } 1148 1149 RegStorage reg_class = TargetReg(kArg1, kRef); 1150 Clobber(reg_class); 1151 LockTemp(reg_class); 1152 if (use_direct_type_ptr) { 1153 LoadConstant(reg_class, direct_type_ptr); 1154 } else { 1155 uint16_t type_idx = ref.first->GetClassDef(ref.second).class_idx_; 1156 LoadClassType(*ref.first, type_idx, kArg1); 1157 } 1158 1159 uint32_t slow_path_flag_offset = cu_->compiler_driver->GetReferenceSlowFlagOffset(); 1160 uint32_t disable_flag_offset = cu_->compiler_driver->GetReferenceDisableFlagOffset(); 1161 CHECK(slow_path_flag_offset && disable_flag_offset && 1162 (slow_path_flag_offset != disable_flag_offset)); 1163 1164 // intrinsic logic start. 1165 RegLocation rl_obj = info->args[0]; 1166 rl_obj = LoadValue(rl_obj, kRefReg); 1167 1168 RegStorage reg_slow_path = AllocTemp(); 1169 RegStorage reg_disabled = AllocTemp(); 1170 Load8Disp(reg_class, slow_path_flag_offset, reg_slow_path); 1171 Load8Disp(reg_class, disable_flag_offset, reg_disabled); 1172 FreeTemp(reg_class); 1173 LIR* or_inst = OpRegRegReg(kOpOr, reg_slow_path, reg_slow_path, reg_disabled); 1174 FreeTemp(reg_disabled); 1175 1176 // if slow path, jump to JNI path target 1177 LIR* slow_path_branch; 1178 if (or_inst->u.m.def_mask->HasBit(ResourceMask::kCCode)) { 1179 // Generate conditional branch only, as the OR set a condition state (we are interested in a 'Z' flag). 1180 slow_path_branch = OpCondBranch(kCondNe, nullptr); 1181 } else { 1182 // Generate compare and branch. 1183 slow_path_branch = OpCmpImmBranch(kCondNe, reg_slow_path, 0, nullptr); 1184 } 1185 FreeTemp(reg_slow_path); 1186 1187 // slow path not enabled, simply load the referent of the reference object 1188 RegLocation rl_dest = InlineTarget(info); 1189 RegLocation rl_result = EvalLoc(rl_dest, kRefReg, true); 1190 GenNullCheck(rl_obj.reg, info->opt_flags); 1191 LoadRefDisp(rl_obj.reg, mirror::Reference::ReferentOffset().Int32Value(), rl_result.reg, 1192 kNotVolatile); 1193 MarkPossibleNullPointerException(info->opt_flags); 1194 StoreValue(rl_dest, rl_result); 1195 1196 LIR* intrinsic_finish = NewLIR0(kPseudoTargetLabel); 1197 AddIntrinsicSlowPath(info, slow_path_branch, intrinsic_finish); 1198 ClobberCallerSave(); // We must clobber everything because slow path will return here 1199 return true; 1200} 1201 1202bool Mir2Lir::GenInlinedCharAt(CallInfo* info) { 1203 if (cu_->instruction_set == kMips) { 1204 // TODO - add Mips implementation 1205 return false; 1206 } 1207 // Location of reference to data array 1208 int value_offset = mirror::String::ValueOffset().Int32Value(); 1209 // Location of count 1210 int count_offset = mirror::String::CountOffset().Int32Value(); 1211 // Starting offset within data array 1212 int offset_offset = mirror::String::OffsetOffset().Int32Value(); 1213 // Start of char data with array_ 1214 int data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Int32Value(); 1215 1216 RegLocation rl_obj = info->args[0]; 1217 RegLocation rl_idx = info->args[1]; 1218 rl_obj = LoadValue(rl_obj, kRefReg); 1219 rl_idx = LoadValue(rl_idx, kCoreReg); 1220 RegStorage reg_max; 1221 GenNullCheck(rl_obj.reg, info->opt_flags); 1222 bool range_check = (!(info->opt_flags & MIR_IGNORE_RANGE_CHECK)); 1223 LIR* range_check_branch = nullptr; 1224 RegStorage reg_off; 1225 RegStorage reg_ptr; 1226 reg_off = AllocTemp(); 1227 reg_ptr = AllocTempRef(); 1228 if (range_check) { 1229 reg_max = AllocTemp(); 1230 Load32Disp(rl_obj.reg, count_offset, reg_max); 1231 MarkPossibleNullPointerException(info->opt_flags); 1232 } 1233 Load32Disp(rl_obj.reg, offset_offset, reg_off); 1234 MarkPossibleNullPointerException(info->opt_flags); 1235 LoadRefDisp(rl_obj.reg, value_offset, reg_ptr, kNotVolatile); 1236 if (range_check) { 1237 // Set up a slow path to allow retry in case of bounds violation */ 1238 OpRegReg(kOpCmp, rl_idx.reg, reg_max); 1239 FreeTemp(reg_max); 1240 range_check_branch = OpCondBranch(kCondUge, nullptr); 1241 } 1242 OpRegImm(kOpAdd, reg_ptr, data_offset); 1243 if (rl_idx.is_const) { 1244 OpRegImm(kOpAdd, reg_off, mir_graph_->ConstantValue(rl_idx.orig_sreg)); 1245 } else { 1246 OpRegReg(kOpAdd, reg_off, rl_idx.reg); 1247 } 1248 FreeTemp(rl_obj.reg); 1249 if (rl_idx.location == kLocPhysReg) { 1250 FreeTemp(rl_idx.reg); 1251 } 1252 RegLocation rl_dest = InlineTarget(info); 1253 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true); 1254 LoadBaseIndexed(reg_ptr, reg_off, rl_result.reg, 1, kUnsignedHalf); 1255 FreeTemp(reg_off); 1256 FreeTemp(reg_ptr); 1257 StoreValue(rl_dest, rl_result); 1258 if (range_check) { 1259 DCHECK(range_check_branch != nullptr); 1260 info->opt_flags |= MIR_IGNORE_NULL_CHECK; // Record that we've already null checked. 1261 AddIntrinsicSlowPath(info, range_check_branch); 1262 } 1263 return true; 1264} 1265 1266// Generates an inlined String.is_empty or String.length. 1267bool Mir2Lir::GenInlinedStringIsEmptyOrLength(CallInfo* info, bool is_empty) { 1268 if (cu_->instruction_set == kMips) { 1269 // TODO - add Mips implementation 1270 return false; 1271 } 1272 // dst = src.length(); 1273 RegLocation rl_obj = info->args[0]; 1274 rl_obj = LoadValue(rl_obj, kRefReg); 1275 RegLocation rl_dest = InlineTarget(info); 1276 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true); 1277 GenNullCheck(rl_obj.reg, info->opt_flags); 1278 Load32Disp(rl_obj.reg, mirror::String::CountOffset().Int32Value(), rl_result.reg); 1279 MarkPossibleNullPointerException(info->opt_flags); 1280 if (is_empty) { 1281 // dst = (dst == 0); 1282 if (cu_->instruction_set == kThumb2) { 1283 RegStorage t_reg = AllocTemp(); 1284 OpRegReg(kOpNeg, t_reg, rl_result.reg); 1285 OpRegRegReg(kOpAdc, rl_result.reg, rl_result.reg, t_reg); 1286 } else if (cu_->instruction_set == kArm64) { 1287 OpRegImm(kOpSub, rl_result.reg, 1); 1288 OpRegRegImm(kOpLsr, rl_result.reg, rl_result.reg, 31); 1289 } else { 1290 DCHECK(cu_->instruction_set == kX86 || cu_->instruction_set == kX86_64); 1291 OpRegImm(kOpSub, rl_result.reg, 1); 1292 OpRegImm(kOpLsr, rl_result.reg, 31); 1293 } 1294 } 1295 StoreValue(rl_dest, rl_result); 1296 return true; 1297} 1298 1299bool Mir2Lir::GenInlinedReverseBytes(CallInfo* info, OpSize size) { 1300 if (cu_->instruction_set == kMips) { 1301 // TODO - add Mips implementation. 1302 return false; 1303 } 1304 RegLocation rl_src_i = info->args[0]; 1305 RegLocation rl_i = IsWide(size) ? LoadValueWide(rl_src_i, kCoreReg) : LoadValue(rl_src_i, kCoreReg); 1306 RegLocation rl_dest = IsWide(size) ? InlineTargetWide(info) : InlineTarget(info); // result reg 1307 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true); 1308 if (IsWide(size)) { 1309 if (cu_->instruction_set == kArm64 || cu_->instruction_set == kX86_64) { 1310 OpRegReg(kOpRev, rl_result.reg, rl_i.reg); 1311 StoreValueWide(rl_dest, rl_result); 1312 return true; 1313 } 1314 RegStorage r_i_low = rl_i.reg.GetLow(); 1315 if (rl_i.reg.GetLowReg() == rl_result.reg.GetLowReg()) { 1316 // First REV shall clobber rl_result.reg.GetReg(), save the value in a temp for the second REV. 1317 r_i_low = AllocTemp(); 1318 OpRegCopy(r_i_low, rl_i.reg); 1319 } 1320 OpRegReg(kOpRev, rl_result.reg.GetLow(), rl_i.reg.GetHigh()); 1321 OpRegReg(kOpRev, rl_result.reg.GetHigh(), r_i_low); 1322 if (rl_i.reg.GetLowReg() == rl_result.reg.GetLowReg()) { 1323 FreeTemp(r_i_low); 1324 } 1325 StoreValueWide(rl_dest, rl_result); 1326 } else { 1327 DCHECK(size == k32 || size == kSignedHalf); 1328 OpKind op = (size == k32) ? kOpRev : kOpRevsh; 1329 OpRegReg(op, rl_result.reg, rl_i.reg); 1330 StoreValue(rl_dest, rl_result); 1331 } 1332 return true; 1333} 1334 1335bool Mir2Lir::GenInlinedAbsInt(CallInfo* info) { 1336 if (cu_->instruction_set == kMips) { 1337 // TODO - add Mips implementation 1338 return false; 1339 } 1340 RegLocation rl_src = info->args[0]; 1341 rl_src = LoadValue(rl_src, kCoreReg); 1342 RegLocation rl_dest = InlineTarget(info); 1343 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true); 1344 RegStorage sign_reg = AllocTemp(); 1345 // abs(x) = y<=x>>31, (x+y)^y. 1346 OpRegRegImm(kOpAsr, sign_reg, rl_src.reg, 31); 1347 OpRegRegReg(kOpAdd, rl_result.reg, rl_src.reg, sign_reg); 1348 OpRegReg(kOpXor, rl_result.reg, sign_reg); 1349 StoreValue(rl_dest, rl_result); 1350 return true; 1351} 1352 1353bool Mir2Lir::GenInlinedAbsLong(CallInfo* info) { 1354 if (cu_->instruction_set == kMips) { 1355 // TODO - add Mips implementation 1356 return false; 1357 } 1358 RegLocation rl_src = info->args[0]; 1359 rl_src = LoadValueWide(rl_src, kCoreReg); 1360 RegLocation rl_dest = InlineTargetWide(info); 1361 RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true); 1362 1363 // If on x86 or if we would clobber a register needed later, just copy the source first. 1364 if (cu_->instruction_set != kX86_64 && 1365 (cu_->instruction_set == kX86 || 1366 rl_result.reg.GetLowReg() == rl_src.reg.GetHighReg())) { 1367 OpRegCopyWide(rl_result.reg, rl_src.reg); 1368 if (rl_result.reg.GetLowReg() != rl_src.reg.GetLowReg() && 1369 rl_result.reg.GetLowReg() != rl_src.reg.GetHighReg() && 1370 rl_result.reg.GetHighReg() != rl_src.reg.GetLowReg() && 1371 rl_result.reg.GetHighReg() != rl_src.reg.GetHighReg()) { 1372 // Reuse source registers to avoid running out of temps. 1373 FreeTemp(rl_src.reg); 1374 } 1375 rl_src = rl_result; 1376 } 1377 1378 // abs(x) = y<=x>>31, (x+y)^y. 1379 RegStorage sign_reg; 1380 if (cu_->instruction_set == kX86_64) { 1381 sign_reg = AllocTempWide(); 1382 OpRegRegImm(kOpAsr, sign_reg, rl_src.reg, 63); 1383 OpRegRegReg(kOpAdd, rl_result.reg, rl_src.reg, sign_reg); 1384 OpRegReg(kOpXor, rl_result.reg, sign_reg); 1385 } else { 1386 sign_reg = AllocTemp(); 1387 OpRegRegImm(kOpAsr, sign_reg, rl_src.reg.GetHigh(), 31); 1388 OpRegRegReg(kOpAdd, rl_result.reg.GetLow(), rl_src.reg.GetLow(), sign_reg); 1389 OpRegRegReg(kOpAdc, rl_result.reg.GetHigh(), rl_src.reg.GetHigh(), sign_reg); 1390 OpRegReg(kOpXor, rl_result.reg.GetLow(), sign_reg); 1391 OpRegReg(kOpXor, rl_result.reg.GetHigh(), sign_reg); 1392 } 1393 FreeTemp(sign_reg); 1394 StoreValueWide(rl_dest, rl_result); 1395 return true; 1396} 1397 1398bool Mir2Lir::GenInlinedReverseBits(CallInfo* info, OpSize size) { 1399 // Currently implemented only for ARM64. 1400 UNUSED(info, size); 1401 return false; 1402} 1403 1404bool Mir2Lir::GenInlinedMinMaxFP(CallInfo* info, bool is_min, bool is_double) { 1405 // Currently implemented only for ARM64. 1406 UNUSED(info, is_min, is_double); 1407 return false; 1408} 1409 1410bool Mir2Lir::GenInlinedCeil(CallInfo* info) { 1411 UNUSED(info); 1412 return false; 1413} 1414 1415bool Mir2Lir::GenInlinedFloor(CallInfo* info) { 1416 UNUSED(info); 1417 return false; 1418} 1419 1420bool Mir2Lir::GenInlinedRint(CallInfo* info) { 1421 UNUSED(info); 1422 return false; 1423} 1424 1425bool Mir2Lir::GenInlinedRound(CallInfo* info, bool is_double) { 1426 UNUSED(info, is_double); 1427 return false; 1428} 1429 1430bool Mir2Lir::GenInlinedFloatCvt(CallInfo* info) { 1431 if (cu_->instruction_set == kMips) { 1432 // TODO - add Mips implementation 1433 return false; 1434 } 1435 RegLocation rl_src = info->args[0]; 1436 RegLocation rl_dest = InlineTarget(info); 1437 StoreValue(rl_dest, rl_src); 1438 return true; 1439} 1440 1441bool Mir2Lir::GenInlinedDoubleCvt(CallInfo* info) { 1442 if (cu_->instruction_set == kMips) { 1443 // TODO - add Mips implementation 1444 return false; 1445 } 1446 RegLocation rl_src = info->args[0]; 1447 RegLocation rl_dest = InlineTargetWide(info); 1448 StoreValueWide(rl_dest, rl_src); 1449 return true; 1450} 1451 1452bool Mir2Lir::GenInlinedArrayCopyCharArray(CallInfo* info) { 1453 UNUSED(info); 1454 return false; 1455} 1456 1457 1458/* 1459 * Fast String.indexOf(I) & (II). Tests for simple case of char <= 0xFFFF, 1460 * otherwise bails to standard library code. 1461 */ 1462bool Mir2Lir::GenInlinedIndexOf(CallInfo* info, bool zero_based) { 1463 if (cu_->instruction_set == kMips) { 1464 // TODO - add Mips implementation 1465 return false; 1466 } 1467 if (cu_->instruction_set == kX86_64) { 1468 // TODO - add kX86_64 implementation 1469 return false; 1470 } 1471 RegLocation rl_obj = info->args[0]; 1472 RegLocation rl_char = info->args[1]; 1473 if (rl_char.is_const && (mir_graph_->ConstantValue(rl_char) & ~0xFFFF) != 0) { 1474 // Code point beyond 0xFFFF. Punt to the real String.indexOf(). 1475 return false; 1476 } 1477 1478 ClobberCallerSave(); 1479 LockCallTemps(); // Using fixed registers 1480 RegStorage reg_ptr = TargetReg(kArg0, kRef); 1481 RegStorage reg_char = TargetReg(kArg1, kNotWide); 1482 RegStorage reg_start = TargetReg(kArg2, kNotWide); 1483 1484 LoadValueDirectFixed(rl_obj, reg_ptr); 1485 LoadValueDirectFixed(rl_char, reg_char); 1486 if (zero_based) { 1487 LoadConstant(reg_start, 0); 1488 } else { 1489 RegLocation rl_start = info->args[2]; // 3rd arg only present in III flavor of IndexOf. 1490 LoadValueDirectFixed(rl_start, reg_start); 1491 } 1492 RegStorage r_tgt = LoadHelper(kQuickIndexOf); 1493 GenExplicitNullCheck(reg_ptr, info->opt_flags); 1494 LIR* high_code_point_branch = 1495 rl_char.is_const ? nullptr : OpCmpImmBranch(kCondGt, reg_char, 0xFFFF, nullptr); 1496 // NOTE: not a safepoint 1497 OpReg(kOpBlx, r_tgt); 1498 if (!rl_char.is_const) { 1499 // Add the slow path for code points beyond 0xFFFF. 1500 DCHECK(high_code_point_branch != nullptr); 1501 LIR* resume_tgt = NewLIR0(kPseudoTargetLabel); 1502 info->opt_flags |= MIR_IGNORE_NULL_CHECK; // Record that we've null checked. 1503 AddIntrinsicSlowPath(info, high_code_point_branch, resume_tgt); 1504 ClobberCallerSave(); // We must clobber everything because slow path will return here 1505 } else { 1506 DCHECK_EQ(mir_graph_->ConstantValue(rl_char) & ~0xFFFF, 0); 1507 DCHECK(high_code_point_branch == nullptr); 1508 } 1509 RegLocation rl_return = GetReturn(kCoreReg); 1510 RegLocation rl_dest = InlineTarget(info); 1511 StoreValue(rl_dest, rl_return); 1512 return true; 1513} 1514 1515/* Fast string.compareTo(Ljava/lang/string;)I. */ 1516bool Mir2Lir::GenInlinedStringCompareTo(CallInfo* info) { 1517 if (cu_->instruction_set == kMips) { 1518 // TODO - add Mips implementation 1519 return false; 1520 } 1521 ClobberCallerSave(); 1522 LockCallTemps(); // Using fixed registers 1523 RegStorage reg_this = TargetReg(kArg0, kRef); 1524 RegStorage reg_cmp = TargetReg(kArg1, kRef); 1525 1526 RegLocation rl_this = info->args[0]; 1527 RegLocation rl_cmp = info->args[1]; 1528 LoadValueDirectFixed(rl_this, reg_this); 1529 LoadValueDirectFixed(rl_cmp, reg_cmp); 1530 RegStorage r_tgt; 1531 if (cu_->instruction_set != kX86 && cu_->instruction_set != kX86_64) { 1532 r_tgt = LoadHelper(kQuickStringCompareTo); 1533 } else { 1534 r_tgt = RegStorage::InvalidReg(); 1535 } 1536 GenExplicitNullCheck(reg_this, info->opt_flags); 1537 info->opt_flags |= MIR_IGNORE_NULL_CHECK; // Record that we've null checked. 1538 // TUNING: check if rl_cmp.s_reg_low is already null checked 1539 LIR* cmp_null_check_branch = OpCmpImmBranch(kCondEq, reg_cmp, 0, nullptr); 1540 AddIntrinsicSlowPath(info, cmp_null_check_branch); 1541 // NOTE: not a safepoint 1542 CallHelper(r_tgt, kQuickStringCompareTo, false, true); 1543 RegLocation rl_return = GetReturn(kCoreReg); 1544 RegLocation rl_dest = InlineTarget(info); 1545 StoreValue(rl_dest, rl_return); 1546 return true; 1547} 1548 1549bool Mir2Lir::GenInlinedCurrentThread(CallInfo* info) { 1550 RegLocation rl_dest = InlineTarget(info); 1551 1552 // Early exit if the result is unused. 1553 if (rl_dest.orig_sreg < 0) { 1554 return true; 1555 } 1556 1557 RegLocation rl_result = EvalLoc(rl_dest, kRefReg, true); 1558 1559 switch (cu_->instruction_set) { 1560 case kArm: 1561 // Fall-through. 1562 case kThumb2: 1563 // Fall-through. 1564 case kMips: 1565 Load32Disp(TargetPtrReg(kSelf), Thread::PeerOffset<4>().Int32Value(), rl_result.reg); 1566 break; 1567 1568 case kArm64: 1569 LoadRefDisp(TargetPtrReg(kSelf), Thread::PeerOffset<8>().Int32Value(), rl_result.reg, 1570 kNotVolatile); 1571 break; 1572 1573 default: 1574 LOG(FATAL) << "Unexpected isa " << cu_->instruction_set; 1575 } 1576 StoreValue(rl_dest, rl_result); 1577 return true; 1578} 1579 1580bool Mir2Lir::GenInlinedUnsafeGet(CallInfo* info, 1581 bool is_long, bool is_volatile) { 1582 if (cu_->instruction_set == kMips) { 1583 // TODO - add Mips implementation 1584 return false; 1585 } 1586 // Unused - RegLocation rl_src_unsafe = info->args[0]; 1587 RegLocation rl_src_obj = info->args[1]; // Object 1588 RegLocation rl_src_offset = info->args[2]; // long low 1589 rl_src_offset = NarrowRegLoc(rl_src_offset); // ignore high half in info->args[3] 1590 RegLocation rl_dest = is_long ? InlineTargetWide(info) : InlineTarget(info); // result reg 1591 1592 RegLocation rl_object = LoadValue(rl_src_obj, kRefReg); 1593 RegLocation rl_offset = LoadValue(rl_src_offset, kCoreReg); 1594 RegLocation rl_result = EvalLoc(rl_dest, LocToRegClass(rl_dest), true); 1595 if (is_long) { 1596 if (cu_->instruction_set == kX86 || cu_->instruction_set == kX86_64 1597 || cu_->instruction_set == kArm64) { 1598 LoadBaseIndexed(rl_object.reg, rl_offset.reg, rl_result.reg, 0, k64); 1599 } else { 1600 RegStorage rl_temp_offset = AllocTemp(); 1601 OpRegRegReg(kOpAdd, rl_temp_offset, rl_object.reg, rl_offset.reg); 1602 LoadBaseDisp(rl_temp_offset, 0, rl_result.reg, k64, kNotVolatile); 1603 FreeTemp(rl_temp_offset); 1604 } 1605 } else { 1606 if (rl_result.ref) { 1607 LoadRefIndexed(rl_object.reg, rl_offset.reg, rl_result.reg, 0); 1608 } else { 1609 LoadBaseIndexed(rl_object.reg, rl_offset.reg, rl_result.reg, 0, k32); 1610 } 1611 } 1612 1613 if (is_volatile) { 1614 GenMemBarrier(kLoadAny); 1615 } 1616 1617 if (is_long) { 1618 StoreValueWide(rl_dest, rl_result); 1619 } else { 1620 StoreValue(rl_dest, rl_result); 1621 } 1622 return true; 1623} 1624 1625bool Mir2Lir::GenInlinedUnsafePut(CallInfo* info, bool is_long, 1626 bool is_object, bool is_volatile, bool is_ordered) { 1627 if (cu_->instruction_set == kMips) { 1628 // TODO - add Mips implementation 1629 return false; 1630 } 1631 // Unused - RegLocation rl_src_unsafe = info->args[0]; 1632 RegLocation rl_src_obj = info->args[1]; // Object 1633 RegLocation rl_src_offset = info->args[2]; // long low 1634 rl_src_offset = NarrowRegLoc(rl_src_offset); // ignore high half in info->args[3] 1635 RegLocation rl_src_value = info->args[4]; // value to store 1636 if (is_volatile || is_ordered) { 1637 GenMemBarrier(kAnyStore); 1638 } 1639 RegLocation rl_object = LoadValue(rl_src_obj, kRefReg); 1640 RegLocation rl_offset = LoadValue(rl_src_offset, kCoreReg); 1641 RegLocation rl_value; 1642 if (is_long) { 1643 rl_value = LoadValueWide(rl_src_value, kCoreReg); 1644 if (cu_->instruction_set == kX86 || cu_->instruction_set == kX86_64 1645 || cu_->instruction_set == kArm64) { 1646 StoreBaseIndexed(rl_object.reg, rl_offset.reg, rl_value.reg, 0, k64); 1647 } else { 1648 RegStorage rl_temp_offset = AllocTemp(); 1649 OpRegRegReg(kOpAdd, rl_temp_offset, rl_object.reg, rl_offset.reg); 1650 StoreBaseDisp(rl_temp_offset, 0, rl_value.reg, k64, kNotVolatile); 1651 FreeTemp(rl_temp_offset); 1652 } 1653 } else { 1654 rl_value = LoadValue(rl_src_value, LocToRegClass(rl_src_value)); 1655 if (rl_value.ref) { 1656 StoreRefIndexed(rl_object.reg, rl_offset.reg, rl_value.reg, 0); 1657 } else { 1658 StoreBaseIndexed(rl_object.reg, rl_offset.reg, rl_value.reg, 0, k32); 1659 } 1660 } 1661 1662 // Free up the temp early, to ensure x86 doesn't run out of temporaries in MarkGCCard. 1663 FreeTemp(rl_offset.reg); 1664 1665 if (is_volatile) { 1666 // Prevent reordering with a subsequent volatile load. 1667 // May also be needed to address store atomicity issues. 1668 GenMemBarrier(kAnyAny); 1669 } 1670 if (is_object) { 1671 MarkGCCard(rl_value.reg, rl_object.reg); 1672 } 1673 return true; 1674} 1675 1676void Mir2Lir::GenInvoke(CallInfo* info) { 1677 DCHECK(cu_->compiler_driver->GetMethodInlinerMap() != nullptr); 1678 if (cu_->compiler_driver->GetMethodInlinerMap()->GetMethodInliner(cu_->dex_file) 1679 ->GenIntrinsic(this, info)) { 1680 return; 1681 } 1682 GenInvokeNoInline(info); 1683} 1684 1685void Mir2Lir::GenInvokeNoInline(CallInfo* info) { 1686 int call_state = 0; 1687 LIR* null_ck; 1688 LIR** p_null_ck = NULL; 1689 NextCallInsn next_call_insn; 1690 FlushAllRegs(); /* Everything to home location */ 1691 // Explicit register usage 1692 LockCallTemps(); 1693 1694 const MirMethodLoweringInfo& method_info = mir_graph_->GetMethodLoweringInfo(info->mir); 1695 cu_->compiler_driver->ProcessedInvoke(method_info.GetInvokeType(), method_info.StatsFlags()); 1696 InvokeType original_type = static_cast<InvokeType>(method_info.GetInvokeType()); 1697 info->type = method_info.GetSharpType(); 1698 bool fast_path = method_info.FastPath(); 1699 bool skip_this; 1700 if (info->type == kInterface) { 1701 next_call_insn = fast_path ? NextInterfaceCallInsn : NextInterfaceCallInsnWithAccessCheck; 1702 skip_this = fast_path; 1703 } else if (info->type == kDirect) { 1704 if (fast_path) { 1705 p_null_ck = &null_ck; 1706 } 1707 next_call_insn = fast_path ? GetNextSDCallInsn() : NextDirectCallInsnSP; 1708 skip_this = false; 1709 } else if (info->type == kStatic) { 1710 next_call_insn = fast_path ? GetNextSDCallInsn() : NextStaticCallInsnSP; 1711 skip_this = false; 1712 } else if (info->type == kSuper) { 1713 DCHECK(!fast_path); // Fast path is a direct call. 1714 next_call_insn = NextSuperCallInsnSP; 1715 skip_this = false; 1716 } else { 1717 DCHECK_EQ(info->type, kVirtual); 1718 next_call_insn = fast_path ? NextVCallInsn : NextVCallInsnSP; 1719 skip_this = fast_path; 1720 } 1721 MethodReference target_method = method_info.GetTargetMethod(); 1722 if (!info->is_range) { 1723 call_state = GenDalvikArgsNoRange(info, call_state, p_null_ck, 1724 next_call_insn, target_method, method_info.VTableIndex(), 1725 method_info.DirectCode(), method_info.DirectMethod(), 1726 original_type, skip_this); 1727 } else { 1728 call_state = GenDalvikArgsRange(info, call_state, p_null_ck, 1729 next_call_insn, target_method, method_info.VTableIndex(), 1730 method_info.DirectCode(), method_info.DirectMethod(), 1731 original_type, skip_this); 1732 } 1733 // Finish up any of the call sequence not interleaved in arg loading 1734 while (call_state >= 0) { 1735 call_state = next_call_insn(cu_, info, call_state, target_method, method_info.VTableIndex(), 1736 method_info.DirectCode(), method_info.DirectMethod(), original_type); 1737 } 1738 LIR* call_insn = GenCallInsn(method_info); 1739 MarkSafepointPC(call_insn); 1740 1741 ClobberCallerSave(); 1742 if (info->result.location != kLocInvalid) { 1743 // We have a following MOVE_RESULT - do it now. 1744 if (info->result.wide) { 1745 RegLocation ret_loc = GetReturnWide(LocToRegClass(info->result)); 1746 StoreValueWide(info->result, ret_loc); 1747 } else { 1748 RegLocation ret_loc = GetReturn(LocToRegClass(info->result)); 1749 StoreValue(info->result, ret_loc); 1750 } 1751 } 1752} 1753 1754NextCallInsn Mir2Lir::GetNextSDCallInsn() { 1755 return NextSDCallInsn; 1756} 1757 1758LIR* Mir2Lir::GenCallInsn(const MirMethodLoweringInfo& method_info) { 1759 UNUSED(method_info); 1760 DCHECK(cu_->instruction_set != kX86 && cu_->instruction_set != kX86_64 && 1761 cu_->instruction_set != kThumb2 && cu_->instruction_set != kArm && 1762 cu_->instruction_set != kArm64); 1763 return OpReg(kOpBlx, TargetPtrReg(kInvokeTgt)); 1764} 1765 1766} // namespace art 1767