Home | History | Annotate | Download | only in interpreter
      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);
     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.
    347 class 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