bytecode-array-builder.h revision 014dc512cdd3e367bee49a713fdc5ed92584a3e5
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/bytecodes.h"
10#include "src/interpreter/constant-array-builder.h"
11#include "src/zone-containers.h"
12
13namespace v8 {
14namespace internal {
15
16class Isolate;
17
18namespace interpreter {
19
20class BytecodeLabel;
21class ConstantArrayBuilder;
22class Register;
23
24// TODO(rmcilroy): Unify this with CreateArgumentsParameters::Type in Turbofan
25// when rest parameters implementation has settled down.
26enum class CreateArgumentsType { kMappedArguments, kUnmappedArguments };
27
28class BytecodeArrayBuilder final {
29 public:
30  BytecodeArrayBuilder(Isolate* isolate, Zone* zone);
31  ~BytecodeArrayBuilder();
32
33  Handle<BytecodeArray> ToBytecodeArray();
34
35  // Set the number of parameters expected by function.
36  void set_parameter_count(int number_of_params);
37  int parameter_count() const {
38    DCHECK_GE(parameter_count_, 0);
39    return parameter_count_;
40  }
41
42  // Set the number of locals required for bytecode array.
43  void set_locals_count(int number_of_locals);
44  int locals_count() const {
45    DCHECK_GE(local_register_count_, 0);
46    return local_register_count_;
47  }
48
49  // Set number of contexts required for bytecode array.
50  void set_context_count(int number_of_contexts);
51  int context_count() const {
52    DCHECK_GE(context_register_count_, 0);
53    return context_register_count_;
54  }
55
56  Register first_context_register() const;
57  Register last_context_register() const;
58
59  // Returns the number of fixed (non-temporary) registers.
60  int fixed_register_count() const { return context_count() + locals_count(); }
61
62  Register Parameter(int parameter_index) const;
63
64  // Return true if the register |reg| represents a parameter or a
65  // local.
66  bool RegisterIsParameterOrLocal(Register reg) const;
67
68  // Return true if the register |reg| represents a temporary register.
69  bool RegisterIsTemporary(Register reg) const;
70
71  // Constant loads to accumulator.
72  BytecodeArrayBuilder& LoadLiteral(v8::internal::Smi* value);
73  BytecodeArrayBuilder& LoadLiteral(Handle<Object> object);
74  BytecodeArrayBuilder& LoadUndefined();
75  BytecodeArrayBuilder& LoadNull();
76  BytecodeArrayBuilder& LoadTheHole();
77  BytecodeArrayBuilder& LoadTrue();
78  BytecodeArrayBuilder& LoadFalse();
79  BytecodeArrayBuilder& LoadBooleanConstant(bool value);
80
81  // Global loads to the accumulator and stores from the accumulator.
82  BytecodeArrayBuilder& LoadGlobal(const Handle<String> name, int feedback_slot,
83                                   LanguageMode language_mode,
84                                   TypeofMode typeof_mode);
85  BytecodeArrayBuilder& StoreGlobal(const Handle<String> name,
86                                    int feedback_slot,
87                                    LanguageMode language_mode);
88
89  // Load the object at |slot_index| in |context| into the accumulator.
90  BytecodeArrayBuilder& LoadContextSlot(Register context, int slot_index);
91
92  // Stores the object in the accumulator into |slot_index| of |context|.
93  BytecodeArrayBuilder& StoreContextSlot(Register context, int slot_index);
94
95  // Register-accumulator transfers.
96  BytecodeArrayBuilder& LoadAccumulatorWithRegister(Register reg);
97  BytecodeArrayBuilder& StoreAccumulatorInRegister(Register reg);
98
99  // Register-register transfer.
100  BytecodeArrayBuilder& MoveRegister(Register from, Register to);
101  BytecodeArrayBuilder& ExchangeRegisters(Register reg0, Register reg1);
102
103  // Named load property.
104  BytecodeArrayBuilder& LoadNamedProperty(Register object,
105                                          const Handle<String> name,
106                                          int feedback_slot,
107                                          LanguageMode language_mode);
108  // Keyed load property. The key should be in the accumulator.
109  BytecodeArrayBuilder& LoadKeyedProperty(Register object, int feedback_slot,
110                                          LanguageMode language_mode);
111
112  // Store properties. The value to be stored should be in the accumulator.
113  BytecodeArrayBuilder& StoreNamedProperty(Register object,
114                                           const Handle<String> name,
115                                           int feedback_slot,
116                                           LanguageMode language_mode);
117  BytecodeArrayBuilder& StoreKeyedProperty(Register object, Register key,
118                                           int feedback_slot,
119                                           LanguageMode language_mode);
120
121  // Lookup the variable with |name|.
122  BytecodeArrayBuilder& LoadLookupSlot(const Handle<String> name,
123                                       TypeofMode typeof_mode);
124
125  // Store value in the accumulator into the variable with |name|.
126  BytecodeArrayBuilder& StoreLookupSlot(const Handle<String> name,
127                                        LanguageMode language_mode);
128
129  // Create a new closure for the SharedFunctionInfo.
130  BytecodeArrayBuilder& CreateClosure(Handle<SharedFunctionInfo> shared_info,
131                                      PretenureFlag tenured);
132
133  // Create a new arguments object in the accumulator.
134  BytecodeArrayBuilder& CreateArguments(CreateArgumentsType type);
135
136  // Literals creation.  Constant elements should be in the accumulator.
137  BytecodeArrayBuilder& CreateRegExpLiteral(Handle<String> pattern,
138                                            int literal_index, int flags);
139  BytecodeArrayBuilder& CreateArrayLiteral(Handle<FixedArray> constant_elements,
140                                           int literal_index, int flags);
141  BytecodeArrayBuilder& CreateObjectLiteral(
142      Handle<FixedArray> constant_properties, int literal_index, int flags);
143
144  // Push the context in accumulator as the new context, and store in register
145  // |context|.
146  BytecodeArrayBuilder& PushContext(Register context);
147
148  // Pop the current context and replace with |context|.
149  BytecodeArrayBuilder& PopContext(Register context);
150
151  // Call a JS function. The JSFunction or Callable to be called should be in
152  // |callable|, the receiver should be in |receiver| and all subsequent
153  // arguments should be in registers <receiver + 1> to
154  // <receiver + 1 + arg_count>.
155  BytecodeArrayBuilder& Call(Register callable, Register receiver,
156                             size_t arg_count, int feedback_slot);
157
158  // Call the new operator. The |constructor| register is followed by
159  // |arg_count| consecutive registers containing arguments to be
160  // applied to the constructor.
161  BytecodeArrayBuilder& New(Register constructor, Register first_arg,
162                            size_t arg_count);
163
164  // Call the runtime function with |function_id|. The first argument should be
165  // in |first_arg| and all subsequent arguments should be in registers
166  // <first_arg + 1> to <first_arg + 1 + arg_count>.
167  BytecodeArrayBuilder& CallRuntime(Runtime::FunctionId function_id,
168                                    Register first_arg, size_t arg_count);
169
170  // Call the runtime function with |function_id| that returns a pair of values.
171  // The first argument should be in |first_arg| and all subsequent arguments
172  // should be in registers <first_arg + 1> to <first_arg + 1 + arg_count>. The
173  // return values will be returned in <first_return> and <first_return + 1>.
174  BytecodeArrayBuilder& CallRuntimeForPair(Runtime::FunctionId function_id,
175                                           Register first_arg, size_t arg_count,
176                                           Register first_return);
177
178  // Call the JS runtime function with |context_index|. The the receiver should
179  // be in |receiver| and all subsequent arguments should be in registers
180  // <receiver + 1> to <receiver + 1 + arg_count>.
181  BytecodeArrayBuilder& CallJSRuntime(int context_index, Register receiver,
182                                      size_t arg_count);
183
184  // Operators (register holds the lhs value, accumulator holds the rhs value).
185  BytecodeArrayBuilder& BinaryOperation(Token::Value binop, Register reg,
186                                        Strength strength);
187
188  // Count Operators (value stored in accumulator).
189  BytecodeArrayBuilder& CountOperation(Token::Value op, Strength strength);
190
191  // Unary Operators.
192  BytecodeArrayBuilder& LogicalNot();
193  BytecodeArrayBuilder& TypeOf();
194
195  // Deletes property from an object. This expects that accumulator contains
196  // the key to be deleted and the register contains a reference to the object.
197  BytecodeArrayBuilder& Delete(Register object, LanguageMode language_mode);
198  BytecodeArrayBuilder& DeleteLookupSlot();
199
200  // Tests.
201  BytecodeArrayBuilder& CompareOperation(Token::Value op, Register reg,
202                                         Strength strength);
203
204  // Casts.
205  BytecodeArrayBuilder& CastAccumulatorToBoolean();
206  BytecodeArrayBuilder& CastAccumulatorToJSObject();
207  BytecodeArrayBuilder& CastAccumulatorToName();
208  BytecodeArrayBuilder& CastAccumulatorToNumber();
209
210  // Flow Control.
211  BytecodeArrayBuilder& Bind(BytecodeLabel* label);
212  BytecodeArrayBuilder& Bind(const BytecodeLabel& target, BytecodeLabel* label);
213
214  BytecodeArrayBuilder& Jump(BytecodeLabel* label);
215  BytecodeArrayBuilder& JumpIfTrue(BytecodeLabel* label);
216  BytecodeArrayBuilder& JumpIfFalse(BytecodeLabel* label);
217  BytecodeArrayBuilder& JumpIfNull(BytecodeLabel* label);
218  BytecodeArrayBuilder& JumpIfUndefined(BytecodeLabel* label);
219
220  BytecodeArrayBuilder& Throw();
221  BytecodeArrayBuilder& Return();
222
223  // Complex flow control.
224  BytecodeArrayBuilder& ForInPrepare(Register cache_type, Register cache_array,
225                                     Register cache_length);
226  BytecodeArrayBuilder& ForInDone(Register index, Register cache_length);
227  BytecodeArrayBuilder& ForInNext(Register receiver, Register cache_type,
228                                  Register cache_array, Register index);
229  BytecodeArrayBuilder& ForInStep(Register index);
230
231  // Accessors
232  Zone* zone() const { return zone_; }
233
234 private:
235  ZoneVector<uint8_t>* bytecodes() { return &bytecodes_; }
236  const ZoneVector<uint8_t>* bytecodes() const { return &bytecodes_; }
237  Isolate* isolate() const { return isolate_; }
238  ConstantArrayBuilder* constant_array_builder() {
239    return &constant_array_builder_;
240  }
241  const ConstantArrayBuilder* constant_array_builder() const {
242    return &constant_array_builder_;
243  }
244
245  static Bytecode BytecodeForBinaryOperation(Token::Value op);
246  static Bytecode BytecodeForCountOperation(Token::Value op);
247  static Bytecode BytecodeForCompareOperation(Token::Value op);
248  static Bytecode BytecodeForWideOperands(Bytecode bytecode);
249  static Bytecode BytecodeForLoadIC(LanguageMode language_mode);
250  static Bytecode BytecodeForKeyedLoadIC(LanguageMode language_mode);
251  static Bytecode BytecodeForStoreIC(LanguageMode language_mode);
252  static Bytecode BytecodeForKeyedStoreIC(LanguageMode language_mode);
253  static Bytecode BytecodeForLoadGlobal(LanguageMode language_mode,
254                                        TypeofMode typeof_mode);
255  static Bytecode BytecodeForStoreGlobal(LanguageMode language_mode);
256  static Bytecode BytecodeForStoreLookupSlot(LanguageMode language_mode);
257  static Bytecode BytecodeForCreateArguments(CreateArgumentsType type);
258  static Bytecode BytecodeForDelete(LanguageMode language_mode);
259
260  static bool FitsInIdx8Operand(int value);
261  static bool FitsInIdx8Operand(size_t value);
262  static bool FitsInImm8Operand(int value);
263  static bool FitsInIdx16Operand(int value);
264  static bool FitsInIdx16Operand(size_t value);
265  static bool FitsInReg8Operand(Register value);
266  static bool FitsInReg16Operand(Register value);
267
268  static Bytecode GetJumpWithConstantOperand(Bytecode jump_smi8_operand);
269  static Bytecode GetJumpWithConstantWideOperand(Bytecode jump_smi8_operand);
270  static Bytecode GetJumpWithToBoolean(Bytecode jump_smi8_operand);
271
272  Register MapRegister(Register reg);
273  Register MapRegisters(Register reg, Register args_base, int args_length = 1);
274
275  template <size_t N>
276  INLINE(void Output(Bytecode bytecode, uint32_t(&operands)[N]));
277  void Output(Bytecode bytecode, uint32_t operand0, uint32_t operand1,
278              uint32_t operand2, uint32_t operand3);
279  void Output(Bytecode bytecode, uint32_t operand0, uint32_t operand1,
280              uint32_t operand2);
281  void Output(Bytecode bytecode, uint32_t operand0, uint32_t operand1);
282  void Output(Bytecode bytecode, uint32_t operand0);
283  void Output(Bytecode bytecode);
284
285  BytecodeArrayBuilder& OutputJump(Bytecode jump_bytecode,
286                                   BytecodeLabel* label);
287  void PatchJump(const ZoneVector<uint8_t>::iterator& jump_target,
288                 const ZoneVector<uint8_t>::iterator& jump_location);
289  void PatchIndirectJumpWith8BitOperand(
290      const ZoneVector<uint8_t>::iterator& jump_location, int delta);
291  void PatchIndirectJumpWith16BitOperand(
292      const ZoneVector<uint8_t>::iterator& jump_location, int delta);
293
294  void LeaveBasicBlock();
295  void EnsureReturn();
296
297  bool OperandIsValid(Bytecode bytecode, int operand_index,
298                      uint32_t operand_value) const;
299  bool LastBytecodeInSameBlock() const;
300
301  bool NeedToBooleanCast();
302  bool IsRegisterInAccumulator(Register reg);
303
304  bool RegisterIsValid(Register reg) const;
305
306  // Temporary register management.
307  int BorrowTemporaryRegister();
308  int BorrowTemporaryRegisterNotInRange(int start_index, int end_index);
309  void ReturnTemporaryRegister(int reg_index);
310  int PrepareForConsecutiveTemporaryRegisters(size_t count);
311  void BorrowConsecutiveTemporaryRegister(int reg_index);
312  bool TemporaryRegisterIsLive(Register reg) const;
313
314  Register first_temporary_register() const;
315  Register last_temporary_register() const;
316
317  // Gets a constant pool entry for the |object|.
318  size_t GetConstantPoolEntry(Handle<Object> object);
319
320  Isolate* isolate_;
321  Zone* zone_;
322  ZoneVector<uint8_t> bytecodes_;
323  bool bytecode_generated_;
324  ConstantArrayBuilder constant_array_builder_;
325  size_t last_block_end_;
326  size_t last_bytecode_start_;
327  bool exit_seen_in_block_;
328  int unbound_jumps_;
329
330  int parameter_count_;
331  int local_register_count_;
332  int context_register_count_;
333  int temporary_register_count_;
334  ZoneSet<int> free_temporaries_;
335
336  class PreviousBytecodeHelper;
337  friend class BytecodeRegisterAllocator;
338
339  DISALLOW_COPY_AND_ASSIGN(BytecodeArrayBuilder);
340};
341
342
343// A label representing a branch target in a bytecode array. When a
344// label is bound, it represents a known position in the bytecode
345// array. For labels that are forward references there can be at most
346// one reference whilst it is unbound.
347class BytecodeLabel final {
348 public:
349  BytecodeLabel() : bound_(false), offset_(kInvalidOffset) {}
350
351  bool is_bound() const { return bound_; }
352  size_t offset() const { return offset_; }
353
354 private:
355  static const size_t kInvalidOffset = static_cast<size_t>(-1);
356
357  void bind_to(size_t offset) {
358    DCHECK(!bound_ && offset != kInvalidOffset);
359    offset_ = offset;
360    bound_ = true;
361  }
362
363  void set_referrer(size_t offset) {
364    DCHECK(!bound_ && offset != kInvalidOffset && offset_ == kInvalidOffset);
365    offset_ = offset;
366  }
367
368  bool is_forward_target() const {
369    return offset() != kInvalidOffset && !is_bound();
370  }
371
372  // There are three states for a label:
373  //                    bound_   offset_
374  //  UNSET             false    kInvalidOffset
375  //  FORWARD_TARGET    false    Offset of referring jump
376  //  BACKWARD_TARGET    true    Offset of label in bytecode array when bound
377  bool bound_;
378  size_t offset_;
379
380  friend class BytecodeArrayBuilder;
381};
382
383}  // namespace interpreter
384}  // namespace internal
385}  // namespace v8
386
387#endif  // V8_INTERPRETER_BYTECODE_ARRAY_BUILDER_H_
388