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_CONTROL_FLOW_BUILDERS_H_
      6 #define V8_INTERPRETER_CONTROL_FLOW_BUILDERS_H_
      7 
      8 #include "src/interpreter/bytecode-array-builder.h"
      9 
     10 #include "src/ast/ast-source-ranges.h"
     11 #include "src/interpreter/block-coverage-builder.h"
     12 #include "src/interpreter/bytecode-label.h"
     13 #include "src/zone/zone-containers.h"
     14 
     15 namespace v8 {
     16 namespace internal {
     17 namespace interpreter {
     18 
     19 class V8_EXPORT_PRIVATE ControlFlowBuilder BASE_EMBEDDED {
     20  public:
     21   explicit ControlFlowBuilder(BytecodeArrayBuilder* builder)
     22       : builder_(builder) {}
     23   virtual ~ControlFlowBuilder() {}
     24 
     25  protected:
     26   BytecodeArrayBuilder* builder() const { return builder_; }
     27 
     28  private:
     29   BytecodeArrayBuilder* builder_;
     30 
     31   DISALLOW_COPY_AND_ASSIGN(ControlFlowBuilder);
     32 };
     33 
     34 class V8_EXPORT_PRIVATE BreakableControlFlowBuilder
     35     : public ControlFlowBuilder {
     36  public:
     37   BreakableControlFlowBuilder(BytecodeArrayBuilder* builder,
     38                               BlockCoverageBuilder* block_coverage_builder,
     39                               AstNode* node)
     40       : ControlFlowBuilder(builder),
     41         break_labels_(builder->zone()),
     42         node_(node),
     43         block_coverage_builder_(block_coverage_builder) {}
     44   virtual ~BreakableControlFlowBuilder();
     45 
     46   // This method is called when visiting break statements in the AST.
     47   // Inserts a jump to an unbound label that is patched when the corresponding
     48   // BindBreakTarget is called.
     49   void Break() { EmitJump(&break_labels_); }
     50   void BreakIfTrue(BytecodeArrayBuilder::ToBooleanMode mode) {
     51     EmitJumpIfTrue(mode, &break_labels_);
     52   }
     53   void BreakIfFalse(BytecodeArrayBuilder::ToBooleanMode mode) {
     54     EmitJumpIfFalse(mode, &break_labels_);
     55   }
     56   void BreakIfUndefined() { EmitJumpIfUndefined(&break_labels_); }
     57   void BreakIfNull() { EmitJumpIfNull(&break_labels_); }
     58 
     59   BytecodeLabels* break_labels() { return &break_labels_; }
     60 
     61   void set_needs_continuation_counter() { needs_continuation_counter_ = true; }
     62   bool needs_continuation_counter() const {
     63     return needs_continuation_counter_;
     64   }
     65 
     66  protected:
     67   void EmitJump(BytecodeLabels* labels);
     68   void EmitJumpIfTrue(BytecodeArrayBuilder::ToBooleanMode mode,
     69                       BytecodeLabels* labels);
     70   void EmitJumpIfFalse(BytecodeArrayBuilder::ToBooleanMode mode,
     71                        BytecodeLabels* labels);
     72   void EmitJumpIfUndefined(BytecodeLabels* labels);
     73   void EmitJumpIfNull(BytecodeLabels* labels);
     74 
     75   // Called from the destructor to update sites that emit jumps for break.
     76   void BindBreakTarget();
     77 
     78   // Unbound labels that identify jumps for break statements in the code.
     79   BytecodeLabels break_labels_;
     80 
     81   // A continuation counter (for block coverage) is needed e.g. when
     82   // encountering a break statement.
     83   AstNode* node_;
     84   bool needs_continuation_counter_ = false;
     85   BlockCoverageBuilder* block_coverage_builder_;
     86 };
     87 
     88 
     89 // Class to track control flow for block statements (which can break in JS).
     90 class V8_EXPORT_PRIVATE BlockBuilder final
     91     : public BreakableControlFlowBuilder {
     92  public:
     93   BlockBuilder(BytecodeArrayBuilder* builder,
     94                BlockCoverageBuilder* block_coverage_builder,
     95                BreakableStatement* statement)
     96       : BreakableControlFlowBuilder(builder, block_coverage_builder,
     97                                     statement) {}
     98 };
     99 
    100 
    101 // A class to help with co-ordinating break and continue statements with
    102 // their loop.
    103 class V8_EXPORT_PRIVATE LoopBuilder final : public BreakableControlFlowBuilder {
    104  public:
    105   LoopBuilder(BytecodeArrayBuilder* builder,
    106               BlockCoverageBuilder* block_coverage_builder, AstNode* node)
    107       : BreakableControlFlowBuilder(builder, block_coverage_builder, node),
    108         continue_labels_(builder->zone()) {
    109     if (block_coverage_builder_ != nullptr) {
    110       set_needs_continuation_counter();
    111       block_coverage_body_slot_ =
    112           block_coverage_builder_->AllocateBlockCoverageSlot(
    113               node, SourceRangeKind::kBody);
    114     }
    115   }
    116   ~LoopBuilder();
    117 
    118   void LoopHeader();
    119   void LoopBody();
    120   void JumpToHeader(int loop_depth);
    121   void BindContinueTarget();
    122 
    123   // This method is called when visiting continue statements in the AST.
    124   // Inserts a jump to an unbound label that is patched when BindContinueTarget
    125   // is called.
    126   void Continue() { EmitJump(&continue_labels_); }
    127   void ContinueIfUndefined() { EmitJumpIfUndefined(&continue_labels_); }
    128   void ContinueIfNull() { EmitJumpIfNull(&continue_labels_); }
    129 
    130  private:
    131   BytecodeLabel loop_header_;
    132 
    133   // Unbound labels that identify jumps for continue statements in the code and
    134   // jumps from checking the loop condition to the header for do-while loops.
    135   BytecodeLabels continue_labels_;
    136 
    137   int block_coverage_body_slot_;
    138 };
    139 
    140 
    141 // A class to help with co-ordinating break statements with their switch.
    142 class V8_EXPORT_PRIVATE SwitchBuilder final
    143     : public BreakableControlFlowBuilder {
    144  public:
    145   SwitchBuilder(BytecodeArrayBuilder* builder,
    146                 BlockCoverageBuilder* block_coverage_builder,
    147                 SwitchStatement* statement, int number_of_cases)
    148       : BreakableControlFlowBuilder(builder, block_coverage_builder, statement),
    149         case_sites_(builder->zone()) {
    150     case_sites_.resize(number_of_cases);
    151   }
    152   ~SwitchBuilder();
    153 
    154   // This method should be called by the SwitchBuilder owner when the case
    155   // statement with |index| is emitted to update the case jump site.
    156   void SetCaseTarget(int index, CaseClause* clause);
    157 
    158   // This method is called when visiting case comparison operation for |index|.
    159   // Inserts a JumpIfTrue with ToBooleanMode |mode| to a unbound label that is
    160   // patched when the corresponding SetCaseTarget is called.
    161   void Case(BytecodeArrayBuilder::ToBooleanMode mode, int index) {
    162     builder()->JumpIfTrue(mode, &case_sites_.at(index));
    163   }
    164 
    165   // This method is called when all cases comparisons have been emitted if there
    166   // is a default case statement. Inserts a Jump to a unbound label that is
    167   // patched when the corresponding SetCaseTarget is called.
    168   void DefaultAt(int index) { builder()->Jump(&case_sites_.at(index)); }
    169 
    170  private:
    171   // Unbound labels that identify jumps for case statements in the code.
    172   ZoneVector<BytecodeLabel> case_sites_;
    173 };
    174 
    175 
    176 // A class to help with co-ordinating control flow in try-catch statements.
    177 class V8_EXPORT_PRIVATE TryCatchBuilder final : public ControlFlowBuilder {
    178  public:
    179   TryCatchBuilder(BytecodeArrayBuilder* builder,
    180                   BlockCoverageBuilder* block_coverage_builder,
    181                   TryCatchStatement* statement,
    182                   HandlerTable::CatchPrediction catch_prediction)
    183       : ControlFlowBuilder(builder),
    184         handler_id_(builder->NewHandlerEntry()),
    185         catch_prediction_(catch_prediction),
    186         block_coverage_builder_(block_coverage_builder),
    187         statement_(statement) {}
    188 
    189   ~TryCatchBuilder();
    190 
    191   void BeginTry(Register context);
    192   void EndTry();
    193   void EndCatch();
    194 
    195  private:
    196   int handler_id_;
    197   HandlerTable::CatchPrediction catch_prediction_;
    198   BytecodeLabel handler_;
    199   BytecodeLabel exit_;
    200 
    201   BlockCoverageBuilder* block_coverage_builder_;
    202   TryCatchStatement* statement_;
    203 };
    204 
    205 
    206 // A class to help with co-ordinating control flow in try-finally statements.
    207 class V8_EXPORT_PRIVATE TryFinallyBuilder final : public ControlFlowBuilder {
    208  public:
    209   TryFinallyBuilder(BytecodeArrayBuilder* builder,
    210                     BlockCoverageBuilder* block_coverage_builder,
    211                     TryFinallyStatement* statement,
    212                     HandlerTable::CatchPrediction catch_prediction)
    213       : ControlFlowBuilder(builder),
    214         handler_id_(builder->NewHandlerEntry()),
    215         catch_prediction_(catch_prediction),
    216         finalization_sites_(builder->zone()),
    217         block_coverage_builder_(block_coverage_builder),
    218         statement_(statement) {}
    219 
    220   ~TryFinallyBuilder();
    221 
    222   void BeginTry(Register context);
    223   void LeaveTry();
    224   void EndTry();
    225   void BeginHandler();
    226   void BeginFinally();
    227   void EndFinally();
    228 
    229  private:
    230   int handler_id_;
    231   HandlerTable::CatchPrediction catch_prediction_;
    232   BytecodeLabel handler_;
    233 
    234   // Unbound labels that identify jumps to the finally block in the code.
    235   BytecodeLabels finalization_sites_;
    236 
    237   BlockCoverageBuilder* block_coverage_builder_;
    238   TryFinallyStatement* statement_;
    239 };
    240 
    241 class V8_EXPORT_PRIVATE ConditionalControlFlowBuilder final
    242     : public ControlFlowBuilder {
    243  public:
    244   ConditionalControlFlowBuilder(BytecodeArrayBuilder* builder,
    245                                 BlockCoverageBuilder* block_coverage_builder,
    246                                 AstNode* node)
    247       : ControlFlowBuilder(builder),
    248         end_labels_(builder->zone()),
    249         then_labels_(builder->zone()),
    250         else_labels_(builder->zone()),
    251         node_(node),
    252         block_coverage_builder_(block_coverage_builder) {
    253     DCHECK(node->IsIfStatement() || node->IsConditional());
    254     if (block_coverage_builder != nullptr) {
    255       block_coverage_then_slot_ =
    256           block_coverage_builder->AllocateBlockCoverageSlot(
    257               node, SourceRangeKind::kThen);
    258       block_coverage_else_slot_ =
    259           block_coverage_builder->AllocateBlockCoverageSlot(
    260               node, SourceRangeKind::kElse);
    261     }
    262   }
    263   ~ConditionalControlFlowBuilder();
    264 
    265   BytecodeLabels* then_labels() { return &then_labels_; }
    266   BytecodeLabels* else_labels() { return &else_labels_; }
    267 
    268   void Then();
    269   void Else();
    270 
    271   void JumpToEnd();
    272 
    273  private:
    274   BytecodeLabels end_labels_;
    275   BytecodeLabels then_labels_;
    276   BytecodeLabels else_labels_;
    277 
    278   AstNode* node_;
    279   int block_coverage_then_slot_;
    280   int block_coverage_else_slot_;
    281   BlockCoverageBuilder* block_coverage_builder_;
    282 };
    283 
    284 }  // namespace interpreter
    285 }  // namespace internal
    286 }  // namespace v8
    287 
    288 #endif  // V8_INTERPRETER_CONTROL_FLOW_BUILDERS_H_
    289