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 |