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/base/compiler-specific.h"
     10 #include "src/globals.h"
     11 #include "src/interpreter/bytecode-array-writer.h"
     12 #include "src/interpreter/bytecode-register-allocator.h"
     13 #include "src/interpreter/bytecode-register.h"
     14 #include "src/interpreter/bytecodes.h"
     15 #include "src/interpreter/constant-array-builder.h"
     16 #include "src/interpreter/handler-table-builder.h"
     17 #include "src/zone/zone-containers.h"
     18 
     19 namespace v8 {
     20 namespace internal {
     21 
     22 class Isolate;
     23 
     24 namespace interpreter {
     25 
     26 class BytecodeLabel;
     27 class BytecodeNode;
     28 class BytecodePipelineStage;
     29 class BytecodeRegisterOptimizer;
     30 class Register;
     31 
     32 class V8_EXPORT_PRIVATE BytecodeArrayBuilder final
     33     : public NON_EXPORTED_BASE(ZoneObject) {
     34  public:
     35   BytecodeArrayBuilder(
     36       Isolate* isolate, Zone* zone, int parameter_count, int context_count,
     37       int locals_count, FunctionLiteral* literal = nullptr,
     38       SourcePositionTableBuilder::RecordingMode source_position_mode =
     39           SourcePositionTableBuilder::RECORD_SOURCE_POSITIONS);
     40 
     41   Handle<BytecodeArray> ToBytecodeArray(Isolate* isolate);
     42 
     43   // Get the number of parameters expected by function.
     44   int parameter_count() const {
     45     DCHECK_GE(parameter_count_, 0);
     46     return parameter_count_;
     47   }
     48 
     49   // Get the number of locals required for bytecode array.
     50   int locals_count() const {
     51     DCHECK_GE(local_register_count_, 0);
     52     return local_register_count_;
     53   }
     54 
     55   // Get number of contexts required for bytecode array.
     56   int context_count() const {
     57     DCHECK_GE(context_register_count_, 0);
     58     return context_register_count_;
     59   }
     60 
     61   Register first_context_register() const;
     62   Register last_context_register() const;
     63 
     64   // Returns the number of fixed (non-temporary) registers.
     65   int fixed_register_count() const { return context_count() + locals_count(); }
     66 
     67   // Returns the number of fixed and temporary registers.
     68   int total_register_count() const {
     69     DCHECK_LE(fixed_register_count(),
     70               register_allocator()->maximum_register_count());
     71     return register_allocator()->maximum_register_count();
     72   }
     73 
     74   Register Parameter(int parameter_index) const;
     75 
     76   // Constant loads to accumulator.
     77   BytecodeArrayBuilder& LoadConstantPoolEntry(size_t entry);
     78   BytecodeArrayBuilder& LoadLiteral(v8::internal::Smi* value);
     79   BytecodeArrayBuilder& LoadLiteral(Handle<Object> object);
     80   BytecodeArrayBuilder& LoadUndefined();
     81   BytecodeArrayBuilder& LoadNull();
     82   BytecodeArrayBuilder& LoadTheHole();
     83   BytecodeArrayBuilder& LoadTrue();
     84   BytecodeArrayBuilder& LoadFalse();
     85 
     86   // Global loads to the accumulator and stores from the accumulator.
     87   BytecodeArrayBuilder& LoadGlobal(int feedback_slot, TypeofMode typeof_mode);
     88   BytecodeArrayBuilder& StoreGlobal(const Handle<String> name,
     89                                     int feedback_slot,
     90                                     LanguageMode language_mode);
     91 
     92   // Load the object at |slot_index| at |depth| in the context chain starting
     93   // with |context| into the accumulator.
     94   BytecodeArrayBuilder& LoadContextSlot(Register context, int slot_index,
     95                                         int depth);
     96 
     97   // Stores the object in the accumulator into |slot_index| at |depth| in the
     98   // context chain starting with |context|.
     99   BytecodeArrayBuilder& StoreContextSlot(Register context, int slot_index,
    100                                          int depth);
    101 
    102   // Load from a module variable into the accumulator. |depth| is the depth of
    103   // the current context relative to the module context.
    104   BytecodeArrayBuilder& LoadModuleVariable(int cell_index, int depth);
    105 
    106   // Store from the accumulator into a module variable. |depth| is the depth of
    107   // the current context relative to the module context.
    108   BytecodeArrayBuilder& StoreModuleVariable(int cell_index, int depth);
    109 
    110   // Register-accumulator transfers.
    111   BytecodeArrayBuilder& LoadAccumulatorWithRegister(Register reg);
    112   BytecodeArrayBuilder& StoreAccumulatorInRegister(Register reg);
    113 
    114   // Register-register transfer.
    115   BytecodeArrayBuilder& MoveRegister(Register from, Register to);
    116 
    117   // Named load property.
    118   BytecodeArrayBuilder& LoadNamedProperty(Register object,
    119                                           const Handle<Name> name,
    120                                           int feedback_slot);
    121   // Keyed load property. The key should be in the accumulator.
    122   BytecodeArrayBuilder& LoadKeyedProperty(Register object, int feedback_slot);
    123 
    124   // Store properties. The value to be stored should be in the accumulator.
    125   BytecodeArrayBuilder& StoreNamedProperty(Register object,
    126                                            const Handle<Name> name,
    127                                            int feedback_slot,
    128                                            LanguageMode language_mode);
    129   BytecodeArrayBuilder& StoreKeyedProperty(Register object, Register key,
    130                                            int feedback_slot,
    131                                            LanguageMode language_mode);
    132 
    133   // Lookup the variable with |name|.
    134   BytecodeArrayBuilder& LoadLookupSlot(const Handle<String> name,
    135                                        TypeofMode typeof_mode);
    136 
    137   // Lookup the variable with |name|, which is known to be at |slot_index| at
    138   // |depth| in the context chain if not shadowed by a context extension
    139   // somewhere in that context chain.
    140   BytecodeArrayBuilder& LoadLookupContextSlot(const Handle<String> name,
    141                                               TypeofMode typeof_mode,
    142                                               int slot_index, int depth);
    143 
    144   // Lookup the variable with |name|, which has its feedback in |feedback_slot|
    145   // and is known to be global if not shadowed by a context extension somewhere
    146   // up to |depth| in that context chain.
    147   BytecodeArrayBuilder& LoadLookupGlobalSlot(const Handle<String> name,
    148                                              TypeofMode typeof_mode,
    149                                              int feedback_slot, int depth);
    150 
    151   // Store value in the accumulator into the variable with |name|.
    152   BytecodeArrayBuilder& StoreLookupSlot(const Handle<String> name,
    153                                         LanguageMode language_mode);
    154 
    155   // Create a new closure for a SharedFunctionInfo which will be inserted at
    156   // constant pool index |entry|.
    157   BytecodeArrayBuilder& CreateClosure(size_t entry, int flags);
    158 
    159   // Create a new local context for a |scope_info| and a closure which should be
    160   // in the accumulator.
    161   BytecodeArrayBuilder& CreateBlockContext(Handle<ScopeInfo> scope_info);
    162 
    163   // Create a new context for a catch block with |exception|, |name|,
    164   // |scope_info|, and the closure in the accumulator.
    165   BytecodeArrayBuilder& CreateCatchContext(Register exception,
    166                                            Handle<String> name,
    167                                            Handle<ScopeInfo> scope_info);
    168 
    169   // Create a new context with size |slots|.
    170   BytecodeArrayBuilder& CreateFunctionContext(int slots);
    171 
    172   // Creates a new context with the given |scope_info| for a with-statement
    173   // with the |object| in a register and the closure in the accumulator.
    174   BytecodeArrayBuilder& CreateWithContext(Register object,
    175                                           Handle<ScopeInfo> scope_info);
    176 
    177   // Create a new arguments object in the accumulator.
    178   BytecodeArrayBuilder& CreateArguments(CreateArgumentsType type);
    179 
    180   // Literals creation.  Constant elements should be in the accumulator.
    181   BytecodeArrayBuilder& CreateRegExpLiteral(Handle<String> pattern,
    182                                             int literal_index, int flags);
    183   BytecodeArrayBuilder& CreateArrayLiteral(Handle<FixedArray> constant_elements,
    184                                            int literal_index, int flags);
    185   BytecodeArrayBuilder& CreateObjectLiteral(
    186       Handle<FixedArray> constant_properties, int literal_index, int flags,
    187       Register output);
    188 
    189   // Push the context in accumulator as the new context, and store in register
    190   // |context|.
    191   BytecodeArrayBuilder& PushContext(Register context);
    192 
    193   // Pop the current context and replace with |context|.
    194   BytecodeArrayBuilder& PopContext(Register context);
    195 
    196   // Call a JS function. The JSFunction or Callable to be called should be in
    197   // |callable|. The arguments should be in |args|, with the receiver in
    198   // |args[0]|. The call type of the expression is in |call_type|. Type feedback
    199   // is recorded in the |feedback_slot| in the type feedback vector.
    200   BytecodeArrayBuilder& Call(
    201       Register callable, RegisterList args, int feedback_slot,
    202       Call::CallType call_type,
    203       TailCallMode tail_call_mode = TailCallMode::kDisallow);
    204 
    205   // Call the new operator. The accumulator holds the |new_target|.
    206   // The |constructor| is in a register and arguments are in |args|.
    207   BytecodeArrayBuilder& New(Register constructor, RegisterList args,
    208                             int feedback_slot);
    209 
    210   // Call the runtime function with |function_id| and arguments |args|.
    211   BytecodeArrayBuilder& CallRuntime(Runtime::FunctionId function_id,
    212                                     RegisterList args);
    213   // Call the runtime function with |function_id| with single argument |arg|.
    214   BytecodeArrayBuilder& CallRuntime(Runtime::FunctionId function_id,
    215                                     Register arg);
    216   // Call the runtime function with |function_id| with no arguments.
    217   BytecodeArrayBuilder& CallRuntime(Runtime::FunctionId function_id);
    218 
    219   // Call the runtime function with |function_id| and arguments |args|, that
    220   // returns a pair of values. The return values will be returned in
    221   // |return_pair|.
    222   BytecodeArrayBuilder& CallRuntimeForPair(Runtime::FunctionId function_id,
    223                                            RegisterList args,
    224                                            RegisterList return_pair);
    225   // Call the runtime function with |function_id| with single argument |arg|
    226   // that returns a pair of values. The return values will be returned in
    227   // |return_pair|.
    228   BytecodeArrayBuilder& CallRuntimeForPair(Runtime::FunctionId function_id,
    229                                            Register arg,
    230                                            RegisterList return_pair);
    231 
    232   // Call the JS runtime function with |context_index| and arguments |args|.
    233   BytecodeArrayBuilder& CallJSRuntime(int context_index, RegisterList args);
    234 
    235   // Operators (register holds the lhs value, accumulator holds the rhs value).
    236   // Type feedback will be recorded in the |feedback_slot|
    237   BytecodeArrayBuilder& BinaryOperation(Token::Value binop, Register reg,
    238                                         int feedback_slot);
    239 
    240   // Count Operators (value stored in accumulator).
    241   // Type feedback will be recorded in the |feedback_slot|
    242   BytecodeArrayBuilder& CountOperation(Token::Value op, int feedback_slot);
    243 
    244   // Unary Operators.
    245   BytecodeArrayBuilder& LogicalNot();
    246   BytecodeArrayBuilder& TypeOf();
    247 
    248   // Deletes property from an object. This expects that accumulator contains
    249   // the key to be deleted and the register contains a reference to the object.
    250   BytecodeArrayBuilder& Delete(Register object, LanguageMode language_mode);
    251 
    252   // Tests.
    253   BytecodeArrayBuilder& CompareOperation(Token::Value op, Register reg,
    254                                          int feedback_slot = kNoFeedbackSlot);
    255 
    256   // Converts accumulator and stores result in register |out|.
    257   BytecodeArrayBuilder& ConvertAccumulatorToObject(Register out);
    258   BytecodeArrayBuilder& ConvertAccumulatorToName(Register out);
    259   BytecodeArrayBuilder& ConvertAccumulatorToNumber(Register out);
    260 
    261   // Flow Control.
    262   BytecodeArrayBuilder& Bind(BytecodeLabel* label);
    263   BytecodeArrayBuilder& Bind(const BytecodeLabel& target, BytecodeLabel* label);
    264 
    265   BytecodeArrayBuilder& Jump(BytecodeLabel* label);
    266   BytecodeArrayBuilder& JumpIfTrue(BytecodeLabel* label);
    267   BytecodeArrayBuilder& JumpIfFalse(BytecodeLabel* label);
    268   BytecodeArrayBuilder& JumpIfNotHole(BytecodeLabel* label);
    269   BytecodeArrayBuilder& JumpIfNull(BytecodeLabel* label);
    270   BytecodeArrayBuilder& JumpIfUndefined(BytecodeLabel* label);
    271   BytecodeArrayBuilder& JumpLoop(BytecodeLabel* label, int loop_depth);
    272 
    273   BytecodeArrayBuilder& StackCheck(int position);
    274 
    275   BytecodeArrayBuilder& Throw();
    276   BytecodeArrayBuilder& ReThrow();
    277   BytecodeArrayBuilder& Return();
    278 
    279   // Debugger.
    280   BytecodeArrayBuilder& Debugger();
    281 
    282   // Complex flow control.
    283   BytecodeArrayBuilder& ForInPrepare(Register receiver,
    284                                      RegisterList cache_info_triple);
    285   BytecodeArrayBuilder& ForInContinue(Register index, Register cache_length);
    286   BytecodeArrayBuilder& ForInNext(Register receiver, Register index,
    287                                   RegisterList cache_type_array_pair,
    288                                   int feedback_slot);
    289   BytecodeArrayBuilder& ForInStep(Register index);
    290 
    291   // Generators.
    292   BytecodeArrayBuilder& SuspendGenerator(Register generator);
    293   BytecodeArrayBuilder& ResumeGenerator(Register generator);
    294 
    295   // Exception handling.
    296   BytecodeArrayBuilder& MarkHandler(int handler_id,
    297                                     HandlerTable::CatchPrediction will_catch);
    298   BytecodeArrayBuilder& MarkTryBegin(int handler_id, Register context);
    299   BytecodeArrayBuilder& MarkTryEnd(int handler_id);
    300 
    301   // Creates a new handler table entry and returns a {hander_id} identifying the
    302   // entry, so that it can be referenced by above exception handling support.
    303   int NewHandlerEntry() { return handler_table_builder()->NewHandlerEntry(); }
    304 
    305   // Allocates a slot in the constant pool which can later be inserted.
    306   size_t AllocateConstantPoolEntry();
    307   // Inserts a entry into an allocated constant pool entry.
    308   void InsertConstantPoolEntryAt(size_t entry, Handle<Object> object);
    309 
    310   void InitializeReturnPosition(FunctionLiteral* literal);
    311 
    312   void SetStatementPosition(Statement* stmt) {
    313     if (stmt->position() == kNoSourcePosition) return;
    314     latest_source_info_.MakeStatementPosition(stmt->position());
    315   }
    316 
    317   void SetExpressionPosition(Expression* expr) {
    318     if (expr->position() == kNoSourcePosition) return;
    319     if (!latest_source_info_.is_statement()) {
    320       // Ensure the current expression position is overwritten with the
    321       // latest value.
    322       latest_source_info_.MakeExpressionPosition(expr->position());
    323     }
    324   }
    325 
    326   void SetExpressionAsStatementPosition(Expression* expr) {
    327     if (expr->position() == kNoSourcePosition) return;
    328     latest_source_info_.MakeStatementPosition(expr->position());
    329   }
    330 
    331   bool RequiresImplicitReturn() const { return !return_seen_in_block_; }
    332 
    333   // Returns the raw operand value for the given register or register list.
    334   uint32_t GetInputRegisterOperand(Register reg);
    335   uint32_t GetOutputRegisterOperand(Register reg);
    336   uint32_t GetInputRegisterListOperand(RegisterList reg_list);
    337   uint32_t GetOutputRegisterListOperand(RegisterList reg_list);
    338 
    339   // Accessors
    340   BytecodeRegisterAllocator* register_allocator() {
    341     return &register_allocator_;
    342   }
    343   const BytecodeRegisterAllocator* register_allocator() const {
    344     return &register_allocator_;
    345   }
    346   Zone* zone() const { return zone_; }
    347 
    348  private:
    349   friend class BytecodeRegisterAllocator;
    350   template <OperandType... operand_types>
    351   friend class BytecodeNodeBuilder;
    352 
    353   // Returns the current source position for the given |bytecode|.
    354   INLINE(BytecodeSourceInfo CurrentSourcePosition(Bytecode bytecode));
    355 
    356 #define DECLARE_BYTECODE_OUTPUT(Name, ...)         \
    357   template <typename... Operands>                  \
    358   INLINE(void Output##Name(Operands... operands)); \
    359   template <typename... Operands>                  \
    360   INLINE(void Output##Name(BytecodeLabel* label, Operands... operands));
    361   BYTECODE_LIST(DECLARE_BYTECODE_OUTPUT)
    362 #undef DECLARE_OPERAND_TYPE_INFO
    363 
    364   bool RegisterIsValid(Register reg) const;
    365   bool RegisterListIsValid(RegisterList reg_list) const;
    366 
    367   // Set position for return.
    368   void SetReturnPosition();
    369 
    370   // Gets a constant pool entry for the |object|.
    371   size_t GetConstantPoolEntry(Handle<Object> object);
    372 
    373   // Not implemented as the illegal bytecode is used inside internally
    374   // to indicate a bytecode field is not valid or an error has occured
    375   // during bytecode generation.
    376   BytecodeArrayBuilder& Illegal();
    377 
    378   void PrepareToOutputBytecode(Bytecode bytecode);
    379 
    380   void LeaveBasicBlock() { return_seen_in_block_ = false; }
    381 
    382   BytecodeArrayWriter* bytecode_array_writer() {
    383     return &bytecode_array_writer_;
    384   }
    385   BytecodePipelineStage* pipeline() { return pipeline_; }
    386   ConstantArrayBuilder* constant_array_builder() {
    387     return &constant_array_builder_;
    388   }
    389   const ConstantArrayBuilder* constant_array_builder() const {
    390     return &constant_array_builder_;
    391   }
    392   HandlerTableBuilder* handler_table_builder() {
    393     return &handler_table_builder_;
    394   }
    395 
    396   Zone* zone_;
    397   bool bytecode_generated_;
    398   ConstantArrayBuilder constant_array_builder_;
    399   HandlerTableBuilder handler_table_builder_;
    400   bool return_seen_in_block_;
    401   int parameter_count_;
    402   int local_register_count_;
    403   int context_register_count_;
    404   int return_position_;
    405   BytecodeRegisterAllocator register_allocator_;
    406   BytecodeArrayWriter bytecode_array_writer_;
    407   BytecodePipelineStage* pipeline_;
    408   BytecodeRegisterOptimizer* register_optimizer_;
    409   BytecodeSourceInfo latest_source_info_;
    410 
    411   static int const kNoFeedbackSlot = 0;
    412 
    413   DISALLOW_COPY_AND_ASSIGN(BytecodeArrayBuilder);
    414 };
    415 
    416 }  // namespace interpreter
    417 }  // namespace internal
    418 }  // namespace v8
    419 
    420 #endif  // V8_INTERPRETER_BYTECODE_ARRAY_BUILDER_H_
    421