1 /* 2 * Copyright (C) 2014 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 #ifndef ART_COMPILER_OPTIMIZING_CODE_GENERATOR_ARM64_H_ 18 #define ART_COMPILER_OPTIMIZING_CODE_GENERATOR_ARM64_H_ 19 20 #include "arch/arm64/quick_method_frame_info_arm64.h" 21 #include "code_generator.h" 22 #include "common_arm64.h" 23 #include "dex/compiler_enums.h" 24 #include "driver/compiler_options.h" 25 #include "nodes.h" 26 #include "parallel_move_resolver.h" 27 #include "utils/arm64/assembler_arm64.h" 28 #include "utils/string_reference.h" 29 #include "vixl/a64/disasm-a64.h" 30 #include "vixl/a64/macro-assembler-a64.h" 31 32 namespace art { 33 namespace arm64 { 34 35 class CodeGeneratorARM64; 36 37 // Use a local definition to prevent copying mistakes. 38 static constexpr size_t kArm64WordSize = kArm64PointerSize; 39 40 static const vixl::Register kParameterCoreRegisters[] = { 41 vixl::x1, vixl::x2, vixl::x3, vixl::x4, vixl::x5, vixl::x6, vixl::x7 42 }; 43 static constexpr size_t kParameterCoreRegistersLength = arraysize(kParameterCoreRegisters); 44 static const vixl::FPRegister kParameterFPRegisters[] = { 45 vixl::d0, vixl::d1, vixl::d2, vixl::d3, vixl::d4, vixl::d5, vixl::d6, vixl::d7 46 }; 47 static constexpr size_t kParameterFPRegistersLength = arraysize(kParameterFPRegisters); 48 49 const vixl::Register tr = vixl::x19; // Thread Register 50 static const vixl::Register kArtMethodRegister = vixl::x0; // Method register on invoke. 51 52 const vixl::CPURegList vixl_reserved_core_registers(vixl::ip0, vixl::ip1); 53 const vixl::CPURegList vixl_reserved_fp_registers(vixl::d31); 54 55 const vixl::CPURegList runtime_reserved_core_registers(tr, vixl::lr); 56 57 // Callee-saved registers AAPCS64 (without x19 - Thread Register) 58 const vixl::CPURegList callee_saved_core_registers(vixl::CPURegister::kRegister, 59 vixl::kXRegSize, 60 vixl::x20.code(), 61 vixl::x30.code()); 62 const vixl::CPURegList callee_saved_fp_registers(vixl::CPURegister::kFPRegister, 63 vixl::kDRegSize, 64 vixl::d8.code(), 65 vixl::d15.code()); 66 Location ARM64ReturnLocation(Primitive::Type return_type); 67 68 class SlowPathCodeARM64 : public SlowPathCode { 69 public: 70 explicit SlowPathCodeARM64(HInstruction* instruction) 71 : SlowPathCode(instruction), entry_label_(), exit_label_() {} 72 73 vixl::Label* GetEntryLabel() { return &entry_label_; } 74 vixl::Label* GetExitLabel() { return &exit_label_; } 75 76 void SaveLiveRegisters(CodeGenerator* codegen, LocationSummary* locations) OVERRIDE; 77 void RestoreLiveRegisters(CodeGenerator* codegen, LocationSummary* locations) OVERRIDE; 78 79 private: 80 vixl::Label entry_label_; 81 vixl::Label exit_label_; 82 83 DISALLOW_COPY_AND_ASSIGN(SlowPathCodeARM64); 84 }; 85 86 class JumpTableARM64 : public DeletableArenaObject<kArenaAllocSwitchTable> { 87 public: 88 explicit JumpTableARM64(HPackedSwitch* switch_instr) 89 : switch_instr_(switch_instr), table_start_() {} 90 91 vixl::Label* GetTableStartLabel() { return &table_start_; } 92 93 void EmitTable(CodeGeneratorARM64* codegen); 94 95 private: 96 HPackedSwitch* const switch_instr_; 97 vixl::Label table_start_; 98 99 DISALLOW_COPY_AND_ASSIGN(JumpTableARM64); 100 }; 101 102 static const vixl::Register kRuntimeParameterCoreRegisters[] = 103 { vixl::x0, vixl::x1, vixl::x2, vixl::x3, vixl::x4, vixl::x5, vixl::x6, vixl::x7 }; 104 static constexpr size_t kRuntimeParameterCoreRegistersLength = 105 arraysize(kRuntimeParameterCoreRegisters); 106 static const vixl::FPRegister kRuntimeParameterFpuRegisters[] = 107 { vixl::d0, vixl::d1, vixl::d2, vixl::d3, vixl::d4, vixl::d5, vixl::d6, vixl::d7 }; 108 static constexpr size_t kRuntimeParameterFpuRegistersLength = 109 arraysize(kRuntimeParameterCoreRegisters); 110 111 class InvokeRuntimeCallingConvention : public CallingConvention<vixl::Register, vixl::FPRegister> { 112 public: 113 static constexpr size_t kParameterCoreRegistersLength = arraysize(kParameterCoreRegisters); 114 115 InvokeRuntimeCallingConvention() 116 : CallingConvention(kRuntimeParameterCoreRegisters, 117 kRuntimeParameterCoreRegistersLength, 118 kRuntimeParameterFpuRegisters, 119 kRuntimeParameterFpuRegistersLength, 120 kArm64PointerSize) {} 121 122 Location GetReturnLocation(Primitive::Type return_type); 123 124 private: 125 DISALLOW_COPY_AND_ASSIGN(InvokeRuntimeCallingConvention); 126 }; 127 128 class InvokeDexCallingConvention : public CallingConvention<vixl::Register, vixl::FPRegister> { 129 public: 130 InvokeDexCallingConvention() 131 : CallingConvention(kParameterCoreRegisters, 132 kParameterCoreRegistersLength, 133 kParameterFPRegisters, 134 kParameterFPRegistersLength, 135 kArm64PointerSize) {} 136 137 Location GetReturnLocation(Primitive::Type return_type) const { 138 return ARM64ReturnLocation(return_type); 139 } 140 141 142 private: 143 DISALLOW_COPY_AND_ASSIGN(InvokeDexCallingConvention); 144 }; 145 146 class InvokeDexCallingConventionVisitorARM64 : public InvokeDexCallingConventionVisitor { 147 public: 148 InvokeDexCallingConventionVisitorARM64() {} 149 virtual ~InvokeDexCallingConventionVisitorARM64() {} 150 151 Location GetNextLocation(Primitive::Type type) OVERRIDE; 152 Location GetReturnLocation(Primitive::Type return_type) const OVERRIDE { 153 return calling_convention.GetReturnLocation(return_type); 154 } 155 Location GetMethodLocation() const OVERRIDE; 156 157 private: 158 InvokeDexCallingConvention calling_convention; 159 160 DISALLOW_COPY_AND_ASSIGN(InvokeDexCallingConventionVisitorARM64); 161 }; 162 163 class FieldAccessCallingConventionARM64 : public FieldAccessCallingConvention { 164 public: 165 FieldAccessCallingConventionARM64() {} 166 167 Location GetObjectLocation() const OVERRIDE { 168 return helpers::LocationFrom(vixl::x1); 169 } 170 Location GetFieldIndexLocation() const OVERRIDE { 171 return helpers::LocationFrom(vixl::x0); 172 } 173 Location GetReturnLocation(Primitive::Type type ATTRIBUTE_UNUSED) const OVERRIDE { 174 return helpers::LocationFrom(vixl::x0); 175 } 176 Location GetSetValueLocation(Primitive::Type type, bool is_instance) const OVERRIDE { 177 return Primitive::Is64BitType(type) 178 ? helpers::LocationFrom(vixl::x2) 179 : (is_instance 180 ? helpers::LocationFrom(vixl::x2) 181 : helpers::LocationFrom(vixl::x1)); 182 } 183 Location GetFpuLocation(Primitive::Type type ATTRIBUTE_UNUSED) const OVERRIDE { 184 return helpers::LocationFrom(vixl::d0); 185 } 186 187 private: 188 DISALLOW_COPY_AND_ASSIGN(FieldAccessCallingConventionARM64); 189 }; 190 191 class InstructionCodeGeneratorARM64 : public InstructionCodeGenerator { 192 public: 193 InstructionCodeGeneratorARM64(HGraph* graph, CodeGeneratorARM64* codegen); 194 195 #define DECLARE_VISIT_INSTRUCTION(name, super) \ 196 void Visit##name(H##name* instr) OVERRIDE; 197 198 FOR_EACH_CONCRETE_INSTRUCTION_COMMON(DECLARE_VISIT_INSTRUCTION) 199 FOR_EACH_CONCRETE_INSTRUCTION_ARM64(DECLARE_VISIT_INSTRUCTION) 200 FOR_EACH_CONCRETE_INSTRUCTION_SHARED(DECLARE_VISIT_INSTRUCTION) 201 202 #undef DECLARE_VISIT_INSTRUCTION 203 204 void VisitInstruction(HInstruction* instruction) OVERRIDE { 205 LOG(FATAL) << "Unreachable instruction " << instruction->DebugName() 206 << " (id " << instruction->GetId() << ")"; 207 } 208 209 Arm64Assembler* GetAssembler() const { return assembler_; } 210 vixl::MacroAssembler* GetVIXLAssembler() { return GetAssembler()->vixl_masm_; } 211 212 private: 213 void GenerateClassInitializationCheck(SlowPathCodeARM64* slow_path, vixl::Register class_reg); 214 void GenerateSuspendCheck(HSuspendCheck* instruction, HBasicBlock* successor); 215 void HandleBinaryOp(HBinaryOperation* instr); 216 217 void HandleFieldSet(HInstruction* instruction, 218 const FieldInfo& field_info, 219 bool value_can_be_null); 220 void HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info); 221 void HandleCondition(HCondition* instruction); 222 223 // Generate a heap reference load using one register `out`: 224 // 225 // out <- *(out + offset) 226 // 227 // while honoring heap poisoning and/or read barriers (if any). 228 // 229 // Location `maybe_temp` is used when generating a read barrier and 230 // shall be a register in that case; it may be an invalid location 231 // otherwise. 232 void GenerateReferenceLoadOneRegister(HInstruction* instruction, 233 Location out, 234 uint32_t offset, 235 Location maybe_temp); 236 // Generate a heap reference load using two different registers 237 // `out` and `obj`: 238 // 239 // out <- *(obj + offset) 240 // 241 // while honoring heap poisoning and/or read barriers (if any). 242 // 243 // Location `maybe_temp` is used when generating a Baker's (fast 244 // path) read barrier and shall be a register in that case; it may 245 // be an invalid location otherwise. 246 void GenerateReferenceLoadTwoRegisters(HInstruction* instruction, 247 Location out, 248 Location obj, 249 uint32_t offset, 250 Location maybe_temp); 251 // Generate a GC root reference load: 252 // 253 // root <- *(obj + offset) 254 // 255 // while honoring read barriers (if any). 256 void GenerateGcRootFieldLoad(HInstruction* instruction, 257 Location root, 258 vixl::Register obj, 259 uint32_t offset, 260 vixl::Label* fixup_label = nullptr); 261 262 // Generate a floating-point comparison. 263 void GenerateFcmp(HInstruction* instruction); 264 265 void HandleShift(HBinaryOperation* instr); 266 void GenerateTestAndBranch(HInstruction* instruction, 267 size_t condition_input_index, 268 vixl::Label* true_target, 269 vixl::Label* false_target); 270 void DivRemOneOrMinusOne(HBinaryOperation* instruction); 271 void DivRemByPowerOfTwo(HBinaryOperation* instruction); 272 void GenerateDivRemWithAnyConstant(HBinaryOperation* instruction); 273 void GenerateDivRemIntegral(HBinaryOperation* instruction); 274 void HandleGoto(HInstruction* got, HBasicBlock* successor); 275 276 Arm64Assembler* const assembler_; 277 CodeGeneratorARM64* const codegen_; 278 279 DISALLOW_COPY_AND_ASSIGN(InstructionCodeGeneratorARM64); 280 }; 281 282 class LocationsBuilderARM64 : public HGraphVisitor { 283 public: 284 LocationsBuilderARM64(HGraph* graph, CodeGeneratorARM64* codegen) 285 : HGraphVisitor(graph), codegen_(codegen) {} 286 287 #define DECLARE_VISIT_INSTRUCTION(name, super) \ 288 void Visit##name(H##name* instr) OVERRIDE; 289 290 FOR_EACH_CONCRETE_INSTRUCTION_COMMON(DECLARE_VISIT_INSTRUCTION) 291 FOR_EACH_CONCRETE_INSTRUCTION_ARM64(DECLARE_VISIT_INSTRUCTION) 292 FOR_EACH_CONCRETE_INSTRUCTION_SHARED(DECLARE_VISIT_INSTRUCTION) 293 294 #undef DECLARE_VISIT_INSTRUCTION 295 296 void VisitInstruction(HInstruction* instruction) OVERRIDE { 297 LOG(FATAL) << "Unreachable instruction " << instruction->DebugName() 298 << " (id " << instruction->GetId() << ")"; 299 } 300 301 private: 302 void HandleBinaryOp(HBinaryOperation* instr); 303 void HandleFieldSet(HInstruction* instruction); 304 void HandleFieldGet(HInstruction* instruction); 305 void HandleInvoke(HInvoke* instr); 306 void HandleCondition(HCondition* instruction); 307 void HandleShift(HBinaryOperation* instr); 308 309 CodeGeneratorARM64* const codegen_; 310 InvokeDexCallingConventionVisitorARM64 parameter_visitor_; 311 312 DISALLOW_COPY_AND_ASSIGN(LocationsBuilderARM64); 313 }; 314 315 class ParallelMoveResolverARM64 : public ParallelMoveResolverNoSwap { 316 public: 317 ParallelMoveResolverARM64(ArenaAllocator* allocator, CodeGeneratorARM64* codegen) 318 : ParallelMoveResolverNoSwap(allocator), codegen_(codegen), vixl_temps_() {} 319 320 protected: 321 void PrepareForEmitNativeCode() OVERRIDE; 322 void FinishEmitNativeCode() OVERRIDE; 323 Location AllocateScratchLocationFor(Location::Kind kind) OVERRIDE; 324 void FreeScratchLocation(Location loc) OVERRIDE; 325 void EmitMove(size_t index) OVERRIDE; 326 327 private: 328 Arm64Assembler* GetAssembler() const; 329 vixl::MacroAssembler* GetVIXLAssembler() const { 330 return GetAssembler()->vixl_masm_; 331 } 332 333 CodeGeneratorARM64* const codegen_; 334 vixl::UseScratchRegisterScope vixl_temps_; 335 336 DISALLOW_COPY_AND_ASSIGN(ParallelMoveResolverARM64); 337 }; 338 339 class CodeGeneratorARM64 : public CodeGenerator { 340 public: 341 CodeGeneratorARM64(HGraph* graph, 342 const Arm64InstructionSetFeatures& isa_features, 343 const CompilerOptions& compiler_options, 344 OptimizingCompilerStats* stats = nullptr); 345 virtual ~CodeGeneratorARM64() {} 346 347 void GenerateFrameEntry() OVERRIDE; 348 void GenerateFrameExit() OVERRIDE; 349 350 vixl::CPURegList GetFramePreservedCoreRegisters() const; 351 vixl::CPURegList GetFramePreservedFPRegisters() const; 352 353 void Bind(HBasicBlock* block) OVERRIDE; 354 355 vixl::Label* GetLabelOf(HBasicBlock* block) { 356 block = FirstNonEmptyBlock(block); 357 return &(block_labels_[block->GetBlockId()]); 358 } 359 360 size_t GetWordSize() const OVERRIDE { 361 return kArm64WordSize; 362 } 363 364 size_t GetFloatingPointSpillSlotSize() const OVERRIDE { 365 // Allocated in D registers, which are word sized. 366 return kArm64WordSize; 367 } 368 369 uintptr_t GetAddressOf(HBasicBlock* block) OVERRIDE { 370 vixl::Label* block_entry_label = GetLabelOf(block); 371 DCHECK(block_entry_label->IsBound()); 372 return block_entry_label->location(); 373 } 374 375 HGraphVisitor* GetLocationBuilder() OVERRIDE { return &location_builder_; } 376 HGraphVisitor* GetInstructionVisitor() OVERRIDE { return &instruction_visitor_; } 377 Arm64Assembler* GetAssembler() OVERRIDE { return &assembler_; } 378 const Arm64Assembler& GetAssembler() const OVERRIDE { return assembler_; } 379 vixl::MacroAssembler* GetVIXLAssembler() { return GetAssembler()->vixl_masm_; } 380 381 // Emit a write barrier. 382 void MarkGCCard(vixl::Register object, vixl::Register value, bool value_can_be_null); 383 384 void GenerateMemoryBarrier(MemBarrierKind kind); 385 386 // Register allocation. 387 388 void SetupBlockedRegisters() const OVERRIDE; 389 390 size_t SaveCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE; 391 size_t RestoreCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE; 392 size_t SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) OVERRIDE; 393 size_t RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) OVERRIDE; 394 395 // The number of registers that can be allocated. The register allocator may 396 // decide to reserve and not use a few of them. 397 // We do not consider registers sp, xzr, wzr. They are either not allocatable 398 // (xzr, wzr), or make for poor allocatable registers (sp alignment 399 // requirements, etc.). This also facilitates our task as all other registers 400 // can easily be mapped via to or from their type and index or code. 401 static const int kNumberOfAllocatableRegisters = vixl::kNumberOfRegisters - 1; 402 static const int kNumberOfAllocatableFPRegisters = vixl::kNumberOfFPRegisters; 403 static constexpr int kNumberOfAllocatableRegisterPairs = 0; 404 405 void DumpCoreRegister(std::ostream& stream, int reg) const OVERRIDE; 406 void DumpFloatingPointRegister(std::ostream& stream, int reg) const OVERRIDE; 407 408 InstructionSet GetInstructionSet() const OVERRIDE { 409 return InstructionSet::kArm64; 410 } 411 412 const Arm64InstructionSetFeatures& GetInstructionSetFeatures() const { 413 return isa_features_; 414 } 415 416 void Initialize() OVERRIDE { 417 block_labels_.resize(GetGraph()->GetBlocks().size()); 418 } 419 420 JumpTableARM64* CreateJumpTable(HPackedSwitch* switch_instr) { 421 jump_tables_.emplace_back(new (GetGraph()->GetArena()) JumpTableARM64(switch_instr)); 422 return jump_tables_.back().get(); 423 } 424 425 void Finalize(CodeAllocator* allocator) OVERRIDE; 426 427 // Code generation helpers. 428 void MoveConstant(vixl::CPURegister destination, HConstant* constant); 429 void MoveConstant(Location destination, int32_t value) OVERRIDE; 430 void MoveLocation(Location dst, Location src, Primitive::Type dst_type) OVERRIDE; 431 void AddLocationAsTemp(Location location, LocationSummary* locations) OVERRIDE; 432 433 void Load(Primitive::Type type, vixl::CPURegister dst, const vixl::MemOperand& src); 434 void Store(Primitive::Type type, vixl::CPURegister src, const vixl::MemOperand& dst); 435 void LoadAcquire(HInstruction* instruction, 436 vixl::CPURegister dst, 437 const vixl::MemOperand& src, 438 bool needs_null_check); 439 void StoreRelease(Primitive::Type type, vixl::CPURegister src, const vixl::MemOperand& dst); 440 441 // Generate code to invoke a runtime entry point. 442 void InvokeRuntime(QuickEntrypointEnum entrypoint, 443 HInstruction* instruction, 444 uint32_t dex_pc, 445 SlowPathCode* slow_path) OVERRIDE; 446 447 void InvokeRuntime(int32_t offset, 448 HInstruction* instruction, 449 uint32_t dex_pc, 450 SlowPathCode* slow_path); 451 452 ParallelMoveResolverARM64* GetMoveResolver() OVERRIDE { return &move_resolver_; } 453 454 bool NeedsTwoRegisters(Primitive::Type type ATTRIBUTE_UNUSED) const OVERRIDE { 455 return false; 456 } 457 458 // Check if the desired_string_load_kind is supported. If it is, return it, 459 // otherwise return a fall-back kind that should be used instead. 460 HLoadString::LoadKind GetSupportedLoadStringKind( 461 HLoadString::LoadKind desired_string_load_kind) OVERRIDE; 462 463 // Check if the desired_dispatch_info is supported. If it is, return it, 464 // otherwise return a fall-back info that should be used instead. 465 HInvokeStaticOrDirect::DispatchInfo GetSupportedInvokeStaticOrDirectDispatch( 466 const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info, 467 MethodReference target_method) OVERRIDE; 468 469 void GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp) OVERRIDE; 470 void GenerateVirtualCall(HInvokeVirtual* invoke, Location temp) OVERRIDE; 471 472 void MoveFromReturnRegister(Location trg ATTRIBUTE_UNUSED, 473 Primitive::Type type ATTRIBUTE_UNUSED) OVERRIDE { 474 UNIMPLEMENTED(FATAL); 475 } 476 477 // Add a new PC-relative string patch for an instruction and return the label 478 // to be bound before the instruction. The instruction will be either the 479 // ADRP (pass `adrp_label = null`) or the ADD (pass `adrp_label` pointing 480 // to the associated ADRP patch label). 481 vixl::Label* NewPcRelativeStringPatch(const DexFile& dex_file, 482 uint32_t string_index, 483 vixl::Label* adrp_label = nullptr); 484 485 // Add a new PC-relative dex cache array patch for an instruction and return 486 // the label to be bound before the instruction. The instruction will be 487 // either the ADRP (pass `adrp_label = null`) or the LDR (pass `adrp_label` 488 // pointing to the associated ADRP patch label). 489 vixl::Label* NewPcRelativeDexCacheArrayPatch(const DexFile& dex_file, 490 uint32_t element_offset, 491 vixl::Label* adrp_label = nullptr); 492 493 vixl::Literal<uint32_t>* DeduplicateBootImageStringLiteral(const DexFile& dex_file, 494 uint32_t string_index); 495 vixl::Literal<uint32_t>* DeduplicateBootImageAddressLiteral(uint64_t address); 496 vixl::Literal<uint64_t>* DeduplicateDexCacheAddressLiteral(uint64_t address); 497 498 void EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) OVERRIDE; 499 500 // Fast path implementation of ReadBarrier::Barrier for a heap 501 // reference field load when Baker's read barriers are used. 502 void GenerateFieldLoadWithBakerReadBarrier(HInstruction* instruction, 503 Location ref, 504 vixl::Register obj, 505 uint32_t offset, 506 vixl::Register temp, 507 bool needs_null_check, 508 bool use_load_acquire); 509 // Fast path implementation of ReadBarrier::Barrier for a heap 510 // reference array load when Baker's read barriers are used. 511 void GenerateArrayLoadWithBakerReadBarrier(HInstruction* instruction, 512 Location ref, 513 vixl::Register obj, 514 uint32_t data_offset, 515 Location index, 516 vixl::Register temp, 517 bool needs_null_check); 518 519 // Generate a read barrier for a heap reference within `instruction` 520 // using a slow path. 521 // 522 // A read barrier for an object reference read from the heap is 523 // implemented as a call to the artReadBarrierSlow runtime entry 524 // point, which is passed the values in locations `ref`, `obj`, and 525 // `offset`: 526 // 527 // mirror::Object* artReadBarrierSlow(mirror::Object* ref, 528 // mirror::Object* obj, 529 // uint32_t offset); 530 // 531 // The `out` location contains the value returned by 532 // artReadBarrierSlow. 533 // 534 // When `index` is provided (i.e. for array accesses), the offset 535 // value passed to artReadBarrierSlow is adjusted to take `index` 536 // into account. 537 void GenerateReadBarrierSlow(HInstruction* instruction, 538 Location out, 539 Location ref, 540 Location obj, 541 uint32_t offset, 542 Location index = Location::NoLocation()); 543 544 // If read barriers are enabled, generate a read barrier for a heap 545 // reference using a slow path. If heap poisoning is enabled, also 546 // unpoison the reference in `out`. 547 void MaybeGenerateReadBarrierSlow(HInstruction* instruction, 548 Location out, 549 Location ref, 550 Location obj, 551 uint32_t offset, 552 Location index = Location::NoLocation()); 553 554 // Generate a read barrier for a GC root within `instruction` using 555 // a slow path. 556 // 557 // A read barrier for an object reference GC root is implemented as 558 // a call to the artReadBarrierForRootSlow runtime entry point, 559 // which is passed the value in location `root`: 560 // 561 // mirror::Object* artReadBarrierForRootSlow(GcRoot<mirror::Object>* root); 562 // 563 // The `out` location contains the value returned by 564 // artReadBarrierForRootSlow. 565 void GenerateReadBarrierForRootSlow(HInstruction* instruction, Location out, Location root); 566 567 void GenerateNop(); 568 569 void GenerateImplicitNullCheck(HNullCheck* instruction); 570 void GenerateExplicitNullCheck(HNullCheck* instruction); 571 572 private: 573 // Factored implementation of GenerateFieldLoadWithBakerReadBarrier 574 // and GenerateArrayLoadWithBakerReadBarrier. 575 void GenerateReferenceLoadWithBakerReadBarrier(HInstruction* instruction, 576 Location ref, 577 vixl::Register obj, 578 uint32_t offset, 579 Location index, 580 vixl::Register temp, 581 bool needs_null_check, 582 bool use_load_acquire); 583 584 using Uint64ToLiteralMap = ArenaSafeMap<uint64_t, vixl::Literal<uint64_t>*>; 585 using Uint32ToLiteralMap = ArenaSafeMap<uint32_t, vixl::Literal<uint32_t>*>; 586 using MethodToLiteralMap = ArenaSafeMap<MethodReference, 587 vixl::Literal<uint64_t>*, 588 MethodReferenceComparator>; 589 using BootStringToLiteralMap = ArenaSafeMap<StringReference, 590 vixl::Literal<uint32_t>*, 591 StringReferenceValueComparator>; 592 593 vixl::Literal<uint32_t>* DeduplicateUint32Literal(uint32_t value, Uint32ToLiteralMap* map); 594 vixl::Literal<uint64_t>* DeduplicateUint64Literal(uint64_t value); 595 vixl::Literal<uint64_t>* DeduplicateMethodLiteral(MethodReference target_method, 596 MethodToLiteralMap* map); 597 vixl::Literal<uint64_t>* DeduplicateMethodAddressLiteral(MethodReference target_method); 598 vixl::Literal<uint64_t>* DeduplicateMethodCodeLiteral(MethodReference target_method); 599 600 // The PcRelativePatchInfo is used for PC-relative addressing of dex cache arrays 601 // and boot image strings. The only difference is the interpretation of the offset_or_index. 602 struct PcRelativePatchInfo { 603 PcRelativePatchInfo(const DexFile& dex_file, uint32_t off_or_idx) 604 : target_dex_file(dex_file), offset_or_index(off_or_idx), label(), pc_insn_label() { } 605 606 const DexFile& target_dex_file; 607 // Either the dex cache array element offset or the string index. 608 uint32_t offset_or_index; 609 vixl::Label label; 610 vixl::Label* pc_insn_label; 611 }; 612 613 vixl::Label* NewPcRelativePatch(const DexFile& dex_file, 614 uint32_t offset_or_index, 615 vixl::Label* adrp_label, 616 ArenaDeque<PcRelativePatchInfo>* patches); 617 618 void EmitJumpTables(); 619 620 // Labels for each block that will be compiled. 621 // We use a deque so that the `vixl::Label` objects do not move in memory. 622 ArenaDeque<vixl::Label> block_labels_; // Indexed by block id. 623 vixl::Label frame_entry_label_; 624 ArenaVector<std::unique_ptr<JumpTableARM64>> jump_tables_; 625 626 LocationsBuilderARM64 location_builder_; 627 InstructionCodeGeneratorARM64 instruction_visitor_; 628 ParallelMoveResolverARM64 move_resolver_; 629 Arm64Assembler assembler_; 630 const Arm64InstructionSetFeatures& isa_features_; 631 632 // Deduplication map for 32-bit literals, used for non-patchable boot image addresses. 633 Uint32ToLiteralMap uint32_literals_; 634 // Deduplication map for 64-bit literals, used for non-patchable method address, method code 635 // or string dex cache address. 636 Uint64ToLiteralMap uint64_literals_; 637 // Method patch info, map MethodReference to a literal for method address and method code. 638 MethodToLiteralMap method_patches_; 639 MethodToLiteralMap call_patches_; 640 // Relative call patch info. 641 // Using ArenaDeque<> which retains element addresses on push/emplace_back(). 642 ArenaDeque<MethodPatchInfo<vixl::Label>> relative_call_patches_; 643 // PC-relative DexCache access info. 644 ArenaDeque<PcRelativePatchInfo> pc_relative_dex_cache_patches_; 645 // Deduplication map for boot string literals for kBootImageLinkTimeAddress. 646 BootStringToLiteralMap boot_image_string_patches_; 647 // PC-relative String patch info. 648 ArenaDeque<PcRelativePatchInfo> pc_relative_string_patches_; 649 // Deduplication map for patchable boot image addresses. 650 Uint32ToLiteralMap boot_image_address_patches_; 651 652 DISALLOW_COPY_AND_ASSIGN(CodeGeneratorARM64); 653 }; 654 655 inline Arm64Assembler* ParallelMoveResolverARM64::GetAssembler() const { 656 return codegen_->GetAssembler(); 657 } 658 659 } // namespace arm64 660 } // namespace art 661 662 #endif // ART_COMPILER_OPTIMIZING_CODE_GENERATOR_ARM64_H_ 663