diff options
Diffstat (limited to 'compiler')
| -rw-r--r-- | compiler/linker/arm/relative_patcher_arm_base.cc | 52 | ||||
| -rw-r--r-- | compiler/linker/arm/relative_patcher_arm_base.h | 59 | ||||
| -rw-r--r-- | compiler/linker/arm/relative_patcher_thumb2.cc | 145 | ||||
| -rw-r--r-- | compiler/linker/arm/relative_patcher_thumb2.h | 26 | ||||
| -rw-r--r-- | compiler/linker/arm/relative_patcher_thumb2_test.cc | 19 | ||||
| -rw-r--r-- | compiler/linker/arm64/relative_patcher_arm64.cc | 148 | ||||
| -rw-r--r-- | compiler/linker/arm64/relative_patcher_arm64.h | 26 | ||||
| -rw-r--r-- | compiler/linker/arm64/relative_patcher_arm64_test.cc | 19 |
8 files changed, 219 insertions, 275 deletions
diff --git a/compiler/linker/arm/relative_patcher_arm_base.cc b/compiler/linker/arm/relative_patcher_arm_base.cc index f55d5a6fb8..e9d579d2b3 100644 --- a/compiler/linker/arm/relative_patcher_arm_base.cc +++ b/compiler/linker/arm/relative_patcher_arm_base.cc @@ -249,7 +249,7 @@ uint32_t ArmBaseRelativePatcher::ReserveSpaceInternal(uint32_t offset, // All remaining method call patches will be handled by this thunk. DCHECK(!unprocessed_method_call_patches_.empty()); DCHECK_LE(thunk_offset - unprocessed_method_call_patches_.front().GetPatchOffset(), - MaxPositiveDisplacement(ThunkType::kMethodCall)); + MaxPositiveDisplacement(GetMethodCallKey())); unprocessed_method_call_patches_.clear(); } } @@ -271,8 +271,8 @@ uint32_t ArmBaseRelativePatcher::CalculateMethodCallDisplacement(uint32_t patch_ DCHECK(method_call_thunk_ != nullptr); // Unsigned arithmetic with its well-defined overflow behavior is just fine here. uint32_t displacement = target_offset - patch_offset; - uint32_t max_positive_displacement = MaxPositiveDisplacement(ThunkType::kMethodCall); - uint32_t max_negative_displacement = MaxNegativeDisplacement(ThunkType::kMethodCall); + uint32_t max_positive_displacement = MaxPositiveDisplacement(GetMethodCallKey()); + uint32_t max_negative_displacement = MaxNegativeDisplacement(GetMethodCallKey()); // NOTE: With unsigned arithmetic we do mean to use && rather than || below. if (displacement > max_positive_displacement && displacement < -max_negative_displacement) { // Unwritten thunks have higher offsets, check if it's within range. @@ -299,29 +299,42 @@ uint32_t ArmBaseRelativePatcher::GetThunkTargetOffset(const ThunkKey& key, uint3 if (data.HasWrittenOffset()) { uint32_t offset = data.LastWrittenOffset(); DCHECK_LT(offset, patch_offset); - if (patch_offset - offset <= MaxNegativeDisplacement(key.GetType())) { + if (patch_offset - offset <= MaxNegativeDisplacement(key)) { return offset; } } DCHECK(data.HasPendingOffset()); uint32_t offset = data.GetPendingOffset(); DCHECK_GT(offset, patch_offset); - DCHECK_LE(offset - patch_offset, MaxPositiveDisplacement(key.GetType())); + DCHECK_LE(offset - patch_offset, MaxPositiveDisplacement(key)); return offset; } +ArmBaseRelativePatcher::ThunkKey ArmBaseRelativePatcher::GetMethodCallKey() { + return ThunkKey(ThunkType::kMethodCall, ThunkParams{{ 0u, 0u }}); // NOLINT(whitespace/braces) +} + +ArmBaseRelativePatcher::ThunkKey ArmBaseRelativePatcher::GetBakerThunkKey( + const LinkerPatch& patch) { + DCHECK_EQ(patch.GetType(), LinkerPatch::Type::kBakerReadBarrierBranch); + ThunkParams params; + params.baker_params.custom_value1 = patch.GetBakerCustomValue1(); + params.baker_params.custom_value2 = patch.GetBakerCustomValue2(); + ThunkKey key(ThunkType::kBakerReadBarrier, params); + return key; +} + void ArmBaseRelativePatcher::ProcessPatches(const CompiledMethod* compiled_method, uint32_t code_offset) { for (const LinkerPatch& patch : compiled_method->GetPatches()) { uint32_t patch_offset = code_offset + patch.LiteralOffset(); - ThunkType key_type = static_cast<ThunkType>(-1); + ThunkKey key(static_cast<ThunkType>(-1), ThunkParams{{ 0u, 0u }}); // NOLINT(whitespace/braces) ThunkData* old_data = nullptr; if (patch.GetType() == LinkerPatch::Type::kCallRelative) { - key_type = ThunkType::kMethodCall; + key = GetMethodCallKey(); unprocessed_method_call_patches_.emplace_back(patch_offset, patch.TargetMethod()); if (method_call_thunk_ == nullptr) { - ThunkKey key(key_type, ThunkParams{{ 0u, 0u }}); // NOLINT(whitespace/braces) - uint32_t max_next_offset = CalculateMaxNextOffset(patch_offset, key_type); + uint32_t max_next_offset = CalculateMaxNextOffset(patch_offset, key); auto it = thunks_.Put(key, ThunkData(CompileThunk(key), max_next_offset)); method_call_thunk_ = &it->second; AddUnreservedThunk(method_call_thunk_); @@ -329,11 +342,10 @@ void ArmBaseRelativePatcher::ProcessPatches(const CompiledMethod* compiled_metho old_data = method_call_thunk_; } } else if (patch.GetType() == LinkerPatch::Type::kBakerReadBarrierBranch) { - ThunkKey key = GetBakerReadBarrierKey(patch); - key_type = key.GetType(); + key = GetBakerThunkKey(patch); auto lb = thunks_.lower_bound(key); if (lb == thunks_.end() || thunks_.key_comp()(key, lb->first)) { - uint32_t max_next_offset = CalculateMaxNextOffset(patch_offset, key_type); + uint32_t max_next_offset = CalculateMaxNextOffset(patch_offset, key); auto it = thunks_.PutBefore(lb, key, ThunkData(CompileThunk(key), max_next_offset)); AddUnreservedThunk(&it->second); } else { @@ -342,16 +354,16 @@ void ArmBaseRelativePatcher::ProcessPatches(const CompiledMethod* compiled_metho } if (old_data != nullptr) { // Shared path where an old thunk may need an update. - DCHECK(key_type != static_cast<ThunkType>(-1)); + DCHECK(key.GetType() != static_cast<ThunkType>(-1)); DCHECK(!old_data->HasReservedOffset() || old_data->LastReservedOffset() < patch_offset); if (old_data->NeedsNextThunk()) { // Patches for a method are ordered by literal offset, so if we still need to place // this thunk for a previous patch, that thunk shall be in range for this patch. - DCHECK_LE(old_data->MaxNextOffset(), CalculateMaxNextOffset(patch_offset, key_type)); + DCHECK_LE(old_data->MaxNextOffset(), CalculateMaxNextOffset(patch_offset, key)); } else { if (!old_data->HasReservedOffset() || - patch_offset - old_data->LastReservedOffset() > MaxNegativeDisplacement(key_type)) { - old_data->SetMaxNextOffset(CalculateMaxNextOffset(patch_offset, key_type)); + patch_offset - old_data->LastReservedOffset() > MaxNegativeDisplacement(key)) { + old_data->SetMaxNextOffset(CalculateMaxNextOffset(patch_offset, key)); AddUnreservedThunk(old_data); } } @@ -385,8 +397,8 @@ void ArmBaseRelativePatcher::ResolveMethodCalls(uint32_t quick_code_offset, DCHECK(!unreserved_thunks_.empty()); DCHECK(!unprocessed_method_call_patches_.empty()); DCHECK(method_call_thunk_ != nullptr); - uint32_t max_positive_displacement = MaxPositiveDisplacement(ThunkType::kMethodCall); - uint32_t max_negative_displacement = MaxNegativeDisplacement(ThunkType::kMethodCall); + uint32_t max_positive_displacement = MaxPositiveDisplacement(GetMethodCallKey()); + uint32_t max_negative_displacement = MaxNegativeDisplacement(GetMethodCallKey()); // Process as many patches as possible, stop only on unresolved targets or calls too far back. while (!unprocessed_method_call_patches_.empty()) { MethodReference target_method = unprocessed_method_call_patches_.front().GetTargetMethod(); @@ -439,8 +451,8 @@ void ArmBaseRelativePatcher::ResolveMethodCalls(uint32_t quick_code_offset, } inline uint32_t ArmBaseRelativePatcher::CalculateMaxNextOffset(uint32_t patch_offset, - ThunkType type) { - return RoundDown(patch_offset + MaxPositiveDisplacement(type), + const ThunkKey& key) { + return RoundDown(patch_offset + MaxPositiveDisplacement(key), GetInstructionSetAlignment(instruction_set_)); } diff --git a/compiler/linker/arm/relative_patcher_arm_base.h b/compiler/linker/arm/relative_patcher_arm_base.h index 47f840fd65..fd204c05a6 100644 --- a/compiler/linker/arm/relative_patcher_arm_base.h +++ b/compiler/linker/arm/relative_patcher_arm_base.h @@ -42,29 +42,12 @@ class ArmBaseRelativePatcher : public RelativePatcher { enum class ThunkType { kMethodCall, // Method call thunk. - kBakerReadBarrierField, // Baker read barrier, load field or array element at known offset. - kBakerReadBarrierArray, // Baker read barrier, array load with index in register. - kBakerReadBarrierRoot, // Baker read barrier, GC root load. + kBakerReadBarrier, // Baker read barrier. }; - struct BakerReadBarrierFieldParams { - uint32_t holder_reg; // Holder object for reading lock word. - uint32_t base_reg; // Base register, different from holder for large offset. - // If base differs from holder, it should be a pre-defined - // register to limit the number of thunks we need to emit. - // The offset is retrieved using introspection. - }; - - struct BakerReadBarrierArrayParams { - uint32_t base_reg; // Reference to the start of the data. - uint32_t dummy; // Dummy field. - // The index register is retrieved using introspection - // to limit the number of thunks we need to emit. - }; - - struct BakerReadBarrierRootParams { - uint32_t root_reg; // The register holding the GC root. - uint32_t dummy; // Dummy field. + struct BakerReadBarrierParams { + uint32_t custom_value1; + uint32_t custom_value2; }; struct RawThunkParams { @@ -74,12 +57,8 @@ class ArmBaseRelativePatcher : public RelativePatcher { union ThunkParams { RawThunkParams raw_params; - BakerReadBarrierFieldParams field_params; - BakerReadBarrierArrayParams array_params; - BakerReadBarrierRootParams root_params; - static_assert(sizeof(raw_params) == sizeof(field_params), "field_params size check"); - static_assert(sizeof(raw_params) == sizeof(array_params), "array_params size check"); - static_assert(sizeof(raw_params) == sizeof(root_params), "root_params size check"); + BakerReadBarrierParams baker_params; + static_assert(sizeof(raw_params) == sizeof(baker_params), "baker_params size check"); }; class ThunkKey { @@ -90,19 +69,9 @@ class ArmBaseRelativePatcher : public RelativePatcher { return type_; } - BakerReadBarrierFieldParams GetFieldParams() const { - DCHECK(type_ == ThunkType::kBakerReadBarrierField); - return params_.field_params; - } - - BakerReadBarrierArrayParams GetArrayParams() const { - DCHECK(type_ == ThunkType::kBakerReadBarrierArray); - return params_.array_params; - } - - BakerReadBarrierRootParams GetRootParams() const { - DCHECK(type_ == ThunkType::kBakerReadBarrierRoot); - return params_.root_params; + BakerReadBarrierParams GetBakerReadBarrierParams() const { + DCHECK(type_ == ThunkType::kBakerReadBarrier); + return params_.baker_params; } RawThunkParams GetRawParams() const { @@ -127,6 +96,9 @@ class ArmBaseRelativePatcher : public RelativePatcher { } }; + static ThunkKey GetMethodCallKey(); + static ThunkKey GetBakerThunkKey(const LinkerPatch& patch); + uint32_t ReserveSpaceInternal(uint32_t offset, const CompiledMethod* compiled_method, MethodReference method_ref, @@ -136,10 +108,9 @@ class ArmBaseRelativePatcher : public RelativePatcher { uint32_t CalculateMethodCallDisplacement(uint32_t patch_offset, uint32_t target_offset); - virtual ThunkKey GetBakerReadBarrierKey(const LinkerPatch& patch) = 0; virtual std::vector<uint8_t> CompileThunk(const ThunkKey& key) = 0; - virtual uint32_t MaxPositiveDisplacement(ThunkType type) = 0; - virtual uint32_t MaxNegativeDisplacement(ThunkType type) = 0; + virtual uint32_t MaxPositiveDisplacement(const ThunkKey& key) = 0; + virtual uint32_t MaxNegativeDisplacement(const ThunkKey& key) = 0; private: class ThunkData; @@ -149,7 +120,7 @@ class ArmBaseRelativePatcher : public RelativePatcher { void ResolveMethodCalls(uint32_t quick_code_offset, MethodReference method_ref); - uint32_t CalculateMaxNextOffset(uint32_t patch_offset, ThunkType type); + uint32_t CalculateMaxNextOffset(uint32_t patch_offset, const ThunkKey& key); RelativePatcherTargetProvider* const provider_; const InstructionSet instruction_set_; diff --git a/compiler/linker/arm/relative_patcher_thumb2.cc b/compiler/linker/arm/relative_patcher_thumb2.cc index f2ccc4bcd3..ced52ff07a 100644 --- a/compiler/linker/arm/relative_patcher_thumb2.cc +++ b/compiler/linker/arm/relative_patcher_thumb2.cc @@ -105,32 +105,37 @@ void Thumb2RelativePatcher::PatchBakerReadBarrierBranch(std::vector<uint8_t>* co DCHECK_LT(literal_offset, code->size()); uint32_t insn = GetInsn32(code, literal_offset); DCHECK_EQ(insn, 0xf0408000); // BNE +0 (unpatched) - ThunkKey key = GetBakerReadBarrierKey(patch); + ThunkKey key = GetBakerThunkKey(patch); if (kIsDebugBuild) { + const uint32_t encoded_data = key.GetBakerReadBarrierParams().custom_value1; + BakerReadBarrierKind kind = BakerReadBarrierKindField::Decode(encoded_data); // Check that the next instruction matches the expected LDR. - switch (key.GetType()) { - case ThunkType::kBakerReadBarrierField: { + switch (kind) { + case BakerReadBarrierKind::kField: { DCHECK_GE(code->size() - literal_offset, 8u); uint32_t next_insn = GetInsn32(code, literal_offset + 4u); // LDR (immediate) with correct base_reg. CheckValidReg((next_insn >> 12) & 0xfu); // Check destination register. - CHECK_EQ(next_insn & 0xffff0000u, 0xf8d00000u | (key.GetFieldParams().base_reg << 16)); + const uint32_t base_reg = BakerReadBarrierFirstRegField::Decode(encoded_data); + CHECK_EQ(next_insn & 0xffff0000u, 0xf8d00000u | (base_reg << 16)); break; } - case ThunkType::kBakerReadBarrierArray: { + case BakerReadBarrierKind::kArray: { DCHECK_GE(code->size() - literal_offset, 8u); uint32_t next_insn = GetInsn32(code, literal_offset + 4u); // LDR (register) with correct base_reg, S=1 and option=011 (LDR Wt, [Xn, Xm, LSL #2]). CheckValidReg((next_insn >> 12) & 0xfu); // Check destination register. - CHECK_EQ(next_insn & 0xffff0ff0u, 0xf8500020u | (key.GetArrayParams().base_reg << 16)); + const uint32_t base_reg = BakerReadBarrierFirstRegField::Decode(encoded_data); + CHECK_EQ(next_insn & 0xffff0ff0u, 0xf8500020u | (base_reg << 16)); CheckValidReg(next_insn & 0xf); // Check index register break; } - case ThunkType::kBakerReadBarrierRoot: { + case BakerReadBarrierKind::kGcRoot: { DCHECK_GE(literal_offset, 4u); uint32_t prev_insn = GetInsn32(code, literal_offset - 4u); // LDR (immediate) with correct root_reg. - CHECK_EQ(prev_insn & 0xfff0f000u, 0xf8d00000u | (key.GetRootParams().root_reg << 12)); + const uint32_t root_reg = BakerReadBarrierFirstRegField::Decode(encoded_data); + CHECK_EQ(prev_insn & 0xfff0f000u, 0xf8d00000u | (root_reg << 12)); break; } default: @@ -150,49 +155,6 @@ void Thumb2RelativePatcher::PatchBakerReadBarrierBranch(std::vector<uint8_t>* co SetInsn32(code, literal_offset, insn); } -ArmBaseRelativePatcher::ThunkKey Thumb2RelativePatcher::GetBakerReadBarrierKey( - const LinkerPatch& patch) { - DCHECK_EQ(patch.GetType(), LinkerPatch::Type::kBakerReadBarrierBranch); - uint32_t value = patch.GetBakerCustomValue1(); - BakerReadBarrierKind type = BakerReadBarrierKindField::Decode(value); - ThunkParams params; - switch (type) { - case BakerReadBarrierKind::kField: - params.field_params.base_reg = BakerReadBarrierFirstRegField::Decode(value); - CheckValidReg(params.field_params.base_reg); - params.field_params.holder_reg = BakerReadBarrierSecondRegField::Decode(value); - CheckValidReg(params.field_params.holder_reg); - break; - case BakerReadBarrierKind::kArray: - params.array_params.base_reg = BakerReadBarrierFirstRegField::Decode(value); - CheckValidReg(params.array_params.base_reg); - params.array_params.dummy = 0u; - DCHECK_EQ(BakerReadBarrierSecondRegField::Decode(value), kInvalidEncodedReg); - break; - case BakerReadBarrierKind::kGcRoot: - params.root_params.root_reg = BakerReadBarrierFirstRegField::Decode(value); - CheckValidReg(params.root_params.root_reg); - params.root_params.dummy = 0u; - DCHECK_EQ(BakerReadBarrierSecondRegField::Decode(value), kInvalidEncodedReg); - break; - default: - LOG(FATAL) << "Unexpected type: " << static_cast<uint32_t>(type); - UNREACHABLE(); - } - constexpr uint8_t kTypeTranslationOffset = 1u; - static_assert(static_cast<uint32_t>(BakerReadBarrierKind::kField) + kTypeTranslationOffset == - static_cast<uint32_t>(ThunkType::kBakerReadBarrierField), - "Thunk type translation check."); - static_assert(static_cast<uint32_t>(BakerReadBarrierKind::kArray) + kTypeTranslationOffset == - static_cast<uint32_t>(ThunkType::kBakerReadBarrierArray), - "Thunk type translation check."); - static_assert(static_cast<uint32_t>(BakerReadBarrierKind::kGcRoot) + kTypeTranslationOffset == - static_cast<uint32_t>(ThunkType::kBakerReadBarrierRoot), - "Thunk type translation check."); - return ThunkKey(static_cast<ThunkType>(static_cast<uint32_t>(type) + kTypeTranslationOffset), - params); -} - #define __ assembler.GetVIXLAssembler()-> static void EmitGrayCheckAndFastPath(arm::ArmVIXLAssembler& assembler, @@ -223,30 +185,20 @@ static void EmitGrayCheckAndFastPath(arm::ArmVIXLAssembler& assembler, // Note: The fake dependency is unnecessary for the slow path. } -std::vector<uint8_t> Thumb2RelativePatcher::CompileThunk(const ThunkKey& key) { +void Thumb2RelativePatcher::CompileBakerReadBarrierThunk(arm::ArmVIXLAssembler& assembler, + uint32_t encoded_data) { using namespace vixl::aarch32; // NOLINT(build/namespaces) - ArenaPool pool; - ArenaAllocator arena(&pool); - arm::ArmVIXLAssembler assembler(&arena); - - switch (key.GetType()) { - case ThunkType::kMethodCall: - // The thunk just uses the entry point in the ArtMethod. This works even for calls - // to the generic JNI and interpreter trampolines. - assembler.LoadFromOffset( - arm::kLoadWord, - vixl::aarch32::pc, - vixl::aarch32::r0, - ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArmPointerSize).Int32Value()); - __ Bkpt(0); - break; - case ThunkType::kBakerReadBarrierField: { + BakerReadBarrierKind kind = BakerReadBarrierKindField::Decode(encoded_data); + switch (kind) { + case BakerReadBarrierKind::kField: { // Check if the holder is gray and, if not, add fake dependency to the base register // and return to the LDR instruction to load the reference. Otherwise, use introspection // to load the reference and call the entrypoint (in kBakerCcEntrypointRegister) // that performs further checks on the reference and marks it if needed. - Register holder_reg(key.GetFieldParams().holder_reg); - Register base_reg(key.GetFieldParams().base_reg); + Register base_reg(BakerReadBarrierFirstRegField::Decode(encoded_data)); + CheckValidReg(base_reg.GetCode()); + Register holder_reg(BakerReadBarrierSecondRegField::Decode(encoded_data)); + CheckValidReg(holder_reg.GetCode()); UseScratchRegisterScope temps(assembler.GetVIXLAssembler()); temps.Exclude(ip); // If base_reg differs from holder_reg, the offset was too large and we must have @@ -277,8 +229,10 @@ std::vector<uint8_t> Thumb2RelativePatcher::CompileThunk(const ThunkKey& key) { } break; } - case ThunkType::kBakerReadBarrierArray: { - Register base_reg(key.GetArrayParams().base_reg); + case BakerReadBarrierKind::kArray: { + Register base_reg(BakerReadBarrierFirstRegField::Decode(encoded_data)); + CheckValidReg(base_reg.GetCode()); + DCHECK_EQ(kInvalidEncodedReg, BakerReadBarrierSecondRegField::Decode(encoded_data)); UseScratchRegisterScope temps(assembler.GetVIXLAssembler()); temps.Exclude(ip); vixl::aarch32::Label slow_path; @@ -299,12 +253,14 @@ std::vector<uint8_t> Thumb2RelativePatcher::CompileThunk(const ThunkKey& key) { __ Bx(ep_reg); // Jump to the entrypoint's array switch case. break; } - case ThunkType::kBakerReadBarrierRoot: { + case BakerReadBarrierKind::kGcRoot: { // Check if the reference needs to be marked and if so (i.e. not null, not marked yet // and it does not have a forwarding address), call the correct introspection entrypoint; // otherwise return the reference (or the extracted forwarding address). // There is no gray bit check for GC roots. - Register root_reg(key.GetRootParams().root_reg); + Register root_reg(BakerReadBarrierFirstRegField::Decode(encoded_data)); + CheckValidReg(root_reg.GetCode()); + DCHECK_EQ(kInvalidEncodedReg, BakerReadBarrierSecondRegField::Decode(encoded_data)); UseScratchRegisterScope temps(assembler.GetVIXLAssembler()); temps.Exclude(ip); vixl::aarch32::Label return_label, not_marked, forwarding_address; @@ -332,6 +288,31 @@ std::vector<uint8_t> Thumb2RelativePatcher::CompileThunk(const ThunkKey& key) { __ Bx(lr); break; } + default: + LOG(FATAL) << "Unexpected kind: " << static_cast<uint32_t>(kind); + UNREACHABLE(); + } +} + +std::vector<uint8_t> Thumb2RelativePatcher::CompileThunk(const ThunkKey& key) { + ArenaPool pool; + ArenaAllocator arena(&pool); + arm::ArmVIXLAssembler assembler(&arena); + + switch (key.GetType()) { + case ThunkType::kMethodCall: + // The thunk just uses the entry point in the ArtMethod. This works even for calls + // to the generic JNI and interpreter trampolines. + assembler.LoadFromOffset( + arm::kLoadWord, + vixl::aarch32::pc, + vixl::aarch32::r0, + ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArmPointerSize).Int32Value()); + __ Bkpt(0); + break; + case ThunkType::kBakerReadBarrier: + CompileBakerReadBarrierThunk(assembler, key.GetBakerReadBarrierParams().custom_value1); + break; } assembler.FinalizeCode(); @@ -343,24 +324,20 @@ std::vector<uint8_t> Thumb2RelativePatcher::CompileThunk(const ThunkKey& key) { #undef __ -uint32_t Thumb2RelativePatcher::MaxPositiveDisplacement(ThunkType type) { - switch (type) { +uint32_t Thumb2RelativePatcher::MaxPositiveDisplacement(const ThunkKey& key) { + switch (key.GetType()) { case ThunkType::kMethodCall: return kMaxMethodCallPositiveDisplacement; - case ThunkType::kBakerReadBarrierField: - case ThunkType::kBakerReadBarrierArray: - case ThunkType::kBakerReadBarrierRoot: + case ThunkType::kBakerReadBarrier: return kMaxBcondPositiveDisplacement; } } -uint32_t Thumb2RelativePatcher::MaxNegativeDisplacement(ThunkType type) { - switch (type) { +uint32_t Thumb2RelativePatcher::MaxNegativeDisplacement(const ThunkKey& key) { + switch (key.GetType()) { case ThunkType::kMethodCall: return kMaxMethodCallNegativeDisplacement; - case ThunkType::kBakerReadBarrierField: - case ThunkType::kBakerReadBarrierArray: - case ThunkType::kBakerReadBarrierRoot: + case ThunkType::kBakerReadBarrier: return kMaxBcondNegativeDisplacement; } } diff --git a/compiler/linker/arm/relative_patcher_thumb2.h b/compiler/linker/arm/relative_patcher_thumb2.h index 9eb06894d3..7fad245856 100644 --- a/compiler/linker/arm/relative_patcher_thumb2.h +++ b/compiler/linker/arm/relative_patcher_thumb2.h @@ -24,19 +24,17 @@ #include "linker/arm/relative_patcher_arm_base.h" namespace art { + +namespace arm { +class ArmVIXLAssembler; +} // namespace arm + namespace linker { class Thumb2RelativePatcher FINAL : public ArmBaseRelativePatcher { public: static constexpr uint32_t kBakerCcEntrypointRegister = 4u; - enum class 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. - kLast - }; - static uint32_t EncodeBakerReadBarrierFieldData(uint32_t base_reg, uint32_t holder_reg) { CheckValidReg(base_reg); CheckValidReg(holder_reg); @@ -74,14 +72,20 @@ class Thumb2RelativePatcher FINAL : public ArmBaseRelativePatcher { uint32_t patch_offset) OVERRIDE; protected: - ThunkKey GetBakerReadBarrierKey(const LinkerPatch& patch) OVERRIDE; std::vector<uint8_t> CompileThunk(const ThunkKey& key) OVERRIDE; - uint32_t MaxPositiveDisplacement(ThunkType type) OVERRIDE; - uint32_t MaxNegativeDisplacement(ThunkType type) OVERRIDE; + uint32_t MaxPositiveDisplacement(const ThunkKey& key) OVERRIDE; + uint32_t MaxNegativeDisplacement(const ThunkKey& key) OVERRIDE; private: static constexpr uint32_t kInvalidEncodedReg = /* pc is invalid */ 15u; + enum class 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. + kLast + }; + static constexpr size_t kBitsForBakerReadBarrierKind = MinimumBitsToStore(static_cast<size_t>(BakerReadBarrierKind::kLast)); static constexpr size_t kBitsForRegister = 4u; @@ -96,6 +100,8 @@ class Thumb2RelativePatcher FINAL : public ArmBaseRelativePatcher { DCHECK(reg < 12u && reg != kBakerCcEntrypointRegister); } + void CompileBakerReadBarrierThunk(arm::ArmVIXLAssembler& assembler, uint32_t encoded_data); + void SetInsn32(std::vector<uint8_t>* code, uint32_t offset, uint32_t value); static uint32_t GetInsn32(ArrayRef<const uint8_t> code, uint32_t offset); diff --git a/compiler/linker/arm/relative_patcher_thumb2_test.cc b/compiler/linker/arm/relative_patcher_thumb2_test.cc index 8bc3eb4505..2e28349231 100644 --- a/compiler/linker/arm/relative_patcher_thumb2_test.cc +++ b/compiler/linker/arm/relative_patcher_thumb2_test.cc @@ -185,9 +185,7 @@ class Thumb2RelativePatcherTest : public RelativePatcherTest { } std::vector<uint8_t> CompileMethodCallThunk() { - ArmBaseRelativePatcher::ThunkKey key( - ArmBaseRelativePatcher::ThunkType::kMethodCall, - ArmBaseRelativePatcher::ThunkParams{{ 0, 0 }}); // NOLINT(whitespace/braces) + ArmBaseRelativePatcher::ThunkKey key = ArmBaseRelativePatcher::GetMethodCallKey(); return static_cast<Thumb2RelativePatcher*>(patcher_.get())->CompileThunk(key); } @@ -228,25 +226,22 @@ class Thumb2RelativePatcherTest : public RelativePatcherTest { std::vector<uint8_t> CompileBakerOffsetThunk(uint32_t base_reg, uint32_t holder_reg) { const LinkerPatch patch = LinkerPatch::BakerReadBarrierBranchPatch( 0u, Thumb2RelativePatcher::EncodeBakerReadBarrierFieldData(base_reg, holder_reg)); - auto* patcher = down_cast<Thumb2RelativePatcher*>(patcher_.get()); - ArmBaseRelativePatcher::ThunkKey key = patcher->GetBakerReadBarrierKey(patch); - return patcher->CompileThunk(key); + ArmBaseRelativePatcher::ThunkKey key = ArmBaseRelativePatcher::GetBakerThunkKey(patch); + return down_cast<Thumb2RelativePatcher*>(patcher_.get())->CompileThunk(key); } std::vector<uint8_t> CompileBakerArrayThunk(uint32_t base_reg) { LinkerPatch patch = LinkerPatch::BakerReadBarrierBranchPatch( 0u, Thumb2RelativePatcher::EncodeBakerReadBarrierArrayData(base_reg)); - auto* patcher = down_cast<Thumb2RelativePatcher*>(patcher_.get()); - ArmBaseRelativePatcher::ThunkKey key = patcher->GetBakerReadBarrierKey(patch); - return patcher->CompileThunk(key); + ArmBaseRelativePatcher::ThunkKey key = ArmBaseRelativePatcher::GetBakerThunkKey(patch); + return down_cast<Thumb2RelativePatcher*>(patcher_.get())->CompileThunk(key); } std::vector<uint8_t> CompileBakerGcRootThunk(uint32_t root_reg) { LinkerPatch patch = LinkerPatch::BakerReadBarrierBranchPatch( 0u, Thumb2RelativePatcher::EncodeBakerReadBarrierGcRootData(root_reg)); - auto* patcher = down_cast<Thumb2RelativePatcher*>(patcher_.get()); - ArmBaseRelativePatcher::ThunkKey key = patcher->GetBakerReadBarrierKey(patch); - return patcher->CompileThunk(key); + ArmBaseRelativePatcher::ThunkKey key = ArmBaseRelativePatcher::GetBakerThunkKey(patch); + return down_cast<Thumb2RelativePatcher*>(patcher_.get())->CompileThunk(key); } uint32_t GetOutputInsn32(uint32_t offset) { diff --git a/compiler/linker/arm64/relative_patcher_arm64.cc b/compiler/linker/arm64/relative_patcher_arm64.cc index 5c6fb504cf..2b06e3f649 100644 --- a/compiler/linker/arm64/relative_patcher_arm64.cc +++ b/compiler/linker/arm64/relative_patcher_arm64.cc @@ -305,37 +305,42 @@ void Arm64RelativePatcher::PatchBakerReadBarrierBranch(std::vector<uint8_t>* cod DCHECK_LT(literal_offset, code->size()); uint32_t insn = GetInsn(code, literal_offset); DCHECK_EQ(insn & 0xffffffe0u, 0xb5000000); // CBNZ Xt, +0 (unpatched) - ThunkKey key = GetBakerReadBarrierKey(patch); + ThunkKey key = GetBakerThunkKey(patch); if (kIsDebugBuild) { + const uint32_t encoded_data = key.GetBakerReadBarrierParams().custom_value1; + BakerReadBarrierKind kind = BakerReadBarrierKindField::Decode(encoded_data); // Check that the next instruction matches the expected LDR. - switch (key.GetType()) { - case ThunkType::kBakerReadBarrierField: { + switch (kind) { + case BakerReadBarrierKind::kField: { DCHECK_GE(code->size() - literal_offset, 8u); uint32_t next_insn = GetInsn(code, literal_offset + 4u); // LDR (immediate) with correct base_reg. CheckValidReg(next_insn & 0x1fu); // Check destination register. - CHECK_EQ(next_insn & 0xffc003e0u, 0xb9400000u | (key.GetFieldParams().base_reg << 5)); + const uint32_t base_reg = BakerReadBarrierFirstRegField::Decode(encoded_data); + CHECK_EQ(next_insn & 0xffc003e0u, 0xb9400000u | (base_reg << 5)); break; } - case ThunkType::kBakerReadBarrierArray: { + case BakerReadBarrierKind::kArray: { DCHECK_GE(code->size() - literal_offset, 8u); uint32_t next_insn = GetInsn(code, literal_offset + 4u); // LDR (register) with the correct base_reg, size=10 (32-bit), option=011 (extend = LSL), // and S=1 (shift amount = 2 for 32-bit version), i.e. LDR Wt, [Xn, Xm, LSL #2]. CheckValidReg(next_insn & 0x1fu); // Check destination register. - CHECK_EQ(next_insn & 0xffe0ffe0u, 0xb8607800u | (key.GetArrayParams().base_reg << 5)); + const uint32_t base_reg = BakerReadBarrierFirstRegField::Decode(encoded_data); + CHECK_EQ(next_insn & 0xffe0ffe0u, 0xb8607800u | (base_reg << 5)); CheckValidReg((next_insn >> 16) & 0x1f); // Check index register break; } - case ThunkType::kBakerReadBarrierRoot: { + case BakerReadBarrierKind::kGcRoot: { DCHECK_GE(literal_offset, 4u); uint32_t prev_insn = GetInsn(code, literal_offset - 4u); // LDR (immediate) with correct root_reg. - CHECK_EQ(prev_insn & 0xffc0001fu, 0xb9400000u | key.GetRootParams().root_reg); + const uint32_t root_reg = BakerReadBarrierFirstRegField::Decode(encoded_data); + CHECK_EQ(prev_insn & 0xffc0001fu, 0xb9400000u | root_reg); break; } default: - LOG(FATAL) << "Unexpected type: " << static_cast<uint32_t>(key.GetType()); + LOG(FATAL) << "Unexpected kind: " << static_cast<uint32_t>(kind); UNREACHABLE(); } } @@ -347,49 +352,6 @@ void Arm64RelativePatcher::PatchBakerReadBarrierBranch(std::vector<uint8_t>* cod SetInsn(code, literal_offset, insn); } -ArmBaseRelativePatcher::ThunkKey Arm64RelativePatcher::GetBakerReadBarrierKey( - const LinkerPatch& patch) { - DCHECK_EQ(patch.GetType(), LinkerPatch::Type::kBakerReadBarrierBranch); - uint32_t value = patch.GetBakerCustomValue1(); - BakerReadBarrierKind type = BakerReadBarrierKindField::Decode(value); - ThunkParams params; - switch (type) { - case BakerReadBarrierKind::kField: - params.field_params.base_reg = BakerReadBarrierFirstRegField::Decode(value); - CheckValidReg(params.field_params.base_reg); - params.field_params.holder_reg = BakerReadBarrierSecondRegField::Decode(value); - CheckValidReg(params.field_params.holder_reg); - break; - case BakerReadBarrierKind::kArray: - params.array_params.base_reg = BakerReadBarrierFirstRegField::Decode(value); - CheckValidReg(params.array_params.base_reg); - params.array_params.dummy = 0u; - DCHECK_EQ(BakerReadBarrierSecondRegField::Decode(value), kInvalidEncodedReg); - break; - case BakerReadBarrierKind::kGcRoot: - params.root_params.root_reg = BakerReadBarrierFirstRegField::Decode(value); - CheckValidReg(params.root_params.root_reg); - params.root_params.dummy = 0u; - DCHECK_EQ(BakerReadBarrierSecondRegField::Decode(value), kInvalidEncodedReg); - break; - default: - LOG(FATAL) << "Unexpected type: " << static_cast<uint32_t>(type); - UNREACHABLE(); - } - constexpr uint8_t kTypeTranslationOffset = 1u; - static_assert(static_cast<uint32_t>(BakerReadBarrierKind::kField) + kTypeTranslationOffset == - static_cast<uint32_t>(ThunkType::kBakerReadBarrierField), - "Thunk type translation check."); - static_assert(static_cast<uint32_t>(BakerReadBarrierKind::kArray) + kTypeTranslationOffset == - static_cast<uint32_t>(ThunkType::kBakerReadBarrierArray), - "Thunk type translation check."); - static_assert(static_cast<uint32_t>(BakerReadBarrierKind::kGcRoot) + kTypeTranslationOffset == - static_cast<uint32_t>(ThunkType::kBakerReadBarrierRoot), - "Thunk type translation check."); - return ThunkKey(static_cast<ThunkType>(static_cast<uint32_t>(type) + kTypeTranslationOffset), - params); -} - #define __ assembler.GetVIXLAssembler()-> static void EmitGrayCheckAndFastPath(arm64::Arm64Assembler& assembler, @@ -419,28 +381,22 @@ static void EmitGrayCheckAndFastPath(arm64::Arm64Assembler& assembler, // Note: The fake dependency is unnecessary for the slow path. } -std::vector<uint8_t> Arm64RelativePatcher::CompileThunk(const ThunkKey& key) { +void Arm64RelativePatcher::CompileBakerReadBarrierThunk(arm64::Arm64Assembler& assembler, + uint32_t encoded_data) { using namespace vixl::aarch64; // NOLINT(build/namespaces) - ArenaPool pool; - ArenaAllocator arena(&pool); - arm64::Arm64Assembler assembler(&arena); - - switch (key.GetType()) { - case ThunkType::kMethodCall: { - // The thunk just uses the entry point in the ArtMethod. This works even for calls - // to the generic JNI and interpreter trampolines. - Offset offset(ArtMethod::EntryPointFromQuickCompiledCodeOffset( - kArm64PointerSize).Int32Value()); - assembler.JumpTo(ManagedRegister(arm64::X0), offset, ManagedRegister(arm64::IP0)); - break; - } - case ThunkType::kBakerReadBarrierField: { + BakerReadBarrierKind kind = BakerReadBarrierKindField::Decode(encoded_data); + switch (kind) { + case BakerReadBarrierKind::kField: { // Check if the holder is gray and, if not, add fake dependency to the base register // and return to the LDR instruction to load the reference. Otherwise, use introspection // to load the reference and call the entrypoint (in IP1) that performs further checks // on the reference and marks it if needed. - auto holder_reg = Register::GetXRegFromCode(key.GetFieldParams().holder_reg); - auto base_reg = Register::GetXRegFromCode(key.GetFieldParams().base_reg); + auto base_reg = + Register::GetXRegFromCode(BakerReadBarrierFirstRegField::Decode(encoded_data)); + CheckValidReg(base_reg.GetCode()); + auto holder_reg = + Register::GetXRegFromCode(BakerReadBarrierSecondRegField::Decode(encoded_data)); + CheckValidReg(holder_reg.GetCode()); UseScratchRegisterScope temps(assembler.GetVIXLAssembler()); temps.Exclude(ip0, ip1); // If base_reg differs from holder_reg, the offset was too large and we must have @@ -469,8 +425,11 @@ std::vector<uint8_t> Arm64RelativePatcher::CompileThunk(const ThunkKey& key) { } break; } - case ThunkType::kBakerReadBarrierArray: { - auto base_reg = Register::GetXRegFromCode(key.GetArrayParams().base_reg); + case BakerReadBarrierKind::kArray: { + auto base_reg = + Register::GetXRegFromCode(BakerReadBarrierFirstRegField::Decode(encoded_data)); + CheckValidReg(base_reg.GetCode()); + DCHECK_EQ(kInvalidEncodedReg, BakerReadBarrierSecondRegField::Decode(encoded_data)); UseScratchRegisterScope temps(assembler.GetVIXLAssembler()); temps.Exclude(ip0, ip1); vixl::aarch64::Label slow_path; @@ -489,12 +448,15 @@ std::vector<uint8_t> Arm64RelativePatcher::CompileThunk(const ThunkKey& key) { __ Br(ip1); // Jump to the entrypoint's array switch case. break; } - case ThunkType::kBakerReadBarrierRoot: { + case BakerReadBarrierKind::kGcRoot: { // Check if the reference needs to be marked and if so (i.e. not null, not marked yet // and it does not have a forwarding address), call the correct introspection entrypoint; // otherwise return the reference (or the extracted forwarding address). // There is no gray bit check for GC roots. - auto root_reg = Register::GetWRegFromCode(key.GetRootParams().root_reg); + auto root_reg = + Register::GetWRegFromCode(BakerReadBarrierFirstRegField::Decode(encoded_data)); + CheckValidReg(root_reg.GetCode()); + DCHECK_EQ(kInvalidEncodedReg, BakerReadBarrierSecondRegField::Decode(encoded_data)); UseScratchRegisterScope temps(assembler.GetVIXLAssembler()); temps.Exclude(ip0, ip1); vixl::aarch64::Label return_label, not_marked, forwarding_address; @@ -517,6 +479,30 @@ std::vector<uint8_t> Arm64RelativePatcher::CompileThunk(const ThunkKey& key) { __ Br(lr); break; } + default: + LOG(FATAL) << "Unexpected kind: " << static_cast<uint32_t>(kind); + UNREACHABLE(); + } +} + +std::vector<uint8_t> Arm64RelativePatcher::CompileThunk(const ThunkKey& key) { + ArenaPool pool; + ArenaAllocator arena(&pool); + arm64::Arm64Assembler assembler(&arena); + + switch (key.GetType()) { + case ThunkType::kMethodCall: { + // The thunk just uses the entry point in the ArtMethod. This works even for calls + // to the generic JNI and interpreter trampolines. + Offset offset(ArtMethod::EntryPointFromQuickCompiledCodeOffset( + kArm64PointerSize).Int32Value()); + assembler.JumpTo(ManagedRegister(arm64::X0), offset, ManagedRegister(arm64::IP0)); + break; + } + case ThunkType::kBakerReadBarrier: { + CompileBakerReadBarrierThunk(assembler, key.GetBakerReadBarrierParams().custom_value1); + break; + } } // Ensure we emit the literal pool. @@ -529,24 +515,20 @@ std::vector<uint8_t> Arm64RelativePatcher::CompileThunk(const ThunkKey& key) { #undef __ -uint32_t Arm64RelativePatcher::MaxPositiveDisplacement(ThunkType type) { - switch (type) { +uint32_t Arm64RelativePatcher::MaxPositiveDisplacement(const ThunkKey& key) { + switch (key.GetType()) { case ThunkType::kMethodCall: return kMaxMethodCallPositiveDisplacement; - case ThunkType::kBakerReadBarrierField: - case ThunkType::kBakerReadBarrierArray: - case ThunkType::kBakerReadBarrierRoot: + case ThunkType::kBakerReadBarrier: return kMaxBcondPositiveDisplacement; } } -uint32_t Arm64RelativePatcher::MaxNegativeDisplacement(ThunkType type) { - switch (type) { +uint32_t Arm64RelativePatcher::MaxNegativeDisplacement(const ThunkKey& key) { + switch (key.GetType()) { case ThunkType::kMethodCall: return kMaxMethodCallNegativeDisplacement; - case ThunkType::kBakerReadBarrierField: - case ThunkType::kBakerReadBarrierArray: - case ThunkType::kBakerReadBarrierRoot: + case ThunkType::kBakerReadBarrier: return kMaxBcondNegativeDisplacement; } } diff --git a/compiler/linker/arm64/relative_patcher_arm64.h b/compiler/linker/arm64/relative_patcher_arm64.h index 71ab70eda9..d1ab410a7e 100644 --- a/compiler/linker/arm64/relative_patcher_arm64.h +++ b/compiler/linker/arm64/relative_patcher_arm64.h @@ -23,17 +23,15 @@ #include "linker/arm/relative_patcher_arm_base.h" namespace art { + +namespace arm64 { +class Arm64Assembler; +} // namespace arm64 + namespace linker { class Arm64RelativePatcher FINAL : public ArmBaseRelativePatcher { public: - enum class 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. - kLast - }; - static uint32_t EncodeBakerReadBarrierFieldData(uint32_t base_reg, uint32_t holder_reg) { CheckValidReg(base_reg); CheckValidReg(holder_reg); @@ -77,14 +75,20 @@ class Arm64RelativePatcher FINAL : public ArmBaseRelativePatcher { uint32_t patch_offset) OVERRIDE; protected: - ThunkKey GetBakerReadBarrierKey(const LinkerPatch& patch) OVERRIDE; std::vector<uint8_t> CompileThunk(const ThunkKey& key) OVERRIDE; - uint32_t MaxPositiveDisplacement(ThunkType type) OVERRIDE; - uint32_t MaxNegativeDisplacement(ThunkType type) OVERRIDE; + uint32_t MaxPositiveDisplacement(const ThunkKey& key) OVERRIDE; + uint32_t MaxNegativeDisplacement(const ThunkKey& key) OVERRIDE; private: static constexpr uint32_t kInvalidEncodedReg = /* sp/zr is invalid */ 31u; + enum class 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. + kLast + }; + static constexpr size_t kBitsForBakerReadBarrierKind = MinimumBitsToStore(static_cast<size_t>(BakerReadBarrierKind::kLast)); static constexpr size_t kBitsForRegister = 5u; @@ -99,6 +103,8 @@ class Arm64RelativePatcher FINAL : public ArmBaseRelativePatcher { DCHECK(reg < 30u && reg != 16u && reg != 17u); } + void CompileBakerReadBarrierThunk(arm64::Arm64Assembler& assembler, uint32_t encoded_data); + static uint32_t PatchAdrp(uint32_t adrp, uint32_t disp); static bool NeedsErratum843419Thunk(ArrayRef<const uint8_t> code, uint32_t literal_offset, diff --git a/compiler/linker/arm64/relative_patcher_arm64_test.cc b/compiler/linker/arm64/relative_patcher_arm64_test.cc index 57ea886586..b6549eefb3 100644 --- a/compiler/linker/arm64/relative_patcher_arm64_test.cc +++ b/compiler/linker/arm64/relative_patcher_arm64_test.cc @@ -167,9 +167,7 @@ class Arm64RelativePatcherTest : public RelativePatcherTest { } std::vector<uint8_t> CompileMethodCallThunk() { - ArmBaseRelativePatcher::ThunkKey key( - ArmBaseRelativePatcher::ThunkType::kMethodCall, - ArmBaseRelativePatcher::ThunkParams{{ 0, 0 }}); // NOLINT(whitespace/braces) + ArmBaseRelativePatcher::ThunkKey key = ArmBaseRelativePatcher::GetMethodCallKey(); return down_cast<Arm64RelativePatcher*>(patcher_.get())->CompileThunk(key); } @@ -473,25 +471,22 @@ class Arm64RelativePatcherTest : public RelativePatcherTest { std::vector<uint8_t> CompileBakerOffsetThunk(uint32_t base_reg, uint32_t holder_reg) { const LinkerPatch patch = LinkerPatch::BakerReadBarrierBranchPatch( 0u, Arm64RelativePatcher::EncodeBakerReadBarrierFieldData(base_reg, holder_reg)); - auto* patcher = down_cast<Arm64RelativePatcher*>(patcher_.get()); - ArmBaseRelativePatcher::ThunkKey key = patcher->GetBakerReadBarrierKey(patch); - return patcher->CompileThunk(key); + ArmBaseRelativePatcher::ThunkKey key = ArmBaseRelativePatcher::GetBakerThunkKey(patch); + return down_cast<Arm64RelativePatcher*>(patcher_.get())->CompileThunk(key); } std::vector<uint8_t> CompileBakerArrayThunk(uint32_t base_reg) { LinkerPatch patch = LinkerPatch::BakerReadBarrierBranchPatch( 0u, Arm64RelativePatcher::EncodeBakerReadBarrierArrayData(base_reg)); - auto* patcher = down_cast<Arm64RelativePatcher*>(patcher_.get()); - ArmBaseRelativePatcher::ThunkKey key = patcher->GetBakerReadBarrierKey(patch); - return patcher->CompileThunk(key); + ArmBaseRelativePatcher::ThunkKey key = ArmBaseRelativePatcher::GetBakerThunkKey(patch); + return down_cast<Arm64RelativePatcher*>(patcher_.get())->CompileThunk(key); } std::vector<uint8_t> CompileBakerGcRootThunk(uint32_t root_reg) { LinkerPatch patch = LinkerPatch::BakerReadBarrierBranchPatch( 0u, Arm64RelativePatcher::EncodeBakerReadBarrierGcRootData(root_reg)); - auto* patcher = down_cast<Arm64RelativePatcher*>(patcher_.get()); - ArmBaseRelativePatcher::ThunkKey key = patcher->GetBakerReadBarrierKey(patch); - return patcher->CompileThunk(key); + ArmBaseRelativePatcher::ThunkKey key = ArmBaseRelativePatcher::GetBakerThunkKey(patch); + return down_cast<Arm64RelativePatcher*>(patcher_.get())->CompileThunk(key); } uint32_t GetOutputInsn(uint32_t offset) { |