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