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 V8_EXPORT_PRIVATE 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 V8_EXPORT_PRIVATE BreakableControlFlowBuilder 33 : public ControlFlowBuilder { 34 public: BreakableControlFlowBuilder(BytecodeArrayBuilder * builder)35 explicit BreakableControlFlowBuilder(BytecodeArrayBuilder* builder) 36 : ControlFlowBuilder(builder), break_labels_(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 BindBreakTarget(); 42 43 // This method is called when visiting break statements in the AST. 44 // Inserts a jump to an unbound label that is patched when the corresponding 45 // BindBreakTarget is called. Break()46 void Break() { EmitJump(&break_labels_); } BreakIfTrue()47 void BreakIfTrue() { EmitJumpIfTrue(&break_labels_); } BreakIfFalse()48 void BreakIfFalse() { EmitJumpIfFalse(&break_labels_); } BreakIfUndefined()49 void BreakIfUndefined() { EmitJumpIfUndefined(&break_labels_); } BreakIfNull()50 void BreakIfNull() { EmitJumpIfNull(&break_labels_); } 51 break_labels()52 BytecodeLabels* break_labels() { return &break_labels_; } 53 54 protected: 55 void EmitJump(BytecodeLabels* labels); 56 void EmitJumpIfTrue(BytecodeLabels* labels); 57 void EmitJumpIfFalse(BytecodeLabels* labels); 58 void EmitJumpIfUndefined(BytecodeLabels* labels); 59 void EmitJumpIfNull(BytecodeLabels* labels); 60 61 // Unbound labels that identify jumps for break statements in the code. 62 BytecodeLabels break_labels_; 63 }; 64 65 66 // Class to track control flow for block statements (which can break in JS). 67 class V8_EXPORT_PRIVATE BlockBuilder final 68 : public BreakableControlFlowBuilder { 69 public: BlockBuilder(BytecodeArrayBuilder * builder)70 explicit BlockBuilder(BytecodeArrayBuilder* builder) 71 : BreakableControlFlowBuilder(builder) {} 72 73 void EndBlock(); 74 75 private: 76 BytecodeLabel block_end_; 77 }; 78 79 80 // A class to help with co-ordinating break and continue statements with 81 // their loop. 82 class V8_EXPORT_PRIVATE LoopBuilder final : public BreakableControlFlowBuilder { 83 public: LoopBuilder(BytecodeArrayBuilder * builder)84 explicit LoopBuilder(BytecodeArrayBuilder* builder) 85 : BreakableControlFlowBuilder(builder), 86 continue_labels_(builder->zone()), 87 header_labels_(builder->zone()) {} 88 ~LoopBuilder(); 89 90 void LoopHeader(ZoneVector<BytecodeLabel>* additional_labels = nullptr); 91 void JumpToHeader(int loop_depth); 92 void BindContinueTarget(); 93 void EndLoop(); 94 95 // This method is called when visiting continue statements in the AST. 96 // Inserts a jump to an unbound label that is patched when BindContinueTarget 97 // is called. Continue()98 void Continue() { EmitJump(&continue_labels_); } ContinueIfTrue()99 void ContinueIfTrue() { EmitJumpIfTrue(&continue_labels_); } ContinueIfUndefined()100 void ContinueIfUndefined() { EmitJumpIfUndefined(&continue_labels_); } ContinueIfNull()101 void ContinueIfNull() { EmitJumpIfNull(&continue_labels_); } 102 103 private: 104 BytecodeLabel loop_header_; 105 106 // Unbound labels that identify jumps for continue statements in the code and 107 // jumps from checking the loop condition to the header for do-while loops. 108 BytecodeLabels continue_labels_; 109 BytecodeLabels header_labels_; 110 }; 111 112 113 // A class to help with co-ordinating break statements with their switch. 114 class V8_EXPORT_PRIVATE SwitchBuilder final 115 : 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) { builder()->JumpIfTrue(&case_sites_.at(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) { builder()->Jump(&case_sites_.at(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 V8_EXPORT_PRIVATE TryCatchBuilder final : public ControlFlowBuilder { 146 public: TryCatchBuilder(BytecodeArrayBuilder * builder,HandlerTable::CatchPrediction catch_prediction)147 explicit TryCatchBuilder(BytecodeArrayBuilder* builder, 148 HandlerTable::CatchPrediction catch_prediction) 149 : ControlFlowBuilder(builder), 150 handler_id_(builder->NewHandlerEntry()), 151 catch_prediction_(catch_prediction) {} 152 153 void BeginTry(Register context); 154 void EndTry(); 155 void EndCatch(); 156 157 private: 158 int handler_id_; 159 HandlerTable::CatchPrediction catch_prediction_; 160 BytecodeLabel handler_; 161 BytecodeLabel exit_; 162 }; 163 164 165 // A class to help with co-ordinating control flow in try-finally statements. 166 class V8_EXPORT_PRIVATE TryFinallyBuilder final : public ControlFlowBuilder { 167 public: TryFinallyBuilder(BytecodeArrayBuilder * builder,HandlerTable::CatchPrediction catch_prediction)168 explicit TryFinallyBuilder(BytecodeArrayBuilder* builder, 169 HandlerTable::CatchPrediction catch_prediction) 170 : ControlFlowBuilder(builder), 171 handler_id_(builder->NewHandlerEntry()), 172 catch_prediction_(catch_prediction), 173 finalization_sites_(builder->zone()) {} 174 175 void BeginTry(Register context); 176 void LeaveTry(); 177 void EndTry(); 178 void BeginHandler(); 179 void BeginFinally(); 180 void EndFinally(); 181 182 private: 183 int handler_id_; 184 HandlerTable::CatchPrediction catch_prediction_; 185 BytecodeLabel handler_; 186 187 // Unbound labels that identify jumps to the finally block in the code. 188 BytecodeLabels finalization_sites_; 189 }; 190 191 } // namespace interpreter 192 } // namespace internal 193 } // namespace v8 194 195 #endif // V8_INTERPRETER_CONTROL_FLOW_BUILDERS_H_ 196