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_GENERATOR_H_
      6 #define V8_INTERPRETER_BYTECODE_GENERATOR_H_
      7 
      8 #include "src/ast/ast.h"
      9 #include "src/interpreter/bytecode-array-builder.h"
     10 #include "src/interpreter/bytecode-label.h"
     11 #include "src/interpreter/bytecode-register.h"
     12 #include "src/interpreter/bytecodes.h"
     13 
     14 namespace v8 {
     15 namespace internal {
     16 
     17 class AstNodeSourceRanges;
     18 class AstStringConstants;
     19 class UnoptimizedCompilationInfo;
     20 enum class SourceRangeKind;
     21 
     22 namespace interpreter {
     23 
     24 class GlobalDeclarationsBuilder;
     25 class LoopBuilder;
     26 class BlockCoverageBuilder;
     27 class BytecodeJumpTable;
     28 
     29 class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> {
     30  public:
     31   explicit BytecodeGenerator(
     32       UnoptimizedCompilationInfo* info,
     33       const AstStringConstants* ast_string_constants,
     34       ZoneVector<FunctionLiteral*>* eager_inner_literals);
     35 
     36   void GenerateBytecode(uintptr_t stack_limit);
     37   Handle<BytecodeArray> FinalizeBytecode(Isolate* isolate,
     38                                          Handle<Script> script);
     39 
     40 #define DECLARE_VISIT(type) void Visit##type(type* node);
     41   AST_NODE_LIST(DECLARE_VISIT)
     42 #undef DECLARE_VISIT
     43 
     44   // Visiting function for declarations list and statements are overridden.
     45   void VisitDeclarations(Declaration::List* declarations);
     46   void VisitStatements(ZonePtrList<Statement>* statments);
     47 
     48  private:
     49   class ContextScope;
     50   class ControlScope;
     51   class ControlScopeForBreakable;
     52   class ControlScopeForIteration;
     53   class ControlScopeForTopLevel;
     54   class ControlScopeForTryCatch;
     55   class ControlScopeForTryFinally;
     56   class CurrentScope;
     57   class ExpressionResultScope;
     58   class EffectResultScope;
     59   class FeedbackSlotCache;
     60   class GlobalDeclarationsBuilder;
     61   class IteratorRecord;
     62   class NaryCodeCoverageSlots;
     63   class RegisterAllocationScope;
     64   class TestResultScope;
     65   class ValueResultScope;
     66 
     67   using ToBooleanMode = BytecodeArrayBuilder::ToBooleanMode;
     68 
     69   enum class TestFallthrough { kThen, kElse, kNone };
     70   enum class TypeHint { kAny, kBoolean, kString };
     71 
     72   void GenerateBytecodeBody();
     73   void AllocateDeferredConstants(Isolate* isolate, Handle<Script> script);
     74 
     75   DEFINE_AST_VISITOR_SUBCLASS_MEMBERS();
     76 
     77   // Dispatched from VisitBinaryOperation.
     78   void VisitArithmeticExpression(BinaryOperation* binop);
     79   void VisitCommaExpression(BinaryOperation* binop);
     80   void VisitLogicalOrExpression(BinaryOperation* binop);
     81   void VisitLogicalAndExpression(BinaryOperation* binop);
     82 
     83   // Dispatched from VisitNaryOperation.
     84   void VisitNaryArithmeticExpression(NaryOperation* expr);
     85   void VisitNaryCommaExpression(NaryOperation* expr);
     86   void VisitNaryLogicalOrExpression(NaryOperation* expr);
     87   void VisitNaryLogicalAndExpression(NaryOperation* expr);
     88 
     89   // Dispatched from VisitUnaryOperation.
     90   void VisitVoid(UnaryOperation* expr);
     91   void VisitTypeOf(UnaryOperation* expr);
     92   void VisitNot(UnaryOperation* expr);
     93   void VisitDelete(UnaryOperation* expr);
     94 
     95   // Visits a typeof expression for the value on which to perform the typeof.
     96   void VisitForTypeOfValue(Expression* expr);
     97 
     98   // Used by flow control routines to evaluate loop condition.
     99   void VisitCondition(Expression* expr);
    100 
    101   // Visit the arguments expressions in |args| and store them in |args_regs|,
    102   // growing |args_regs| for each argument visited.
    103   void VisitArguments(ZonePtrList<Expression>* args, RegisterList* arg_regs);
    104 
    105   // Visit a keyed super property load. The optional
    106   // |opt_receiver_out| register will have the receiver stored to it
    107   // if it's a valid register. The loaded value is placed in the
    108   // accumulator.
    109   void VisitKeyedSuperPropertyLoad(Property* property,
    110                                    Register opt_receiver_out);
    111 
    112   // Visit a named super property load. The optional
    113   // |opt_receiver_out| register will have the receiver stored to it
    114   // if it's a valid register. The loaded value is placed in the
    115   // accumulator.
    116   void VisitNamedSuperPropertyLoad(Property* property,
    117                                    Register opt_receiver_out);
    118 
    119   void VisitPropertyLoad(Register obj, Property* expr);
    120   void VisitPropertyLoadForRegister(Register obj, Property* expr,
    121                                     Register destination);
    122 
    123   void BuildLoadNamedProperty(Property* property, Register object,
    124                               const AstRawString* name);
    125   void BuildStoreNamedProperty(Property* property, Register object,
    126                                const AstRawString* name);
    127 
    128   void BuildVariableLoad(Variable* variable, HoleCheckMode hole_check_mode,
    129                          TypeofMode typeof_mode = NOT_INSIDE_TYPEOF);
    130   void BuildVariableLoadForAccumulatorValue(
    131       Variable* variable, HoleCheckMode hole_check_mode,
    132       TypeofMode typeof_mode = NOT_INSIDE_TYPEOF);
    133   void BuildVariableAssignment(
    134       Variable* variable, Token::Value op, HoleCheckMode hole_check_mode,
    135       LookupHoistingMode lookup_hoisting_mode = LookupHoistingMode::kNormal);
    136   void BuildLiteralCompareNil(Token::Value compare_op,
    137                               BytecodeArrayBuilder::NilValue nil);
    138   void BuildReturn(int source_position = kNoSourcePosition);
    139   void BuildAsyncReturn(int source_position = kNoSourcePosition);
    140   void BuildAsyncGeneratorReturn();
    141   void BuildReThrow();
    142   void BuildHoleCheckForVariableAssignment(Variable* variable, Token::Value op);
    143   void BuildThrowIfHole(Variable* variable);
    144 
    145   // Build jump to targets[value], where
    146   // start_index <= value < start_index + size.
    147   void BuildIndexedJump(Register value, size_t start_index, size_t size,
    148                         ZoneVector<BytecodeLabel>& targets);
    149 
    150   void BuildNewLocalActivationContext();
    151   void BuildLocalActivationContextInitialization();
    152   void BuildNewLocalBlockContext(Scope* scope);
    153   void BuildNewLocalCatchContext(Scope* scope);
    154   void BuildNewLocalWithContext(Scope* scope);
    155 
    156   void BuildGeneratorPrologue();
    157   void BuildSuspendPoint(Expression* suspend_expr);
    158 
    159   void BuildAwait(Expression* await_expr);
    160 
    161   void BuildGetIterator(Expression* iterable, IteratorType hint);
    162 
    163   // Create an IteratorRecord with pre-allocated registers holding the next
    164   // method and iterator object.
    165   IteratorRecord BuildGetIteratorRecord(Expression* iterable,
    166                                         Register iterator_next,
    167                                         Register iterator_object,
    168                                         IteratorType hint);
    169 
    170   // Create an IteratorRecord allocating new registers to hold the next method
    171   // and iterator object.
    172   IteratorRecord BuildGetIteratorRecord(Expression* iterable,
    173                                         IteratorType hint);
    174   void BuildIteratorNext(const IteratorRecord& iterator, Register next_result);
    175   void BuildIteratorClose(const IteratorRecord& iterator,
    176                           Expression* expr = nullptr);
    177   void BuildCallIteratorMethod(Register iterator, const AstRawString* method,
    178                                RegisterList receiver_and_args,
    179                                BytecodeLabel* if_called,
    180                                BytecodeLabels* if_notcalled);
    181 
    182   void BuildArrayLiteralSpread(Spread* spread, Register array, Register index,
    183                                FeedbackSlot index_slot,
    184                                FeedbackSlot element_slot);
    185   void BuildArrayLiteralElementsInsertion(Register array,
    186                                           int first_spread_index,
    187                                           ZonePtrList<Expression>* elements,
    188                                           bool skip_constants);
    189 
    190   void BuildCreateObjectLiteral(Register literal, uint8_t flags, size_t entry);
    191   void AllocateTopLevelRegisters();
    192   void VisitArgumentsObject(Variable* variable);
    193   void VisitRestArgumentsArray(Variable* rest);
    194   void VisitCallSuper(Call* call);
    195   void BuildClassLiteral(ClassLiteral* expr);
    196   void VisitNewTargetVariable(Variable* variable);
    197   void VisitThisFunctionVariable(Variable* variable);
    198   void BuildInstanceFieldInitialization(Register constructor,
    199                                         Register instance);
    200   void BuildGeneratorObjectVariableInitialization();
    201   void VisitBlockDeclarationsAndStatements(Block* stmt);
    202   void VisitSetHomeObject(Register value, Register home_object,
    203                           LiteralProperty* property);
    204   void VisitObjectLiteralAccessor(Register home_object,
    205                                   ObjectLiteralProperty* property,
    206                                   Register value_out);
    207   void VisitForInAssignment(Expression* expr);
    208   void VisitModuleNamespaceImports();
    209 
    210   // Visit a logical OR/AND within a test context, rewiring the jumps based
    211   // on the expression values.
    212   void VisitLogicalTest(Token::Value token, Expression* left, Expression* right,
    213                         int right_coverage_slot);
    214   void VisitNaryLogicalTest(Token::Value token, NaryOperation* expr,
    215                             const NaryCodeCoverageSlots* coverage_slots);
    216   // Visit a (non-RHS) test for a logical op, which falls through if the test
    217   // fails or jumps to the appropriate labels if it succeeds.
    218   void VisitLogicalTestSubExpression(Token::Value token, Expression* expr,
    219                                      BytecodeLabels* then_labels,
    220                                      BytecodeLabels* else_labels,
    221                                      int coverage_slot);
    222 
    223   // Helpers for binary and nary logical op value expressions.
    224   bool VisitLogicalOrSubExpression(Expression* expr, BytecodeLabels* end_labels,
    225                                    int coverage_slot);
    226   bool VisitLogicalAndSubExpression(Expression* expr,
    227                                     BytecodeLabels* end_labels,
    228                                     int coverage_slot);
    229 
    230   // Visit the body of a loop iteration.
    231   void VisitIterationBody(IterationStatement* stmt, LoopBuilder* loop_builder);
    232 
    233   // Visit a statement and switch scopes, the context is in the accumulator.
    234   void VisitInScope(Statement* stmt, Scope* scope);
    235 
    236   void BuildPushUndefinedIntoRegisterList(RegisterList* reg_list);
    237 
    238   void BuildLoadPropertyKey(LiteralProperty* property, Register out_reg);
    239 
    240   int AllocateBlockCoverageSlotIfEnabled(AstNode* node, SourceRangeKind kind);
    241   int AllocateNaryBlockCoverageSlotIfEnabled(NaryOperation* node, size_t index);
    242 
    243   void BuildIncrementBlockCoverageCounterIfEnabled(AstNode* node,
    244                                                    SourceRangeKind kind);
    245   void BuildIncrementBlockCoverageCounterIfEnabled(int coverage_array_slot);
    246 
    247   void BuildTest(ToBooleanMode mode, BytecodeLabels* then_labels,
    248                  BytecodeLabels* else_labels, TestFallthrough fallthrough);
    249 
    250   // Visitors for obtaining expression result in the accumulator, in a
    251   // register, or just getting the effect. Some visitors return a TypeHint which
    252   // specifies the type of the result of the visited expression.
    253   TypeHint VisitForAccumulatorValue(Expression* expr);
    254   void VisitForAccumulatorValueOrTheHole(Expression* expr);
    255   V8_WARN_UNUSED_RESULT Register VisitForRegisterValue(Expression* expr);
    256   V8_INLINE void VisitForRegisterValue(Expression* expr, Register destination);
    257   void VisitAndPushIntoRegisterList(Expression* expr, RegisterList* reg_list);
    258   void VisitForEffect(Expression* expr);
    259   void VisitForTest(Expression* expr, BytecodeLabels* then_labels,
    260                     BytecodeLabels* else_labels, TestFallthrough fallthrough);
    261 
    262   void VisitInSameTestExecutionScope(Expression* expr);
    263 
    264   Register GetRegisterForLocalVariable(Variable* variable);
    265 
    266   // Returns the runtime function id for a store to super for the function's
    267   // language mode.
    268   inline Runtime::FunctionId StoreToSuperRuntimeId();
    269   inline Runtime::FunctionId StoreKeyedToSuperRuntimeId();
    270 
    271   // Returns a cached slot, or create and cache a new slot if one doesn't
    272   // already exists.
    273   FeedbackSlot GetCachedLoadGlobalICSlot(TypeofMode typeof_mode,
    274                                          Variable* variable);
    275   FeedbackSlot GetCachedStoreGlobalICSlot(LanguageMode language_mode,
    276                                           Variable* variable);
    277   FeedbackSlot GetCachedCreateClosureSlot(FunctionLiteral* literal);
    278   FeedbackSlot GetCachedLoadICSlot(const Expression* expr,
    279                                    const AstRawString* name);
    280   FeedbackSlot GetCachedStoreICSlot(const Expression* expr,
    281                                     const AstRawString* name);
    282   FeedbackSlot GetDummyCompareICSlot();
    283 
    284   void AddToEagerLiteralsIfEager(FunctionLiteral* literal);
    285 
    286   // Checks if the visited expression is one shot, i.e executed only once. Any
    287   // expression either in a top level code or an IIFE that is not within a loop
    288   // is eligible for one shot optimizations.
    289   inline bool ShouldOptimizeAsOneShot() const;
    290 
    291   static constexpr ToBooleanMode ToBooleanModeFromTypeHint(TypeHint type_hint) {
    292     return type_hint == TypeHint::kBoolean ? ToBooleanMode::kAlreadyBoolean
    293                                            : ToBooleanMode::kConvertToBoolean;
    294   }
    295 
    296   inline Register generator_object() const;
    297 
    298   inline BytecodeArrayBuilder* builder() { return &builder_; }
    299   inline Zone* zone() const { return zone_; }
    300   inline DeclarationScope* closure_scope() const { return closure_scope_; }
    301   inline UnoptimizedCompilationInfo* info() const { return info_; }
    302   inline const AstStringConstants* ast_string_constants() const {
    303     return ast_string_constants_;
    304   }
    305 
    306   inline Scope* current_scope() const { return current_scope_; }
    307   inline void set_current_scope(Scope* scope) { current_scope_ = scope; }
    308 
    309   inline ControlScope* execution_control() const { return execution_control_; }
    310   inline void set_execution_control(ControlScope* scope) {
    311     execution_control_ = scope;
    312   }
    313   inline ContextScope* execution_context() const { return execution_context_; }
    314   inline void set_execution_context(ContextScope* context) {
    315     execution_context_ = context;
    316   }
    317   inline void set_execution_result(ExpressionResultScope* execution_result) {
    318     execution_result_ = execution_result;
    319   }
    320   ExpressionResultScope* execution_result() const { return execution_result_; }
    321   BytecodeRegisterAllocator* register_allocator() {
    322     return builder()->register_allocator();
    323   }
    324 
    325   GlobalDeclarationsBuilder* globals_builder() {
    326     DCHECK_NOT_NULL(globals_builder_);
    327     return globals_builder_;
    328   }
    329   inline LanguageMode language_mode() const;
    330   inline FunctionKind function_kind() const;
    331   inline FeedbackVectorSpec* feedback_spec();
    332   inline int feedback_index(FeedbackSlot slot) const;
    333 
    334   inline FeedbackSlotCache* feedback_slot_cache() {
    335     return feedback_slot_cache_;
    336   }
    337 
    338   inline HandlerTable::CatchPrediction catch_prediction() const {
    339     return catch_prediction_;
    340   }
    341   inline void set_catch_prediction(HandlerTable::CatchPrediction value) {
    342     catch_prediction_ = value;
    343   }
    344 
    345   Zone* zone_;
    346   BytecodeArrayBuilder builder_;
    347   UnoptimizedCompilationInfo* info_;
    348   const AstStringConstants* ast_string_constants_;
    349   DeclarationScope* closure_scope_;
    350   Scope* current_scope_;
    351 
    352   // External vector of literals to be eagerly compiled.
    353   ZoneVector<FunctionLiteral*>* eager_inner_literals_;
    354 
    355   FeedbackSlotCache* feedback_slot_cache_;
    356 
    357   GlobalDeclarationsBuilder* globals_builder_;
    358   BlockCoverageBuilder* block_coverage_builder_;
    359   ZoneVector<GlobalDeclarationsBuilder*> global_declarations_;
    360   ZoneVector<std::pair<FunctionLiteral*, size_t>> function_literals_;
    361   ZoneVector<std::pair<NativeFunctionLiteral*, size_t>>
    362       native_function_literals_;
    363   ZoneVector<std::pair<ObjectLiteral*, size_t>> object_literals_;
    364   ZoneVector<std::pair<ArrayLiteral*, size_t>> array_literals_;
    365   ZoneVector<std::pair<ClassLiteral*, size_t>> class_literals_;
    366   ZoneVector<std::pair<GetTemplateObject*, size_t>> template_objects_;
    367 
    368   ControlScope* execution_control_;
    369   ContextScope* execution_context_;
    370   ExpressionResultScope* execution_result_;
    371 
    372   Register incoming_new_target_or_generator_;
    373 
    374   // Dummy feedback slot for compare operations, where we don't care about
    375   // feedback
    376   FeedbackSlot dummy_feedback_slot_;
    377 
    378   BytecodeJumpTable* generator_jump_table_;
    379   int suspend_count_;
    380   int loop_depth_;
    381 
    382   HandlerTable::CatchPrediction catch_prediction_;
    383 };
    384 
    385 }  // namespace interpreter
    386 }  // namespace internal
    387 }  // namespace v8
    388 
    389 #endif  // V8_INTERPRETER_BYTECODE_GENERATOR_H_
    390