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/interpreter/bytecode-register-allocator.h"
9#include "src/interpreter/bytecodes.h"
10#include "src/zone-containers.h"
11
12namespace v8 {
13namespace internal {
14namespace interpreter {
15
16class BytecodeLabel;
17class BytecodeNode;
18class BytecodeSourceInfo;
19
20// Interface for bytecode pipeline stages.
21class BytecodePipelineStage {
22 public:
23  virtual ~BytecodePipelineStage() {}
24
25  // Write bytecode node |node| into pipeline. The node is only valid
26  // for the duration of the call. Callee's should clone it if
27  // deferring Write() to the next stage.
28  virtual void Write(BytecodeNode* node) = 0;
29
30  // Write jump bytecode node |node| which jumps to |label| into pipeline.
31  // The node and label are only valid for the duration of the call. This call
32  // implicitly ends the current basic block so should always write to the next
33  // stage.
34  virtual void WriteJump(BytecodeNode* node, BytecodeLabel* label) = 0;
35
36  // Binds |label| to the current bytecode location. This call implicitly
37  // ends the current basic block and so any deferred bytecodes should be
38  // written to the next stage.
39  virtual void BindLabel(BytecodeLabel* label) = 0;
40
41  // Binds |label| to the location of |target|. This call implicitly
42  // ends the current basic block and so any deferred bytecodes should be
43  // written to the next stage.
44  virtual void BindLabel(const BytecodeLabel& target, BytecodeLabel* label) = 0;
45
46  // Flush the pipeline and generate a bytecode array.
47  virtual Handle<BytecodeArray> ToBytecodeArray(
48      int fixed_register_count, int parameter_count,
49      Handle<FixedArray> handler_table) = 0;
50};
51
52// Source code position information.
53class BytecodeSourceInfo final {
54 public:
55  static const int kUninitializedPosition = -1;
56
57  BytecodeSourceInfo()
58      : position_type_(PositionType::kNone),
59        source_position_(kUninitializedPosition) {}
60
61  BytecodeSourceInfo(int source_position, bool is_statement)
62      : position_type_(is_statement ? PositionType::kStatement
63                                    : PositionType::kExpression),
64        source_position_(source_position) {
65    DCHECK_GE(source_position, 0);
66  }
67
68  // Makes instance into a statement position.
69  void MakeStatementPosition(int source_position) {
70    // Statement positions can be replaced by other statement
71    // positions. For example , "for (x = 0; x < 3; ++x) 7;" has a
72    // statement position associated with 7 but no bytecode associated
73    // with it. Then Next is emitted after the body and has
74    // statement position and overrides the existing one.
75    position_type_ = PositionType::kStatement;
76    source_position_ = source_position;
77  }
78
79  // Makes instance into an expression position. Instance should not
80  // be a statement position otherwise it could be lost and impair the
81  // debugging experience.
82  void MakeExpressionPosition(int source_position) {
83    DCHECK(!is_statement());
84    position_type_ = PositionType::kExpression;
85    source_position_ = source_position;
86  }
87
88  // Forces an instance into an expression position.
89  void ForceExpressionPosition(int source_position) {
90    position_type_ = PositionType::kExpression;
91    source_position_ = source_position;
92  }
93
94  // Clones a source position. The current instance is expected to be
95  // invalid.
96  void Clone(const BytecodeSourceInfo& other) {
97    DCHECK(!is_valid());
98    position_type_ = other.position_type_;
99    source_position_ = other.source_position_;
100  }
101
102  int source_position() const {
103    DCHECK(is_valid());
104    return source_position_;
105  }
106
107  bool is_statement() const {
108    return position_type_ == PositionType::kStatement;
109  }
110  bool is_expression() const {
111    return position_type_ == PositionType::kExpression;
112  }
113
114  bool is_valid() const { return position_type_ != PositionType::kNone; }
115  void set_invalid() {
116    position_type_ = PositionType::kNone;
117    source_position_ = kUninitializedPosition;
118  }
119
120  bool operator==(const BytecodeSourceInfo& other) const {
121    return position_type_ == other.position_type_ &&
122           source_position_ == other.source_position_;
123  }
124
125  bool operator!=(const BytecodeSourceInfo& other) const {
126    return position_type_ != other.position_type_ ||
127           source_position_ != other.source_position_;
128  }
129
130 private:
131  enum class PositionType : uint8_t { kNone, kExpression, kStatement };
132
133  PositionType position_type_;
134  int source_position_;
135
136  DISALLOW_COPY_AND_ASSIGN(BytecodeSourceInfo);
137};
138
139// A container for a generated bytecode, it's operands, and source information.
140// These must be allocated by a BytecodeNodeAllocator instance.
141class BytecodeNode final : ZoneObject {
142 public:
143  explicit BytecodeNode(Bytecode bytecode = Bytecode::kIllegal);
144  BytecodeNode(Bytecode bytecode, uint32_t operand0);
145  BytecodeNode(Bytecode bytecode, uint32_t operand0, uint32_t operand1);
146  BytecodeNode(Bytecode bytecode, uint32_t operand0, uint32_t operand1,
147               uint32_t operand2);
148  BytecodeNode(Bytecode bytecode, uint32_t operand0, uint32_t operand1,
149               uint32_t operand2, uint32_t operand3);
150
151  BytecodeNode(const BytecodeNode& other);
152  BytecodeNode& operator=(const BytecodeNode& other);
153
154  void set_bytecode(Bytecode bytecode);
155  void set_bytecode(Bytecode bytecode, uint32_t operand0);
156
157  // Clone |other|.
158  void Clone(const BytecodeNode* const other);
159
160  // Print to stream |os|.
161  void Print(std::ostream& os) const;
162
163  // Transform to a node representing |new_bytecode| which has one
164  // operand more than the current bytecode.
165  void Transform(Bytecode new_bytecode, uint32_t extra_operand);
166
167  Bytecode bytecode() const { return bytecode_; }
168
169  uint32_t operand(int i) const {
170    DCHECK_LT(i, operand_count());
171    return operands_[i];
172  }
173  uint32_t* operands() { return operands_; }
174  const uint32_t* operands() const { return operands_; }
175
176  int operand_count() const { return Bytecodes::NumberOfOperands(bytecode_); }
177
178  const BytecodeSourceInfo& source_info() const { return source_info_; }
179  BytecodeSourceInfo& source_info() { return source_info_; }
180
181  bool operator==(const BytecodeNode& other) const;
182  bool operator!=(const BytecodeNode& other) const { return !(*this == other); }
183
184 private:
185  static const int kInvalidPosition = kMinInt;
186  static const size_t kMaxOperands = 4;
187
188  Bytecode bytecode_;
189  uint32_t operands_[kMaxOperands];
190  BytecodeSourceInfo source_info_;
191};
192
193std::ostream& operator<<(std::ostream& os, const BytecodeSourceInfo& info);
194std::ostream& operator<<(std::ostream& os, const BytecodeNode& node);
195
196}  // namespace interpreter
197}  // namespace internal
198}  // namespace v8
199
200#endif  // V8_INTERPRETER_BYTECODE_PIPELINE_H_
201