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/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 
     16 namespace v8 {
     17 namespace internal {
     18 
     19 class Isolate;
     20 
     21 namespace interpreter {
     22 
     23 class BytecodeLabel;
     24 class BytecodeNode;
     25 class BytecodePipelineStage;
     26 class Register;
     27 
     28 class 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