• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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