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_ARRAY_BUILDER_H_
6#define V8_INTERPRETER_BYTECODE_ARRAY_BUILDER_H_
7
8#include "src/ast/ast.h"
9#include "src/interpreter/bytecode-array-writer.h"
10#include "src/interpreter/bytecode-register-allocator.h"
11#include "src/interpreter/bytecodes.h"
12#include "src/interpreter/constant-array-builder.h"
13#include "src/interpreter/handler-table-builder.h"
14#include "src/zone-containers.h"
15
16namespace v8 {
17namespace internal {
18
19class Isolate;
20
21namespace interpreter {
22
23class BytecodeLabel;
24class BytecodeNode;
25class BytecodePipelineStage;
26class Register;
27
28class BytecodeArrayBuilder final : public ZoneObject {
29 public:
30  BytecodeArrayBuilder(Isolate* isolate, Zone* zone, int parameter_count,
31                       int context_count, int locals_count,
32                       FunctionLiteral* literal = nullptr);
33
34  Handle<BytecodeArray> ToBytecodeArray();
35
36  // Get the number of parameters expected by function.
37  int parameter_count() const {
38    DCHECK_GE(parameter_count_, 0);
39    return parameter_count_;
40  }
41
42  // Get the number of locals required for bytecode array.
43  int locals_count() const {
44    DCHECK_GE(local_register_count_, 0);
45    return local_register_count_;
46  }
47
48  // Get number of contexts required for bytecode array.
49  int context_count() const {
50    DCHECK_GE(context_register_count_, 0);
51    return context_register_count_;
52  }
53
54  Register first_context_register() const;
55  Register last_context_register() const;
56
57  // Returns the number of fixed (non-temporary) registers.
58  int fixed_register_count() const { return context_count() + locals_count(); }
59
60  // Returns the number of fixed and temporary registers.
61  int fixed_and_temporary_register_count() const {
62    return fixed_register_count() + temporary_register_count();
63  }
64
65  int temporary_register_count() const {
66    return temporary_register_allocator()->allocation_count();
67  }
68
69  Register Parameter(int parameter_index) const;
70
71  // Return true if the register |reg| represents a parameter or a
72  // local.
73  bool RegisterIsParameterOrLocal(Register reg) const;
74
75  // Returns true if the register |reg| is a live temporary register.
76  bool TemporaryRegisterIsLive(Register reg) const;
77
78  // Constant loads to accumulator.
79  BytecodeArrayBuilder& LoadLiteral(v8::internal::Smi* value);
80  BytecodeArrayBuilder& LoadLiteral(Handle<Object> object);
81  BytecodeArrayBuilder& LoadUndefined();
82  BytecodeArrayBuilder& LoadNull();
83  BytecodeArrayBuilder& LoadTheHole();
84  BytecodeArrayBuilder& LoadTrue();
85  BytecodeArrayBuilder& LoadFalse();
86
87  // Global loads to the accumulator and stores from the accumulator.
88  BytecodeArrayBuilder& LoadGlobal(int feedback_slot, TypeofMode typeof_mode);
89  BytecodeArrayBuilder& StoreGlobal(const Handle<String> name,
90                                    int feedback_slot,
91                                    LanguageMode language_mode);
92
93  // Load the object at |slot_index| in |context| into the accumulator.
94  BytecodeArrayBuilder& LoadContextSlot(Register context, int slot_index);
95
96  // Stores the object in the accumulator into |slot_index| of |context|.
97  BytecodeArrayBuilder& StoreContextSlot(Register context, int slot_index);
98
99  // Register-accumulator transfers.
100  BytecodeArrayBuilder& LoadAccumulatorWithRegister(Register reg);
101  BytecodeArrayBuilder& StoreAccumulatorInRegister(Register reg);
102
103  // Register-register transfer.
104  BytecodeArrayBuilder& MoveRegister(Register from, Register to);
105
106  // Named load property.
107  BytecodeArrayBuilder& LoadNamedProperty(Register object,
108                                          const Handle<Name> name,
109                                          int feedback_slot);
110  // Keyed load property. The key should be in the accumulator.
111  BytecodeArrayBuilder& LoadKeyedProperty(Register object, int feedback_slot);
112
113  // Store properties. The value to be stored should be in the accumulator.
114  BytecodeArrayBuilder& StoreNamedProperty(Register object,
115                                           const Handle<Name> name,
116                                           int feedback_slot,
117                                           LanguageMode language_mode);
118  BytecodeArrayBuilder& StoreKeyedProperty(Register object, Register key,
119                                           int feedback_slot,
120                                           LanguageMode language_mode);
121
122  // Lookup the variable with |name|.
123  BytecodeArrayBuilder& LoadLookupSlot(const Handle<String> name,
124                                       TypeofMode typeof_mode);
125
126  // Store value in the accumulator into the variable with |name|.
127  BytecodeArrayBuilder& StoreLookupSlot(const Handle<String> name,
128                                        LanguageMode language_mode);
129
130  // Create a new closure for the SharedFunctionInfo.
131  BytecodeArrayBuilder& CreateClosure(Handle<SharedFunctionInfo> shared_info,
132                                      PretenureFlag tenured);
133
134  // Create a new arguments object in the accumulator.
135  BytecodeArrayBuilder& CreateArguments(CreateArgumentsType type);
136
137  // Literals creation.  Constant elements should be in the accumulator.
138  BytecodeArrayBuilder& CreateRegExpLiteral(Handle<String> pattern,
139                                            int literal_index, int flags);
140  BytecodeArrayBuilder& CreateArrayLiteral(Handle<FixedArray> constant_elements,
141                                           int literal_index, int flags);
142  BytecodeArrayBuilder& CreateObjectLiteral(
143      Handle<FixedArray> constant_properties, int literal_index, int flags);
144
145  // Push the context in accumulator as the new context, and store in register
146  // |context|.
147  BytecodeArrayBuilder& PushContext(Register context);
148
149  // Pop the current context and replace with |context|.
150  BytecodeArrayBuilder& PopContext(Register context);
151
152  // Call a JS function. The JSFunction or Callable to be called should be in
153  // |callable|, the receiver should be in |receiver_args| and all subsequent
154  // arguments should be in registers <receiver_args + 1> to
155  // <receiver_args + receiver_arg_count - 1>.
156  BytecodeArrayBuilder& Call(
157      Register callable, Register receiver_args, size_t receiver_arg_count,
158      int feedback_slot, TailCallMode tail_call_mode = TailCallMode::kDisallow);
159
160  BytecodeArrayBuilder& TailCall(Register callable, Register receiver_args,
161                                 size_t receiver_arg_count, int feedback_slot) {
162    return Call(callable, receiver_args, receiver_arg_count, feedback_slot,
163                TailCallMode::kAllow);
164  }
165
166  // Call the new operator. The accumulator holds the |new_target|.
167  // The |constructor| is in a register followed by |arg_count|
168  // consecutive arguments starting at |first_arg| for the constuctor
169  // invocation.
170  BytecodeArrayBuilder& New(Register constructor, Register first_arg,
171                            size_t arg_count);
172
173  // Call the runtime function with |function_id|. The first argument should be
174  // in |first_arg| and all subsequent arguments should be in registers
175  // <first_arg + 1> to <first_arg + arg_count - 1>.
176  BytecodeArrayBuilder& CallRuntime(Runtime::FunctionId function_id,
177                                    Register first_arg, size_t arg_count);
178
179  // Call the runtime function with |function_id| that returns a pair of values.
180  // The first argument should be in |first_arg| and all subsequent arguments
181  // should be in registers <first_arg + 1> to <first_arg + arg_count - 1>. The
182  // return values will be returned in <first_return> and <first_return + 1>.
183  BytecodeArrayBuilder& CallRuntimeForPair(Runtime::FunctionId function_id,
184                                           Register first_arg, size_t arg_count,
185                                           Register first_return);
186
187  // Call the JS runtime function with |context_index|. The the receiver should
188  // be in |receiver_args| and all subsequent arguments should be in registers
189  // <receiver + 1> to <receiver + receiver_args_count - 1>.
190  BytecodeArrayBuilder& CallJSRuntime(int context_index, Register receiver_args,
191                                      size_t receiver_args_count);
192
193  // Operators (register holds the lhs value, accumulator holds the rhs value).
194  BytecodeArrayBuilder& BinaryOperation(Token::Value binop, Register reg);
195
196  // Count Operators (value stored in accumulator).
197  BytecodeArrayBuilder& CountOperation(Token::Value op);
198
199  // Unary Operators.
200  BytecodeArrayBuilder& LogicalNot();
201  BytecodeArrayBuilder& TypeOf();
202
203  // Deletes property from an object. This expects that accumulator contains
204  // the key to be deleted and the register contains a reference to the object.
205  BytecodeArrayBuilder& Delete(Register object, LanguageMode language_mode);
206
207  // Tests.
208  BytecodeArrayBuilder& CompareOperation(Token::Value op, Register reg);
209
210  // Casts.
211  BytecodeArrayBuilder& CastAccumulatorToBoolean();
212  BytecodeArrayBuilder& CastAccumulatorToJSObject();
213  BytecodeArrayBuilder& CastAccumulatorToName();
214  BytecodeArrayBuilder& CastAccumulatorToNumber();
215
216  // Flow Control.
217  BytecodeArrayBuilder& Bind(BytecodeLabel* label);
218  BytecodeArrayBuilder& Bind(const BytecodeLabel& target, BytecodeLabel* label);
219
220  BytecodeArrayBuilder& Jump(BytecodeLabel* label);
221  BytecodeArrayBuilder& JumpIfTrue(BytecodeLabel* label);
222  BytecodeArrayBuilder& JumpIfFalse(BytecodeLabel* label);
223  BytecodeArrayBuilder& JumpIfNotHole(BytecodeLabel* label);
224  BytecodeArrayBuilder& JumpIfNull(BytecodeLabel* label);
225  BytecodeArrayBuilder& JumpIfUndefined(BytecodeLabel* label);
226
227  BytecodeArrayBuilder& StackCheck(int position);
228
229  BytecodeArrayBuilder& Throw();
230  BytecodeArrayBuilder& ReThrow();
231  BytecodeArrayBuilder& Return();
232
233  // Debugger.
234  BytecodeArrayBuilder& Debugger();
235
236  // Complex flow control.
237  BytecodeArrayBuilder& ForInPrepare(Register cache_info_triple);
238  BytecodeArrayBuilder& ForInDone(Register index, Register cache_length);
239  BytecodeArrayBuilder& ForInNext(Register receiver, Register index,
240                                  Register cache_type_array_pair,
241                                  int feedback_slot);
242  BytecodeArrayBuilder& ForInStep(Register index);
243
244  // Generators.
245  BytecodeArrayBuilder& SuspendGenerator(Register generator);
246  BytecodeArrayBuilder& ResumeGenerator(Register generator);
247
248  // Exception handling.
249  BytecodeArrayBuilder& MarkHandler(int handler_id, bool will_catch);
250  BytecodeArrayBuilder& MarkTryBegin(int handler_id, Register context);
251  BytecodeArrayBuilder& MarkTryEnd(int handler_id);
252
253  // Creates a new handler table entry and returns a {hander_id} identifying the
254  // entry, so that it can be referenced by above exception handling support.
255  int NewHandlerEntry() { return handler_table_builder()->NewHandlerEntry(); }
256
257  void InitializeReturnPosition(FunctionLiteral* literal);
258
259  void SetStatementPosition(Statement* stmt);
260  void SetExpressionPosition(Expression* expr);
261  void SetExpressionAsStatementPosition(Expression* expr);
262
263  // Accessors
264  TemporaryRegisterAllocator* temporary_register_allocator() {
265    return &temporary_allocator_;
266  }
267  const TemporaryRegisterAllocator* temporary_register_allocator() const {
268    return &temporary_allocator_;
269  }
270  Zone* zone() const { return zone_; }
271
272  void EnsureReturn();
273
274  static uint32_t RegisterOperand(Register reg) {
275    return static_cast<uint32_t>(reg.ToOperand());
276  }
277
278  static uint32_t SignedOperand(int value) {
279    return static_cast<uint32_t>(value);
280  }
281
282  static uint32_t UnsignedOperand(int value) {
283    DCHECK_GE(value, 0);
284    return static_cast<uint32_t>(value);
285  }
286
287  static uint32_t UnsignedOperand(size_t value) {
288    DCHECK_LE(value, kMaxUInt32);
289    return static_cast<uint32_t>(value);
290  }
291
292 private:
293  friend class BytecodeRegisterAllocator;
294
295  static Bytecode BytecodeForBinaryOperation(Token::Value op);
296  static Bytecode BytecodeForCountOperation(Token::Value op);
297  static Bytecode BytecodeForCompareOperation(Token::Value op);
298  static Bytecode BytecodeForStoreNamedProperty(LanguageMode language_mode);
299  static Bytecode BytecodeForStoreKeyedProperty(LanguageMode language_mode);
300  static Bytecode BytecodeForLoadGlobal(TypeofMode typeof_mode);
301  static Bytecode BytecodeForStoreGlobal(LanguageMode language_mode);
302  static Bytecode BytecodeForStoreLookupSlot(LanguageMode language_mode);
303  static Bytecode BytecodeForCreateArguments(CreateArgumentsType type);
304  static Bytecode BytecodeForDelete(LanguageMode language_mode);
305  static Bytecode BytecodeForCall(TailCallMode tail_call_mode);
306
307  void Output(Bytecode bytecode, uint32_t operand0, uint32_t operand1,
308              uint32_t operand2, uint32_t operand3);
309  void Output(Bytecode bytecode, uint32_t operand0, uint32_t operand1,
310              uint32_t operand2);
311  void Output(Bytecode bytecode, uint32_t operand0, uint32_t operand1);
312  void Output(Bytecode bytecode, uint32_t operand0);
313  void Output(Bytecode bytecode);
314
315  BytecodeArrayBuilder& OutputJump(Bytecode jump_bytecode,
316                                   BytecodeLabel* label);
317
318  bool RegisterIsValid(Register reg) const;
319  bool OperandsAreValid(Bytecode bytecode, int operand_count,
320                        uint32_t operand0 = 0, uint32_t operand1 = 0,
321                        uint32_t operand2 = 0, uint32_t operand3 = 0) const;
322
323  // Attach latest source position to |node|.
324  void AttachSourceInfo(BytecodeNode* node);
325
326  // Set position for return.
327  void SetReturnPosition();
328
329  // Gets a constant pool entry for the |object|.
330  size_t GetConstantPoolEntry(Handle<Object> object);
331
332  // Not implemented as the illegal bytecode is used inside internally
333  // to indicate a bytecode field is not valid or an error has occured
334  // during bytecode generation.
335  BytecodeArrayBuilder& Illegal();
336
337  void LeaveBasicBlock() { return_seen_in_block_ = false; }
338
339  Isolate* isolate() const { return isolate_; }
340  BytecodeArrayWriter* bytecode_array_writer() {
341    return &bytecode_array_writer_;
342  }
343  BytecodePipelineStage* pipeline() { return pipeline_; }
344  ConstantArrayBuilder* constant_array_builder() {
345    return &constant_array_builder_;
346  }
347  const ConstantArrayBuilder* constant_array_builder() const {
348    return &constant_array_builder_;
349  }
350  HandlerTableBuilder* handler_table_builder() {
351    return &handler_table_builder_;
352  }
353
354  Isolate* isolate_;
355  Zone* zone_;
356  bool bytecode_generated_;
357  ConstantArrayBuilder constant_array_builder_;
358  HandlerTableBuilder handler_table_builder_;
359  bool return_seen_in_block_;
360  int parameter_count_;
361  int local_register_count_;
362  int context_register_count_;
363  int return_position_;
364  TemporaryRegisterAllocator temporary_allocator_;
365  BytecodeArrayWriter bytecode_array_writer_;
366  BytecodePipelineStage* pipeline_;
367  BytecodeSourceInfo latest_source_info_;
368
369  DISALLOW_COPY_AND_ASSIGN(BytecodeArrayBuilder);
370};
371
372}  // namespace interpreter
373}  // namespace internal
374}  // namespace v8
375
376#endif  // V8_INTERPRETER_BYTECODE_ARRAY_BUILDER_H_
377