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 Local(int index) const;
     75   Register Parameter(int parameter_index) const;
     76 
     77   // Constant loads to accumulator.
     78   BytecodeArrayBuilder& LoadConstantPoolEntry(size_t entry);
     79   BytecodeArrayBuilder& LoadLiteral(v8::internal::Smi* value);
     80   BytecodeArrayBuilder& LoadLiteral(const AstRawString* raw_string);
     81   BytecodeArrayBuilder& LoadLiteral(const Scope* scope);
     82   BytecodeArrayBuilder& LoadLiteral(const AstValue* ast_value);
     83   BytecodeArrayBuilder& LoadUndefined();
     84   BytecodeArrayBuilder& LoadNull();
     85   BytecodeArrayBuilder& LoadTheHole();
     86   BytecodeArrayBuilder& LoadTrue();
     87   BytecodeArrayBuilder& LoadFalse();
     88 
     89   // Global loads to the accumulator and stores from the accumulator.
     90   BytecodeArrayBuilder& LoadGlobal(const AstRawString* name, int feedback_slot,
     91                                    TypeofMode typeof_mode);
     92   BytecodeArrayBuilder& StoreGlobal(const AstRawString* name, int feedback_slot,
     93                                     LanguageMode language_mode);
     94 
     95   // Load the object at |slot_index| at |depth| in the context chain starting
     96   // with |context| into the accumulator.
     97   enum ContextSlotMutability { kImmutableSlot, kMutableSlot };
     98   BytecodeArrayBuilder& LoadContextSlot(Register context, int slot_index,
     99                                         int depth,
    100                                         ContextSlotMutability immutable);
    101 
    102   // Stores the object in the accumulator into |slot_index| at |depth| in the
    103   // context chain starting with |context|.
    104   BytecodeArrayBuilder& StoreContextSlot(Register context, int slot_index,
    105                                          int depth);
    106 
    107   // Load from a module variable into the accumulator. |depth| is the depth of
    108   // the current context relative to the module context.
    109   BytecodeArrayBuilder& LoadModuleVariable(int cell_index, int depth);
    110 
    111   // Store from the accumulator into a module variable. |depth| is the depth of
    112   // the current context relative to the module context.
    113   BytecodeArrayBuilder& StoreModuleVariable(int cell_index, int depth);
    114 
    115   // Register-accumulator transfers.
    116   BytecodeArrayBuilder& LoadAccumulatorWithRegister(Register reg);
    117   BytecodeArrayBuilder& StoreAccumulatorInRegister(Register reg);
    118 
    119   // Register-register transfer.
    120   BytecodeArrayBuilder& MoveRegister(Register from, Register to);
    121 
    122   // Named load property.
    123   BytecodeArrayBuilder& LoadNamedProperty(Register object,
    124                                           const AstRawString* name,
    125                                           int feedback_slot);
    126   // Keyed load property. The key should be in the accumulator.
    127   BytecodeArrayBuilder& LoadKeyedProperty(Register object, int feedback_slot);
    128   // Named load property of the @@iterator symbol.
    129   BytecodeArrayBuilder& LoadIteratorProperty(Register object,
    130                                              int feedback_slot);
    131   // Named load property of the @@asyncIterator symbol.
    132   BytecodeArrayBuilder& LoadAsyncIteratorProperty(Register object,
    133                                                   int feedback_slot);
    134 
    135   // Store properties. Flag for NeedsSetFunctionName() should
    136   // be in the accumulator.
    137   BytecodeArrayBuilder& StoreDataPropertyInLiteral(
    138       Register object, Register name, DataPropertyInLiteralFlags flags,
    139       int feedback_slot);
    140 
    141   // Store a property named by a property name. The value to be stored should be
    142   // in the accumulator.
    143   BytecodeArrayBuilder& StoreNamedProperty(Register object,
    144                                            const AstRawString* name,
    145                                            int feedback_slot,
    146                                            LanguageMode language_mode);
    147   // Store a property named by a constant from the constant pool. The value to
    148   // be stored should be in the accumulator.
    149   BytecodeArrayBuilder& StoreNamedProperty(Register object,
    150                                            size_t constant_pool_entry,
    151                                            int feedback_slot,
    152                                            LanguageMode language_mode);
    153   // Store an own property named by a constant from the constant pool. The
    154   // value to be stored should be in the accumulator.
    155   BytecodeArrayBuilder& StoreNamedOwnProperty(Register object,
    156                                               const AstRawString* name,
    157                                               int feedback_slot);
    158   // Store a property keyed by a value in a register. The value to be stored
    159   // should be in the accumulator.
    160   BytecodeArrayBuilder& StoreKeyedProperty(Register object, Register key,
    161                                            int feedback_slot,
    162                                            LanguageMode language_mode);
    163   // Store the home object property. The value to be stored should be in the
    164   // accumulator.
    165   BytecodeArrayBuilder& StoreHomeObjectProperty(Register object,
    166                                                 int feedback_slot,
    167                                                 LanguageMode language_mode);
    168 
    169   // Lookup the variable with |name|.
    170   BytecodeArrayBuilder& LoadLookupSlot(const AstRawString* name,
    171                                        TypeofMode typeof_mode);
    172 
    173   // Lookup the variable with |name|, which is known to be at |slot_index| at
    174   // |depth| in the context chain if not shadowed by a context extension
    175   // somewhere in that context chain.
    176   BytecodeArrayBuilder& LoadLookupContextSlot(const AstRawString* name,
    177                                               TypeofMode typeof_mode,
    178                                               int slot_index, int depth);
    179 
    180   // Lookup the variable with |name|, which has its feedback in |feedback_slot|
    181   // and is known to be global if not shadowed by a context extension somewhere
    182   // up to |depth| in that context chain.
    183   BytecodeArrayBuilder& LoadLookupGlobalSlot(const AstRawString* name,
    184                                              TypeofMode typeof_mode,
    185                                              int feedback_slot, int depth);
    186 
    187   // Store value in the accumulator into the variable with |name|.
    188   BytecodeArrayBuilder& StoreLookupSlot(const AstRawString* name,
    189                                         LanguageMode language_mode);
    190 
    191   // Create a new closure for a SharedFunctionInfo which will be inserted at
    192   // constant pool index |shared_function_info_entry|.
    193   BytecodeArrayBuilder& CreateClosure(size_t shared_function_info_entry,
    194                                       int slot, int flags);
    195 
    196   // Create a new local context for a |scope| and a closure which should be
    197   // in the accumulator.
    198   BytecodeArrayBuilder& CreateBlockContext(const Scope* scope);
    199 
    200   // Create a new context for a catch block with |exception|, |name|,
    201   // |scope|, and the closure in the accumulator.
    202   BytecodeArrayBuilder& CreateCatchContext(Register exception,
    203                                            const AstRawString* name,
    204                                            const Scope* scope);
    205 
    206   // Create a new context with size |slots|.
    207   BytecodeArrayBuilder& CreateFunctionContext(int slots);
    208 
    209   // Create a new eval context with size |slots|.
    210   BytecodeArrayBuilder& CreateEvalContext(int slots);
    211 
    212   // Creates a new context with the given |scope| for a with-statement
    213   // with the |object| in a register and the closure in the accumulator.
    214   BytecodeArrayBuilder& CreateWithContext(Register object, const Scope* scope);
    215 
    216   // Create a new arguments object in the accumulator.
    217   BytecodeArrayBuilder& CreateArguments(CreateArgumentsType type);
    218 
    219   // Literals creation.  Constant elements should be in the accumulator.
    220   BytecodeArrayBuilder& CreateRegExpLiteral(const AstRawString* pattern,
    221                                             int literal_index, int flags);
    222   BytecodeArrayBuilder& CreateArrayLiteral(size_t constant_elements_entry,
    223                                            int literal_index, int flags);
    224   BytecodeArrayBuilder& CreateObjectLiteral(size_t constant_properties_entry,
    225                                             int literal_index, int flags,
    226                                             Register output);
    227 
    228   // Push the context in accumulator as the new context, and store in register
    229   // |context|.
    230   BytecodeArrayBuilder& PushContext(Register context);
    231 
    232   // Pop the current context and replace with |context|.
    233   BytecodeArrayBuilder& PopContext(Register context);
    234 
    235   // Call a JS function. The JSFunction or Callable to be called should be in
    236   // |callable|. The arguments should be in |args|, with the receiver in
    237   // |args[0]|. The call type of the expression is in |call_type|. Type feedback
    238   // is recorded in the |feedback_slot| in the type feedback vector.
    239   BytecodeArrayBuilder& Call(
    240       Register callable, RegisterList args, int feedback_slot,
    241       Call::CallType call_type,
    242       TailCallMode tail_call_mode = TailCallMode::kDisallow);
    243 
    244   // Call a JS function. The JSFunction or Callable to be called should be in
    245   // |callable|, the receiver in |args[0]| and the arguments in |args[1]|
    246   // onwards. The final argument must be a spread.
    247   BytecodeArrayBuilder& CallWithSpread(Register callable, RegisterList args);
    248 
    249   // Call the Construct operator. The accumulator holds the |new_target|.
    250   // The |constructor| is in a register and arguments are in |args|.
    251   BytecodeArrayBuilder& Construct(Register constructor, RegisterList args,
    252                                   int feedback_slot);
    253 
    254   // Call the Construct operator for use with a spread. The accumulator holds
    255   // the |new_target|. The |constructor| is in a register and arguments are in
    256   // |args|. The final argument must be a spread.
    257   BytecodeArrayBuilder& ConstructWithSpread(Register constructor,
    258                                             RegisterList args);
    259 
    260   // Call the runtime function with |function_id| and arguments |args|.
    261   BytecodeArrayBuilder& CallRuntime(Runtime::FunctionId function_id,
    262                                     RegisterList args);
    263   // Call the runtime function with |function_id| with single argument |arg|.
    264   BytecodeArrayBuilder& CallRuntime(Runtime::FunctionId function_id,
    265                                     Register arg);
    266   // Call the runtime function with |function_id| with no arguments.
    267   BytecodeArrayBuilder& CallRuntime(Runtime::FunctionId function_id);
    268 
    269   // Call the runtime function with |function_id| and arguments |args|, that
    270   // returns a pair of values. The return values will be returned in
    271   // |return_pair|.
    272   BytecodeArrayBuilder& CallRuntimeForPair(Runtime::FunctionId function_id,
    273                                            RegisterList args,
    274                                            RegisterList return_pair);
    275   // Call the runtime function with |function_id| with single argument |arg|
    276   // that returns a pair of values. The return values will be returned in
    277   // |return_pair|.
    278   BytecodeArrayBuilder& CallRuntimeForPair(Runtime::FunctionId function_id,
    279                                            Register arg,
    280                                            RegisterList return_pair);
    281 
    282   // Call the JS runtime function with |context_index| and arguments |args|.
    283   BytecodeArrayBuilder& CallJSRuntime(int context_index, RegisterList args);
    284 
    285   // Operators (register holds the lhs value, accumulator holds the rhs value).
    286   // Type feedback will be recorded in the |feedback_slot|
    287   BytecodeArrayBuilder& BinaryOperation(Token::Value binop, Register reg,
    288                                         int feedback_slot);
    289 
    290   // Count Operators (value stored in accumulator).
    291   // Type feedback will be recorded in the |feedback_slot|
    292   BytecodeArrayBuilder& CountOperation(Token::Value op, int feedback_slot);
    293 
    294   // Unary Operators.
    295   BytecodeArrayBuilder& LogicalNot();
    296   BytecodeArrayBuilder& TypeOf();
    297 
    298   // Expects a heap object in the accumulator. Returns its super constructor in
    299   // the register |out| if it passes the IsConstructor test. Otherwise, it
    300   // throws a TypeError exception.
    301   BytecodeArrayBuilder& GetSuperConstructor(Register out);
    302 
    303   // Deletes property from an object. This expects that accumulator contains
    304   // the key to be deleted and the register contains a reference to the object.
    305   BytecodeArrayBuilder& Delete(Register object, LanguageMode language_mode);
    306 
    307   // Tests.
    308   BytecodeArrayBuilder& CompareOperation(Token::Value op, Register reg,
    309                                          int feedback_slot = kNoFeedbackSlot);
    310 
    311   // Converts accumulator and stores result in register |out|.
    312   BytecodeArrayBuilder& ConvertAccumulatorToObject(Register out);
    313   BytecodeArrayBuilder& ConvertAccumulatorToName(Register out);
    314   BytecodeArrayBuilder& ConvertAccumulatorToNumber(Register out);
    315 
    316   // Flow Control.
    317   BytecodeArrayBuilder& Bind(BytecodeLabel* label);
    318   BytecodeArrayBuilder& Bind(const BytecodeLabel& target, BytecodeLabel* label);
    319 
    320   BytecodeArrayBuilder& Jump(BytecodeLabel* label);
    321   BytecodeArrayBuilder& JumpIfTrue(BytecodeLabel* label);
    322   BytecodeArrayBuilder& JumpIfFalse(BytecodeLabel* label);
    323   BytecodeArrayBuilder& JumpIfNotHole(BytecodeLabel* label);
    324   BytecodeArrayBuilder& JumpIfJSReceiver(BytecodeLabel* label);
    325   BytecodeArrayBuilder& JumpIfNull(BytecodeLabel* label);
    326   BytecodeArrayBuilder& JumpIfUndefined(BytecodeLabel* label);
    327   BytecodeArrayBuilder& JumpLoop(BytecodeLabel* label, int loop_depth);
    328 
    329   BytecodeArrayBuilder& StackCheck(int position);
    330 
    331   // Sets the pending message to the value in the accumulator, and returns the
    332   // previous pending message in the accumulator.
    333   BytecodeArrayBuilder& SetPendingMessage();
    334 
    335   BytecodeArrayBuilder& Throw();
    336   BytecodeArrayBuilder& ReThrow();
    337   BytecodeArrayBuilder& Return();
    338 
    339   // Debugger.
    340   BytecodeArrayBuilder& Debugger();
    341 
    342   // Complex flow control.
    343   BytecodeArrayBuilder& ForInPrepare(Register receiver,
    344                                      RegisterList cache_info_triple);
    345   BytecodeArrayBuilder& ForInContinue(Register index, Register cache_length);
    346   BytecodeArrayBuilder& ForInNext(Register receiver, Register index,
    347                                   RegisterList cache_type_array_pair,
    348                                   int feedback_slot);
    349   BytecodeArrayBuilder& ForInStep(Register index);
    350 
    351   // Generators.
    352   BytecodeArrayBuilder& SuspendGenerator(Register generator);
    353   BytecodeArrayBuilder& ResumeGenerator(Register generator);
    354 
    355   // Exception handling.
    356   BytecodeArrayBuilder& MarkHandler(int handler_id,
    357                                     HandlerTable::CatchPrediction will_catch);
    358   BytecodeArrayBuilder& MarkTryBegin(int handler_id, Register context);
    359   BytecodeArrayBuilder& MarkTryEnd(int handler_id);
    360 
    361   // Creates a new handler table entry and returns a {hander_id} identifying the
    362   // entry, so that it can be referenced by above exception handling support.
    363   int NewHandlerEntry() { return handler_table_builder()->NewHandlerEntry(); }
    364 
    365   // Gets a constant pool entry.
    366   size_t GetConstantPoolEntry(const AstRawString* raw_string);
    367   size_t GetConstantPoolEntry(const AstValue* heap_number);
    368   size_t GetConstantPoolEntry(const Scope* scope);
    369 #define ENTRY_GETTER(NAME, ...) size_t NAME##ConstantPoolEntry();
    370   SINGLETON_CONSTANT_ENTRY_TYPES(ENTRY_GETTER)
    371 #undef ENTRY_GETTER
    372 
    373   // Allocates a slot in the constant pool which can later be set.
    374   size_t AllocateDeferredConstantPoolEntry();
    375   // Sets the deferred value into an allocated constant pool entry.
    376   void SetDeferredConstantPoolEntry(size_t entry, Handle<Object> object);
    377 
    378   void InitializeReturnPosition(FunctionLiteral* literal);
    379 
    380   void SetStatementPosition(Statement* stmt) {
    381     if (stmt->position() == kNoSourcePosition) return;
    382     latest_source_info_.MakeStatementPosition(stmt->position());
    383   }
    384 
    385   void SetExpressionPosition(Expression* expr) {
    386     if (expr->position() == kNoSourcePosition) return;
    387     if (!latest_source_info_.is_statement()) {
    388       // Ensure the current expression position is overwritten with the
    389       // latest value.
    390       latest_source_info_.MakeExpressionPosition(expr->position());
    391     }
    392   }
    393 
    394   void SetExpressionAsStatementPosition(Expression* expr) {
    395     if (expr->position() == kNoSourcePosition) return;
    396     latest_source_info_.MakeStatementPosition(expr->position());
    397   }
    398 
    399   bool RequiresImplicitReturn() const { return !return_seen_in_block_; }
    400 
    401   // Returns the raw operand value for the given register or register list.
    402   uint32_t GetInputRegisterOperand(Register reg);
    403   uint32_t GetOutputRegisterOperand(Register reg);
    404   uint32_t GetInputRegisterListOperand(RegisterList reg_list);
    405   uint32_t GetOutputRegisterListOperand(RegisterList reg_list);
    406 
    407   // Accessors
    408   BytecodeRegisterAllocator* register_allocator() {
    409     return &register_allocator_;
    410   }
    411   const BytecodeRegisterAllocator* register_allocator() const {
    412     return &register_allocator_;
    413   }
    414   Zone* zone() const { return zone_; }
    415 
    416  private:
    417   friend class BytecodeRegisterAllocator;
    418   template <Bytecode bytecode, AccumulatorUse accumulator_use,
    419             OperandType... operand_types>
    420   friend class BytecodeNodeBuilder;
    421 
    422   const FeedbackVectorSpec* feedback_vector_spec() const {
    423     return literal_->feedback_vector_spec();
    424   }
    425 
    426   // Returns the current source position for the given |bytecode|.
    427   INLINE(BytecodeSourceInfo CurrentSourcePosition(Bytecode bytecode));
    428 
    429 #define DECLARE_BYTECODE_OUTPUT(Name, ...)         \
    430   template <typename... Operands>                  \
    431   INLINE(void Output##Name(Operands... operands)); \
    432   template <typename... Operands>                  \
    433   INLINE(void Output##Name(BytecodeLabel* label, Operands... operands));
    434   BYTECODE_LIST(DECLARE_BYTECODE_OUTPUT)
    435 #undef DECLARE_OPERAND_TYPE_INFO
    436 
    437   bool RegisterIsValid(Register reg) const;
    438   bool RegisterListIsValid(RegisterList reg_list) const;
    439 
    440   // Set position for return.
    441   void SetReturnPosition();
    442 
    443   // Not implemented as the illegal bytecode is used inside internally
    444   // to indicate a bytecode field is not valid or an error has occured
    445   // during bytecode generation.
    446   BytecodeArrayBuilder& Illegal();
    447 
    448   template <Bytecode bytecode, AccumulatorUse accumulator_use>
    449   void PrepareToOutputBytecode();
    450 
    451   void LeaveBasicBlock() { return_seen_in_block_ = false; }
    452 
    453   BytecodeArrayWriter* bytecode_array_writer() {
    454     return &bytecode_array_writer_;
    455   }
    456   BytecodePipelineStage* pipeline() { return pipeline_; }
    457   ConstantArrayBuilder* constant_array_builder() {
    458     return &constant_array_builder_;
    459   }
    460   const ConstantArrayBuilder* constant_array_builder() const {
    461     return &constant_array_builder_;
    462   }
    463   HandlerTableBuilder* handler_table_builder() {
    464     return &handler_table_builder_;
    465   }
    466 
    467   Zone* zone_;
    468   FunctionLiteral* literal_;
    469   bool bytecode_generated_;
    470   ConstantArrayBuilder constant_array_builder_;
    471   HandlerTableBuilder handler_table_builder_;
    472   bool return_seen_in_block_;
    473   int parameter_count_;
    474   int local_register_count_;
    475   int context_register_count_;
    476   int return_position_;
    477   BytecodeRegisterAllocator register_allocator_;
    478   BytecodeArrayWriter bytecode_array_writer_;
    479   BytecodePipelineStage* pipeline_;
    480   BytecodeRegisterOptimizer* register_optimizer_;
    481   BytecodeSourceInfo latest_source_info_;
    482 
    483   static int const kNoFeedbackSlot = 0;
    484 
    485   DISALLOW_COPY_AND_ASSIGN(BytecodeArrayBuilder);
    486 };
    487 
    488 }  // namespace interpreter
    489 }  // namespace internal
    490 }  // namespace v8
    491 
    492 #endif  // V8_INTERPRETER_BYTECODE_ARRAY_BUILDER_H_
    493