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