Skip to content

Commit 466a492

Browse files
LeszekSwirskiv8-scoped@luci-project-accounts.iam.gserviceaccount.com
authored andcommitted
[maglev] Use ContextScopeInfo distance in FunctionContextSpecialization
Resolve the outer specialization context in O(1) in FunctionContextSpecialization::TryToRef using the distance tracked in ContextScopeInfo, and route depth-0 context slot accesses through GetContextAtDepth. Previously, TryToRef required MinimizeContextChainDepth to unwrap a context node all the way back to the entry InitialValue(current_context), and depth-0 accesses bypassed GetContextAtDepth (requiring BuildRegisterFrameInitialization to special-case distance 0 at function entry). Using ContextScopeInfo's distance allows specializing from any tracked context value. Move specialization context and incoming ContextScopeInfo initialization to MaglevCompilationUnit via InitializeSpecializationContextForTopLevel and InitializeSpecializationContextForInlined, walking the incoming ScopeInfo chain to compute the specialization context distance for inlined units. TAG=agy CONV=a214c4a6-336e-4bef-9ebc-8451c556429e Bug: 558654408 Change-Id: I115c8de70941937eec45f4dc00346982b3a4b242 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/8445036 Auto-Submit: Leszek Swirski <leszeks@chromium.org> Reviewed-by: Toon Verwaest <verwaest@chromium.org> Commit-Queue: Leszek Swirski <leszeks@chromium.org> Cr-Commit-Position: refs/heads/main@{#110246}
1 parent ea680fe commit 466a492

8 files changed

Lines changed: 390 additions & 200 deletions

‎src/maglev/maglev-compilation-info.cc‎

Lines changed: 0 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -65,43 +65,6 @@ static bool SpecializeToFunctionContext(
6565

6666
} // namespace
6767

