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