[maglev][inline] Refactor inner graph building to BuildInlined

Bug: v8:7700
Change-Id: Ie17aff5cff54f4640dd94f822e95e92bfd373890
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4218732
Reviewed-by: Leszek Swirski <leszeks@chromium.org>
Auto-Submit: Victor Gomes <victorgomes@chromium.org>
Commit-Queue: Victor Gomes <victorgomes@chromium.org>
Cr-Commit-Position: refs/heads/main@{#85662}
This commit is contained in:
Victor Gomes 2023-02-03 17:58:46 +01:00 committed by V8 LUCI CQ
parent 1cf95e3e49
commit 64af278b30
2 changed files with 72 additions and 62 deletions

View File

@ -2998,6 +2998,70 @@ void MaglevGraphBuilder::VisitFindNonDefaultConstructorOrConstruct() {
StoreRegisterPair(result, call_builtin);
}
ReduceResult MaglevGraphBuilder::BuildInlined(const CallArguments& args,
BasicBlockRef* start_ref,
BasicBlockRef* end_ref) {
DCHECK(is_inline());
// Manually create the prologue of the inner function graph, so that we
// can manually set up the arguments.
StartPrologue();
RootConstant* undefined_constant =
GetRootConstant(RootIndex::kUndefinedValue);
if (args.receiver_mode() == ConvertReceiverMode::kNullOrUndefined) {
if (function().shared().language_mode() == LanguageMode::kSloppy) {
// TODO(leszeks): Store the global proxy somehow.
SetArgument(0, undefined_constant);
} else {
SetArgument(0, undefined_constant);
}
} else {
SetArgument(0, args.receiver());
}
for (int i = 1; i < parameter_count(); i++) {
ValueNode* arg_value = args[i - 1];
if (arg_value == nullptr) arg_value = undefined_constant;
SetArgument(i, arg_value);
}
BuildRegisterFrameInitialization(GetConstant(function().context()),
GetConstant(function()));
BuildMergeStates();
BasicBlock* inlined_prologue = EndPrologue();
// Set the entry JumpToInlined to jump to the prologue block.
// TODO(leszeks): Passing start_ref to JumpToInlined creates a two-element
// linked list of refs. Consider adding a helper to explicitly set the target
// instead.
start_ref->SetToBlockAndReturnNext(inlined_prologue)
->SetToBlockAndReturnNext(inlined_prologue);
// Build the inlined function body.
BuildBody();
// All returns in the inlined body jump to a merge point one past the
// bytecode length (i.e. at offset bytecode.length()). Create a block at
// this fake offset and have it jump out of the inlined function, into a new
// block that we create which resumes execution of the outer function.
// TODO(leszeks): Wrap this up in a helper.
DCHECK_NULL(current_block_);
// If we don't have a merge state at the inline_exit_offset, then there is no
// control flow that reaches the end of the inlined function, either because
// of infinite loops or deopts
if (merge_states_[inline_exit_offset()] == nullptr) {
return ReduceResult::DoneWithAbort();
}
ProcessMergePoint(inline_exit_offset());
StartNewBlock(inline_exit_offset());
FinishBlock<JumpFromInlined>({}, end_ref);
// Pull the returned accumulator value out of the inlined function's final
// merged return state.
return current_interpreter_frame_.accumulator();
}
ReduceResult MaglevGraphBuilder::TryBuildInlinedCall(
compiler::JSFunctionRef function, CallArguments& args) {
// Don't try to inline if the target function hasn't been compiled yet.
@ -3025,12 +3089,6 @@ ReduceResult MaglevGraphBuilder::TryBuildInlinedCall(
if (v8_flags.trace_maglev_inlining) {
std::cout << " inlining " << function.shared() << std::endl;
}
// The undefined constant node has to be created before the inner graph is
// created.
RootConstant* undefined_constant;
if (args.receiver_mode() == ConvertReceiverMode::kNullOrUndefined) {
undefined_constant = GetRootConstant(RootIndex::kUndefinedValue);
}
// Create a new compilation unit and graph builder for the inlined
// function.
@ -3043,60 +3101,13 @@ ReduceResult MaglevGraphBuilder::TryBuildInlinedCall(
BasicBlockRef start_ref, end_ref;
BasicBlock* block = FinishBlock<JumpToInlined>({}, &start_ref, inner_unit);
// Manually create the prologue of the inner function graph, so that we
// can manually set up the arguments.
inner_graph_builder.StartPrologue();
if (args.receiver_mode() == ConvertReceiverMode::kNullOrUndefined) {
if (function.shared().language_mode() == LanguageMode::kSloppy) {
// TODO(leszeks): Store the global proxy somehow.
inner_graph_builder.SetArgument(0, undefined_constant);
} else {
inner_graph_builder.SetArgument(0, undefined_constant);
}
} else {
inner_graph_builder.SetArgument(0, args.receiver());
}
for (int i = 1; i < inner_unit->parameter_count(); i++) {
ValueNode* arg_value = args[i - 1];
if (arg_value == nullptr) arg_value = undefined_constant;
inner_graph_builder.SetArgument(i, arg_value);
}
inner_graph_builder.BuildRegisterFrameInitialization(
GetConstant(function.context()), GetConstant(function));
inner_graph_builder.BuildMergeStates();
BasicBlock* inlined_prologue = inner_graph_builder.EndPrologue();
// Set the entry JumpToInlined to jump to the prologue block.
// TODO(leszeks): Passing start_ref to JumpToInlined creates a two-element
// linked list of refs. Consider adding a helper to explicitly set the target
// instead.
start_ref.SetToBlockAndReturnNext(inlined_prologue)
->SetToBlockAndReturnNext(inlined_prologue);
// Build the inlined function body.
inner_graph_builder.BuildBody();
// All returns in the inlined body jump to a merge point one past the
// bytecode length (i.e. at offset bytecode.length()). Create a block at
// this fake offset and have it jump out of the inlined function, into a new
// block that we create which resumes execution of the outer function.
// TODO(leszeks): Wrap this up in a helper.
DCHECK_NULL(inner_graph_builder.current_block_);
// If we don't have a merge state at the inline_exit_offset, then all the
// paths in the inlined function emit a "soft" deopt.
if (inner_graph_builder
.merge_states_[inner_graph_builder.inline_exit_offset()] == nullptr) {
// Mark parent branch as dead.
ReduceResult result =
inner_graph_builder.BuildInlined(args, &start_ref, &end_ref);
if (result.IsDoneWithAbort()) {
MarkBytecodeDead();
return ReduceResult::DoneWithAbort();
}
inner_graph_builder.ProcessMergePoint(
inner_graph_builder.inline_exit_offset());
inner_graph_builder.StartNewBlock(inner_graph_builder.inline_exit_offset());
inner_graph_builder.FinishBlock<JumpFromInlined>({}, &end_ref);
DCHECK(result.HasValue());
// Create a new block at our current offset, and resume execution. Do this
// manually to avoid trying to resolve any merges to this offset, which will
@ -3111,12 +3122,8 @@ ReduceResult MaglevGraphBuilder::TryBuildInlinedCall(
end_ref.SetToBlockAndReturnNext(current_block_)
->SetToBlockAndReturnNext(current_block_);
// Pull the returned accumulator value out of the inlined function's final
// merged return state.
ValueNode* result =
inner_graph_builder.current_interpreter_frame_.accumulator();
#ifdef DEBUG
new_nodes_.insert(result);
new_nodes_.insert(result.value());
#endif
return result;
}

View File

@ -154,6 +154,9 @@ class MaglevGraphBuilder {
BuildBody();
}
ReduceResult BuildInlined(const CallArguments& args, BasicBlockRef* start_ref,
BasicBlockRef* end_ref);
void StartPrologue();
void SetArgument(int i, ValueNode* value);
void InitializeRegister(interpreter::Register reg,