Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 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. |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 26 | bool CreateGraph(); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 27 | |
| 28 | private: |
| 29 | class Environment; |
| 30 | class FrameStateBeforeAndAfter; |
| 31 | |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 32 | void VisitBytecodes(); |
| 33 | |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 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 | |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 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 | |
| 50 | void set_environment(Environment* env) { environment_ = env; } |
| 51 | const Environment* environment() const { return 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 | |
| 59 | Node* NewNode(const Operator* op, Node* n1) { |
| 60 | Node* buffer[] = {n1}; |
| 61 | return MakeNode(op, arraysize(buffer), buffer, false); |
| 62 | } |
| 63 | |
| 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 | |
| 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 | |
| 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. |
| 80 | Node* NewIfTrue() { return NewNode(common()->IfTrue()); } |
| 81 | Node* NewIfFalse() { return NewNode(common()->IfFalse()); } |
| 82 | Node* NewMerge() { return NewNode(common()->Merge(1), true); } |
| 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 | |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 102 | Node** EnsureInputBufferSize(int size); |
| 103 | |
| 104 | Node* ProcessCallArguments(const Operator* call_op, Node* callee, |
| 105 | interpreter::Register receiver, size_t arity); |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 106 | Node* ProcessCallNewArguments(const Operator* call_new_op, Node* callee, |
| 107 | Node* new_target, |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 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 | |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 113 | void BuildCreateLiteral(const Operator* op); |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 114 | void BuildCreateArguments(CreateArgumentsType type); |
Ben Murdoch | 61f157c | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 115 | Node* BuildLoadContextSlot(); |
| 116 | Node* BuildLoadGlobal(TypeofMode typeof_mode); |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 117 | void BuildStoreGlobal(LanguageMode language_mode); |
Ben Murdoch | 61f157c | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 118 | Node* BuildNamedLoad(); |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 119 | void BuildNamedStore(LanguageMode language_mode); |
Ben Murdoch | 61f157c | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 120 | Node* BuildKeyedLoad(); |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 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); |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 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(); |
Ben Murdoch | da12d29 | 2016-06-02 14:46:10 +0100 | [diff] [blame] | 132 | void BuildInvokeIntrinsic(); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 133 | |
| 134 | // Control flow plumbing. |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 135 | void BuildJump(); |
| 136 | void BuildConditionalJump(Node* condition); |
| 137 | void BuildJumpIfEqual(Node* comperand); |
| 138 | void BuildJumpIfToBooleanEqual(Node* boolean_comperand); |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 139 | void BuildJumpIfNotHole(); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 140 | |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 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); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 145 | |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 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); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 151 | |
| 152 | // Growth increment for the temporary buffer used to construct input lists to |
| 153 | // new nodes. |
| 154 | static const int kInputBufferSizeIncrement = 64; |
| 155 | |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 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 | |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 171 | // Field accessors |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 172 | Graph* graph() const { return jsgraph_->graph(); } |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 173 | CommonOperatorBuilder* common() const { return jsgraph_->common(); } |
| 174 | Zone* graph_zone() const { return graph()->zone(); } |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 175 | JSGraph* jsgraph() const { return jsgraph_; } |
| 176 | JSOperatorBuilder* javascript() const { return jsgraph_->javascript(); } |
| 177 | Zone* local_zone() const { return local_zone_; } |
| 178 | const Handle<BytecodeArray>& bytecode_array() const { |
| 179 | return bytecode_array_; |
| 180 | } |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 181 | const Handle<HandlerTable>& exception_handler_table() const { |
| 182 | return exception_handler_table_; |
| 183 | } |
| 184 | const Handle<TypeFeedbackVector>& feedback_vector() const { |
| 185 | return feedback_vector_; |
| 186 | } |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 187 | const FrameStateFunctionInfo* frame_state_function_info() const { |
| 188 | return frame_state_function_info_; |
| 189 | } |
| 190 | |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 191 | const interpreter::BytecodeArrayIterator& bytecode_iterator() const { |
| 192 | return *bytecode_iterator_; |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 193 | } |
| 194 | |
| 195 | void set_bytecode_iterator( |
| 196 | const interpreter::BytecodeArrayIterator* bytecode_iterator) { |
| 197 | bytecode_iterator_ = bytecode_iterator; |
| 198 | } |
| 199 | |
| 200 | const BytecodeBranchAnalysis* branch_analysis() const { |
| 201 | return branch_analysis_; |
| 202 | } |
| 203 | |
| 204 | void set_branch_analysis(const BytecodeBranchAnalysis* branch_analysis) { |
| 205 | branch_analysis_ = branch_analysis; |
| 206 | } |
| 207 | |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 208 | #define DECLARE_VISIT_BYTECODE(name, ...) void Visit##name(); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 209 | BYTECODE_LIST(DECLARE_VISIT_BYTECODE) |
| 210 | #undef DECLARE_VISIT_BYTECODE |
| 211 | |
| 212 | Zone* local_zone_; |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 213 | JSGraph* jsgraph_; |
| 214 | Handle<BytecodeArray> bytecode_array_; |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 215 | Handle<HandlerTable> exception_handler_table_; |
| 216 | Handle<TypeFeedbackVector> feedback_vector_; |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 217 | const FrameStateFunctionInfo* frame_state_function_info_; |
| 218 | const interpreter::BytecodeArrayIterator* bytecode_iterator_; |
| 219 | const BytecodeBranchAnalysis* branch_analysis_; |
| 220 | Environment* environment_; |
| 221 | |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 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. |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 225 | ZoneMap<int, Environment*> merge_environments_; |
| 226 | |
Ben Murdoch | 097c5b2 | 2016-05-18 11:27:45 +0100 | [diff] [blame] | 227 | // Exception handlers currently entered by the iteration. |
| 228 | ZoneStack<ExceptionHandler> exception_handlers_; |
| 229 | int current_exception_handler_; |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 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 | |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 240 | // Control nodes that exit the function body. |
| 241 | ZoneVector<Node*> exit_controls_; |
| 242 | |
| 243 | DISALLOW_COPY_AND_ASSIGN(BytecodeGraphBuilder); |
| 244 | }; |
| 245 | |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 246 | } // namespace compiler |
| 247 | } // namespace internal |
| 248 | } // namespace v8 |
| 249 | |
| 250 | #endif // V8_COMPILER_BYTECODE_GRAPH_BUILDER_H_ |