Skip to content

Commit

Permalink
[vm/compiler] Fix relocator to take out-of-range backwards calls into…
Browse files Browse the repository at this point in the history
… acount

There was a missing check for whether a backwards call is out-of-range.

The CL also removes leftover code related to [max_offset_into_target_] -
which wasn't used. The intended use is already over approximated via
[max_instructions_size_].

The CL makes the pc-relative call/tail-call distances pluggable so a
newly added test can modify them for testing in-range/out-of-range
forward/backwards calls.

TEST=vm/cc/CodeRelocator_*

Fixes flutter/flutter#80043

Change-Id: Id4bdb7176108b61235dafb7ffc125da4a2bf07fa
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/195682
Commit-Queue: Martin Kustermann <kustermann@google.com>
Reviewed-by: Vyacheslav Egorov <vegorov@google.com>
  • Loading branch information
mkustermann authored and athomas committed Apr 26, 2021
1 parent ffd84c4 commit d9e96c1
Show file tree
Hide file tree
Showing 8 changed files with 481 additions and 62 deletions.
1 change: 1 addition & 0 deletions runtime/vm/compiler/compiler_sources.gni
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ compiler_sources_tests = [
"backend/typed_data_aot_test.cc",
"backend/yield_position_test.cc",
"cha_test.cc",
"relocation_test.cc",
"ffi/native_type_vm_test.cc",
"frontend/kernel_binary_flowgraph_test.cc",
"write_barrier_elimination_test.cc",
Expand Down
105 changes: 56 additions & 49 deletions runtime/vm/compiler/relocation.cc
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,47 @@ DEFINE_FLAG(bool,
false,
"Generate always trampolines (for testing purposes).");

DEFINE_FLAG(int,
lower_tail_pc_relative_call_distance,
-1,
"Lower tail call distance.");
DEFINE_FLAG(int,
upper_tail_pc_relative_call_distance,
-1,
"Upper tail call distance.");
DEFINE_FLAG(int, lower_pc_relative_call_distance, -1, "Lower call distance.");
DEFINE_FLAG(int, upper_pc_relative_call_distance, -1, "Upper call distance.");

struct TailCallDistanceLimits {
static intptr_t Lower() {
if (FLAG_lower_tail_pc_relative_call_distance != -1) {
return FLAG_lower_tail_pc_relative_call_distance;
}
return PcRelativeTailCallPattern::kLowerCallingRange;
}
static intptr_t Upper() {
if (FLAG_upper_tail_pc_relative_call_distance != -1) {
return FLAG_upper_tail_pc_relative_call_distance;
}
return PcRelativeTailCallPattern::kUpperCallingRange;
}
};

struct CallDistanceLimits {
static intptr_t Lower() {
if (FLAG_lower_pc_relative_call_distance != -1) {
return FLAG_lower_pc_relative_call_distance;
}
return PcRelativeCallPattern::kLowerCallingRange;
}
static intptr_t Upper() {
if (FLAG_upper_pc_relative_call_distance != -1) {
return FLAG_upper_pc_relative_call_distance;
}
return PcRelativeCallPattern::kUpperCallingRange;
}
};

const intptr_t kTrampolineSize =
Utils::RoundUp(PcRelativeTrampolineJumpPattern::kLengthInBytes,
compiler::target::Instructions::kBarePayloadAlignment);
Expand All @@ -46,7 +87,7 @@ void CodeRelocator::Relocate(bool is_vm_isolate) {
// * the maximum number of calls
// * the maximum offset into a target instruction
//
FindInstructionAndCallLimits();
FindLargestInstruction();

// Emit all instructions and do relocations on the way.
for (intptr_t i = 0; i < code_objects_->length(); ++i) {
Expand All @@ -65,7 +106,8 @@ void CodeRelocator::Relocate(bool is_vm_isolate) {

// If we have forward/backwards calls which are almost out-of-range, we'll
// create trampolines now.
BuildTrampolinesForAlmostOutOfRangeCalls();
BuildTrampolinesForAlmostOutOfRangeCalls(
/*force=*/(i == (code_objects_->length() - 1)));
}

// We're guaranteed to have all calls resolved, since
Expand Down Expand Up @@ -101,7 +143,7 @@ void CodeRelocator::Relocate(bool is_vm_isolate) {
// however we might need it to write information into V8 snapshot profile.
}

void CodeRelocator::FindInstructionAndCallLimits() {
void CodeRelocator::FindLargestInstruction() {
auto zone = thread_->zone();
auto& current_caller = Code::Handle(zone);
auto& call_targets = Array::Handle(zone);
Expand All @@ -122,48 +164,10 @@ void CodeRelocator::FindInstructionAndCallLimits() {
kind_type_and_offset_ = call.Get<Code::kSCallTableKindAndOffset>();
const auto kind =
Code::KindField::decode(kind_type_and_offset_.Value());
const auto return_pc_offset =
Code::OffsetField::decode(kind_type_and_offset_.Value());
const auto call_entry_point =
Code::EntryPointField::decode(kind_type_and_offset_.Value());

if (kind == Code::kCallViaCode) {
continue;
}

destination_ = GetTarget(call);
num_calls++;

// A call site can decide to jump not to the beginning of a function but
// rather jump into it at a certain (positive) offset.
int32_t offset_into_target = 0;
if (kind == Code::kPcRelativeCall || kind == Code::kPcRelativeTTSCall) {
const intptr_t call_instruction_offset =
return_pc_offset - PcRelativeCallPattern::kLengthInBytes;
PcRelativeCallPattern call(current_caller.PayloadStart() +
call_instruction_offset);
ASSERT(call.IsValid());
offset_into_target = call.distance();
} else {
ASSERT(kind == Code::kPcRelativeTailCall);
const intptr_t call_instruction_offset =
return_pc_offset - PcRelativeTailCallPattern::kLengthInBytes;
PcRelativeTailCallPattern call(current_caller.PayloadStart() +
call_instruction_offset);
ASSERT(call.IsValid());
offset_into_target = call.distance();
}

const uword destination_payload = destination_.PayloadStart();
const uword entry_point = call_entry_point == Code::kUncheckedEntry
? destination_.UncheckedEntryPoint()
: destination_.EntryPoint();

offset_into_target += (entry_point - destination_payload);

if (offset_into_target > max_offset_into_target_) {
max_offset_into_target_ = offset_into_target;
}
}

if (num_calls > max_calls_) {
Expand Down Expand Up @@ -323,8 +327,11 @@ bool CodeRelocator::TryResolveBackwardsCall(UnresolvedCall* unresolved_call) {
auto map_entry = text_offsets_.Lookup(callee);
if (map_entry == nullptr) return false;

ResolveCall(unresolved_call);
return true;
if (IsTargetInRangeFor(unresolved_call, map_entry->value)) {
ResolveCall(unresolved_call);
return true;
}
return false;
}

void CodeRelocator::ResolveUnresolvedCallsTargeting(
Expand Down Expand Up @@ -411,11 +418,11 @@ bool CodeRelocator::IsTargetInRangeFor(UnresolvedCall* unresolved_call,
const auto forward_distance =
target_text_offset - unresolved_call->text_offset;
if (unresolved_call->is_tail_call) {
return PcRelativeTailCallPattern::kLowerCallingRange < forward_distance &&
forward_distance < PcRelativeTailCallPattern::kUpperCallingRange;
return TailCallDistanceLimits::Lower() < forward_distance &&
forward_distance < TailCallDistanceLimits::Upper();
} else {
return PcRelativeCallPattern::kLowerCallingRange < forward_distance &&
forward_distance < PcRelativeCallPattern::kUpperCallingRange;
return CallDistanceLimits::Lower() < forward_distance &&
forward_distance < CallDistanceLimits::Upper();
}
}

Expand Down Expand Up @@ -471,7 +478,7 @@ CodePtr CodeRelocator::GetTarget(const StaticCallsTableEntry& call) {
return destination_.ptr();
}

void CodeRelocator::BuildTrampolinesForAlmostOutOfRangeCalls() {
void CodeRelocator::BuildTrampolinesForAlmostOutOfRangeCalls(bool force) {
while (!all_unresolved_calls_.IsEmpty()) {
UnresolvedCall* unresolved_call = all_unresolved_calls_.First();

Expand All @@ -484,7 +491,7 @@ void CodeRelocator::BuildTrampolinesForAlmostOutOfRangeCalls() {
kTrampolineSize *
(unresolved_calls_by_destination_.Length() + max_calls_);
if (IsTargetInRangeFor(unresolved_call, future_boundary) &&
!FLAG_always_generate_trampolines_for_testing) {
!FLAG_always_generate_trampolines_for_testing && !force) {
break;
}

Expand Down
5 changes: 2 additions & 3 deletions runtime/vm/compiler/relocation.h
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ class CodeRelocator : public StackResource {

void Relocate(bool is_vm_isolate);

void FindInstructionAndCallLimits();
void FindLargestInstruction();

bool AddInstructionsToText(CodePtr code);
void ScanCallTargets(const Code& code,
Expand All @@ -183,7 +183,7 @@ class CodeRelocator : public StackResource {
intptr_t destination_text);
void ResolveTrampoline(UnresolvedTrampoline* unresolved_trampoline);

void BuildTrampolinesForAlmostOutOfRangeCalls();
void BuildTrampolinesForAlmostOutOfRangeCalls(bool force);

intptr_t FindDestinationInText(const InstructionsPtr destination,
intptr_t offset_into_target);
Expand All @@ -207,7 +207,6 @@ class CodeRelocator : public StackResource {
intptr_t max_instructions_size_ = 0;
// The maximum number of pc-relative calls in an instructions object.
intptr_t max_calls_ = 0;
intptr_t max_offset_into_target_ = 0;

// Data structures used for relocation.
intptr_t next_text_offset_ = 0;
Expand Down
Loading

0 comments on commit d9e96c1

Please sign in to comment.