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: ControlFlowBuilder(BytecodeArrayBuilder * builder)19 explicit ControlFlowBuilder(BytecodeArrayBuilder* builder) 20 : builder_(builder) {} ~ControlFlowBuilder()21 virtual ~ControlFlowBuilder() {} 22 23 protected: builder()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: BreakableControlFlowBuilder(BytecodeArrayBuilder * builder)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. Break()46 void Break() { EmitJump(&break_sites_); } BreakIfTrue()47 void BreakIfTrue() { EmitJumpIfTrue(&break_sites_); } BreakIfFalse()48 void BreakIfFalse() { EmitJumpIfFalse(&break_sites_); } BreakIfUndefined()49 void BreakIfUndefined() { EmitJumpIfUndefined(&break_sites_); } BreakIfNull()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: BlockBuilder(BytecodeArrayBuilder * builder)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: LoopBuilder(BytecodeArrayBuilder * builder)86 explicit LoopBuilder(BytecodeArrayBuilder* builder) 87 : BreakableControlFlowBuilder(builder), 88 continue_sites_(builder->zone()) {} 89 ~LoopBuilder(); 90 91 void LoopHeader(ZoneVector<BytecodeLabel>* additional_labels); JumpToHeader()92 void JumpToHeader() { builder()->Jump(&loop_header_); } JumpToHeaderIfTrue()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. Continue()100 void Continue() { EmitJump(&continue_sites_); } ContinueIfTrue()101 void ContinueIfTrue() { EmitJumpIfTrue(&continue_sites_); } ContinueIfUndefined()102 void ContinueIfUndefined() { EmitJumpIfUndefined(&continue_sites_); } ContinueIfNull()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: SwitchBuilder(BytecodeArrayBuilder * builder,int number_of_cases)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. Case(int index)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. DefaultAt(int index)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: TryCatchBuilder(BytecodeArrayBuilder * builder)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: TryFinallyBuilder(BytecodeArrayBuilder * builder,bool will_catch)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