// 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"aarch32/constants-aarch32.h" #include"aarch32/instructions-aarch32.h" #include"aarch32/macro-assembler-aarch32.h" #pragma GCC diagnostic pop
namespace art HIDDEN {
namespace linker { class Thumb2RelativePatcherTest;
} // namespace linker
namespace arm {
// This constant is used as an approximate margin when emission of veneer and literal pools // must be blocked. static constexpr int kMaxMacroInstructionSizeInBytes = 15 * vixl::aarch32::kMaxInstructionSizeInBytes;
// Callee saves core registers r5, r6, r7, r8 (except when emitting Baker // read barriers, where it is used as Marking Register), r10, r11, and lr. staticconst vixl::aarch32::RegisterList kCoreCalleeSaves = vixl::aarch32::RegisterList::Union(
vixl::aarch32::RegisterList(vixl::aarch32::r5,
vixl::aarch32::r6,
vixl::aarch32::r7), // Do not consider r8 as a callee-save register with Baker read barriers.
(kReserveMarkingRegister
? vixl::aarch32::RegisterList()
: vixl::aarch32::RegisterList(vixl::aarch32::r8)),
vixl::aarch32::RegisterList(vixl::aarch32::r10,
vixl::aarch32::r11,
vixl::aarch32::lr));
ALWAYS_INLINE inline StoreOperandType GetStoreOperandType(DataType::Type type) { switch (type) { case DataType::Type::kReference: return kStoreWord; case DataType::Type::kBool: case DataType::Type::kUint8: case DataType::Type::kInt8: return kStoreByte; case DataType::Type::kUint16: case DataType::Type::kInt16: return kStoreHalfword; case DataType::Type::kInt32: return kStoreWord; case DataType::Type::kInt64: return kStoreWordPair; case DataType::Type::kFloat32: return kStoreSWord; case DataType::Type::kFloat64: return kStoreDWord; default:
LOG(FATAL) << "Unreachable type " << type;
UNREACHABLE();
}
}
class JumpTableARMVIXL : public DeletableArenaObject<kArenaAllocSwitchTable> { public:
JumpTableARMVIXL(HPackedSwitch* switch_instr, ArenaAllocator* allocator)
: switch_instr_(switch_instr),
table_start_(),
bb_addresses_(allocator->Adapter(kArenaAllocCodeGenerator)) {
uint32_t num_entries = switch_instr_->GetNumEntries();
bb_addresses_.reserve(num_entries); for (uint32_t i = 0; i < num_entries; i++) {
VIXLInt32Literal *lit = new VIXLInt32Literal(0, vixl32::RawLiteral::kManuallyPlaced);
bb_addresses_.emplace_back(lit);
}
}
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 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); void GenerateTestAndBranch(HInstruction* instruction,
size_t condition_input_index,
vixl::aarch32::Label* true_target,
vixl::aarch32::Label* false_target, bool far_target = true); void GenerateCompareTestAndBranch(HCondition* condition,
vixl::aarch32::Label* true_target,
vixl::aarch32::Label* false_target, bool is_far_target = true); void DivRemOneOrMinusOne(HBinaryOperation* instruction); void DivRemByPowerOfTwo(HBinaryOperation* instruction); void GenerateDivRemWithAnyConstant(HBinaryOperation* instruction); void GenerateDivRemConstantIntegral(HBinaryOperation* instruction); void HandleGoto(HInstruction* got, HBasicBlock* successor); void GenerateMethodEntryExitHook(HInstruction* instruction);
vixl::aarch32::MemOperand VecAddress(
HVecMemoryOperation* instruction, // This function may acquire a scratch register.
vixl::aarch32::UseScratchRegisterScope* temps_scope, /*out*/ vixl32::Register* scratch);
vixl::aarch32::AlignedMemOperand VecAddressUnaligned(
HVecMemoryOperation* instruction, // This function may acquire a scratch register.
vixl::aarch32::UseScratchRegisterScope* temps_scope, /*out*/ vixl32::Register* scratch);
// 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);
// 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::aarch32::Register temp,
vixl::aarch32::Register card,
vixl::aarch32::Register object,
vixl::aarch32::Register value, bool emit_null_check);
// 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::aarch32::Register temp,
vixl::aarch32::Register card,
vixl::aarch32::Register object);
// 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;
// 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. // // The PC-relative address is loaded with three instructions, // MOVW+MOVT to load the offset to base_reg and then ADD base_reg, PC. The offset // is calculated from the ADD's effective PC, i.e. PC+4 on Thumb2. Though we // currently emit these 3 instructions together, instruction scheduling could // split this sequence apart, so we keep separate labels for each of them. struct PcRelativePatchInfo {
PcRelativePatchInfo(const DexFile* dex_file, uint32_t off_or_idx)
: target_dex_file(dex_file), offset_or_index(off_or_idx) { }
// Target dex file or null for boot image .data.img.rel.ro patches. const DexFile* target_dex_file; // Either the boot image offset (to write to .data.img.rel.ro) or string/type/method index.
uint32_t offset_or_index;
vixl::aarch32::Label movw_label;
vixl::aarch32::Label movt_label;
vixl::aarch32::Label add_pc_label;
};
// Emit the BL instruction for entrypoint thunk call and record the associated patch for AOT. void EmitEntrypointThunkCall(ThreadOffset32 entrypoint_offset);
// Emit the BNE instruction for baker read barrier and record // the associated patch for AOT or slow path for JIT. void EmitBakerReadBarrierBne(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::aarch32::Register obj,
uint32_t offset,
ReadBarrierOption read_barrier_option); // Generate MOV for an intrinsic to mark the old value with Baker read barrier. void GenerateIntrinsicMoveWithBakerReadBarrier(vixl::aarch32::Register marked_old_value,
vixl::aarch32::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::aarch32::Register obj, const vixl::aarch32::MemOperand& src, bool needs_null_check); // 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::aarch32::Register obj,
uint32_t offset,
Location maybe_temp, bool needs_null_check); // Fast path implementation of ReadBarrier::Barrier for a heap // reference array load when Baker's read barriers are used. void GenerateArrayLoadWithBakerReadBarrier(Location ref,
vixl::aarch32::Register obj,
uint32_t data_offset,
Location index,
Location temp, 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 // used together with kMarkingRegisterCheckBreakCodeBaseCode to // create the value passed to the BKPT instruction. Note that unlike // in the ARM64 code generator, where `__LINE__` is passed as `code` // argument to // CodeGeneratorARM64::MaybeGenerateMarkingRegisterCheck, we cannot // realistically do that here, as Encoding T1 for the BKPT // instruction only accepts 8-bit immediate values. // // 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.
SlowPathCodeARMVIXL* 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);
// `temp` is an extra temporary register that is used for some conditions; // callers may not specify it, in which case the method will use a scratch // register instead. void GenerateConditionWithZero(IfCondition condition,
vixl::aarch32::Register out,
vixl::aarch32::Register in,
vixl::aarch32::Register temp = vixl32::Register());
void MaybeRecordImplicitNullCheck(HInstruction* instr) final { // The function must be only be 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).
kArray, // Array get with index in register.
kGcRoot, // GC root load.
kIntrinsicCas, // Unsafe/VarHandle CAS intrinsic.
kLast = kIntrinsicCas
};
enumclass BakerReadBarrierWidth : uint8_t {
kWide, // 32-bit LDR (and 32-bit NEG if heap poisoning is enabled).
kNarrow, // 16-bit LDR (and 16-bit NEG if heap poisoning is enabled).
kLast = kNarrow
};
static constexpr uint32_t kBakerReadBarrierInvalidEncodedReg = /* pc is invalid */ 15u;
// Labels for each block that will be compiled. // We use a deque so that the `vixl::aarch32::Label` objects do not move in memory.
ArenaDeque<vixl::aarch32::Label> block_labels_; // Indexed by block id.
vixl::aarch32::Label frame_entry_label_;
// 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 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::aarch32::Label>> call_entrypoint_patches_; // Baker read barrier patch info.
ArenaDeque<BakerReadBarrierPatchInfo> baker_read_barrier_patches_;
// Deduplication map for 32-bit literals, used for JIT for boot image addresses.
Uint32ToLiteralMap uint32_literals_; // Patches for string literals in JIT compiled code.
StringToLiteralMap jit_string_patches_; // Patches for class literals in JIT compiled code.
TypeToLiteralMap jit_class_patches_;
// Baker read barrier slow paths, mapping custom data (uint32_t) to label. // Wrap the label to work around vixl::aarch32::Label being non-copyable // and non-moveable and as such unusable in ArenaSafeMap<>. struct LabelWrapper {
LabelWrapper(const LabelWrapper& src)
: label() {
DCHECK(!src.label.IsReferenced() && !src.label.IsBound());
}
LabelWrapper() = default;
vixl::aarch32::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.