1 // Copyright 2012 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.
8 #include "src/allocation.h"
10 #include "src/bailout-reason.h"
16 class AstValueFactory;
17 class HydrogenCodeStub;
19 // ParseRestriction is used to restrict the set of valid statements in a
20 // unit of compilation. Restriction violations cause a syntax error.
21 enum ParseRestriction {
22 NO_PARSE_RESTRICTION, // All expressions are allowed.
23 ONLY_SINGLE_FUNCTION_LITERAL // Only a single FunctionLiteral expression.
27 OffsetRange(int from, int to) : from(from), to(to) {}
35 ScriptData(const byte* data, int length);
37 if (owns_data_) DeleteArray(data_);
40 const byte* data() const { return data_; }
41 int length() const { return length_; }
43 void AcquireDataOwnership() {
48 void ReleaseDataOwnership() {
58 DISALLOW_COPY_AND_ASSIGN(ScriptData);
61 // CompilationInfo encapsulates some information known at compile time. It
62 // is constructed based on the resources available at compile-time.
63 class CompilationInfo {
65 // Various configuration flags for a compilation, as well as some properties
66 // of the compiled code produced by a compilation.
72 kThisHasUses = 1 << 4,
74 kDeferredCalling = 1 << 6,
75 kNonDeferredCalling = 1 << 7,
76 kSavesCallerDoubles = 1 << 8,
77 kRequiresFrame = 1 << 9,
78 kMustNotHaveEagerFrame = 1 << 10,
79 kDeoptimizationSupport = 1 << 11,
81 kCompilingForDebugging = 1 << 13,
82 kParseRestriction = 1 << 14,
83 kSerializing = 1 << 15,
84 kContextSpecializing = 1 << 16,
85 kInliningEnabled = 1 << 17,
86 kTypingEnabled = 1 << 18,
87 kDisableFutureOptimization = 1 << 19,
88 kAbortedDueToDependency = 1 << 20
91 CompilationInfo(Handle<JSFunction> closure, Zone* zone);
92 CompilationInfo(Isolate* isolate, Zone* zone);
93 virtual ~CompilationInfo();
95 Isolate* isolate() const {
98 Zone* zone() { return zone_; }
99 bool is_osr() const { return !osr_ast_id_.IsNone(); }
100 bool is_lazy() const { return GetFlag(kLazy); }
101 bool is_eval() const { return GetFlag(kEval); }
102 bool is_global() const { return GetFlag(kGlobal); }
103 StrictMode strict_mode() const {
104 return GetFlag(kStrictMode) ? STRICT : SLOPPY;
106 FunctionLiteral* function() const { return function_; }
107 Scope* scope() const { return scope_; }
108 Scope* global_scope() const { return global_scope_; }
109 Handle<Code> code() const { return code_; }
110 Handle<JSFunction> closure() const { return closure_; }
111 Handle<SharedFunctionInfo> shared_info() const { return shared_info_; }
112 Handle<Script> script() const { return script_; }
113 void set_script(Handle<Script> script) { script_ = script; }
114 HydrogenCodeStub* code_stub() const {return code_stub_; }
115 v8::Extension* extension() const { return extension_; }
116 ScriptData** cached_data() const { return cached_data_; }
117 ScriptCompiler::CompileOptions compile_options() const {
118 return compile_options_;
120 ScriptCompiler::ExternalSourceStream* source_stream() const {
121 return source_stream_;
123 ScriptCompiler::StreamedSource::Encoding source_stream_encoding() const {
124 return source_stream_encoding_;
126 Handle<Context> context() const { return context_; }
127 BailoutId osr_ast_id() const { return osr_ast_id_; }
128 Handle<Code> unoptimized_code() const { return unoptimized_code_; }
129 int opt_count() const { return opt_count_; }
130 int num_parameters() const;
131 int num_heap_slots() const;
132 Code::Flags flags() const;
139 void MarkAsGlobal() {
144 void set_parameter_count(int parameter_count) {
146 parameter_count_ = parameter_count;
149 void set_this_has_uses(bool has_no_uses) {
150 SetFlag(kThisHasUses, has_no_uses);
153 bool this_has_uses() { return GetFlag(kThisHasUses); }
155 void SetStrictMode(StrictMode strict_mode) {
156 SetFlag(kStrictMode, strict_mode == STRICT);
159 void MarkAsNative() { SetFlag(kNative); }
161 bool is_native() const { return GetFlag(kNative); }
163 bool is_calling() const {
164 return GetFlag(kDeferredCalling) || GetFlag(kNonDeferredCalling);
167 void MarkAsDeferredCalling() { SetFlag(kDeferredCalling); }
169 bool is_deferred_calling() const { return GetFlag(kDeferredCalling); }
171 void MarkAsNonDeferredCalling() { SetFlag(kNonDeferredCalling); }
173 bool is_non_deferred_calling() const { return GetFlag(kNonDeferredCalling); }
175 void MarkAsSavesCallerDoubles() { SetFlag(kSavesCallerDoubles); }
177 bool saves_caller_doubles() const { return GetFlag(kSavesCallerDoubles); }
179 void MarkAsRequiresFrame() { SetFlag(kRequiresFrame); }
181 bool requires_frame() const { return GetFlag(kRequiresFrame); }
183 void MarkMustNotHaveEagerFrame() { SetFlag(kMustNotHaveEagerFrame); }
185 bool GetMustNotHaveEagerFrame() const {
186 return GetFlag(kMustNotHaveEagerFrame);
189 void MarkAsDebug() { SetFlag(kDebug); }
191 bool is_debug() const { return GetFlag(kDebug); }
193 void PrepareForSerializing() { SetFlag(kSerializing); }
195 bool will_serialize() const { return GetFlag(kSerializing); }
197 void MarkAsContextSpecializing() { SetFlag(kContextSpecializing); }
199 bool is_context_specializing() const { return GetFlag(kContextSpecializing); }
201 void MarkAsInliningEnabled() { SetFlag(kInliningEnabled); }
203 void MarkAsInliningDisabled() { SetFlag(kInliningEnabled, false); }
205 bool is_inlining_enabled() const { return GetFlag(kInliningEnabled); }
207 void MarkAsTypingEnabled() { SetFlag(kTypingEnabled); }
209 bool is_typing_enabled() const { return GetFlag(kTypingEnabled); }
211 bool IsCodePreAgingActive() const {
212 return FLAG_optimize_for_size && FLAG_age_code && !will_serialize() &&
216 void SetParseRestriction(ParseRestriction restriction) {
217 SetFlag(kParseRestriction, restriction != NO_PARSE_RESTRICTION);
220 ParseRestriction parse_restriction() const {
221 return GetFlag(kParseRestriction) ? ONLY_SINGLE_FUNCTION_LITERAL
222 : NO_PARSE_RESTRICTION;
225 void SetFunction(FunctionLiteral* literal) {
226 DCHECK(function_ == NULL);
229 void PrepareForCompilation(Scope* scope);
230 void SetGlobalScope(Scope* global_scope) {
231 DCHECK(global_scope_ == NULL);
232 global_scope_ = global_scope;
234 Handle<TypeFeedbackVector> feedback_vector() const {
235 return feedback_vector_;
237 void SetCode(Handle<Code> code) { code_ = code; }
238 void SetExtension(v8::Extension* extension) {
240 extension_ = extension;
242 void SetCachedData(ScriptData** cached_data,
243 ScriptCompiler::CompileOptions compile_options) {
244 compile_options_ = compile_options;
245 if (compile_options == ScriptCompiler::kNoCompileOptions) {
249 cached_data_ = cached_data;
252 void SetContext(Handle<Context> context) {
256 void MarkCompilingForDebugging() { SetFlag(kCompilingForDebugging); }
257 bool IsCompilingForDebugging() { return GetFlag(kCompilingForDebugging); }
258 void MarkNonOptimizable() {
259 SetMode(CompilationInfo::NONOPT);
262 bool ShouldTrapOnDeopt() const {
263 return (FLAG_trap_on_deopt && IsOptimizing()) ||
264 (FLAG_trap_on_stub_deopt && IsStub());
267 bool has_global_object() const {
268 return !closure().is_null() &&
269 (closure()->context()->global_object() != NULL);
272 GlobalObject* global_object() const {
273 return has_global_object() ? closure()->context()->global_object() : NULL;
276 // Accessors for the different compilation modes.
277 bool IsOptimizing() const { return mode_ == OPTIMIZE; }
278 bool IsOptimizable() const { return mode_ == BASE; }
279 bool IsStub() const { return mode_ == STUB; }
280 void SetOptimizing(BailoutId osr_ast_id, Handle<Code> unoptimized) {
281 DCHECK(!shared_info_.is_null());
283 osr_ast_id_ = osr_ast_id;
284 unoptimized_code_ = unoptimized;
285 optimization_id_ = isolate()->NextOptimizationId();
288 // Deoptimization support.
289 bool HasDeoptimizationSupport() const {
290 return GetFlag(kDeoptimizationSupport);
292 void EnableDeoptimizationSupport() {
293 DCHECK(IsOptimizable());
294 SetFlag(kDeoptimizationSupport);
297 // Determines whether or not to insert a self-optimization header.
298 bool ShouldSelfOptimize();
300 void set_deferred_handles(DeferredHandles* deferred_handles) {
301 DCHECK(deferred_handles_ == NULL);
302 deferred_handles_ = deferred_handles;
305 ZoneList<Handle<HeapObject> >* dependencies(
306 DependentCode::DependencyGroup group) {
307 if (dependencies_[group] == NULL) {
308 dependencies_[group] = new(zone_) ZoneList<Handle<HeapObject> >(2, zone_);
310 return dependencies_[group];
313 void CommitDependencies(Handle<Code> code);
315 void RollbackDependencies();
318 SaveHandle(&closure_);
319 SaveHandle(&shared_info_);
320 SaveHandle(&context_);
321 SaveHandle(&script_);
322 SaveHandle(&unoptimized_code_);
325 void AbortOptimization(BailoutReason reason) {
326 if (bailout_reason_ != kNoReason) bailout_reason_ = reason;
327 SetFlag(kDisableFutureOptimization);
330 void RetryOptimization(BailoutReason reason) {
331 if (bailout_reason_ != kNoReason) bailout_reason_ = reason;
334 BailoutReason bailout_reason() const { return bailout_reason_; }
336 int prologue_offset() const {
337 DCHECK_NE(Code::kPrologueOffsetNotSet, prologue_offset_);
338 return prologue_offset_;
341 void set_prologue_offset(int prologue_offset) {
342 DCHECK_EQ(Code::kPrologueOffsetNotSet, prologue_offset_);
343 prologue_offset_ = prologue_offset;
346 // Adds offset range [from, to) where fp register does not point
347 // to the current frame base. Used in CPU profiler to detect stack
348 // samples where top frame is not set up.
349 inline void AddNoFrameRange(int from, int to) {
350 if (no_frame_ranges_) no_frame_ranges_->Add(OffsetRange(from, to));
353 List<OffsetRange>* ReleaseNoFrameRanges() {
354 List<OffsetRange>* result = no_frame_ranges_;
355 no_frame_ranges_ = NULL;
359 Handle<Foreign> object_wrapper() {
360 if (object_wrapper_.is_null()) {
362 isolate()->factory()->NewForeign(reinterpret_cast<Address>(this));
364 return object_wrapper_;
367 void AbortDueToDependencyChange() {
368 DCHECK(!OptimizingCompilerThread::IsOptimizerThread(isolate()));
369 SetFlag(kAbortedDueToDependency);
372 bool HasAbortedDueToDependencyChange() const {
373 DCHECK(!OptimizingCompilerThread::IsOptimizerThread(isolate()));
374 return GetFlag(kAbortedDueToDependency);
377 bool HasSameOsrEntry(Handle<JSFunction> function, BailoutId osr_ast_id) {
378 return osr_ast_id_ == osr_ast_id && function.is_identical_to(closure_);
381 int optimization_id() const { return optimization_id_; }
383 AstValueFactory* ast_value_factory() const { return ast_value_factory_; }
384 void SetAstValueFactory(AstValueFactory* ast_value_factory,
386 ast_value_factory_ = ast_value_factory;
387 ast_value_factory_owned_ = owned;
390 AstNode::IdGen* ast_node_id_gen() { return &ast_node_id_gen_; }
393 CompilationInfo(Handle<Script> script,
395 CompilationInfo(Handle<SharedFunctionInfo> shared_info,
397 CompilationInfo(HydrogenCodeStub* stub,
400 CompilationInfo(ScriptCompiler::ExternalSourceStream* source_stream,
401 ScriptCompiler::StreamedSource::Encoding encoding,
402 Isolate* isolate, Zone* zone);
409 // BASE is generated by the full codegen, optionally prepared for bailouts.
410 // OPTIMIZE is optimized code generated by the Hydrogen-based backend.
411 // NONOPT is generated by the full codegen and is not prepared for
412 // recompilation/bailouts. These functions are never recompiled.
420 void Initialize(Isolate* isolate, Mode mode, Zone* zone);
422 void SetMode(Mode mode) {
426 void SetFlag(Flag flag) { flags_ |= flag; }
428 void SetFlag(Flag flag, bool value) {
429 flags_ = value ? flags_ | flag : flags_ & ~flag;
432 bool GetFlag(Flag flag) const { return (flags_ & flag) != 0; }
436 // Fields filled in by the compilation pipeline.
437 // AST filled in by the parser.
438 FunctionLiteral* function_;
439 // The scope of the function literal as a convenience. Set to indicate
440 // that scopes have been analyzed.
442 // The global scope provided as a convenience.
443 Scope* global_scope_;
444 // For compiled stubs, the stub object
445 HydrogenCodeStub* code_stub_;
446 // The compiled code.
449 // Possible initial inputs to the compilation process.
450 Handle<JSFunction> closure_;
451 Handle<SharedFunctionInfo> shared_info_;
452 Handle<Script> script_;
453 ScriptCompiler::ExternalSourceStream* source_stream_; // Not owned.
454 ScriptCompiler::StreamedSource::Encoding source_stream_encoding_;
456 // Fields possibly needed for eager compilation, NULL by default.
457 v8::Extension* extension_;
458 ScriptData** cached_data_;
459 ScriptCompiler::CompileOptions compile_options_;
461 // The context of the caller for eval code, and the global context for a
462 // global script. Will be a null handle otherwise.
463 Handle<Context> context_;
465 // Used by codegen, ultimately kept rooted by the SharedFunctionInfo.
466 Handle<TypeFeedbackVector> feedback_vector_;
468 // Compilation mode flag and whether deoptimization is allowed.
470 BailoutId osr_ast_id_;
471 // The unoptimized code we patched for OSR may not be the shared code
472 // afterwards, since we may need to compile it again to include deoptimization
473 // data. Keep track which code we patched.
474 Handle<Code> unoptimized_code_;
476 // The zone from which the compilation pipeline working on this
477 // CompilationInfo allocates.
480 DeferredHandles* deferred_handles_;
482 ZoneList<Handle<HeapObject> >* dependencies_[DependentCode::kGroupCount];
485 void SaveHandle(Handle<T> *object) {
486 if (!object->is_null()) {
487 Handle<T> handle(*(*object));
492 BailoutReason bailout_reason_;
494 int prologue_offset_;
496 List<OffsetRange>* no_frame_ranges_;
498 // A copy of shared_info()->opt_count() to avoid handle deref
499 // during graph optimization.
502 // Number of parameters used for compilation of stubs that require arguments.
503 int parameter_count_;
505 Handle<Foreign> object_wrapper_;
507 int optimization_id_;
509 AstValueFactory* ast_value_factory_;
510 bool ast_value_factory_owned_;
511 AstNode::IdGen ast_node_id_gen_;
513 DISALLOW_COPY_AND_ASSIGN(CompilationInfo);
517 // Exactly like a CompilationInfo, except also creates and enters a
518 // Zone on construction and deallocates it on exit.
519 class CompilationInfoWithZone: public CompilationInfo {
521 explicit CompilationInfoWithZone(Handle<Script> script)
522 : CompilationInfo(script, &zone_),
523 zone_(script->GetIsolate()) {}
524 explicit CompilationInfoWithZone(Handle<SharedFunctionInfo> shared_info)
525 : CompilationInfo(shared_info, &zone_),
526 zone_(shared_info->GetIsolate()) {}
527 explicit CompilationInfoWithZone(Handle<JSFunction> closure)
528 : CompilationInfo(closure, &zone_),
529 zone_(closure->GetIsolate()) {}
530 CompilationInfoWithZone(HydrogenCodeStub* stub, Isolate* isolate)
531 : CompilationInfo(stub, isolate, &zone_),
533 CompilationInfoWithZone(ScriptCompiler::ExternalSourceStream* stream,
534 ScriptCompiler::StreamedSource::Encoding encoding,
536 : CompilationInfo(stream, encoding, isolate, &zone_), zone_(isolate) {}
538 // Virtual destructor because a CompilationInfoWithZone has to exit the
539 // zone scope and get rid of dependent maps even when the destructor is
540 // called when cast as a CompilationInfo.
541 virtual ~CompilationInfoWithZone() {
542 RollbackDependencies();
550 // A wrapper around a CompilationInfo that detaches the Handles from
551 // the underlying DeferredHandleScope and stores them in info_ on
553 class CompilationHandleScope BASE_EMBEDDED {
555 explicit CompilationHandleScope(CompilationInfo* info)
556 : deferred_(info->isolate()), info_(info) {}
557 ~CompilationHandleScope() {
558 info_->set_deferred_handles(deferred_.Detach());
562 DeferredHandleScope deferred_;
563 CompilationInfo* info_;
568 class HOptimizedGraphBuilder;
571 // A helper class that calls the three compilation phases in
572 // Crankshaft and keeps track of its state. The three phases
573 // CreateGraph, OptimizeGraph and GenerateAndInstallCode can either
574 // fail, bail-out to the full code generator or succeed. Apart from
575 // their return value, the status of the phase last run can be checked
576 // using last_status().
577 class OptimizedCompileJob: public ZoneObject {
579 explicit OptimizedCompileJob(CompilationInfo* info)
581 graph_builder_(NULL),
584 last_status_(FAILED),
585 awaiting_install_(false) { }
588 FAILED, BAILED_OUT, SUCCEEDED
591 MUST_USE_RESULT Status CreateGraph();
592 MUST_USE_RESULT Status OptimizeGraph();
593 MUST_USE_RESULT Status GenerateCode();
595 Status last_status() const { return last_status_; }
596 CompilationInfo* info() const { return info_; }
597 Isolate* isolate() const { return info()->isolate(); }
599 Status RetryOptimization(BailoutReason reason) {
600 info_->RetryOptimization(reason);
601 return SetLastStatus(BAILED_OUT);
604 Status AbortOptimization(BailoutReason reason) {
605 info_->AbortOptimization(reason);
606 return SetLastStatus(BAILED_OUT);
609 void WaitForInstall() {
610 DCHECK(info_->is_osr());
611 awaiting_install_ = true;
614 bool IsWaitingForInstall() { return awaiting_install_; }
617 CompilationInfo* info_;
618 HOptimizedGraphBuilder* graph_builder_;
621 base::TimeDelta time_taken_to_create_graph_;
622 base::TimeDelta time_taken_to_optimize_;
623 base::TimeDelta time_taken_to_codegen_;
625 bool awaiting_install_;
627 MUST_USE_RESULT Status SetLastStatus(Status status) {
628 last_status_ = status;
631 void RecordOptimizationStats();
634 Timer(OptimizedCompileJob* job, base::TimeDelta* location)
635 : job_(job), location_(location) {
636 DCHECK(location_ != NULL);
641 *location_ += timer_.Elapsed();
644 OptimizedCompileJob* job_;
645 base::ElapsedTimer timer_;
646 base::TimeDelta* location_;
653 // General strategy: Source code is translated into an anonymous function w/o
654 // parameters which then can be executed. If the source code contains other
655 // functions, they will be compiled and allocated as part of the compilation
656 // of the source code.
658 // Please note this interface returns shared function infos. This means you
659 // need to call Factory::NewFunctionFromSharedFunctionInfo before you have a
660 // real function with a context.
662 class Compiler : public AllStatic {
664 MUST_USE_RESULT static MaybeHandle<Code> GetUnoptimizedCode(
665 Handle<JSFunction> function);
666 MUST_USE_RESULT static MaybeHandle<Code> GetLazyCode(
667 Handle<JSFunction> function);
668 MUST_USE_RESULT static MaybeHandle<Code> GetUnoptimizedCode(
669 Handle<SharedFunctionInfo> shared);
670 MUST_USE_RESULT static MaybeHandle<Code> GetDebugCode(
671 Handle<JSFunction> function);
673 static bool EnsureCompiled(Handle<JSFunction> function,
674 ClearExceptionFlag flag);
676 static bool EnsureDeoptimizationSupport(CompilationInfo* info);
678 static void CompileForLiveEdit(Handle<Script> script);
680 // Compile a String source within a context for eval.
681 MUST_USE_RESULT static MaybeHandle<JSFunction> GetFunctionFromEval(
682 Handle<String> source,
683 Handle<Context> context,
684 StrictMode strict_mode,
685 ParseRestriction restriction,
688 // Compile a String source within a context.
689 static Handle<SharedFunctionInfo> CompileScript(
690 Handle<String> source, Handle<Object> script_name, int line_offset,
691 int column_offset, bool is_shared_cross_origin, Handle<Context> context,
692 v8::Extension* extension, ScriptData** cached_data,
693 ScriptCompiler::CompileOptions compile_options,
694 NativesFlag is_natives_code);
696 static Handle<SharedFunctionInfo> CompileStreamedScript(CompilationInfo* info,
699 // Create a shared function info object (the code may be lazily compiled).
700 static Handle<SharedFunctionInfo> BuildFunctionInfo(FunctionLiteral* node,
701 Handle<Script> script,
702 CompilationInfo* outer);
704 enum ConcurrencyMode { NOT_CONCURRENT, CONCURRENT };
706 // Generate and return optimized code or start a concurrent optimization job.
707 // In the latter case, return the InOptimizationQueue builtin. On failure,
708 // return the empty handle.
709 MUST_USE_RESULT static MaybeHandle<Code> GetOptimizedCode(
710 Handle<JSFunction> function,
711 Handle<Code> current_code,
712 ConcurrencyMode mode,
713 BailoutId osr_ast_id = BailoutId::None());
715 // Generate and return code from previously queued optimization job.
716 // On failure, return the empty handle.
717 static Handle<Code> GetConcurrentlyOptimizedCode(OptimizedCompileJob* job);
719 static bool DebuggerWantsEagerCompilation(
720 CompilationInfo* info, bool allow_lazy_without_ctx = false);
724 class CompilationPhase BASE_EMBEDDED {
726 CompilationPhase(const char* name, CompilationInfo* info);
730 bool ShouldProduceTraceOutput() const;
732 const char* name() const { return name_; }
733 CompilationInfo* info() const { return info_; }
734 Isolate* isolate() const { return info()->isolate(); }
735 Zone* zone() { return &zone_; }
739 CompilationInfo* info_;
741 unsigned info_zone_start_allocation_size_;
742 base::ElapsedTimer timer_;
744 DISALLOW_COPY_AND_ASSIGN(CompilationPhase);
747 } } // namespace v8::internal
749 #endif // V8_COMPILER_H_