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/zone-containers.h"
     11 
     12 namespace v8 {
     13 namespace internal {
     14 namespace interpreter {
     15 
     16 class ControlFlowBuilder BASE_EMBEDDED {
     17  public:
     18   explicit ControlFlowBuilder(BytecodeArrayBuilder* builder)
     19       : builder_(builder) {}
     20   virtual ~ControlFlowBuilder() {}
     21 
     22  protected:
     23   BytecodeArrayBuilder* builder() const { return builder_; }
     24 
     25  private:
     26   BytecodeArrayBuilder* builder_;
     27 
     28   DISALLOW_COPY_AND_ASSIGN(ControlFlowBuilder);
     29 };
     30 
     31 class BreakableControlFlowBuilder : public ControlFlowBuilder {
     32  public:
     33   explicit BreakableControlFlowBuilder(BytecodeArrayBuilder* builder)
     34       : ControlFlowBuilder(builder),
     35         break_sites_(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 SetBreakTarget(const BytecodeLabel& break_target);
     41 
     42   // This method is called when visiting break statements in the AST.
     43   // Inserts a jump to a unbound label that is patched when the corresponding
     44   // SetBreakTarget is called.
     45   void Break() { EmitJump(&break_sites_); }
     46   void BreakIfTrue() { EmitJumpIfTrue(&break_sites_); }
     47   void BreakIfFalse() { EmitJumpIfFalse(&break_sites_); }
     48   void BreakIfUndefined() { EmitJumpIfUndefined(&break_sites_); }
     49   void BreakIfNull() { EmitJumpIfNull(&break_sites_); }
     50 
     51  protected:
     52   void EmitJump(ZoneVector<BytecodeLabel>* labels);
     53   void EmitJump(ZoneVector<BytecodeLabel>* labels, int index);
     54   void EmitJumpIfTrue(ZoneVector<BytecodeLabel>* labels);
     55   void EmitJumpIfTrue(ZoneVector<BytecodeLabel>* labels, int index);
     56   void EmitJumpIfFalse(ZoneVector<BytecodeLabel>* labels);
     57   void EmitJumpIfFalse(ZoneVector<BytecodeLabel>* labels, int index);
     58   void EmitJumpIfUndefined(ZoneVector<BytecodeLabel>* labels);
     59   void EmitJumpIfNull(ZoneVector<BytecodeLabel>* labels);
     60 
     61   void BindLabels(const BytecodeLabel& target, ZoneVector<BytecodeLabel>* site);
     62 
     63   // Unbound labels that identify jumps for break statements in the code.
     64   ZoneVector<BytecodeLabel> break_sites_;
     65 };
     66 
     67 
     68 // Class to track control flow for block statements (which can break in JS).
     69 class BlockBuilder final : public BreakableControlFlowBuilder {
     70  public:
     71   explicit BlockBuilder(BytecodeArrayBuilder* builder)
     72       : BreakableControlFlowBuilder(builder) {}
     73 
     74   void EndBlock();
     75 
     76  private:
     77   BytecodeLabel block_end_;
     78 };
     79 
     80 
     81 // A class to help with co-ordinating break and continue statements with
     82 // their loop.
     83 class LoopBuilder final : public BreakableControlFlowBuilder {
     84  public:
     85   explicit LoopBuilder(BytecodeArrayBuilder* builder)
     86       : BreakableControlFlowBuilder(builder),
     87         continue_sites_(builder->zone()) {}
     88   ~LoopBuilder();
     89 
     90   void LoopHeader();
     91   void Condition() { builder()->Bind(&condition_); }
     92   void Next() { builder()->Bind(&next_); }
     93   void JumpToHeader() { builder()->Jump(&loop_header_); }
     94   void JumpToHeaderIfTrue() { builder()->JumpIfTrue(&loop_header_); }
     95   void EndLoop();
     96 
     97   // This method is called when visiting continue statements in the AST.
     98   // Inserts a jump to a unbound label that is patched when the corresponding
     99   // SetContinueTarget 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   void SetContinueTarget(const BytecodeLabel& continue_target);
    107 
    108   BytecodeLabel loop_header_;
    109   BytecodeLabel condition_;
    110   BytecodeLabel next_;
    111   BytecodeLabel loop_end_;
    112 
    113   // Unbound labels that identify jumps for continue statements in the code.
    114   ZoneVector<BytecodeLabel> continue_sites_;
    115 };
    116 
    117 
    118 // A class to help with co-ordinating break statements with their switch.
    119 class SwitchBuilder final : public BreakableControlFlowBuilder {
    120  public:
    121   explicit SwitchBuilder(BytecodeArrayBuilder* builder, int number_of_cases)
    122       : BreakableControlFlowBuilder(builder),
    123         case_sites_(builder->zone()) {
    124     case_sites_.resize(number_of_cases);
    125   }
    126   ~SwitchBuilder();
    127 
    128   // This method should be called by the SwitchBuilder owner when the case
    129   // statement with |index| is emitted to update the case jump site.
    130   void SetCaseTarget(int index);
    131 
    132   // This method is called when visiting case comparison operation for |index|.
    133   // Inserts a JumpIfTrue to a unbound label that is patched when the
    134   // corresponding SetCaseTarget is called.
    135   void Case(int index) { EmitJumpIfTrue(&case_sites_, index); }
    136 
    137   // This method is called when all cases comparisons have been emitted if there
    138   // is a default case statement. Inserts a Jump to a unbound label that is
    139   // patched when the corresponding SetCaseTarget is called.
    140   void DefaultAt(int index) { EmitJump(&case_sites_, index); }
    141 
    142  private:
    143   // Unbound labels that identify jumps for case statements in the code.
    144   ZoneVector<BytecodeLabel> case_sites_;
    145 };
    146 
    147 }  // namespace interpreter
    148 }  // namespace internal
    149 }  // namespace v8
    150 
    151 #endif  // V8_INTERPRETER_CONTROL_FLOW_BUILDERS_H_
    152