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/bytecode-analysis.h" 9 #include "src/compiler/js-graph.h" 10 #include "src/compiler/liveness-analyzer.h" 11 #include "src/compiler/state-values-utils.h" 12 #include "src/interpreter/bytecode-array-iterator.h" 13 #include "src/interpreter/bytecode-flags.h" 14 #include "src/interpreter/bytecodes.h" 15 #include "src/source-position-table.h" 16 17 namespace v8 { 18 namespace internal { 19 namespace compiler { 20 21 class SourcePositionTable; 22 23 // The BytecodeGraphBuilder produces a high-level IR graph based on 24 // interpreter bytecodes. 25 class BytecodeGraphBuilder { 26 public: 27 BytecodeGraphBuilder(Zone* local_zone, Handle<SharedFunctionInfo> shared, 28 Handle<FeedbackVector> feedback_vector, 29 BailoutId osr_ast_id, JSGraph* jsgraph, 30 float invocation_frequency, 31 SourcePositionTable* source_positions, 32 int inlining_id = SourcePosition::kNotInlined); 33 34 // Creates a graph by visiting bytecodes. 35 bool CreateGraph(bool stack_check = true); 36 37 private: 38 class Environment; 39 40 void VisitBytecodes(bool stack_check); 41 42 // Get or create the node that represents the outer function closure. 43 Node* GetFunctionClosure(); 44 45 // Get or create the node that represents the outer function context. 46 Node* GetFunctionContext(); 47 48 // Get or create the node that represents the incoming new target value. 49 Node* GetNewTarget(); 50 51 // Builder for loading the a native context field. 52 Node* BuildLoadNativeContextField(int index); 53 54 // Helper function for creating a pair containing type feedback vector and 55 // a feedback slot. 56 VectorSlotPair CreateVectorSlotPair(int slot_id); 57 set_environment(Environment * env)58 void set_environment(Environment* env) { environment_ = env; } environment()59 const Environment* environment() const { return environment_; } environment()60 Environment* environment() { return environment_; } 61 62 // Node creation helpers 63 Node* NewNode(const Operator* op, bool incomplete = false) { 64 return MakeNode(op, 0, static_cast<Node**>(nullptr), incomplete); 65 } 66 NewNode(const Operator * op,Node * n1)67 Node* NewNode(const Operator* op, Node* n1) { 68 Node* buffer[] = {n1}; 69 return MakeNode(op, arraysize(buffer), buffer, false); 70 } 71 NewNode(const Operator * op,Node * n1,Node * n2)72 Node* NewNode(const Operator* op, Node* n1, Node* n2) { 73 Node* buffer[] = {n1, n2}; 74 return MakeNode(op, arraysize(buffer), buffer, false); 75 } 76 NewNode(const Operator * op,Node * n1,Node * n2,Node * n3)77 Node* NewNode(const Operator* op, Node* n1, Node* n2, Node* n3) { 78 Node* buffer[] = {n1, n2, n3}; 79 return MakeNode(op, arraysize(buffer), buffer, false); 80 } 81 NewNode(const Operator * op,Node * n1,Node * n2,Node * n3,Node * n4)82 Node* NewNode(const Operator* op, Node* n1, Node* n2, Node* n3, Node* n4) { 83 Node* buffer[] = {n1, n2, n3, n4}; 84 return MakeNode(op, arraysize(buffer), buffer, false); 85 } 86 87 // Helpers to create new control nodes. NewIfTrue()88 Node* NewIfTrue() { return NewNode(common()->IfTrue()); } NewIfFalse()89 Node* NewIfFalse() { return NewNode(common()->IfFalse()); } NewMerge()90 Node* NewMerge() { return NewNode(common()->Merge(1), true); } NewLoop()91 Node* NewLoop() { return NewNode(common()->Loop(1), true); } 92 Node* NewBranch(Node* condition, BranchHint hint = BranchHint::kNone) { 93 return NewNode(common()->Branch(hint), condition); 94 } 95 96 // Creates a new Phi node having {count} input values. 97 Node* NewPhi(int count, Node* input, Node* control); 98 Node* NewEffectPhi(int count, Node* input, Node* control); 99 100 // Helpers for merging control, effect or value dependencies. 101 Node* MergeControl(Node* control, Node* other); 102 Node* MergeEffect(Node* effect, Node* other_effect, Node* control); 103 Node* MergeValue(Node* value, Node* other_value, Node* control); 104 105 // The main node creation chokepoint. Adds context, frame state, effect, 106 // and control dependencies depending on the operator. 107 Node* MakeNode(const Operator* op, int value_input_count, Node** value_inputs, 108 bool incomplete); 109 110 Node** EnsureInputBufferSize(int size); 111 112 Node* ProcessCallArguments(const Operator* call_op, Node* callee, 113 interpreter::Register receiver, size_t arity); 114 Node* ProcessConstructArguments(const Operator* call_new_op, Node* callee, 115 Node* new_target, 116 interpreter::Register first_arg, 117 size_t arity); 118 Node* ProcessConstructWithSpreadArguments(const Operator* op, Node* callee, 119 Node* new_target, 120 interpreter::Register first_arg, 121 size_t arity); 122 Node* ProcessCallRuntimeArguments(const Operator* call_runtime_op, 123 interpreter::Register first_arg, 124 size_t arity); 125 126 // Prepare information for eager deoptimization. This information is carried 127 // by dedicated {Checkpoint} nodes that are wired into the effect chain. 128 // Conceptually this frame state is "before" a given operation. 129 void PrepareEagerCheckpoint(); 130 131 // Prepare information for lazy deoptimization. This information is attached 132 // to the given node and the output value produced by the node is combined. 133 // Conceptually this frame state is "after" a given operation. 134 void PrepareFrameState(Node* node, OutputFrameStateCombine combine); 135 136 void BuildCreateArguments(CreateArgumentsType type); 137 Node* BuildLoadGlobal(Handle<Name> name, uint32_t feedback_slot_index, 138 TypeofMode typeof_mode); 139 void BuildStoreGlobal(LanguageMode language_mode); 140 141 enum class StoreMode { 142 // Check the prototype chain before storing. 143 kNormal, 144 // Store value to the receiver without checking the prototype chain. 145 kOwn, 146 }; 147 void BuildNamedStore(LanguageMode language_mode, StoreMode store_mode); 148 void BuildKeyedStore(LanguageMode language_mode); 149 void BuildLdaLookupSlot(TypeofMode typeof_mode); 150 void BuildLdaLookupContextSlot(TypeofMode typeof_mode); 151 void BuildLdaLookupGlobalSlot(TypeofMode typeof_mode); 152 void BuildStaLookupSlot(LanguageMode language_mode); 153 void BuildCall(TailCallMode tail_call_mode, 154 ConvertReceiverMode receiver_hint); 155 void BuildBinaryOp(const Operator* op); 156 void BuildBinaryOpWithImmediate(const Operator* op); 157 void BuildCompareOp(const Operator* op); 158 void BuildDelete(LanguageMode language_mode); 159 void BuildCastOperator(const Operator* op); 160 void BuildForInPrepare(); 161 void BuildForInNext(); 162 void BuildInvokeIntrinsic(); 163 164 // Optional early lowering to the simplified operator level. Returns the node 165 // representing the lowered operation or {nullptr} if no lowering available. 166 // Note that the result has already been wired into the environment just like 167 // any other invocation of {NewNode} would do. 168 Node* TryBuildSimplifiedBinaryOp(const Operator* op, Node* left, Node* right, 169 FeedbackSlot slot); 170 171 // Check the context chain for extensions, for lookup fast paths. 172 Environment* CheckContextExtensions(uint32_t depth); 173 174 // Helper function to create binary operation hint from the recorded 175 // type feedback. 176 BinaryOperationHint GetBinaryOperationHint(int operand_index); 177 178 // Helper function to create compare operation hint from the recorded 179 // type feedback. 180 CompareOperationHint GetCompareOperationHint(); 181 182 // Helper function to compute call frequency from the recorded type 183 // feedback. 184 float ComputeCallFrequency(int slot_id) const; 185 186 // Control flow plumbing. 187 void BuildJump(); 188 void BuildJumpIf(Node* condition); 189 void BuildJumpIfNot(Node* condition); 190 void BuildJumpIfEqual(Node* comperand); 191 void BuildJumpIfTrue(); 192 void BuildJumpIfFalse(); 193 void BuildJumpIfToBooleanTrue(); 194 void BuildJumpIfToBooleanFalse(); 195 void BuildJumpIfNotHole(); 196 void BuildJumpIfJSReceiver(); 197 198 // Simulates control flow by forward-propagating environments. 199 void MergeIntoSuccessorEnvironment(int target_offset); 200 void BuildLoopHeaderEnvironment(int current_offset); 201 void SwitchToMergeEnvironment(int current_offset); 202 203 // Simulates control flow that exits the function body. 204 void MergeControlToLeaveFunction(Node* exit); 205 206 // Builds entry points that are used by OSR deconstruction. 207 void BuildOSRLoopEntryPoint(int current_offset); 208 void BuildOSRNormalEntryPoint(); 209 210 // Builds loop exit nodes for every exited loop between the current bytecode 211 // offset and {target_offset}. 212 void BuildLoopExitsForBranch(int target_offset); 213 void BuildLoopExitsForFunctionExit(); 214 void BuildLoopExitsUntilLoop(int loop_offset); 215 216 // Simulates entry and exit of exception handlers. 217 void EnterAndExitExceptionHandlers(int current_offset); 218 219 // Update the current position of the {SourcePositionTable} to that of the 220 // bytecode at {offset}, if any. 221 void UpdateCurrentSourcePosition(SourcePositionTableIterator* it, int offset); 222 223 // Growth increment for the temporary buffer used to construct input lists to 224 // new nodes. 225 static const int kInputBufferSizeIncrement = 64; 226 227 // An abstract representation for an exception handler that is being 228 // entered and exited while the graph builder is iterating over the 229 // underlying bytecode. The exception handlers within the bytecode are 230 // well scoped, hence will form a stack during iteration. 231 struct ExceptionHandler { 232 int start_offset_; // Start offset of the handled area in the bytecode. 233 int end_offset_; // End offset of the handled area in the bytecode. 234 int handler_offset_; // Handler entry offset within the bytecode. 235 int context_register_; // Index of register holding handler context. 236 }; 237 238 // Field accessors graph()239 Graph* graph() const { return jsgraph_->graph(); } common()240 CommonOperatorBuilder* common() const { return jsgraph_->common(); } graph_zone()241 Zone* graph_zone() const { return graph()->zone(); } jsgraph()242 JSGraph* jsgraph() const { return jsgraph_; } javascript()243 JSOperatorBuilder* javascript() const { return jsgraph_->javascript(); } simplified()244 SimplifiedOperatorBuilder* simplified() const { 245 return jsgraph_->simplified(); 246 } local_zone()247 Zone* local_zone() const { return local_zone_; } bytecode_array()248 const Handle<BytecodeArray>& bytecode_array() const { 249 return bytecode_array_; 250 } exception_handler_table()251 const Handle<HandlerTable>& exception_handler_table() const { 252 return exception_handler_table_; 253 } feedback_vector()254 const Handle<FeedbackVector>& feedback_vector() const { 255 return feedback_vector_; 256 } frame_state_function_info()257 const FrameStateFunctionInfo* frame_state_function_info() const { 258 return frame_state_function_info_; 259 } 260 bytecode_iterator()261 const interpreter::BytecodeArrayIterator& bytecode_iterator() const { 262 return *bytecode_iterator_; 263 } 264 set_bytecode_iterator(const interpreter::BytecodeArrayIterator * bytecode_iterator)265 void set_bytecode_iterator( 266 const interpreter::BytecodeArrayIterator* bytecode_iterator) { 267 bytecode_iterator_ = bytecode_iterator; 268 } 269 bytecode_analysis()270 const BytecodeAnalysis* bytecode_analysis() const { 271 return bytecode_analysis_; 272 } 273 set_bytecode_analysis(const BytecodeAnalysis * bytecode_analysis)274 void set_bytecode_analysis(const BytecodeAnalysis* bytecode_analysis) { 275 bytecode_analysis_ = bytecode_analysis; 276 } 277 needs_eager_checkpoint()278 bool needs_eager_checkpoint() const { return needs_eager_checkpoint_; } mark_as_needing_eager_checkpoint(bool value)279 void mark_as_needing_eager_checkpoint(bool value) { 280 needs_eager_checkpoint_ = value; 281 } 282 283 #define DECLARE_VISIT_BYTECODE(name, ...) void Visit##name(); 284 BYTECODE_LIST(DECLARE_VISIT_BYTECODE) 285 #undef DECLARE_VISIT_BYTECODE 286 287 Zone* local_zone_; 288 JSGraph* jsgraph_; 289 float const invocation_frequency_; 290 Handle<BytecodeArray> bytecode_array_; 291 Handle<HandlerTable> exception_handler_table_; 292 Handle<FeedbackVector> feedback_vector_; 293 const FrameStateFunctionInfo* frame_state_function_info_; 294 const interpreter::BytecodeArrayIterator* bytecode_iterator_; 295 const BytecodeAnalysis* bytecode_analysis_; 296 Environment* environment_; 297 BailoutId osr_ast_id_; 298 int osr_loop_offset_; 299 300 // Merge environments are snapshots of the environment at points where the 301 // control flow merges. This models a forward data flow propagation of all 302 // values from all predecessors of the merge in question. 303 ZoneMap<int, Environment*> merge_environments_; 304 305 // Exception handlers currently entered by the iteration. 306 ZoneStack<ExceptionHandler> exception_handlers_; 307 int current_exception_handler_; 308 309 // Temporary storage for building node input lists. 310 int input_buffer_size_; 311 Node** input_buffer_; 312 313 // Optimization to only create checkpoints when the current position in the 314 // control-flow is not effect-dominated by another checkpoint already. All 315 // operations that do not have observable side-effects can be re-evaluated. 316 bool needs_eager_checkpoint_; 317 318 // Nodes representing values in the activation record. 319 SetOncePointer<Node> function_context_; 320 SetOncePointer<Node> function_closure_; 321 SetOncePointer<Node> new_target_; 322 323 // Control nodes that exit the function body. 324 ZoneVector<Node*> exit_controls_; 325 326 StateValuesCache state_values_cache_; 327 328 // The source position table, to be populated. 329 SourcePositionTable* source_positions_; 330 331 SourcePosition const start_position_; 332 333 static int const kBinaryOperationHintIndex = 1; 334 static int const kCountOperationHintIndex = 0; 335 static int const kBinaryOperationSmiHintIndex = 2; 336 337 DISALLOW_COPY_AND_ASSIGN(BytecodeGraphBuilder); 338 }; 339 340 } // namespace compiler 341 } // namespace internal 342 } // namespace v8 343 344 #endif // V8_COMPILER_BYTECODE_GRAPH_BUILDER_H_ 345