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_COMPILER_BYTECODE_GRAPH_BUILDER_H_ 6 #define V8_COMPILER_BYTECODE_GRAPH_BUILDER_H_ 7 8 #include "src/compiler.h" 9 #include "src/compiler/bytecode-branch-analysis.h" 10 #include "src/compiler/js-graph.h" 11 #include "src/interpreter/bytecode-array-iterator.h" 12 #include "src/interpreter/bytecodes.h" 13 14 namespace v8 { 15 namespace internal { 16 namespace compiler { 17 18 // The BytecodeGraphBuilder produces a high-level IR graph based on 19 // interpreter bytecodes. 20 class BytecodeGraphBuilder { 21 public: 22 BytecodeGraphBuilder(Zone* local_zone, CompilationInfo* info, 23 JSGraph* jsgraph); 24 25 // Creates a graph by visiting bytecodes. 26 bool CreateGraph(); 27 28 private: 29 class Environment; 30 class FrameStateBeforeAndAfter; 31 32 void VisitBytecodes(); 33 34 // Get or create the node that represents the outer function closure. 35 Node* GetFunctionClosure(); 36 37 // Get or create the node that represents the outer function context. 38 Node* GetFunctionContext(); 39 40 // Get or create the node that represents the incoming new target value. 41 Node* GetNewTarget(); 42 43 // Builder for loading the a native context field. 44 Node* BuildLoadNativeContextField(int index); 45 46 // Helper function for creating a pair containing type feedback vector and 47 // a feedback slot. 48 VectorSlotPair CreateVectorSlotPair(int slot_id); 49 set_environment(Environment * env)50 void set_environment(Environment* env) { environment_ = env; } environment()51 const Environment* environment() const { return environment_; } environment()52 Environment* environment() { return environment_; } 53 54 // Node creation helpers 55 Node* NewNode(const Operator* op, bool incomplete = false) { 56 return MakeNode(op, 0, static_cast<Node**>(nullptr), incomplete); 57 } 58 NewNode(const Operator * op,Node * n1)59 Node* NewNode(const Operator* op, Node* n1) { 60 Node* buffer[] = {n1}; 61 return MakeNode(op, arraysize(buffer), buffer, false); 62 } 63 NewNode(const Operator * op,Node * n1,Node * n2)64 Node* NewNode(const Operator* op, Node* n1, Node* n2) { 65 Node* buffer[] = {n1, n2}; 66 return MakeNode(op, arraysize(buffer), buffer, false); 67 } 68 NewNode(const Operator * op,Node * n1,Node * n2,Node * n3)69 Node* NewNode(const Operator* op, Node* n1, Node* n2, Node* n3) { 70 Node* buffer[] = {n1, n2, n3}; 71 return MakeNode(op, arraysize(buffer), buffer, false); 72 } 73 NewNode(const Operator * op,Node * n1,Node * n2,Node * n3,Node * n4)74 Node* NewNode(const Operator* op, Node* n1, Node* n2, Node* n3, Node* n4) { 75 Node* buffer[] = {n1, n2, n3, n4}; 76 return MakeNode(op, arraysize(buffer), buffer, false); 77 } 78 79 // Helpers to create new control nodes. NewIfTrue()80 Node* NewIfTrue() { return NewNode(common()->IfTrue()); } NewIfFalse()81 Node* NewIfFalse() { return NewNode(common()->IfFalse()); } NewMerge()82 Node* NewMerge() { return NewNode(common()->Merge(1), true); } NewLoop()83 Node* NewLoop() { return NewNode(common()->Loop(1), true); } 84 Node* NewBranch(Node* condition, BranchHint hint = BranchHint::kNone) { 85 return NewNode(common()->Branch(hint), condition); 86 } 87 88 // Creates a new Phi node having {count} input values. 89 Node* NewPhi(int count, Node* input, Node* control); 90 Node* NewEffectPhi(int count, Node* input, Node* control); 91 92 // Helpers for merging control, effect or value dependencies. 93 Node* MergeControl(Node* control, Node* other); 94 Node* MergeEffect(Node* effect, Node* other_effect, Node* control); 95 Node* MergeValue(Node* value, Node* other_value, Node* control); 96 97 // The main node creation chokepoint. Adds context, frame state, effect, 98 // and control dependencies depending on the operator. 99 Node* MakeNode(const Operator* op, int value_input_count, Node** value_inputs, 100 bool incomplete); 101 102 Node** EnsureInputBufferSize(int size); 103 104 Node* ProcessCallArguments(const Operator* call_op, Node* callee, 105 interpreter::Register receiver, size_t arity); 106 Node* ProcessCallNewArguments(const Operator* call_new_op, Node* callee, 107 Node* new_target, 108 interpreter::Register first_arg, size_t arity); 109 Node* ProcessCallRuntimeArguments(const Operator* call_runtime_op, 110 interpreter::Register first_arg, 111 size_t arity); 112 113 void BuildCreateLiteral(const Operator* op); 114 void BuildCreateArguments(CreateArgumentsType type); 115 Node* BuildLoadContextSlot(); 116 Node* BuildLoadGlobal(TypeofMode typeof_mode); 117 void BuildStoreGlobal(LanguageMode language_mode); 118 Node* BuildNamedLoad(); 119 void BuildNamedStore(LanguageMode language_mode); 120 Node* BuildKeyedLoad(); 121 void BuildKeyedStore(LanguageMode language_mode); 122 void BuildLdaLookupSlot(TypeofMode typeof_mode); 123 void BuildStaLookupSlot(LanguageMode language_mode); 124 void BuildCall(TailCallMode tail_call_mode); 125 void BuildThrow(); 126 void BuildBinaryOp(const Operator* op); 127 void BuildCompareOp(const Operator* op); 128 void BuildDelete(LanguageMode language_mode); 129 void BuildCastOperator(const Operator* op); 130 void BuildForInPrepare(); 131 void BuildForInNext(); 132 void BuildInvokeIntrinsic(); 133 134 // Control flow plumbing. 135 void BuildJump(); 136 void BuildConditionalJump(Node* condition); 137 void BuildJumpIfEqual(Node* comperand); 138 void BuildJumpIfToBooleanEqual(Node* boolean_comperand); 139 void BuildJumpIfNotHole(); 140 141 // Simulates control flow by forward-propagating environments. 142 void MergeIntoSuccessorEnvironment(int target_offset); 143 void BuildLoopHeaderEnvironment(int current_offset); 144 void SwitchToMergeEnvironment(int current_offset); 145 146 // Simulates control flow that exits the function body. 147 void MergeControlToLeaveFunction(Node* exit); 148 149 // Simulates entry and exit of exception handlers. 150 void EnterAndExitExceptionHandlers(int current_offset); 151 152 // Growth increment for the temporary buffer used to construct input lists to 153 // new nodes. 154 static const int kInputBufferSizeIncrement = 64; 155 156 // The catch prediction from the handler table is reused. 157 typedef HandlerTable::CatchPrediction CatchPrediction; 158 159 // An abstract representation for an exception handler that is being 160 // entered and exited while the graph builder is iterating over the 161 // underlying bytecode. The exception handlers within the bytecode are 162 // well scoped, hence will form a stack during iteration. 163 struct ExceptionHandler { 164 int start_offset_; // Start offset of the handled area in the bytecode. 165 int end_offset_; // End offset of the handled area in the bytecode. 166 int handler_offset_; // Handler entry offset within the bytecode. 167 int context_register_; // Index of register holding handler context. 168 CatchPrediction pred_; // Prediction of whether handler is catching. 169 }; 170 171 // Field accessors graph()172 Graph* graph() const { return jsgraph_->graph(); } common()173 CommonOperatorBuilder* common() const { return jsgraph_->common(); } graph_zone()174 Zone* graph_zone() const { return graph()->zone(); } jsgraph()175 JSGraph* jsgraph() const { return jsgraph_; } javascript()176 JSOperatorBuilder* javascript() const { return jsgraph_->javascript(); } local_zone()177 Zone* local_zone() const { return local_zone_; } bytecode_array()178 const Handle<BytecodeArray>& bytecode_array() const { 179 return bytecode_array_; 180 } exception_handler_table()181 const Handle<HandlerTable>& exception_handler_table() const { 182 return exception_handler_table_; 183 } feedback_vector()184 const Handle<TypeFeedbackVector>& feedback_vector() const { 185 return feedback_vector_; 186 } frame_state_function_info()187 const FrameStateFunctionInfo* frame_state_function_info() const { 188 return frame_state_function_info_; 189 } 190 bytecode_iterator()191 const interpreter::BytecodeArrayIterator& bytecode_iterator() const { 192 return *bytecode_iterator_; 193 } 194 set_bytecode_iterator(const interpreter::BytecodeArrayIterator * bytecode_iterator)195 void set_bytecode_iterator( 196 const interpreter::BytecodeArrayIterator* bytecode_iterator) { 197 bytecode_iterator_ = bytecode_iterator; 198 } 199 branch_analysis()200 const BytecodeBranchAnalysis* branch_analysis() const { 201 return branch_analysis_; 202 } 203 set_branch_analysis(const BytecodeBranchAnalysis * branch_analysis)204 void set_branch_analysis(const BytecodeBranchAnalysis* branch_analysis) { 205 branch_analysis_ = branch_analysis; 206 } 207 208 #define DECLARE_VISIT_BYTECODE(name, ...) void Visit##name(); 209 BYTECODE_LIST(DECLARE_VISIT_BYTECODE) 210 #undef DECLARE_VISIT_BYTECODE 211 212 Zone* local_zone_; 213 JSGraph* jsgraph_; 214 Handle<BytecodeArray> bytecode_array_; 215 Handle<HandlerTable> exception_handler_table_; 216 Handle<TypeFeedbackVector> feedback_vector_; 217 const FrameStateFunctionInfo* frame_state_function_info_; 218 const interpreter::BytecodeArrayIterator* bytecode_iterator_; 219 const BytecodeBranchAnalysis* branch_analysis_; 220 Environment* environment_; 221 222 // Merge environments are snapshots of the environment at points where the 223 // control flow merges. This models a forward data flow propagation of all 224 // values from all predecessors of the merge in question. 225 ZoneMap<int, Environment*> merge_environments_; 226 227 // Exception handlers currently entered by the iteration. 228 ZoneStack<ExceptionHandler> exception_handlers_; 229 int current_exception_handler_; 230 231 // Temporary storage for building node input lists. 232 int input_buffer_size_; 233 Node** input_buffer_; 234 235 // Nodes representing values in the activation record. 236 SetOncePointer<Node> function_context_; 237 SetOncePointer<Node> function_closure_; 238 SetOncePointer<Node> new_target_; 239 240 // Control nodes that exit the function body. 241 ZoneVector<Node*> exit_controls_; 242 243 DISALLOW_COPY_AND_ASSIGN(BytecodeGraphBuilder); 244 }; 245 246 } // namespace compiler 247 } // namespace internal 248 } // namespace v8 249 250 #endif // V8_COMPILER_BYTECODE_GRAPH_BUILDER_H_ 251