Home | History | Annotate | Download | only in optimizing
      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