[maglev] Hand over KnownNodeAspects on unconditional jumps

RecomputeKnownNodeAspectsProcessor merges the current KNA into the
target's merge state on every Jump/CheckpointedJump. For the first
predecessor, MergeNodeAspects deep-copies the KNA.

After an unconditional jump the source KNA is dead. If the target has no
KNA yet, it can therefore take the pointer (move) instead of a copy,
Otherwise we merge as before.

This helps heavily inlined straight-line code, as it produces long
chains of single-predecessor blocks whose KNA keeps growing along the
body.

Bug: 42204525
Change-Id: I677e2263417964ae03c96267866e3ab16a6a6964
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/8493464
Reviewed-by: Darius Mercadier <dmercadier@chromium.org>
Commit-Queue: Marco Vitale <mrcvtl@chromium.org>
Cr-Commit-Position: refs/heads/main@{#110216}
This commit is contained in:
Marco Vitale authored and v8-scoped@luci-project-accounts.iam.gserviceaccount.com committed 2026-10-01 01:01:18 -07:00
1 parent c6d7e7fc8f
commit fb2fbf17f6
2 files changed
+33 -10

No files matched your search

@@ -492,6 +492,19 @@ class MergePointInterpreterFrameState {
}
}
// Adopts or merges `known_node_aspects`, and nulls it out to guarantee
// it is not reused by the caller.
void MergeNodeAspects(Zone* zone, KnownNodeAspects** known_node_aspects) {
DCHECK_NOT_NULL(known_node_aspects);
KnownNodeAspects* source = std::exchange(*known_node_aspects, nullptr);
DCHECK_NOT_NULL(source);
if (!known_node_aspects_) {
known_node_aspects_ = source;
} else {
known_node_aspects_->Merge(*source, zone);
}
}
const CompactInterpreterFrameState& frame_state() const {
return frame_state_;
}
+20 -10
View File
@@ -79,6 +79,13 @@ class RecomputeKnownNodeAspectsProcessor {
return &current_node()->eager_deopt_info()->top_frame();
}
static BasicBlock* SkipEdgeSplits(BasicBlock* block) {
while (block->is_edge_split_block()) {
block = block->control_node()->Cast<Jump>()->target();
}
return block;
}
BlockProcessResult PreProcessBasicBlock(BasicBlock* block) {
// TODO(victorgomes): Clean up set_current_block usage; now both
// MaglevGraphOptimizer and RecomputeKnownNodeAspectsProcessor set it.
@@ -107,11 +114,8 @@ class RecomputeKnownNodeAspectsProcessor {
known_node_aspects_ = block->state()->TakeKnownNodeAspects();
} else if (block->is_edge_split_block()) {
// Clone the next available KNA.
BasicBlock* next_block = block;
while (next_block->is_edge_split_block()) {
next_block = next_block->control_node()->Cast<Jump>()->target();
}
known_node_aspects_ = next_block->state()->CloneKnownNodeAspects(zone());
known_node_aspects_ =
SkipEdgeSplits(block)->state()->CloneKnownNodeAspects(zone());
} else {
is_fallthrough = true;
}
@@ -229,12 +233,12 @@ class RecomputeKnownNodeAspectsProcessor {
}
ProcessResult Process(Jump* node, const ProcessingState& state) {
Merge(node->target());
MergeFromDeadSource(node->target());
return ProcessResult::kContinue;
}
ProcessResult Process(CheckpointedJump* node, const ProcessingState& state) {
Merge(node->target());
MergeFromDeadSource(node->target());
return ProcessResult::kContinue;
}
@@ -302,14 +306,20 @@ class RecomputeKnownNodeAspectsProcessor {
V8_NODISCARD ProcessResult OnContradiction();
void Merge(BasicBlock* block) {
while (block->is_edge_split_block()) {
block = block->control_node()->Cast<Jump>()->target();
}
block = SkipEdgeSplits(block);
// If we don't have state, this must be a fallthrough basic block.
if (!block->has_state()) return;
block->state()->MergeNodeAspects(zone(), *known_node_aspects_);
}
// Like Merge, but consume known_node_aspects_ instead of copying it.
void MergeFromDeadSource(BasicBlock* block) {
block = SkipEdgeSplits(block);
// If we don't have state, this must be a fallthrough basic block.
if (!block->has_state()) return;
block->state()->MergeNodeAspects(zone(), &known_node_aspects_);
}
template <typename NodeT>
void MarkPossibleSideEffect(NodeT* node) {
known_node_aspects().MarkPossibleSideEffect(node, broker(),