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