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 
13 namespace v8 {
14 namespace internal {
15 
16 class Isolate;
17 
18 namespace interpreter {
19 
20 class BytecodeLabel;
21 class ConstantArrayBuilder;
22 class Register;
23 
24 // TODO(rmcilroy): Unify this with CreateArgumentsParameters::Type in Turbofan
25 // when rest parameters implementation has settled down.
26 enum class CreateArgumentsType { kMappedArguments, kUnmappedArguments };
27 
28 class 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);
parameter_count()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);
locals_count()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);
context_count()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.
fixed_register_count()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
zone()232   Zone* zone() const { return zone_; }
233 
234  private:
bytecodes()235   ZoneVector<uint8_t>* bytecodes() { return &bytecodes_; }
bytecodes()236   const ZoneVector<uint8_t>* bytecodes() const { return &bytecodes_; }
isolate()237   Isolate* isolate() const { return isolate_; }
constant_array_builder()238   ConstantArrayBuilder* constant_array_builder() {
239     return &constant_array_builder_;
240   }
constant_array_builder()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.
347 class BytecodeLabel final {
348  public:
BytecodeLabel()349   BytecodeLabel() : bound_(false), offset_(kInvalidOffset) {}
350 
is_bound()351   bool is_bound() const { return bound_; }
offset()352   size_t offset() const { return offset_; }
353 
354  private:
355   static const size_t kInvalidOffset = static_cast<size_t>(-1);
356 
bind_to(size_t offset)357   void bind_to(size_t offset) {
358     DCHECK(!bound_ && offset != kInvalidOffset);
359     offset_ = offset;
360     bound_ = true;
361   }
362 
set_referrer(size_t offset)363   void set_referrer(size_t offset) {
364     DCHECK(!bound_ && offset != kInvalidOffset && offset_ == kInvalidOffset);
365     offset_ = offset;
366   }
367 
is_forward_target()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