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-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),
     36         break_sites_(builder->zone()) {}
     37   virtual ~BreakableControlFlowBuilder();
     38 
     39   // This method should be called by the control flow owner before
     40   // destruction to update sites that emit jumps for break.
     41   void SetBreakTarget(const BytecodeLabel& break_target);
     42 
     43   // This method is called when visiting break statements in the AST.
     44   // Inserts a jump to a unbound label that is patched when the corresponding
     45   // SetBreakTarget is called.
     46   void Break() { EmitJump(&break_sites_); }
     47   void BreakIfTrue() { EmitJumpIfTrue(&break_sites_); }
     48   void BreakIfFalse() { EmitJumpIfFalse(&break_sites_); }
     49   void BreakIfUndefined() { EmitJumpIfUndefined(&break_sites_); }
     50   void BreakIfNull() { EmitJumpIfNull(&break_sites_); }
     51 
     52  protected:
     53   void EmitJump(ZoneVector<BytecodeLabel>* labels);
     54   void EmitJump(ZoneVector<BytecodeLabel>* labels, int index);
     55   void EmitJumpIfTrue(ZoneVector<BytecodeLabel>* labels);
     56   void EmitJumpIfTrue(ZoneVector<BytecodeLabel>* labels, int index);
     57   void EmitJumpIfFalse(ZoneVector<BytecodeLabel>* labels);
     58   void EmitJumpIfFalse(ZoneVector<BytecodeLabel>* labels, int index);
     59   void EmitJumpIfUndefined(ZoneVector<BytecodeLabel>* labels);
     60   void EmitJumpIfNull(ZoneVector<BytecodeLabel>* labels);
     61 
     62   void BindLabels(const BytecodeLabel& target, ZoneVector<BytecodeLabel>* site);
     63 
     64   // Unbound labels that identify jumps for break statements in the code.
     65   ZoneVector<BytecodeLabel> break_sites_;
     66 };
     67 
     68 
     69 // Class to track control flow for block statements (which can break in JS).
     70 class BlockBuilder final : public BreakableControlFlowBuilder {
     71  public:
     72   explicit BlockBuilder(BytecodeArrayBuilder* builder)
     73       : BreakableControlFlowBuilder(builder) {}
     74 
     75   void EndBlock();
     76 
     77  private:
     78   BytecodeLabel block_end_;
     79 };
     80 
     81 
     82 // A class to help with co-ordinating break and continue statements with
     83 // their loop.
     84 class LoopBuilder final : public BreakableControlFlowBuilder {
     85  public:
     86   explicit LoopBuilder(BytecodeArrayBuilder* builder)
     87       : BreakableControlFlowBuilder(builder),
     88         continue_sites_(builder->zone()) {}
     89   ~LoopBuilder();
     90 
     91   void LoopHeader(ZoneVector<BytecodeLabel>* additional_labels);
     92   void JumpToHeader() { builder()->Jump(&loop_header_); }
     93   void JumpToHeaderIfTrue() { builder()->JumpIfTrue(&loop_header_); }
     94   void SetContinueTarget();
     95   void EndLoop();
     96 
     97   // This method is called when visiting continue statements in the AST.
     98   // Inserts a jump to an unbound label that is patched when SetContinueTarget
     99   // is called.
    100   void Continue() { EmitJump(&continue_sites_); }
    101   void ContinueIfTrue() { EmitJumpIfTrue(&continue_sites_); }
    102   void ContinueIfUndefined() { EmitJumpIfUndefined(&continue_sites_); }
    103   void ContinueIfNull() { EmitJumpIfNull(&continue_sites_); }
    104 
    105  private:
    106   BytecodeLabel loop_header_;
    107   BytecodeLabel loop_end_;
    108 
    109   // Unbound labels that identify jumps for continue statements in the code.
    110   ZoneVector<BytecodeLabel> continue_sites_;
    111 };
    112 
    113 
    114 // A class to help with co-ordinating break statements with their switch.
    115 class SwitchBuilder final : public BreakableControlFlowBuilder {
    116  public:
    117   explicit SwitchBuilder(BytecodeArrayBuilder* builder, int number_of_cases)
    118       : BreakableControlFlowBuilder(builder),
    119         case_sites_(builder->zone()) {
    120     case_sites_.resize(number_of_cases);
    121   }
    122   ~SwitchBuilder();
    123 
    124   // This method should be called by the SwitchBuilder owner when the case
    125   // statement with |index| is emitted to update the case jump site.
    126   void SetCaseTarget(int index);
    127 
    128   // This method is called when visiting case comparison operation for |index|.
    129   // Inserts a JumpIfTrue to a unbound label that is patched when the
    130   // corresponding SetCaseTarget is called.
    131   void Case(int index) { EmitJumpIfTrue(&case_sites_, index); }
    132 
    133   // This method is called when all cases comparisons have been emitted if there
    134   // is a default case statement. Inserts a Jump to a unbound label that is
    135   // patched when the corresponding SetCaseTarget is called.
    136   void DefaultAt(int index) { EmitJump(&case_sites_, index); }
    137 
    138  private:
    139   // Unbound labels that identify jumps for case statements in the code.
    140   ZoneVector<BytecodeLabel> case_sites_;
    141 };
    142 
    143 
    144 // A class to help with co-ordinating control flow in try-catch statements.
    145 class TryCatchBuilder final : public ControlFlowBuilder {
    146  public:
    147   explicit TryCatchBuilder(BytecodeArrayBuilder* builder)
    148       : ControlFlowBuilder(builder), handler_id_(builder->NewHandlerEntry()) {}
    149 
    150   void BeginTry(Register context);
    151   void EndTry();
    152   void EndCatch();
    153 
    154  private:
    155   int handler_id_;
    156   BytecodeLabel handler_;
    157   BytecodeLabel exit_;
    158 };
    159 
    160 
    161 // A class to help with co-ordinating control flow in try-finally statements.
    162 class TryFinallyBuilder final : public ControlFlowBuilder {
    163  public:
    164   explicit TryFinallyBuilder(BytecodeArrayBuilder* builder, bool will_catch)
    165       : ControlFlowBuilder(builder),
    166         handler_id_(builder->NewHandlerEntry()),
    167         finalization_sites_(builder->zone()),
    168         will_catch_(will_catch) {}
    169 
    170   void BeginTry(Register context);
    171   void LeaveTry();
    172   void EndTry();
    173   void BeginHandler();
    174   void BeginFinally();
    175   void EndFinally();
    176 
    177  private:
    178   int handler_id_;
    179   BytecodeLabel handler_;
    180 
    181   // Unbound labels that identify jumps to the finally block in the code.
    182   ZoneVector<BytecodeLabel> finalization_sites_;
    183 
    184   // Conservative prediction of whether exceptions thrown into the handler for
    185   // this finally block will be caught. Note that such a prediction depends on
    186   // whether this try-finally is nested inside a surrounding try-catch.
    187   bool will_catch_;
    188 };
    189 
    190 }  // namespace interpreter
    191 }  // namespace internal
    192 }  // namespace v8
    193 
    194 #endif  // V8_INTERPRETER_CONTROL_FLOW_BUILDERS_H_
    195