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