v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
frame-elider.cc
Go to the documentation of this file.
1// Copyright 2015 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
6
7#include "src/base/iterator.h"
8
9namespace v8 {
10namespace internal {
11namespace compiler {
12
13FrameElider::FrameElider(InstructionSequence* code, bool has_dummy_end_block,
14 bool is_wasm_to_js)
15 : code_(code),
16 has_dummy_end_block_(has_dummy_end_block),
17 is_wasm_to_js_(is_wasm_to_js) {}
18
20 if (!v8_flags.turbo_elide_frames) {
21#ifdef DEBUG
22 for (InstructionBlock* block : instruction_blocks()) {
23 CHECK(block->needs_frame());
24 }
25#endif
26 return;
27 }
28 MarkBlocks();
31}
32
34 for (InstructionBlock* block : instruction_blocks()) {
35 if (block->needs_frame()) continue;
36 for (int i = block->code_start(); i < block->code_end(); ++i) {
38 if (instr->IsCall() || instr->IsDeoptimizeCall() ||
39 instr->arch_opcode() == ArchOpcode::kArchStackPointerGreaterThan ||
40 instr->arch_opcode() == ArchOpcode::kArchFramePointer) {
41 block->mark_needs_frame();
42 break;
43 }
44 if (instr->arch_opcode() == ArchOpcode::kArchStackSlot &&
45 ((instr->InputAt(0)->IsImmediate() &&
46 code_->GetImmediate(ImmediateOperand::cast(instr->InputAt(0)))
47 .ToInt32() > 0) ||
49 // We shouldn't allow accesses to the stack below the current stack
50 // pointer (indicated by positive slot indices).
51 // This is in particular because signal handlers (which could, of
52 // course, be triggered at any point in time) will overwrite this
53 // memory.
54 // Additionally wasm-to-JS code always requires a frame to address
55 // stack slots, because the stack pointer may switch to the central
56 // stack at the beginning of the code.
57 block->mark_needs_frame();
58 break;
59 }
60 }
61 }
62}
63
68
70 for (InstructionBlock* block : instruction_blocks()) {
71 if (block->needs_frame()) {
72 // Special case: The start block needs a frame.
73 if (block->predecessors().empty()) {
74 block->mark_must_construct_frame();
75 if (block->SuccessorCount() == 0) {
76 // We only have a single block, so the block also needs to be marked
77 // to deconstruct the frame.
78 const Instruction* last =
79 InstructionAt(block->last_instruction_index());
80 // The only cases when we need to deconstruct are ret and jump.
81 if (last->IsRet() || last->IsJump()) {
82 block->mark_must_deconstruct_frame();
83 }
84 }
85 }
86 // Find "frame -> no frame" transitions, inserting frame
87 // deconstructions.
88 for (RpoNumber& succ : block->successors()) {
89 if (!InstructionBlockAt(succ)->needs_frame()) {
90 DCHECK_EQ(1U, block->SuccessorCount());
91 const Instruction* last =
92 InstructionAt(block->last_instruction_index());
93 if (last->IsThrow() || last->IsTailCall() ||
94 last->IsDeoptimizeCall()) {
95 // We need to keep the frame if we exit the block through any
96 // of these.
97 continue;
98 }
99 // The only cases when we need to deconstruct are ret and jump.
100 DCHECK(last->IsRet() || last->IsJump());
101 block->mark_must_deconstruct_frame();
102 }
103 }
104 if (block->SuccessorCount() == 0) {
105 const Instruction* last =
106 InstructionAt(block->last_instruction_index());
107 // The only cases when we need to deconstruct are ret and jump.
108 if (last->IsRet() || last->IsJump()) {
109 block->mark_must_deconstruct_frame();
110 }
111 }
112 } else {
113 // Find "no frame -> frame" transitions, inserting frame constructions.
114 for (RpoNumber& succ : block->successors()) {
115 if (InstructionBlockAt(succ)->needs_frame()) {
116 DCHECK_NE(1U, block->SuccessorCount());
118 }
119 }
120 }
121 }
122}
123
125 bool changed = false;
126 for (InstructionBlock* block : instruction_blocks()) {
127 changed |= PropagateIntoBlock(block);
128 }
129 return changed;
130}
131
133 bool changed = false;
135 changed |= PropagateIntoBlock(block);
136 }
137 return changed;
138}
139
141 // Already marked, nothing to do...
142 if (block->needs_frame()) return false;
143
144 // Turbofan does have an empty dummy end block, which we need to ignore here.
145 // However, Turboshaft does not have such a block.
147 // Never mark the dummy end node, otherwise we might incorrectly decide to
148 // put frame deconstruction code there later,
149 if (block->successors().empty()) return false;
150 }
151
152 // Propagate towards the end ("downwards") if there is a predecessor needing
153 // a frame, but don't "bleed" from deferred code to non-deferred code.
154 for (RpoNumber& pred : block->predecessors()) {
155 if (InstructionBlockAt(pred)->needs_frame() &&
156 (!InstructionBlockAt(pred)->IsDeferred() || block->IsDeferred())) {
157 block->mark_needs_frame();
158 return true;
159 }
160 }
161
162 // Propagate towards start ("upwards")
163 bool need_frame_successors = false;
164 if (block->SuccessorCount() == 1) {
165 // For single successors, propagate the needs_frame information.
166 need_frame_successors =
167 InstructionBlockAt(block->successors()[0])->needs_frame();
168 } else {
169 // For multiple successors, each successor must only have a single
170 // predecessor (because the graph is in edge-split form), so each successor
171 // can independently create/dismantle a frame if needed. Given this
172 // independent control, only propagate needs_frame if all non-deferred
173 // blocks need a frame.
174 for (RpoNumber& succ : block->successors()) {
175 InstructionBlock* successor_block = InstructionBlockAt(succ);
176 DCHECK_EQ(1, successor_block->PredecessorCount());
177 if (!successor_block->IsDeferred()) {
178 if (successor_block->needs_frame()) {
179 need_frame_successors = true;
180 } else {
181 return false;
182 }
183 }
184 }
185 }
186 if (need_frame_successors) {
187 block->mark_needs_frame();
188 return true;
189 } else {
190 return false;
191 }
192}
193
197
199 return code_->InstructionBlockAt(rpo_number);
200}
201
203 return code_->InstructionAt(index);
204}
205
206} // namespace compiler
207} // namespace internal
208} // namespace v8
InstructionBlock * InstructionBlockAt(RpoNumber rpo_number) const
InstructionSequence *const code_
Instruction * InstructionAt(int index) const
const InstructionBlocks & instruction_blocks() const
bool PropagateIntoBlock(InstructionBlock *block)
FrameElider(InstructionSequence *code, bool has_dummy_end_block, bool is_wasm_to_js)
Constant GetImmediate(const ImmediateOperand *op) const
Instruction * InstructionAt(int index) const
const InstructionBlocks & instruction_blocks() const
InstructionBlock * InstructionBlockAt(RpoNumber rpo_number)
ZoneList< RegExpInstruction > code_
Instruction * instr
auto Reversed(T &t)
Definition iterator.h:105
V8_EXPORT_PRIVATE FlagValues v8_flags
#define CHECK(condition)
Definition logging.h:124
#define DCHECK_NE(v1, v2)
Definition logging.h:486
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_EQ(v1, v2)
Definition logging.h:485