68-
void MaglevCompilationInfo::InitializeSpecializationContext() {
69-
#ifdef DEBUG
70-
specialization_context_initialized_ = true;
71-
#endif
72-
if (!v8_flags.always_specialize_for_script_context || toplevel_is_osr()) {
73-
return;
74-
}
75-
compiler::JSFunctionRef func_ref = compiler::MakeRefAssumeMemoryFence(
76-
broker_, broker_->CanonicalPersistentHandle(toplevel_function_));
77-
compiler::ContextRef current = func_ref.context(broker_);
78-
if (current.map(broker_).instance_type() == NATIVE_CONTEXT_TYPE) {
79-
return;
80-
}
81-
if (specialize_to_function_context_) {
82-
specialization_context_ = current;
83-
specialization_context_distance_ = 0;
84-
return;
85-
}
86-
size_t distance = 0;
87-
while (true) {
88-
InstanceType instance_type = current.map(broker_).instance_type();
89-
if (instance_type == NATIVE_CONTEXT_TYPE) {
90-
break;
91-
}
92-
if (instance_type == MODULE_CONTEXT_TYPE ||
93-
instance_type == SCRIPT_CONTEXT_TYPE) {
94-
specialization_context_ = current;
95-
specialization_context_distance_ = distance;
96-
return;
97-
}
98-
size_t step = 1;
99-
current = current.previous(broker_, &step);
100-
if (step != 0) break;
101-
distance++;
102-
}
103-
}
104-
10568
MaglevCompilationInfo::MaglevCompilationInfo(
10669
Isolate* isolate, IndirectHandle<JSFunction> function,
10770
BytecodeOffset osr_offset, std::optional<compiler::JSHeapBroker*> js_broker,

‎src/maglev/maglev-compilation-info.h‎

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -193,17 +193,6 @@ class MaglevCompilationInfo final {
193193
return specialize_to_function_context_;
194194
}
195195

196-
void InitializeSpecializationContext();
197-
198-
compiler::OptionalContextRef specialization_context() const {
199-
DCHECK(specialization_context_initialized_);
200-
return specialization_context_;
201-
}
202-
size_t specialization_context_distance() const {
203-
DCHECK(specialization_context_initialized_);
204-
return specialization_context_distance_;
205-
}
206-
207196
// Must be called from within a MaglevCompilationHandleScope. Transfers owned
208197
// handles (e.g. shared_, function_) to the new scope.
209198
void ReopenAndCanonicalizeHandlesInNewScope(Isolate* isolate);
@@ -292,12 +281,6 @@ class MaglevCompilationInfo final {
292281
// contexts.
293282
const bool specialize_to_function_context_;
294283

295-
compiler::OptionalContextRef specialization_context_;
296-
size_t specialization_context_distance_ = 0;
297-
#ifdef DEBUG
298-
bool specialization_context_initialized_ = false;
299-
#endif
300-
301284
// 1) PersistentHandles created via PersistentHandlesScope inside of
302285
// CompilationHandleScope.
303286
// 2) Owned by MaglevCompilationInfo.

‎src/maglev/maglev-compilation-unit.cc‎

Lines changed: 142 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include "src/compiler/js-heap-broker.h"
99
#include "src/maglev/maglev-compilation-info.h"
1010
#include "src/maglev/maglev-graph-labeller.h"
11+
#include "src/maglev/maglev-ir.h"
1112
#include "src/objects/js-function-inl.h"
1213

1314
namespace v8 {
@@ -26,7 +27,8 @@ MaglevCompilationUnit::MaglevCompilationUnit(MaglevCompilationInfo* info,
2627
MaglevCompilationUnit::MaglevCompilationUnit(
2728
MaglevCompilationInfo* info, const MaglevCompilationUnit* caller,
2829
compiler::SharedFunctionInfoRef shared_function_info,
29-
compiler::FeedbackCellRef feedback_cell)
30+
compiler::FeedbackCellRef feedback_cell, ValueNode* context,
31+
ValueNode* function)
3032
: info_(info),
3133
caller_(caller),
3234
shared_function_info_(shared_function_info),
@@ -41,6 +43,145 @@ MaglevCompilationUnit::MaglevCompilationUnit(
4143
DCHECK_EQ(bytecode_->parameter_count(),
4244
shared_function_info
4345
.internal_formal_parameter_count_with_receiver_deprecated());
46+
if (caller != nullptr) {
47+
InitializeSpecializationContextForInlined(context, function);
48+
}
49+
}
50+
51+
namespace {
52+
std::pair<compiler::ScopeInfoRef, bool> GetIncomingContextScopeInfo(
53+
compiler::JSHeapBroker* broker,
54+
compiler::SharedFunctionInfoRef shared_function_info) {
55+
compiler::ScopeInfoRef scope_info = shared_function_info.scope_info(broker);
56+
if (scope_info.HasOuterScopeInfo()) {
57+
scope_info = scope_info.OuterScopeInfo(broker);
58+
CHECK(scope_info.HasContext());
59+
return {scope_info, true};
60+
}
61+
return {scope_info,
62+
shared_function_info.is_toplevel() && scope_info.HasContext()};
63+
}
64+
65+
std::optional<std::pair<compiler::ContextRef, size_t>>
66+
FindModuleOrScriptContext(compiler::JSHeapBroker* broker,
67+
compiler::ContextRef current) {
68+
size_t dist = 0;
69+
while (true) {
70+
InstanceType instance_type = current.map(broker).instance_type();
71+
if (instance_type == NATIVE_CONTEXT_TYPE) {
72+
return std::nullopt;
73+
}
74+
if (instance_type == MODULE_CONTEXT_TYPE ||
75+
instance_type == SCRIPT_CONTEXT_TYPE) {
76+
return std::make_pair(current, dist);
77+
}
78+
size_t step = 1;
79+
current = current.previous(broker, &step);
80+
if (step != 0) return std::nullopt;
81+
dist++;
82+
}
83+
}
84+
} // namespace
85+
86+
void MaglevCompilationUnit::InitializeSpecializationContextFromKnownContext(
87+
compiler::ContextRef current, compiler::ScopeInfoRef scope_info,
88+
bool has_incoming_context_scope, bool specialize_to_function_context) {
89+
std::optional<size_t> distance;
90+
if (has_incoming_context_scope) {
91+
if (specialize_to_function_context) {
92+
if (current.map(broker()).instance_type() != NATIVE_CONTEXT_TYPE) {
93+
specialization_context_ = current;
94+
distance = 0;
95+
}
96+
} else if (v8_flags.always_specialize_for_script_context) {
97+
if (auto found = FindModuleOrScriptContext(broker(), current)) {
98+
specialization_context_ = found->first;
99+
distance = found->second;
100+
}
101+
}
102+
}
103+
incoming_context_scope_info_ = ContextScopeInfo(scope_info, distance);
104+
}
105+
106+
void MaglevCompilationUnit::InitializeSpecializationContextForTopLevel() {
107+
DCHECK(!is_inline());
108+
DCHECK(!specialization_context_initialized_);
109+
#ifdef DEBUG
110+
specialization_context_initialized_ = true;
111+
#endif
112+
auto [scope_info, has_incoming_context_scope] =
113+
GetIncomingContextScopeInfo(broker(), *shared_function_info_);
114+
if (v8_flags.always_specialize_for_script_context && !is_osr()) {
115+
compiler::JSFunctionRef func_ref = compiler::MakeRefAssumeMemoryFence(
116+
broker(),
117+
broker()->CanonicalPersistentHandle(info_->toplevel_function()));
118+
InitializeSpecializationContextFromKnownContext(
119+
func_ref.context(broker()), scope_info, has_incoming_context_scope,
120+
info_->specialize_to_function_context());
121+
} else {
122+
incoming_context_scope_info_ = ContextScopeInfo(scope_info);
123+
}
124+
}
125+
126+
void MaglevCompilationUnit::InitializeSpecializationContextForInlined(
127+
ValueNode* context, ValueNode* function) {
128+
DCHECK(is_inline());
129+
DCHECK_NOT_NULL(context);
130+
DCHECK_NOT_NULL(function);
131+
DCHECK(!specialization_context_initialized_);
132+
#ifdef DEBUG
133+
specialization_context_initialized_ = true;
134+
#endif
135+
auto [scope_info, has_incoming_context_scope] =
136+
GetIncomingContextScopeInfo(broker(), *shared_function_info_);
137+
if (!v8_flags.always_specialize_for_script_context ||
138+
info_->toplevel_is_osr() || !has_incoming_context_scope) {
139+
incoming_context_scope_info_ = ContextScopeInfo(scope_info);
140+
return;
141+
}
142+
143+
// Case 1: Inlined unit with a known constant context (e.g. a known constant
144+
// JSFunctionRef, which could even be from another script).
145+
if (HeapConstant* constant_context = context->TryCast<HeapConstant>()) {
146+
InitializeSpecializationContextFromKnownContext(
147+
constant_context->ref().AsContext(), scope_info,
148+
has_incoming_context_scope,
149+
v8_flags.maglev_function_context_specialization);
150+
return;
151+
}
152+
153+
// Case 2: Closure created by us (`FastCreateClosure` / `CreateClosure`) can
154+
// specialize to `caller_->specialization_context()`.
155+
// Case 3: Dynamic closure via `FeedbackCell` cannot specialize to a
156+
// `FunctionContext`, so walk `caller_->specialization_context()` outward to
157+
// find an enclosing `SCRIPT_CONTEXT_TYPE` or `MODULE_CONTEXT_TYPE`.
158+
compiler::OptionalContextRef candidate;
159+
if (function->Is<FastCreateClosure>() || function->Is<CreateClosure>()) {
160+
candidate = caller_->specialization_context();
161+
} else if (caller_->specialization_context().has_value()) {
162+
if (auto found = FindModuleOrScriptContext(
163+
broker(), *caller_->specialization_context())) {
164+
candidate = found->first;
165+
}
166+
}
167+
168+
std::optional<size_t> distance;
169+
if (candidate.has_value()) {
170+
compiler::ScopeInfoRef outer_scope = candidate->scope_info(broker());
171+
compiler::ScopeInfoRef curr = scope_info;
172+
size_t dist = 0;
173+
while (true) {
174+
if (curr.equals(outer_scope)) {
175+
specialization_context_ = candidate;
176+
distance = dist;
177+
break;
178+
}
179+
if (!curr.HasOuterScopeInfo()) break;
180+
curr = curr.OuterScopeInfo(broker());
181+
dist++;
182+
}
183+
}
184+
incoming_context_scope_info_ = ContextScopeInfo(scope_info, distance);
44185
}
45186

46187
MaglevCompilationUnit::MaglevCompilationUnit(

0 commit comments

Comments
 (0)