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 // Replace the bytecode of this node with |bytecode| and keep the operands.
195 void replace_bytecode(Bytecode bytecode) {
196 DCHECK_EQ(Bytecodes::NumberOfOperands(bytecode_),
197 Bytecodes::NumberOfOperands(bytecode));
198 bytecode_ = bytecode;
199 }
200
201 void set_bytecode(Bytecode bytecode) {
202 DCHECK_EQ(Bytecodes::NumberOfOperands(bytecode), 0);
203 bytecode_ = bytecode;
204 operand_count_ = 0;
205 operand_scale_ = OperandScale::kSingle;
206 }
207
208 void set_bytecode(Bytecode bytecode, uint32_t operand0) {
209 DCHECK_EQ(Bytecodes::NumberOfOperands(bytecode), 1);
210 bytecode_ = bytecode;
211 operand_count_ = 1;
212 operand_scale_ = OperandScale::kSingle;
213 SetOperand(0, operand0);
214 }
215
216 void set_bytecode(Bytecode bytecode, uint32_t operand0, uint32_t operand1) {
217 DCHECK_EQ(Bytecodes::NumberOfOperands(bytecode), 2);
218 bytecode_ = bytecode;
219 operand_count_ = 2;
220 operand_scale_ = OperandScale::kSingle;
221 SetOperand(0, operand0);
222 SetOperand(1, operand1);
223 }
224
225 void set_bytecode(Bytecode bytecode, uint32_t operand0, uint32_t operand1,
226 uint32_t operand2) {
227 DCHECK_EQ(Bytecodes::NumberOfOperands(bytecode), 3);
228 bytecode_ = bytecode;
229 operand_count_ = 3;
230 operand_scale_ = OperandScale::kSingle;
231 SetOperand(0, operand0);
232 SetOperand(1, operand1);
233 SetOperand(2, operand2);
234 }
235
236 // Print to stream |os|.
237 void Print(std::ostream& os) const;
238
239 // Transform to a node representing |new_bytecode| which has one
240 // operand more than the current bytecode.
241 void Transform(Bytecode new_bytecode, uint32_t extra_operand) {
242 DCHECK_EQ(Bytecodes::NumberOfOperands(new_bytecode),
243 Bytecodes::NumberOfOperands(bytecode()) + 1);
244 DCHECK(Bytecodes::NumberOfOperands(bytecode()) < 1 ||
245 Bytecodes::GetOperandType(new_bytecode, 0) ==
246 Bytecodes::GetOperandType(bytecode(), 0));
247 DCHECK(Bytecodes::NumberOfOperands(bytecode()) < 2 ||
248 Bytecodes::GetOperandType(new_bytecode, 1) ==
249 Bytecodes::GetOperandType(bytecode(), 1));
250 DCHECK(Bytecodes::NumberOfOperands(bytecode()) < 3 ||
251 Bytecodes::GetOperandType(new_bytecode, 2) ==
252 Bytecodes::GetOperandType(bytecode(), 2));
253 DCHECK(Bytecodes::NumberOfOperands(bytecode()) < 4);
254
255 bytecode_ = new_bytecode;
256 operand_count_++;
257 SetOperand(operand_count() - 1, extra_operand);
258 }
259
260 Bytecode bytecode() const { return bytecode_; }
261
262 uint32_t operand(int i) const {
263 DCHECK_LT(i, operand_count());
264 return operands_[i];
265 }
266 const uint32_t* operands() const { return operands_; }
267
268 int operand_count() const { return operand_count_; }
269 OperandScale operand_scale() const { return operand_scale_; }
270
271 const BytecodeSourceInfo& source_info() const { return source_info_; }
272 void set_source_info(BytecodeSourceInfo source_info) {
273 source_info_ = source_info;
274 }
275
276 bool operator==(const BytecodeNode& other) const;
277 bool operator!=(const BytecodeNode& other) const { return !(*this == other); }
278
279 private:
280 INLINE(void UpdateScaleForOperand(int operand_index, uint32_t operand)) {
281 if (Bytecodes::OperandIsScalableSignedByte(bytecode(), operand_index)) {
282 operand_scale_ =
283 std::max(operand_scale_, Bytecodes::ScaleForSignedOperand(operand));
284 } else if (Bytecodes::OperandIsScalableUnsignedByte(bytecode(),
285 operand_index)) {
286 operand_scale_ =
287 std::max(operand_scale_, Bytecodes::ScaleForUnsignedOperand(operand));
288 }
289 }
290
291 INLINE(void SetOperand(int operand_index, uint32_t operand)) {
292 operands_[operand_index] = operand;
293 UpdateScaleForOperand(operand_index, operand);
294 }
295
296 Bytecode bytecode_;
297 uint32_t operands_[Bytecodes::kMaxOperands];
298 int operand_count_;
299 OperandScale operand_scale_;
300 BytecodeSourceInfo source_info_;
301 };
302
303 V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os,
304 const BytecodeSourceInfo& info);
305 V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os,
306 const BytecodeNode& node);
307
308 } // namespace interpreter
309 } // namespace internal
310 } // namespace v8
311
312 #endif // V8_INTERPRETER_BYTECODE_PIPELINE_H_
313