| OLD | NEW |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2016 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #ifndef V8_COMPILER_H_ | 5 #ifndef V8_COMPILATION_INFO_H_ |
| 6 #define V8_COMPILER_H_ | 6 #define V8_COMPILATION_INFO_H_ |
| 7 | 7 |
| 8 #include <memory> | 8 #include <memory> |
| 9 | 9 |
| 10 #include "src/allocation.h" | |
| 11 #include "src/bailout-reason.h" | |
| 12 #include "src/compilation-dependencies.h" | 10 #include "src/compilation-dependencies.h" |
| 13 #include "src/contexts.h" | |
| 14 #include "src/frames.h" | 11 #include "src/frames.h" |
| 15 #include "src/isolate.h" | 12 #include "src/handles.h" |
| 13 #include "src/objects.h" |
| 16 #include "src/source-position-table.h" | 14 #include "src/source-position-table.h" |
| 17 #include "src/source-position.h" | 15 #include "src/utils.h" |
| 18 #include "src/zone.h" | 16 #include "src/vector.h" |
| 19 | 17 |
| 20 namespace v8 { | 18 namespace v8 { |
| 21 namespace internal { | 19 namespace internal { |
| 22 | 20 |
| 23 // Forward declarations. | 21 class DeclarationScope; |
| 24 class CompilationInfo; | 22 class DeferredHandles; |
| 25 class CompilationJob; | 23 class FunctionLiteral; |
| 26 class JavaScriptFrame; | 24 class JavaScriptFrame; |
| 27 class ParseInfo; | 25 class ParseInfo; |
| 28 class ScriptData; | 26 class Isolate; |
| 29 | 27 class Zone; |
| 30 // The V8 compiler API. | |
| 31 // | |
| 32 // This is the central hub for dispatching to the various compilers within V8. | |
| 33 // Logic for which compiler to choose and how to wire compilation results into | |
| 34 // the object heap should be kept inside this class. | |
| 35 // | |
| 36 // General strategy: Scripts are translated into anonymous functions w/o | |
| 37 // parameters which then can be executed. If the source code contains other | |
| 38 // functions, they might be compiled and allocated as part of the compilation | |
| 39 // of the source code or deferred for lazy compilation at a later point. | |
| 40 class Compiler : public AllStatic { | |
| 41 public: | |
| 42 enum ClearExceptionFlag { KEEP_EXCEPTION, CLEAR_EXCEPTION }; | |
| 43 enum ConcurrencyMode { NOT_CONCURRENT, CONCURRENT }; | |
| 44 enum CompilationTier { INTERPRETED, BASELINE, OPTIMIZED }; | |
| 45 | |
| 46 // =========================================================================== | |
| 47 // The following family of methods ensures a given function is compiled. The | |
| 48 // general contract is that failures will be reported by returning {false}, | |
| 49 // whereas successful compilation ensures the {is_compiled} predicate on the | |
| 50 // given function holds (except for live-edit, which compiles the world). | |
| 51 | |
| 52 static bool Compile(Handle<JSFunction> function, ClearExceptionFlag flag); | |
| 53 static bool CompileBaseline(Handle<JSFunction> function); | |
| 54 static bool CompileOptimized(Handle<JSFunction> function, ConcurrencyMode); | |
| 55 static bool CompileDebugCode(Handle<JSFunction> function); | |
| 56 static bool CompileDebugCode(Handle<SharedFunctionInfo> shared); | |
| 57 static MaybeHandle<JSArray> CompileForLiveEdit(Handle<Script> script); | |
| 58 | |
| 59 // Prepare a compilation job for unoptimized code. Requires ParseAndAnalyse. | |
| 60 static CompilationJob* PrepareUnoptimizedCompilationJob( | |
| 61 CompilationInfo* info); | |
| 62 | |
| 63 // Generate and install code from previously queued compilation job. | |
| 64 static bool FinalizeCompilationJob(CompilationJob* job); | |
| 65 | |
| 66 // Give the compiler a chance to perform low-latency initialization tasks of | |
| 67 // the given {function} on its instantiation. Note that only the runtime will | |
| 68 // offer this chance, optimized closure instantiation will not call this. | |
| 69 static void PostInstantiation(Handle<JSFunction> function, PretenureFlag); | |
| 70 | |
| 71 // Parser::Parse, then Compiler::Analyze. | |
| 72 static bool ParseAndAnalyze(ParseInfo* info); | |
| 73 // Rewrite, analyze scopes, and renumber. | |
| 74 static bool Analyze(ParseInfo* info); | |
| 75 // Adds deoptimization support, requires ParseAndAnalyze. | |
| 76 static bool EnsureDeoptimizationSupport(CompilationInfo* info); | |
| 77 // Ensures that bytecode is generated, calls ParseAndAnalyze internally. | |
| 78 static bool EnsureBytecode(CompilationInfo* info); | |
| 79 | |
| 80 // The next compilation tier which the function should be compiled to for | |
| 81 // optimization. This is used as a hint by the runtime profiler. | |
| 82 static CompilationTier NextCompilationTier(JSFunction* function); | |
| 83 | |
| 84 // =========================================================================== | |
| 85 // The following family of methods instantiates new functions for scripts or | |
| 86 // function literals. The decision whether those functions will be compiled, | |
| 87 // is left to the discretion of the compiler. | |
| 88 // | |
| 89 // Please note this interface returns shared function infos. This means you | |
| 90 // need to call Factory::NewFunctionFromSharedFunctionInfo before you have a | |
| 91 // real function with a context. | |
| 92 | |
| 93 // Create a (bound) function for a String source within a context for eval. | |
| 94 MUST_USE_RESULT static MaybeHandle<JSFunction> GetFunctionFromEval( | |
| 95 Handle<String> source, Handle<SharedFunctionInfo> outer_info, | |
| 96 Handle<Context> context, LanguageMode language_mode, | |
| 97 ParseRestriction restriction, int eval_scope_position, int eval_position, | |
| 98 int line_offset = 0, int column_offset = 0, | |
| 99 Handle<Object> script_name = Handle<Object>(), | |
| 100 ScriptOriginOptions options = ScriptOriginOptions()); | |
| 101 | |
| 102 // Create a (bound) function for a String source within a context for eval. | |
| 103 MUST_USE_RESULT static MaybeHandle<JSFunction> GetFunctionFromString( | |
| 104 Handle<Context> context, Handle<String> source, | |
| 105 ParseRestriction restriction); | |
| 106 | |
| 107 // Create a shared function info object for a String source within a context. | |
| 108 static Handle<SharedFunctionInfo> GetSharedFunctionInfoForScript( | |
| 109 Handle<String> source, Handle<Object> script_name, int line_offset, | |
| 110 int column_offset, ScriptOriginOptions resource_options, | |
| 111 Handle<Object> source_map_url, Handle<Context> context, | |
| 112 v8::Extension* extension, ScriptData** cached_data, | |
| 113 ScriptCompiler::CompileOptions compile_options, | |
| 114 NativesFlag is_natives_code, bool is_module); | |
| 115 | |
| 116 // Create a shared function info object for a Script that has already been | |
| 117 // parsed while the script was being loaded from a streamed source. | |
| 118 static Handle<SharedFunctionInfo> GetSharedFunctionInfoForStreamedScript( | |
| 119 Handle<Script> script, ParseInfo* info, int source_length); | |
| 120 | |
| 121 // Create a shared function info object (the code may be lazily compiled). | |
| 122 static Handle<SharedFunctionInfo> GetSharedFunctionInfo( | |
| 123 FunctionLiteral* node, Handle<Script> script, CompilationInfo* outer); | |
| 124 | |
| 125 // Create a shared function info object for a native function literal. | |
| 126 static Handle<SharedFunctionInfo> GetSharedFunctionInfoForNative( | |
| 127 v8::Extension* extension, Handle<String> name); | |
| 128 | |
| 129 // =========================================================================== | |
| 130 // The following family of methods provides support for OSR. Code generated | |
| 131 // for entry via OSR might not be suitable for normal entry, hence will be | |
| 132 // returned directly to the caller. | |
| 133 // | |
| 134 // Please note this interface is the only part dealing with {Code} objects | |
| 135 // directly. Other methods are agnostic to {Code} and can use an interpreter | |
| 136 // instead of generating JIT code for a function at all. | |
| 137 | |
| 138 // Generate and return optimized code for OSR, or empty handle on failure. | |
| 139 MUST_USE_RESULT static MaybeHandle<Code> GetOptimizedCodeForOSR( | |
| 140 Handle<JSFunction> function, BailoutId osr_ast_id, | |
| 141 JavaScriptFrame* osr_frame); | |
| 142 }; | |
| 143 | |
| 144 | 28 |
| 145 // CompilationInfo encapsulates some information known at compile time. It | 29 // CompilationInfo encapsulates some information known at compile time. It |
| 146 // is constructed based on the resources available at compile-time. | 30 // is constructed based on the resources available at compile-time. |
| 147 class CompilationInfo final { | 31 class CompilationInfo final { |
| 148 public: | 32 public: |
| 149 // Various configuration flags for a compilation, as well as some properties | 33 // Various configuration flags for a compilation, as well as some properties |
| 150 // of the compiled code produced by a compilation. | 34 // of the compiled code produced by a compilation. |
| 151 enum Flag { | 35 enum Flag { |
| 152 kDeferredCalling = 1 << 0, | 36 kDeferredCalling = 1 << 0, |
| 153 kNonDeferredCalling = 1 << 1, | 37 kNonDeferredCalling = 1 << 1, |
| (...skipping 28 matching lines...) Expand all Loading... |
| 182 // TODO(titzer): inline and delete accessors of ParseInfo | 66 // TODO(titzer): inline and delete accessors of ParseInfo |
| 183 // ----------------------------------------------------------- | 67 // ----------------------------------------------------------- |
| 184 Handle<Script> script() const; | 68 Handle<Script> script() const; |
| 185 FunctionLiteral* literal() const; | 69 FunctionLiteral* literal() const; |
| 186 DeclarationScope* scope() const; | 70 DeclarationScope* scope() const; |
| 187 Handle<Context> context() const; | 71 Handle<Context> context() const; |
| 188 Handle<SharedFunctionInfo> shared_info() const; | 72 Handle<SharedFunctionInfo> shared_info() const; |
| 189 bool has_shared_info() const; | 73 bool has_shared_info() const; |
| 190 // ----------------------------------------------------------- | 74 // ----------------------------------------------------------- |
| 191 | 75 |
| 192 Isolate* isolate() const { | 76 Isolate* isolate() const { return isolate_; } |
| 193 return isolate_; | |
| 194 } | |
| 195 Zone* zone() { return zone_; } | 77 Zone* zone() { return zone_; } |
| 196 bool is_osr() const { return !osr_ast_id_.IsNone(); } | 78 bool is_osr() const { return !osr_ast_id_.IsNone(); } |
| 197 Handle<JSFunction> closure() const { return closure_; } | 79 Handle<JSFunction> closure() const { return closure_; } |
| 198 Handle<Code> code() const { return code_; } | 80 Handle<Code> code() const { return code_; } |
| 199 Code::Flags code_flags() const { return code_flags_; } | 81 Code::Flags code_flags() const { return code_flags_; } |
| 200 BailoutId osr_ast_id() const { return osr_ast_id_; } | 82 BailoutId osr_ast_id() const { return osr_ast_id_; } |
| 201 JavaScriptFrame* osr_frame() const { return osr_frame_; } | 83 JavaScriptFrame* osr_frame() const { return osr_frame_; } |
| 202 int num_parameters() const; | 84 int num_parameters() const; |
| 203 int num_parameters_including_this() const; | 85 int num_parameters_including_this() const; |
| 204 bool is_this_defined() const; | 86 bool is_this_defined() const; |
| (...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 326 } | 208 } |
| 327 | 209 |
| 328 void SetCode(Handle<Code> code) { code_ = code; } | 210 void SetCode(Handle<Code> code) { code_ = code; } |
| 329 | 211 |
| 330 void SetBytecodeArray(Handle<BytecodeArray> bytecode_array) { | 212 void SetBytecodeArray(Handle<BytecodeArray> bytecode_array) { |
| 331 bytecode_array_ = bytecode_array; | 213 bytecode_array_ = bytecode_array; |
| 332 } | 214 } |
| 333 | 215 |
| 334 bool ShouldTrapOnDeopt() const { | 216 bool ShouldTrapOnDeopt() const { |
| 335 return (FLAG_trap_on_deopt && IsOptimizing()) || | 217 return (FLAG_trap_on_deopt && IsOptimizing()) || |
| 336 (FLAG_trap_on_stub_deopt && IsStub()); | 218 (FLAG_trap_on_stub_deopt && IsStub()); |
| 337 } | 219 } |
| 338 | 220 |
| 339 bool has_native_context() const; | 221 bool has_native_context() const; |
| 340 Context* native_context() const; | 222 Context* native_context() const; |
| 341 | 223 |
| 342 bool has_global_object() const; | 224 bool has_global_object() const; |
| 343 JSGlobalObject* global_object() const; | 225 JSGlobalObject* global_object() const; |
| 344 | 226 |
| 345 // Accessors for the different compilation modes. | 227 // Accessors for the different compilation modes. |
| 346 bool IsOptimizing() const { return mode_ == OPTIMIZE; } | 228 bool IsOptimizing() const { return mode_ == OPTIMIZE; } |
| 347 bool IsStub() const { return mode_ == STUB; } | 229 bool IsStub() const { return mode_ == STUB; } |
| 348 void SetOptimizing() { | 230 void SetOptimizing(); |
| 349 DCHECK(has_shared_info()); | |
| 350 SetMode(OPTIMIZE); | |
| 351 optimization_id_ = isolate()->NextOptimizationId(); | |
| 352 code_flags_ = | |
| 353 Code::KindField::update(code_flags_, Code::OPTIMIZED_FUNCTION); | |
| 354 } | |
| 355 void SetOptimizingForOsr(BailoutId osr_ast_id, JavaScriptFrame* osr_frame) { | 231 void SetOptimizingForOsr(BailoutId osr_ast_id, JavaScriptFrame* osr_frame) { |
| 356 SetOptimizing(); | 232 SetOptimizing(); |
| 357 osr_ast_id_ = osr_ast_id; | 233 osr_ast_id_ = osr_ast_id; |
| 358 osr_frame_ = osr_frame; | 234 osr_frame_ = osr_frame; |
| 359 } | 235 } |
| 360 | 236 |
| 361 // Deoptimization support. | 237 // Deoptimization support. |
| 362 bool HasDeoptimizationSupport() const { | 238 bool HasDeoptimizationSupport() const { |
| 363 return GetFlag(kDeoptimizationSupport); | 239 return GetFlag(kDeoptimizationSupport); |
| 364 } | 240 } |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 444 StackFrame::Type GetOutputStackFrameType() const; | 320 StackFrame::Type GetOutputStackFrameType() const; |
| 445 | 321 |
| 446 int GetDeclareGlobalsFlags() const; | 322 int GetDeclareGlobalsFlags() const; |
| 447 | 323 |
| 448 SourcePositionTableBuilder::RecordingMode SourcePositionRecordingMode() const; | 324 SourcePositionTableBuilder::RecordingMode SourcePositionRecordingMode() const; |
| 449 | 325 |
| 450 private: | 326 private: |
| 451 // Compilation mode. | 327 // Compilation mode. |
| 452 // BASE is generated by the full codegen, optionally prepared for bailouts. | 328 // BASE is generated by the full codegen, optionally prepared for bailouts. |
| 453 // OPTIMIZE is optimized code generated by the Hydrogen-based backend. | 329 // OPTIMIZE is optimized code generated by the Hydrogen-based backend. |
| 454 enum Mode { | 330 enum Mode { BASE, OPTIMIZE, STUB }; |
| 455 BASE, | |
| 456 OPTIMIZE, | |
| 457 STUB | |
| 458 }; | |
| 459 | 331 |
| 460 CompilationInfo(ParseInfo* parse_info, Vector<const char> debug_name, | 332 CompilationInfo(ParseInfo* parse_info, Vector<const char> debug_name, |
| 461 Code::Flags code_flags, Mode mode, Isolate* isolate, | 333 Code::Flags code_flags, Mode mode, Isolate* isolate, |
| 462 Zone* zone); | 334 Zone* zone); |
| 463 | 335 |
| 464 ParseInfo* parse_info_; | 336 ParseInfo* parse_info_; |
| 465 Isolate* isolate_; | 337 Isolate* isolate_; |
| 466 | 338 |
| 467 void SetMode(Mode mode) { | 339 void SetMode(Mode mode) { mode_ = mode; } |
| 468 mode_ = mode; | |
| 469 } | |
| 470 | 340 |
| 471 void SetFlag(Flag flag) { flags_ |= flag; } | 341 void SetFlag(Flag flag) { flags_ |= flag; } |
| 472 | 342 |
| 473 void SetFlag(Flag flag, bool value) { | 343 void SetFlag(Flag flag, bool value) { |
| 474 flags_ = value ? flags_ | flag : flags_ & ~flag; | 344 flags_ = value ? flags_ | flag : flags_ & ~flag; |
| 475 } | 345 } |
| 476 | 346 |
| 477 bool GetFlag(Flag flag) const { return (flags_ & flag) != 0; } | 347 bool GetFlag(Flag flag) const { return (flags_ & flag) != 0; } |
| 478 | 348 |
| 479 unsigned flags_; | 349 unsigned flags_; |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 519 int osr_expr_stack_height_; | 389 int osr_expr_stack_height_; |
| 520 | 390 |
| 521 // The current OSR frame for specialization or {nullptr}. | 391 // The current OSR frame for specialization or {nullptr}. |
| 522 JavaScriptFrame* osr_frame_ = nullptr; | 392 JavaScriptFrame* osr_frame_ = nullptr; |
| 523 | 393 |
| 524 Vector<const char> debug_name_; | 394 Vector<const char> debug_name_; |
| 525 | 395 |
| 526 DISALLOW_COPY_AND_ASSIGN(CompilationInfo); | 396 DISALLOW_COPY_AND_ASSIGN(CompilationInfo); |
| 527 }; | 397 }; |
| 528 | 398 |
| 529 // A base class for compilation jobs intended to run concurrent to the main | |
| 530 // thread. The job is split into three phases which are called in sequence on | |
| 531 // different threads and with different limitations: | |
| 532 // 1) PrepareJob: Runs on main thread. No major limitations. | |
| 533 // 2) ExecuteJob: Runs concurrently. No heap allocation or handle derefs. | |
| 534 // 3) FinalizeJob: Runs on main thread. No dependency changes. | |
| 535 // | |
| 536 // Each of the three phases can either fail or succeed. The current state of | |
| 537 // the job can be checked using {state()}. | |
| 538 class CompilationJob { | |
| 539 public: | |
| 540 enum Status { SUCCEEDED, FAILED }; | |
| 541 enum class State { | |
| 542 kReadyToPrepare, | |
| 543 kReadyToExecute, | |
| 544 kReadyToFinalize, | |
| 545 kSucceeded, | |
| 546 kFailed, | |
| 547 }; | |
| 548 | |
| 549 CompilationJob(Isolate* isolate, CompilationInfo* info, | |
| 550 const char* compiler_name, | |
| 551 State initial_state = State::kReadyToPrepare) | |
| 552 : info_(info), | |
| 553 compiler_name_(compiler_name), | |
| 554 state_(initial_state), | |
| 555 stack_limit_(isolate->stack_guard()->real_climit()) {} | |
| 556 virtual ~CompilationJob() {} | |
| 557 | |
| 558 // Prepare the compile job. Must be called on the main thread. | |
| 559 MUST_USE_RESULT Status PrepareJob(); | |
| 560 | |
| 561 // Executes the compile job. Can be called on a background thread if | |
| 562 // can_execute_on_background_thread() returns true. | |
| 563 MUST_USE_RESULT Status ExecuteJob(); | |
| 564 | |
| 565 // Finalizes the compile job. Must be called on the main thread. | |
| 566 MUST_USE_RESULT Status FinalizeJob(); | |
| 567 | |
| 568 // Report a transient failure, try again next time. Should only be called on | |
| 569 // optimization compilation jobs. | |
| 570 Status RetryOptimization(BailoutReason reason) { | |
| 571 DCHECK(info_->IsOptimizing()); | |
| 572 info_->RetryOptimization(reason); | |
| 573 state_ = State::kFailed; | |
| 574 return FAILED; | |
| 575 } | |
| 576 | |
| 577 // Report a persistent failure, disable future optimization on the function. | |
| 578 // Should only be called on optimization compilation jobs. | |
| 579 Status AbortOptimization(BailoutReason reason) { | |
| 580 DCHECK(info_->IsOptimizing()); | |
| 581 info_->AbortOptimization(reason); | |
| 582 state_ = State::kFailed; | |
| 583 return FAILED; | |
| 584 } | |
| 585 | |
| 586 void RecordOptimizedCompilationStats() const; | |
| 587 void RecordUnoptimizedCompilationStats() const; | |
| 588 | |
| 589 virtual bool can_execute_on_background_thread() const { return true; } | |
| 590 | |
| 591 void set_stack_limit(uintptr_t stack_limit) { stack_limit_ = stack_limit; } | |
| 592 uintptr_t stack_limit() const { return stack_limit_; } | |
| 593 | |
| 594 State state() const { return state_; } | |
| 595 CompilationInfo* info() const { return info_; } | |
| 596 Isolate* isolate() const { return info()->isolate(); } | |
| 597 | |
| 598 protected: | |
| 599 // Overridden by the actual implementation. | |
| 600 virtual Status PrepareJobImpl() = 0; | |
| 601 virtual Status ExecuteJobImpl() = 0; | |
| 602 virtual Status FinalizeJobImpl() = 0; | |
| 603 | |
| 604 // Registers weak object to optimized code dependencies. | |
| 605 // TODO(turbofan): Move this to pipeline.cc once Crankshaft dies. | |
| 606 void RegisterWeakObjectsInOptimizedCode(Handle<Code> code); | |
| 607 | |
| 608 private: | |
| 609 CompilationInfo* info_; | |
| 610 base::TimeDelta time_taken_to_prepare_; | |
| 611 base::TimeDelta time_taken_to_execute_; | |
| 612 base::TimeDelta time_taken_to_finalize_; | |
| 613 const char* compiler_name_; | |
| 614 State state_; | |
| 615 uintptr_t stack_limit_; | |
| 616 | |
| 617 MUST_USE_RESULT Status UpdateState(Status status, State next_state) { | |
| 618 if (status == SUCCEEDED) { | |
| 619 state_ = next_state; | |
| 620 } else { | |
| 621 state_ = State::kFailed; | |
| 622 } | |
| 623 return status; | |
| 624 } | |
| 625 }; | |
| 626 | |
| 627 } // namespace internal | 399 } // namespace internal |
| 628 } // namespace v8 | 400 } // namespace v8 |
| 629 | 401 |
| 630 #endif // V8_COMPILER_H_ | 402 #endif // V8_COMPILATION_INFO_H_ |
| OLD | NEW |