v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
string-escape-analysis-reducer.cc
Go to the documentation of this file.
1// Copyright 2024 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 <utility>
8
12
14
16 for (uint32_t processed = graph_.block_count(); processed > 0; --processed) {
17 BlockIndex block_index = static_cast<BlockIndex>(processed - 1);
18
19 const Block& block = graph_.Get(block_index);
20 ProcessBlock(block);
21 }
22
23 // Because of loop phis, some StringConcat could now be escaping even though
24 // they weren't escaping on first use.
26
27 // Now that we know for a fact which StringConcat will be elided, we can
28 // compute which FrameStates will need to be reconstructed in the reducer.
30}
31
34 switch (it->current_instr()) {
36 case Instr::kInput: {
38 OpIndex input;
39 it->ConsumeInput(&type, &input);
40 MarkAsEscaping(input);
41 return;
42 }
43 case Instr::kArgumentsElements:
44 case Instr::kArgumentsLength:
45 case Instr::kRestLength:
46 case Instr::kDematerializedObjectReference:
47 case Instr::kDematerializedObject:
48 case Instr::kDematerializedStringConcat:
49 case Instr::kDematerializedStringConcatReference:
50 case Instr::kUnusedRegister:
51 return;
52 }
53}
54
56 const FrameStateOp& framestate) {
58 std::max<uint32_t>(max_frame_state_input_count_, framestate.input_count);
59 for (V<Any> input_idx : framestate.inputs()) {
60 if (graph_.Get(input_idx).Is<StringConcatOp>()) {
61 // This FrameState has a StringConcat as input, so we might need to
62 // recreate it in the reducer.
64 break;
65 }
66 }
67
68 // We need to mark the Function and the Receiver as escaping. See
69 // https://crbug.com/40059369.
70 auto it = framestate.data->iterator(framestate.state_values());
71 // Function
73 // 1st parameter = receiver
75
76 // Other FrameState uses are not considered as escaping.
77}
78
80 for (V<Any> index : base::Reversed(graph_.OperationIndices(block))) {
81 const Operation& op = graph_.Get(index);
82 switch (op.opcode) {
83 case Opcode::kFrameState:
85 break;
86 case Opcode::kStringConcat:
87 // The inputs of a StringConcat are only escaping if the StringConcat
88 // itself is already escaping itself.
89 if (IsEscaping(index)) {
91 } else {
93 }
94 break;
95 case Opcode::kStringLength:
96 // The first input to StringConcat is the length of the result, which
97 // means that StringLength won't prevent eliding StringConcat:
98 // StringLength(StringConcat(len, left, rigth)) == len
99 break;
100 default:
101 // By default, all uses are considered as escaping their inputs.
103 }
104 }
105}
106
108 for (V<Any> input : op.inputs()) {
109 if (!graph_.Get(input).Is<FrameStateOp>()) {
110 MarkAsEscaping(input);
111 }
112 }
113}
114
116 const StringConcatOp* concat) {
118 to_mark.push_back(concat);
119
120 while (!to_mark.empty()) {
121 const StringConcatOp* curr = to_mark.back();
122 to_mark.pop_back();
123
124 for (V<Any> input_index : curr->inputs()) {
125 const Operation& input = graph_.Get(input_index);
126 if (input.Is<StringConcatOp>() && !IsEscaping(input_index)) {
127 MarkAsEscaping(input_index);
128 to_mark.push_back(&input.Cast<StringConcatOp>());
129 }
130 }
131 }
132}
133
135 constexpr uint32_t kMaxOpInputCount = std::numeric_limits<
136 decltype(std::declval<Operation>().input_count)>::max();
138 kMaxOpInputCount) {
139 // There is a risk that in order to elide some StringConcat, we end up
140 // needing more inputs for a FrameState than the maximum number of possible
141 // inputs. Note that this is a bit of an overapproximation, but it should
142 // still happen very rarely since it would require a huge function with
143 // thousand of local variables and/or parameters. When this happens, we mark
144 // all operations as "escaping", so that the reducer doesn't try to elide
145 // anything.
147 MarkAsEscaping(index);
148 }
149 }
150
152 if (IsEscaping(index)) {
154 &graph_.Get(index).Cast<StringConcatOp>());
155 }
156 }
157}
158
160 for (V<FrameState> frame_state_idx : maybe_to_reconstruct_frame_states_) {
161 const FrameStateOp& frame_state =
162 graph_.Get(frame_state_idx).Cast<FrameStateOp>();
163 for (V<Any> input : frame_state.inputs()) {
164 if (graph_.Get(input).Is<StringConcatOp>() && !IsEscaping(input)) {
165 RecursiveMarkAsShouldReconstruct(frame_state_idx);
166 break;
167 }
168 }
169 }
170}
171
172} // namespace v8::internal::compiler::turboshaft
void pop_back(size_t count=1)
void ProcessFrameState(V< FrameState > index, const FrameStateOp &framestate)
auto Reversed(T &t)
Definition iterator.h:105
uint32_t concat
base::Vector< const OpIndex > state_values() const
base::Vector< const OpIndex > inputs() const
underlying_operation_t< Op > & Cast()
Definition operations.h:980
wasm::ValueType type