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/interpreter/bytecode-label.h"
     11 #include "src/zone/zone-containers.h"
     12 
     13 namespace v8 {
     14 namespace internal {
     15 namespace interpreter {
     16 
     17 class ControlFlowBuilder BASE_EMBEDDED {
     18  public:
     19   explicit ControlFlowBuilder(BytecodeArrayBuilder* builder)
     20       : builder_(builder) {}
     21   virtual ~ControlFlowBuilder() {}
     22 
     23  protected:
     24   BytecodeArrayBuilder* builder() const { return builder_; }
     25 
     26  private:
     27   BytecodeArrayBuilder* builder_;
     28 
     29   DISALLOW_COPY_AND_ASSIGN(ControlFlowBuilder);
     30 };
     31 
     32 class BreakableControlFlowBuilder : public ControlFlowBuilder {
     33  public:
     34   explicit BreakableControlFlowBuilder(BytecodeArrayBuilder* builder)
     35       : ControlFlowBuilder(builder), break_labels_(builder->zone()) {}
     36   virtual ~BreakableControlFlowBuilder();
     37 
     38   // This method should be called by the control flow owner before
     39   // destruction to update sites that emit jumps for break.
     40   void BindBreakTarget();
     41 
     42   // This method is called when visiting break statements in the AST.
     43   // Inserts a jump to an unbound label that is patched when the corresponding
     44   // BindBreakTarget is called.
     45   void Break() { EmitJump(&break_labels_); }
     46   void BreakIfTrue() { EmitJumpIfTrue(&break_labels_); }
     47   void BreakIfFalse() { EmitJumpIfFalse(&break_labels_); }
     48   void BreakIfUndefined() { EmitJumpIfUndefined(&break_labels_); }
     49   void BreakIfNull() { EmitJumpIfNull(&break_labels_); }
     50 
     51   BytecodeLabels* break_labels() { return &break_labels_; }
     52 
     53  protected:
     54   void EmitJump(BytecodeLabels* labels);
     55   void EmitJumpIfTrue(BytecodeLabels* labels);
     56   void EmitJumpIfFalse(BytecodeLabels* labels);
     57   void EmitJumpIfUndefined(BytecodeLabels* labels);
     58   void EmitJumpIfNull(BytecodeLabels* labels);
     59 
     60   // Unbound labels that identify jumps for break statements in the code.
     61   BytecodeLabels break_labels_;
     62 };
     63 
     64 
     65 // Class to track control flow for block statements (which can break in JS).
     66 class BlockBuilder final : public BreakableControlFlowBuilder {
     67  public:
     68   explicit BlockBuilder(BytecodeArrayBuilder* builder)
     69       : BreakableControlFlowBuilder(builder) {}
     70 
     71   void EndBlock();
     72 
     73  private:
     74   BytecodeLabel block_end_;
     75 };
     76 
     77 
     78 // A class to help with co-ordinating break and continue statements with
     79 // their loop.
     80 class LoopBuilder final : public BreakableControlFlowBuilder {
     81  public:
     82   explicit LoopBuilder(BytecodeArrayBuilder* builder)
     83       : BreakableControlFlowBuilder(builder),
     84         continue_labels_(builder->zone()),
     85         header_labels_(builder->zone()) {}
     86   ~LoopBuilder();
     87 
     88   void LoopHeader(ZoneVector<BytecodeLabel>* additional_labels);
     89   void JumpToHeader(int loop_depth);
     90   void BindContinueTarget();
     91   void EndLoop();
     92 
     93   // This method is called when visiting continue statements in the AST.
     94   // Inserts a jump to an unbound label that is patched when BindContinueTarget
     95   // is called.
     96   void Continue() { EmitJump(&continue_labels_); }
     97   void ContinueIfTrue() { EmitJumpIfTrue(&continue_labels_); }
     98   void ContinueIfUndefined() { EmitJumpIfUndefined(&continue_labels_); }
     99   void ContinueIfNull() { EmitJumpIfNull(&continue_labels_); }
    100 
    101  private:
    102   BytecodeLabel loop_header_;
    103 
    104   // Unbound labels that identify jumps for continue statements in the code and
    105   // jumps from checking the loop condition to the header for do-while loops.
    106   BytecodeLabels continue_labels_;
    107   BytecodeLabels header_labels_;
    108 };
    109 
    110 
    111 // A class to help with co-ordinating break statements with their switch.
    112 class SwitchBuilder final : public BreakableControlFlowBuilder {
    113  public:
    114   explicit SwitchBuilder(BytecodeArrayBuilder* builder, int number_of_cases)
    115       : BreakableControlFlowBuilder(builder),
    116         case_sites_(builder->zone()) {
    117     case_sites_.resize(number_of_cases);
    118   }
    119   ~SwitchBuilder();
    120 
    121   // This method should be called by the SwitchBuilder owner when the case
    122   // statement with |index| is emitted to update the case jump site.
    123   void SetCaseTarget(int index);
    124 
    125   // This method is called when visiting case comparison operation for |index|.
    126   // Inserts a JumpIfTrue to a unbound label that is patched when the
    127   // corresponding SetCaseTarget is called.
    128   void Case(int index) { builder()->JumpIfTrue(&case_sites_.at(index)); }
    129 
    130   // This method is called when all cases comparisons have been emitted if there
    131   // is a default case statement. Inserts a Jump to a unbound label that is
    132   // patched when the corresponding SetCaseTarget is called.
    133   void DefaultAt(int index) { builder()->Jump(&case_sites_.at(index)); }
    134 
    135  private:
    136   // Unbound labels that identify jumps for case statements in the code.
    137   ZoneVector<BytecodeLabel> case_sites_;
    138 };
    139 
    140 
    141 // A class to help with co-ordinating control flow in try-catch statements.
    142 class TryCatchBuilder final : public ControlFlowBuilder {
    143  public:
    144   explicit TryCatchBuilder(BytecodeArrayBuilder* builder,
    145                            HandlerTable::CatchPrediction catch_prediction)
    146       : ControlFlowBuilder(builder),
    147         handler_id_(builder->NewHandlerEntry()),
    148         catch_prediction_(catch_prediction) {}
    149 
    150   void BeginTry(Register context);
    151   void EndTry();
    152   void EndCatch();
    153 
    154  private:
    155   int handler_id_;
    156   HandlerTable::CatchPrediction catch_prediction_;
    157   BytecodeLabel handler_;
    158   BytecodeLabel exit_;
    159 };
    160 
    161 
    162 // A class to help with co-ordinating control flow in try-finally statements.
    163 class TryFinallyBuilder final : public ControlFlowBuilder {
    164  public:
    165   explicit TryFinallyBuilder(BytecodeArrayBuilder* builder,
    166                              HandlerTable::CatchPrediction catch_prediction)
    167       : ControlFlowBuilder(builder),
    168         handler_id_(builder->NewHandlerEntry()),
    169         catch_prediction_(catch_prediction),
    170         finalization_sites_(builder->zone()) {}
    171 
    172   void BeginTry(Register context);
    173   void LeaveTry();
    174   void EndTry();
    175   void BeginHandler();
    176   void BeginFinally();
    177   void EndFinally();
    178 
    179  private:
    180   int handler_id_;
    181   HandlerTable::CatchPrediction catch_prediction_;
    182   BytecodeLabel handler_;
    183 
    184   // Unbound labels that identify jumps to the finally block in the code.
    185   BytecodeLabels finalization_sites_;
    186 };
    187 
    188 }  // namespace interpreter
    189 }  // namespace internal
    190 }  // namespace v8
    191 
    192 #endif  // V8_INTERPRETER_CONTROL_FLOW_BUILDERS_H_
    193