// TODO(VIXL): Make VIXL compile cleanly with -Wshadow, -Wdeprecated-declarations. #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wshadow" #pragma GCC diagnostic ignored "-Wdeprecated-declarations" #include"aarch64/disasm-aarch64.h" #include"aarch64/macro-assembler-aarch64.h" #pragma GCC diagnostic pop
namespace art HIDDEN {
namespace linker { class Arm64RelativePatcherTest;
} // namespace linker
namespace arm64 {
class CodeGeneratorARM64;
// Use a local definition to prevent copying mistakes. static constexpr size_t kArm64WordSize = static_cast<size_t>(kArm64PointerSize);
// This constant is used as an approximate margin when emission of veneer and literal pools // must be blocked. static constexpr int kMaxMacroInstructionSizeInBytes = 15 * vixl::aarch64::kInstructionSize;
// Reference load (except object array loads) is using LDR Wt, [Xn, #offset] which can handle // offset < 16KiB. For offsets >= 16KiB, the load shall be emitted as two or more instructions. // For the Baker read barrier implementation using link-time generated thunks we need to split // the offset explicitly. static constexpr uint32_t kReferenceLoadMinFarOffset = 16 * KB;
const vixl::aarch64::CPURegList runtime_reserved_core_registers =
vixl::aarch64::CPURegList(
tr, // Reserve X20 as Marking Register when emitting Baker read barriers. // TODO: We don't need to reserve marking-register for userfaultfd GC. But // that would require some work in the assembler code as the right GC is // chosen at load-time and not compile time.
(kReserveMarkingRegister ? mr : vixl::aarch64::NoCPUReg),
kImplicitSuspendCheckRegister,
vixl::aarch64::lr);
// Some instructions have special requirements for a temporary, for example // LoadClass/kBssEntry and LoadString/kBssEntry for Baker read barrier require // temp that's not an R0 (to avoid an extra move) and Baker read barrier field // loads with large offsets need a fixed register to limit the number of link-time // thunks we generate. For these and similar cases, we want to reserve a specific // register that's neither callee-save nor an argument register. We choose x15. inline Location FixedTempLocation() { return Location::CoreRegister(vixl::aarch64::x15.GetCode());
}
// Emits the jump table into the code buffer; jump target offsets are not yet known. void EmitTable(CodeGeneratorARM64* codegen);
// Updates the offsets in the jump table, to be used when the jump targets basic blocks // addresses are resolved. void FixTable(CodeGeneratorARM64* codegen);
private: // Register allocator does not support adjusting frame size, so we cannot provide final locations // of stack arguments for register allocation. We ask the register allocator for any location and // move these arguments to the right place after adjusting the SP when generating the call. constbool for_register_allocation_;
size_t gpr_index_ = 0u;
size_t fpr_index_ = 0u;
size_t stack_offset_ = 0u;
// Generate a heap reference load using one register `out`: // // out <- *(out + offset) // // while honoring heap poisoning and/or read barriers (if any). // // Location `maybe_temp` is used when generating a read barrier and // shall be a register in that case; it may be an invalid location // otherwise. void GenerateReferenceLoadOneRegister(HInstruction* instruction,
Location out,
uint32_t offset,
Location maybe_temp,
ReadBarrierOption read_barrier_option); // Generate a heap reference load using two different registers // `out` and `obj`: // // out <- *(obj + offset) // // while honoring heap poisoning and/or read barriers (if any). // // Location `maybe_temp` is used when generating a Baker's (fast // path) read barrier and shall be a register in that case; it may // be an invalid location otherwise. void GenerateReferenceLoadTwoRegisters(HInstruction* instruction,
Location out,
Location obj,
uint32_t offset,
Location maybe_temp,
ReadBarrierOption read_barrier_option);
// Generate a floating-point comparison. void GenerateFcmp(HInstruction* instruction);
// Helpers to set up locations for vector memory operations. Returns the memory operand and, // if used, sets the output parameter scratch to a temporary register used in this operand, // so that the client can release it right after the memory operand use. // Neon version.
vixl::aarch64::MemOperand VecNEONAddress(
HVecMemoryOperation* instruction, // This function may acquire a scratch register.
vixl::aarch64::UseScratchRegisterScope* temps_scope,
size_t size, bool is_string_char_at, /*out*/ vixl::aarch64::Register* scratch); // SVE version.
vixl::aarch64::SVEMemOperand VecSVEAddress(
HVecMemoryOperation* instruction, // This function may acquire a scratch register.
vixl::aarch64::UseScratchRegisterScope* temps_scope,
size_t size, bool is_string_char_at, /*out*/ vixl::aarch64::Register* scratch);
private: // Validate that instruction vector length and packed type are compliant with the SIMD // register size (full SIMD register is used). void ValidateVectorLength(HVecOperation* instr) const;
// Returns a fixed p-reg for predicate setting instruction. // // Currently we only support diamond CF loops for predicated vectorization; also we don't have // register allocator support for vector predicates. Thus we use fixed P-regs for loop main, // True and False predicates as a temporary solution. // // TODO: Support SIMD types and registers in ART. static vixl::aarch64::PRegister GetVecPredSetFixedOutPReg(HVecPredSetOperation* instr) { if (instr->IsVecPredWhile() || instr->IsVecPredSetAll()) { // VecPredWhile and VecPredSetAll live ranges never overlap due to the current vectorization // scheme: the former only is live inside a vectorized loop and the later is never in a // loop and never spans across loops. return vixl::aarch64::p0;
} elseif (instr->IsVecPredNot()) { // This relies on the fact that we only use PredNot manually in the autovectorizer, // so there is only one of them in each loop. return vixl::aarch64::p1;
} else {
DCHECK(instr->IsVecCondition()); return vixl::aarch64::p2;
}
}
// Generate a vector comparison instruction based on the IfCondition. void GenerateIntegerVecComparison(const vixl::aarch64::PRegisterWithLaneSize& pd, const vixl::aarch64::PRegisterZ& pg, const vixl::aarch64::ZRegister& zn, const vixl::aarch64::ZRegister& zm,
IfCondition cond); void HandleVecCondition(HVecCondition* instruction);
};
class LocationsBuilderARM64Sve : public LocationsBuilderARM64 { public:
LocationsBuilderARM64Sve(HGraph* graph, CodeGeneratorARM64* codegen) :
LocationsBuilderARM64(graph, codegen) {}
// Emit a write barrier if: // A) emit_null_check is false // B) emit_null_check is true, and value is not null. void MaybeMarkGCCard(vixl::aarch64::Register object,
vixl::aarch64::Register value, bool emit_null_check);
// Emit a write barrier unconditionally. void MarkGCCard(vixl::aarch64::Register object);
// Crash if the card table is not valid. This check is only emitted for the CC GC. We assert // `(!clean || !self->is_gc_marking)`, since the card table should not be set to clean when the CC // GC is marking for eliminated write barriers. void CheckGCCardIsValid(vixl::aarch64::Register object);
// The number of registers that can be allocated. The register allocator may // decide to reserve and not use a few of them. // We do not consider registers sp, xzr, wzr. They are either not allocatable // (xzr, wzr), or make for poor allocatable registers (sp alignment // requirements, etc.). This also facilitates our task as all other registers // can easily be mapped via to or from their type and index or code. staticconstint kNumberOfAllocatableRegisters = vixl::aarch64::kNumberOfRegisters - 1; staticconstint kNumberOfAllocatableFPRegisters = vixl::aarch64::kNumberOfVRegisters;
void DumpCoreRegister(std::ostream& stream, int reg) const override; void DumpFloatingPointRegister(std::ostream& stream, int reg) const override;
// We want to use the STP and LDP instructions to spill and restore registers for slow paths. // These instructions can only encode offsets that are multiples of the register size accessed.
uint32_t GetPreferredSlotsAlignment() const override { return vixl::aarch64::kXRegSizeInBytes; }
// Generate code to invoke a runtime entry point. void InvokeRuntime(QuickEntrypointEnum entrypoint,
HInstruction* instruction,
SlowPathCode* slow_path = nullptr) override;
// Generate code to invoke a runtime entry point, but do not record // PC-related information in a stack map. void InvokeRuntimeWithoutRecordingPcInfo(int32_t entry_point_offset,
HInstruction* instruction,
SlowPathCode* slow_path);
// Check if the desired_string_load_kind is supported. If it is, return it, // otherwise return a fall-back kind that should be used instead.
HLoadString::LoadKind GetSupportedLoadStringKind(
HLoadString::LoadKind desired_string_load_kind) override;
// Check if the desired_class_load_kind is supported. If it is, return it, // otherwise return a fall-back kind that should be used instead.
HLoadClass::LoadKind GetSupportedLoadClassKind(
HLoadClass::LoadKind desired_class_load_kind) override;
// Check if the desired_dispatch_info is supported. If it is, return it, // otherwise return a fall-back info that should be used instead.
HInvokeStaticOrDirect::DispatchInfo GetSupportedInvokeStaticOrDirectDispatch( const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info,
ArtMethod* method) override;
// Add a new boot image intrinsic patch for an instruction and return the label // to be bound before the instruction. The instruction will be either the // ADRP (pass `adrp_label = null`) or the ADD (pass `adrp_label` pointing // to the associated ADRP patch label).
vixl::aarch64::Label* NewBootImageIntrinsicPatch(uint32_t intrinsic_data,
vixl::aarch64::Label* adrp_label = nullptr);
// Add a new boot image relocation patch for an instruction and return the label // to be bound before the instruction. The instruction will be either the // ADRP (pass `adrp_label = null`) or the LDR (pass `adrp_label` pointing // to the associated ADRP patch label).
vixl::aarch64::Label* NewBootImageRelRoPatch(uint32_t boot_image_offset,
vixl::aarch64::Label* adrp_label = nullptr);
// Add a new boot image method patch for an instruction and return the label // to be bound before the instruction. The instruction will be either the // ADRP (pass `adrp_label = null`) or the ADD (pass `adrp_label` pointing // to the associated ADRP patch label).
vixl::aarch64::Label* NewBootImageMethodPatch(MethodReference target_method,
vixl::aarch64::Label* adrp_label = nullptr);
// Add a new app image method patch for an instruction and return the label // to be bound before the instruction. The instruction will be either the // ADRP (pass `adrp_label = null`) or the LDR (pass `adrp_label` pointing // to the associated ADRP patch label).
vixl::aarch64::Label* NewAppImageMethodPatch(MethodReference target_method,
vixl::aarch64::Label* adrp_label = nullptr);
// Add a new .bss entry method patch for an instruction and return // the label to be bound before the instruction. The instruction will be // either the ADRP (pass `adrp_label = null`) or the LDR (pass `adrp_label` // pointing to the associated ADRP patch label).
vixl::aarch64::Label* NewMethodBssEntryPatch(MethodReference target_method,
vixl::aarch64::Label* adrp_label = nullptr);
// Add a new boot image type patch for an instruction and return the label // to be bound before the instruction. The instruction will be either the // ADRP (pass `adrp_label = null`) or the ADD (pass `adrp_label` pointing // to the associated ADRP patch label).
vixl::aarch64::Label* NewBootImageTypePatch(const DexFile& dex_file,
dex::TypeIndex type_index,
vixl::aarch64::Label* adrp_label = nullptr);
// Add a new app image type patch for an instruction and return the label // to be bound before the instruction. The instruction will be either the // ADRP (pass `adrp_label = null`) or the LDR (pass `adrp_label` pointing // to the associated ADRP patch label).
vixl::aarch64::Label* NewAppImageTypePatch(const DexFile& dex_file,
dex::TypeIndex type_index,
vixl::aarch64::Label* adrp_label = nullptr);
// Add a new .bss entry type patch for an instruction and return the label // to be bound before the instruction. The instruction will be either the // ADRP (pass `adrp_label = null`) or the ADD (pass `adrp_label` pointing // to the associated ADRP patch label).
vixl::aarch64::Label* NewBssEntryTypePatch(HLoadClass* load_class,
vixl::aarch64::Label* adrp_label = nullptr);
// Add a new boot image string patch for an instruction and return the label // to be bound before the instruction. The instruction will be either the // ADRP (pass `adrp_label = null`) or the ADD (pass `adrp_label` pointing // to the associated ADRP patch label).
vixl::aarch64::Label* NewBootImageStringPatch(const DexFile& dex_file,
dex::StringIndex string_index,
vixl::aarch64::Label* adrp_label = nullptr);
// Add a new app image string patch for an instruction and return the label // to be bound before the instruction. The instruction will be either the // ADRP (pass `adrp_label = null`) or the LDR (pass `adrp_label` pointing // to the associated ADRP patch label).
vixl::aarch64::Label* NewAppImageStringPatch(const DexFile& dex_file,
dex::StringIndex string_index,
vixl::aarch64::Label* adrp_label = nullptr);
// Add a new .bss entry string patch for an instruction and return the label // to be bound before the instruction. The instruction will be either the // ADRP (pass `adrp_label = null`) or the ADD (pass `adrp_label` pointing // to the associated ADRP patch label).
vixl::aarch64::Label* NewStringBssEntryPatch(const DexFile& dex_file,
dex::StringIndex string_index,
vixl::aarch64::Label* adrp_label = nullptr);
// Add a new .bss entry MethodType patch for an instruction and return the label // to be bound before the instruction. The instruction will be either the // ADRP (pass `adrp_label = null`) or the ADD (pass `adrp_label` pointing // to the associated ADRP patch label).
vixl::aarch64::Label* NewMethodTypeBssEntryPatch(HLoadMethodType* load_method_type,
vixl::aarch64::Label* adrp_label = nullptr);
// Add a new boot image JNI entrypoint patch for an instruction and return the label // to be bound before the instruction. The instruction will be either the // ADRP (pass `adrp_label = null`) or the LDR (pass `adrp_label` pointing // to the associated ADRP patch label).
vixl::aarch64::Label* NewBootImageJniEntrypointPatch(MethodReference target_method,
vixl::aarch64::Label* adrp_label = nullptr);
// Emit the BL instruction for entrypoint thunk call and record the associated patch for AOT. void EmitEntrypointThunkCall(ThreadOffset64 entrypoint_offset);
// Emit the CBNZ instruction for baker read barrier and record // the associated patch for AOT or slow path for JIT. void EmitBakerReadBarrierCbnz(uint32_t custom_data);
// Generate a GC root reference load: // // root <- *(obj + offset) // // while honoring read barriers based on read_barrier_option. void GenerateGcRootFieldLoad(HInstruction* instruction,
Location root,
vixl::aarch64::Register obj,
uint32_t offset,
vixl::aarch64::Label* fixup_label,
ReadBarrierOption read_barrier_option); // Generate MOV for the `old_value` in intrinsic and mark it with Baker read barrier. void GenerateIntrinsicMoveWithBakerReadBarrier(vixl::aarch64::Register marked_old_value,
vixl::aarch64::Register old_value); // Fast path implementation of ReadBarrier::Barrier for a heap // reference field load when Baker's read barriers are used. // Overload suitable for Unsafe.getObject/-Volatile() intrinsic. void GenerateFieldLoadWithBakerReadBarrier(HInstruction* instruction,
Location ref,
vixl::aarch64::Register obj, const vixl::aarch64::MemOperand& src, bool needs_null_check, bool use_load_acquire); // Fast path implementation of ReadBarrier::Barrier for a heap // reference field load when Baker's read barriers are used. void GenerateFieldLoadWithBakerReadBarrier(HInstruction* instruction,
Location ref,
vixl::aarch64::Register obj,
uint32_t offset,
Location maybe_temp, bool needs_null_check, bool use_load_acquire); // Fast path implementation of ReadBarrier::Barrier for a heap // reference array load when Baker's read barriers are used. void GenerateArrayLoadWithBakerReadBarrier(HArrayGet* instruction,
Location ref,
vixl::aarch64::Register obj,
uint32_t data_offset,
Location index, bool needs_null_check);
// Emit code checking the status of the Marking Register, and // aborting the program if MR does not match the value stored in the // art::Thread object. Code is only emitted in debug mode and if // CompilerOptions::EmitRunTimeChecksInDebugMode returns true. // // Argument `code` is used to identify the different occurrences of // MaybeGenerateMarkingRegisterCheck in the code generator, and is // passed to the BRK instruction. // // If `temp_loc` is a valid location, it is expected to be a // register and will be used as a temporary to generate code; // otherwise, a temporary will be fetched from the core register // scratch pool. virtualvoid MaybeGenerateMarkingRegisterCheck(int code,
Location temp_loc = Location::NoLocation());
// Create slow path for a read barrier for a heap reference within `instruction`. // // This is a helper function for GenerateReadBarrierSlow() that has the same // arguments. The creation and adding of the slow path is exposed for intrinsics // that cannot use GenerateReadBarrierSlow() from their own slow paths.
SlowPathCodeARM64* AddReadBarrierSlowPath(HInstruction* instruction,
Location out,
Location ref,
Location obj,
uint32_t offset,
Location index);
// Generate a read barrier for a heap reference within `instruction` // using a slow path. // // A read barrier for an object reference read from the heap is // implemented as a call to the artReadBarrierSlow runtime entry // point, which is passed the values in locations `ref`, `obj`, and // `offset`: // // mirror::Object* artReadBarrierSlow(mirror::Object* ref, // mirror::Object* obj, // uint32_t offset); // // The `out` location contains the value returned by // artReadBarrierSlow. // // When `index` is provided (i.e. for array accesses), the offset // value passed to artReadBarrierSlow is adjusted to take `index` // into account. void GenerateReadBarrierSlow(HInstruction* instruction,
Location out,
Location ref,
Location obj,
uint32_t offset,
Location index = Location::NoLocation());
// If read barriers are enabled, generate a read barrier for a heap // reference using a slow path. If heap poisoning is enabled, also // unpoison the reference in `out`. void MaybeGenerateReadBarrierSlow(HInstruction* instruction,
Location out,
Location ref,
Location obj,
uint32_t offset,
Location index = Location::NoLocation());
// Generate a read barrier for a GC root within `instruction` using // a slow path. // // A read barrier for an object reference GC root is implemented as // a call to the artReadBarrierForRootSlow runtime entry point, // which is passed the value in location `root`: // // mirror::Object* artReadBarrierForRootSlow(GcRoot<mirror::Object>* root); // // The `out` location contains the value returned by // artReadBarrierForRootSlow. void GenerateReadBarrierForRootSlow(HInstruction* instruction, Location out, Location root);
void MaybeRecordImplicitNullCheck(HInstruction* instr) final { // The function must be only called within special scopes // (EmissionCheckScope, ExactAssemblyScope) which prevent generation of // veneer/literal pools by VIXL assembler.
CHECK_EQ(GetVIXLAssembler()->ArePoolsBlocked(), true)
<< "The function must only be called within EmissionCheckScope or ExactAssemblyScope";
CodeGenerator::MaybeRecordImplicitNullCheck(instr);
}
// Encoding of thunk type and data for link-time generated thunks for Baker read barriers.
enumclass BakerReadBarrierKind : uint8_t {
kField, // Field get or array get with constant offset (i.e. constant index).
kAcquire, // Volatile field get.
kArray, // Array get with index in register.
kGcRoot, // GC root load.
kLast = kGcRoot
};
// The PcRelativePatchInfo is used for PC-relative addressing of methods/strings/types, // whether through .data.img.rel.ro, .bss, or directly in the boot image. struct PcRelativePatchInfo : PatchInfo<vixl::aarch64::Label> {
PcRelativePatchInfo(const DexFile* dex_file, uint32_t off_or_idx)
: PatchInfo<vixl::aarch64::Label>(dex_file, off_or_idx), pc_insn_label() { }
// Returns whether SVE features are supported and should be used. bool ShouldUseSVE() const;
// Labels for each block that will be compiled. // We use a deque so that the `vixl::aarch64::Label` objects do not move in memory.
ArenaDeque<vixl::aarch64::Label> block_labels_; // Indexed by block id.
vixl::aarch64::Label frame_entry_label_;
ArenaVector<std::unique_ptr<JumpTableARM64>> jump_tables_;
// PC-relative method patch info for kBootImageLinkTimePcRelative.
ArenaDeque<PcRelativePatchInfo> boot_image_method_patches_; // PC-relative method patch info for kAppImageRelRo.
ArenaDeque<PcRelativePatchInfo> app_image_method_patches_; // PC-relative method patch info for kBssEntry.
ArenaDeque<PcRelativePatchInfo> method_bss_entry_patches_; // PC-relative type patch info for kBootImageLinkTimePcRelative.
ArenaDeque<PcRelativePatchInfo> boot_image_type_patches_; // PC-relative type patch info for kAppImageRelRo.
ArenaDeque<PcRelativePatchInfo> app_image_type_patches_; // PC-relative type patch info for kBssEntry.
ArenaDeque<PcRelativePatchInfo> type_bss_entry_patches_; // PC-relative public type patch info for kBssEntryPublic.
ArenaDeque<PcRelativePatchInfo> public_type_bss_entry_patches_; // PC-relative package type patch info for kBssEntryPackage.
ArenaDeque<PcRelativePatchInfo> package_type_bss_entry_patches_; // PC-relative String patch info for kBootImageLinkTimePcRelative.
ArenaDeque<PcRelativePatchInfo> boot_image_string_patches_; // PC-relative String patch info for kAppImageRelRo.
ArenaDeque<PcRelativePatchInfo> app_image_string_patches_; // PC-relative String patch info for kBssEntry.
ArenaDeque<PcRelativePatchInfo> string_bss_entry_patches_; // PC-relative MethodType patch info for kBssEntry.
ArenaDeque<PcRelativePatchInfo> method_type_bss_entry_patches_; // PC-relative method patch info for kBootImageLinkTimePcRelative+kCallCriticalNative.
ArenaDeque<PcRelativePatchInfo> boot_image_jni_entrypoint_patches_; // PC-relative patch info for IntrinsicObjects for the boot image, // and for method/type/string patches for kBootImageRelRo otherwise.
ArenaDeque<PcRelativePatchInfo> boot_image_other_patches_; // Patch info for calls to entrypoint dispatch thunks. Used for slow paths.
ArenaDeque<PatchInfo<vixl::aarch64::Label>> call_entrypoint_patches_; // Baker read barrier patch info.
ArenaDeque<BakerReadBarrierPatchInfo> baker_read_barrier_patches_;
JitPatchesARM64 jit_patches_;
// Baker read barrier slow paths, mapping custom data (uint32_t) to label. // Wrap the label to work around vixl::aarch64::Label being non-copyable // and non-moveable and as such unusable in ArenaSafeMap<>. struct LabelWrapper {
LabelWrapper(const LabelWrapper& src)
: label() {
DCHECK(!src.label.IsLinked() && !src.label.IsBound());
}
LabelWrapper() = default;
vixl::aarch64::Label label;
};
ArenaSafeMap<uint32_t, LabelWrapper> jit_baker_read_barrier_slow_paths_;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.