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
5 #ifndef V8_INTERPRETER_BYTECODE_PIPELINE_H_
6 #define V8_INTERPRETER_BYTECODE_PIPELINE_H_
7
8 #include "src/base/compiler-specific.h"
9 #include "src/globals.h"
10 #include "src/interpreter/bytecode-register-allocator.h"
11 #include "src/interpreter/bytecode-register.h"
12 #include "src/interpreter/bytecodes.h"
13 #include "src/objects.h"
14 #include "src/zone/zone-containers.h"
15
16 namespace v8 {
17 namespace internal {
18 namespace interpreter {
19
20 class BytecodeLabel;
21 class BytecodeNode;
22 class BytecodeSourceInfo;
23
24 // Interface for bytecode pipeline stages.
25 class BytecodePipelineStage {
26 public:
~BytecodePipelineStage()27 virtual ~BytecodePipelineStage() {}
28
29 // Write bytecode node |node| into pipeline. The node is only valid
30 // for the duration of the call. Callee's should clone it if
31 // deferring Write() to the next stage.
32 virtual void Write(BytecodeNode* node) = 0;
33
34 // Write jump bytecode node |node| which jumps to |label| into pipeline.
35 // The node and label are only valid for the duration of the call. This call
36 // implicitly ends the current basic block so should always write to the next
37 // stage.
38 virtual void WriteJump(BytecodeNode* node, BytecodeLabel* label) = 0;
39
40 // Binds |label| to the current bytecode location. This call implicitly
41 // ends the current basic block and so any deferred bytecodes should be
42 // written to the next stage.
43 virtual void BindLabel(BytecodeLabel* label) = 0;
44
45 // Binds |label| to the location of |target|. This call implicitly
46 // ends the current basic block and so any deferred bytecodes should be
47 // written to the next stage.
48 virtual void BindLabel(const BytecodeLabel& target, BytecodeLabel* label) = 0;
49
50 // Flush the pipeline and generate a bytecode array.
51 virtual Handle<BytecodeArray> ToBytecodeArray(
52 Isolate* isolate, int register_count, int parameter_count,
53 Handle<FixedArray> handler_table) = 0;
54 };
55
56 // Source code position information.
57 class BytecodeSourceInfo final {
58 public:
59 static const int kUninitializedPosition = -1;
60
BytecodeSourceInfo()61 BytecodeSourceInfo()
62 : position_type_(PositionType::kNone),
63 source_position_(kUninitializedPosition) {}
64
BytecodeSourceInfo(int source_position,bool is_statement)65 BytecodeSourceInfo(int source_position, bool is_statement)
66 : position_type_(is_statement ? PositionType::kStatement
67 : PositionType::kExpression),
68 source_position_(source_position) {
69 DCHECK_GE(source_position, 0);
70 }
71
72 // Makes instance into a statement position.
MakeStatementPosition(int source_position)73 void MakeStatementPosition(int source_position) {
74 // Statement positions can be replaced by other statement
75 // positions. For example , "for (x = 0; x < 3; ++x) 7;" has a
76 // statement position associated with 7 but no bytecode associated
77 // with it. Then Next is emitted after the body and has
78 // statement position and overrides the existing one.
79 position_type_ = PositionType::kStatement;
80 source_position_ = source_position;
81 }
82
83 // Makes instance into an expression position. Instance should not
84 // be a statement position otherwise it could be lost and impair the
85 // debugging experience.
MakeExpressionPosition(int source_position)86 void MakeExpressionPosition(int source_position) {
87 DCHECK(!is_statement());
88 position_type_ = PositionType::kExpression;
89 source_position_ = source_position;
90 }
91
92 // Forces an instance into an expression position.
ForceExpressionPosition(int source_position)93 void ForceExpressionPosition(int source_position) {
94 position_type_ = PositionType::kExpression;
95 source_position_ = source_position;
96 }
97
source_position()98 int source_position() const {
99 DCHECK(is_valid());
100 return source_position_;
101 }
102
is_statement()103 bool is_statement() const {
104 return position_type_ == PositionType::kStatement;
105 }
is_expression()106 bool is_expression() const {
107 return position_type_ == PositionType::kExpression;
108 }
109
is_valid()110 bool is_valid() const { return position_type_ != PositionType::kNone; }
set_invalid()111 void set_invalid() {
112 position_type_ = PositionType::kNone;
113 source_position_ = kUninitializedPosition;
114 }
115
116 bool operator==(const BytecodeSourceInfo& other) const {
117 return position_type_ == other.position_type_ &&
118 source_position_ == other.source_position_;
119 }
120
121 bool operator!=(const BytecodeSourceInfo& other) const {
122 return position_type_ != other.position_type_ ||
123 source_position_ != other.source_position_;
124 }
125
126 private:
127 enum class PositionType : uint8_t { kNone, kExpression, kStatement };
128
129 PositionType position_type_;
130 int source_position_;
131 };
132
133 // A container for a generated bytecode, it's operands, and source information.
134 // These must be allocated by a BytecodeNodeAllocator instance.
NON_EXPORTED_BASE(ZoneObject)135 class V8_EXPORT_PRIVATE BytecodeNode final : NON_EXPORTED_BASE(ZoneObject) {
136 public:
137 INLINE(BytecodeNode(Bytecode bytecode,
138 BytecodeSourceInfo source_info = BytecodeSourceInfo()))
139 : bytecode_(bytecode),
140 operand_count_(0),
141 operand_scale_(OperandScale::kSingle),
142 source_info_(source_info) {
143 DCHECK_EQ(Bytecodes::NumberOfOperands(bytecode), operand_count());
144 }
145
146 INLINE(BytecodeNode(Bytecode bytecode, uint32_t operand0,
147 BytecodeSourceInfo source_info = BytecodeSourceInfo()))
148 : bytecode_(bytecode),
149 operand_count_(1),
150 operand_scale_(OperandScale::kSingle),
151 source_info_(source_info) {
152 DCHECK_EQ(Bytecodes::NumberOfOperands(bytecode), operand_count());
153 SetOperand(0, operand0);
154 }
155
156 INLINE(BytecodeNode(Bytecode bytecode, uint32_t operand0, uint32_t operand1,
157 BytecodeSourceInfo source_info = BytecodeSourceInfo()))
158 : bytecode_(bytecode),
159 operand_count_(2),
160 operand_scale_(OperandScale::kSingle),
161 source_info_(source_info) {
162 DCHECK_EQ(Bytecodes::NumberOfOperands(bytecode), operand_count());
163 SetOperand(0, operand0);
164 SetOperand(1, operand1);
165 }
166
167 INLINE(BytecodeNode(Bytecode bytecode, uint32_t operand0, uint32_t operand1,
168 uint32_t operand2,
169 BytecodeSourceInfo source_info = BytecodeSourceInfo()))
170 : bytecode_(bytecode),
171 operand_count_(3),
172 operand_scale_(OperandScale::kSingle),
173 source_info_(source_info) {
174 DCHECK_EQ(Bytecodes::NumberOfOperands(bytecode), operand_count());
175 SetOperand(0, operand0);
176 SetOperand(1, operand1);
177 SetOperand(2, operand2);
178 }
179
180 INLINE(BytecodeNode(Bytecode bytecode, uint32_t operand0, uint32_t operand1,
181 uint32_t operand2, uint32_t operand3,
182 BytecodeSourceInfo source_info = BytecodeSourceInfo()))
183 : bytecode_(bytecode),
184 operand_count_(4),
185 operand_scale_(OperandScale::kSingle),
186 source_info_(source_info) {
187 DCHECK_EQ(Bytecodes::NumberOfOperands(bytecode), operand_count());
188 SetOperand(0, operand0);
189 SetOperand(1, operand1);
190 SetOperand(2, operand2);
191 SetOperand(3, operand3);
192 }
193
194 #define DEFINE_BYTECODE_NODE_CREATOR(Name, ...) \
195 template <typename... Operands> \
196 INLINE(static BytecodeNode Name(BytecodeSourceInfo source_info, \
197 Operands... operands)) { \
198 return Create<Bytecode::k##Name, __VA_ARGS__>(source_info, operands...); \
199 }
200 BYTECODE_LIST(DEFINE_BYTECODE_NODE_CREATOR)
201 #undef DEFINE_BYTECODE_NODE_CREATOR
202
203 // Replace the bytecode of this node with |bytecode| and keep the operands.
204 void replace_bytecode(Bytecode bytecode) {
205 DCHECK_EQ(Bytecodes::NumberOfOperands(bytecode_),
206 Bytecodes::NumberOfOperands(bytecode));
207 bytecode_ = bytecode;
208 }
209
210 void update_operand0(uint32_t operand0) { SetOperand(0, operand0); }
211
212 // Print to stream |os|.
213 void Print(std::ostream& os) const;
214
215 // Transform to a node representing |new_bytecode| which has one
216 // operand more than the current bytecode.
217 void Transform(Bytecode new_bytecode, uint32_t extra_operand) {
218 DCHECK_EQ(Bytecodes::NumberOfOperands(new_bytecode),
219 Bytecodes::NumberOfOperands(bytecode()) + 1);
220 DCHECK(Bytecodes::NumberOfOperands(bytecode()) < 1 ||
221 Bytecodes::GetOperandType(new_bytecode, 0) ==
222 Bytecodes::GetOperandType(bytecode(), 0));
223 DCHECK(Bytecodes::NumberOfOperands(bytecode()) < 2 ||
224 Bytecodes::GetOperandType(new_bytecode, 1) ==
225 Bytecodes::GetOperandType(bytecode(), 1));
226 DCHECK(Bytecodes::NumberOfOperands(bytecode()) < 3 ||
227 Bytecodes::GetOperandType(new_bytecode, 2) ==
228 Bytecodes::GetOperandType(bytecode(), 2));
229 DCHECK(Bytecodes::NumberOfOperands(bytecode()) < 4);
230
231 bytecode_ = new_bytecode;
232 operand_count_++;
233 SetOperand(operand_count() - 1, extra_operand);
234 }
235
236 Bytecode bytecode() const { return bytecode_; }
237
238 uint32_t operand(int i) const {
239 DCHECK_LT(i, operand_count());
240 return operands_[i];
241 }
242 const uint32_t* operands() const { return operands_; }
243
244 int operand_count() const { return operand_count_; }
245 OperandScale operand_scale() const { return operand_scale_; }
246
247 const BytecodeSourceInfo& source_info() const { return source_info_; }
248 void set_source_info(BytecodeSourceInfo source_info) {
249 source_info_ = source_info;
250 }
251
252 bool operator==(const BytecodeNode& other) const;
253 bool operator!=(const BytecodeNode& other) const { return !(*this == other); }
254
255 private:
256 template <Bytecode bytecode, AccumulatorUse accumulator_use,
257 OperandType... operand_types>
258 friend class BytecodeNodeBuilder;
259
260 INLINE(BytecodeNode(Bytecode bytecode, int operand_count,
261 OperandScale operand_scale,
262 BytecodeSourceInfo source_info, uint32_t operand0 = 0,
263 uint32_t operand1 = 0, uint32_t operand2 = 0,
264 uint32_t operand3 = 0))
265 : bytecode_(bytecode),
266 operand_count_(operand_count),
267 operand_scale_(operand_scale),
268 source_info_(source_info) {
269 DCHECK_EQ(Bytecodes::NumberOfOperands(bytecode), operand_count);
270 operands_[0] = operand0;
271 operands_[1] = operand1;
272 operands_[2] = operand2;
273 operands_[3] = operand3;
274 }
275
276 template <Bytecode bytecode, AccumulatorUse accum_use>
277 INLINE(static BytecodeNode Create(BytecodeSourceInfo source_info)) {
278 return BytecodeNode(bytecode, 0, OperandScale::kSingle, source_info);
279 }
280
281 template <Bytecode bytecode, AccumulatorUse accum_use,
282 OperandType operand0_type>
283 INLINE(static BytecodeNode Create(BytecodeSourceInfo source_info,
284 uint32_t operand0)) {
285 DCHECK_EQ(Bytecodes::GetOperandType(bytecode, 0), operand0_type);
286 OperandScale scale = OperandScale::kSingle;
287 scale = std::max(scale, ScaleForOperand<operand0_type>(operand0));
288 return BytecodeNode(bytecode, 1, scale, source_info, operand0);
289 }
290
291 template <Bytecode bytecode, AccumulatorUse accum_use,
292 OperandType operand0_type, OperandType operand1_type>
293 INLINE(static BytecodeNode Create(BytecodeSourceInfo source_info,
294 uint32_t operand0, uint32_t operand1)) {
295 DCHECK_EQ(Bytecodes::GetOperandType(bytecode, 0), operand0_type);
296 DCHECK_EQ(Bytecodes::GetOperandType(bytecode, 1), operand1_type);
297 OperandScale scale = OperandScale::kSingle;
298 scale = std::max(scale, ScaleForOperand<operand0_type>(operand0));
299 scale = std::max(scale, ScaleForOperand<operand1_type>(operand1));
300 return BytecodeNode(bytecode, 2, scale, source_info, operand0, operand1);
301 }
302
303 template <Bytecode bytecode, AccumulatorUse accum_use,
304 OperandType operand0_type, OperandType operand1_type,
305 OperandType operand2_type>
306 INLINE(static BytecodeNode Create(BytecodeSourceInfo source_info,
307 uint32_t operand0, uint32_t operand1,
308 uint32_t operand2)) {
309 DCHECK_EQ(Bytecodes::GetOperandType(bytecode, 0), operand0_type);
310 DCHECK_EQ(Bytecodes::GetOperandType(bytecode, 1), operand1_type);
311 DCHECK_EQ(Bytecodes::GetOperandType(bytecode, 2), operand2_type);
312 OperandScale scale = OperandScale::kSingle;
313 scale = std::max(scale, ScaleForOperand<operand0_type>(operand0));
314 scale = std::max(scale, ScaleForOperand<operand1_type>(operand1));
315 scale = std::max(scale, ScaleForOperand<operand2_type>(operand2));
316 return BytecodeNode(bytecode, 3, scale, source_info, operand0, operand1,
317 operand2);
318 }
319
320 template <Bytecode bytecode, AccumulatorUse accum_use,
321 OperandType operand0_type, OperandType operand1_type,
322 OperandType operand2_type, OperandType operand3_type>
323 INLINE(static BytecodeNode Create(BytecodeSourceInfo source_info,
324 uint32_t operand0, uint32_t operand1,
325 uint32_t operand2, uint32_t operand3)) {
326 DCHECK_EQ(Bytecodes::GetOperandType(bytecode, 0), operand0_type);
327 DCHECK_EQ(Bytecodes::GetOperandType(bytecode, 1), operand1_type);
328 DCHECK_EQ(Bytecodes::GetOperandType(bytecode, 2), operand2_type);
329 DCHECK_EQ(Bytecodes::GetOperandType(bytecode, 3), operand3_type);
330 OperandScale scale = OperandScale::kSingle;
331 scale = std::max(scale, ScaleForOperand<operand0_type>(operand0));
332 scale = std::max(scale, ScaleForOperand<operand1_type>(operand1));
333 scale = std::max(scale, ScaleForOperand<operand2_type>(operand2));
334 scale = std::max(scale, ScaleForOperand<operand3_type>(operand3));
335 return BytecodeNode(bytecode, 4, scale, source_info, operand0, operand1,
336 operand2, operand3);
337 }
338
339 template <OperandType operand_type>
340 INLINE(static OperandScale ScaleForOperand(uint32_t operand)) {
341 if (BytecodeOperands::IsScalableUnsignedByte(operand_type)) {
342 return Bytecodes::ScaleForUnsignedOperand(operand);
343 } else if (BytecodeOperands::IsScalableSignedByte(operand_type)) {
344 return Bytecodes::ScaleForSignedOperand(operand);
345 } else {
346 return OperandScale::kSingle;
347 }
348 }
349
350 INLINE(void UpdateScaleForOperand(int operand_index, uint32_t operand)) {
351 if (Bytecodes::OperandIsScalableSignedByte(bytecode(), operand_index)) {
352 operand_scale_ =
353 std::max(operand_scale_, Bytecodes::ScaleForSignedOperand(operand));
354 } else if (Bytecodes::OperandIsScalableUnsignedByte(bytecode(),
355 operand_index)) {
356 operand_scale_ =
357 std::max(operand_scale_, Bytecodes::ScaleForUnsignedOperand(operand));
358 }
359 }
360
361 INLINE(void SetOperand(int operand_index, uint32_t operand)) {
362 operands_[operand_index] = operand;
363 UpdateScaleForOperand(operand_index, operand);
364 }
365
366 Bytecode bytecode_;
367 uint32_t operands_[Bytecodes::kMaxOperands];
368 int operand_count_;
369 OperandScale operand_scale_;
370 BytecodeSourceInfo source_info_;
371 };
372
373 V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os,
374 const BytecodeSourceInfo& info);
375 V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os,
376 const BytecodeNode& node);
377
378 } // namespace interpreter
379 } // namespace internal
380 } // namespace v8
381
382 #endif // V8_INTERPRETER_BYTECODE_PIPELINE_H_
383