Index: src/compiler.cc |
diff --git a/src/compiler.cc b/src/compiler.cc |
index 750d822a5177df7083fde2648d8e34f32c4baae6..0b103f0e287a419782bda9ee7f0268addcf3f6f3 100644 |
--- a/src/compiler.cc |
+++ b/src/compiler.cc |
@@ -18,6 +18,7 @@ |
#include "src/debug/debug.h" |
#include "src/debug/liveedit.h" |
#include "src/deoptimizer.h" |
+#include "src/frames-inl.h" |
#include "src/full-codegen/full-codegen.h" |
#include "src/interpreter/interpreter.h" |
#include "src/isolate-inl.h" |
@@ -590,7 +591,6 @@ MUST_USE_RESULT MaybeHandle<Code> GetUnoptimizedCode(CompilationInfo* info) { |
// Compile either unoptimized code or bytecode for the interpreter. |
if (!CompileUnoptimizedCode(info)) return MaybeHandle<Code>(); |
- RecordFunctionCompilation(Logger::LAZY_COMPILE_TAG, info); |
// Update the shared function info with the scope info. |
InstallSharedScopeInfo(info, shared); |
@@ -598,6 +598,9 @@ MUST_USE_RESULT MaybeHandle<Code> GetUnoptimizedCode(CompilationInfo* info) { |
// Install compilation result on the shared function info |
InstallSharedCompilationResult(info, shared); |
+ // Record the function compilation event. |
+ RecordFunctionCompilation(Logger::LAZY_COMPILE_TAG, info); |
+ |
return info->code(); |
} |
@@ -805,8 +808,7 @@ MaybeHandle<Code> GetOptimizedCode(Handle<JSFunction> function, |
return cached_code; |
} |
- DCHECK(AllowCompilation::IsAllowed(isolate)); |
- |
+ // Reset profiler ticks, function is no longer considered hot. |
if (shared->is_compiled()) { |
shared->code()->set_profiler_ticks(0); |
} |
@@ -860,6 +862,103 @@ MaybeHandle<Code> GetOptimizedCode(Handle<JSFunction> function, |
return MaybeHandle<Code>(); |
} |
+class InterpreterActivationsFinder : public ThreadVisitor { |
+ public: |
+ SharedFunctionInfo* shared_; |
+ bool has_activations_; |
+ |
+ explicit InterpreterActivationsFinder(SharedFunctionInfo* shared) |
+ : shared_(shared), has_activations_(false) {} |
+ |
+ void VisitThread(Isolate* isolate, ThreadLocalTop* top) { |
+ JavaScriptFrameIterator it(isolate, top); |
+ for (; !it.done() && !has_activations_; it.Advance()) { |
+ JavaScriptFrame* frame = it.frame(); |
+ if (!frame->is_interpreted()) continue; |
+ if (frame->function()->shared() == shared_) has_activations_ = true; |
+ } |
+ } |
+}; |
+ |
+bool HasInterpreterActivations(Isolate* isolate, SharedFunctionInfo* shared) { |
+ InterpreterActivationsFinder activations_finder(shared); |
+ activations_finder.VisitThread(isolate, isolate->thread_local_top()); |
+ isolate->thread_manager()->IterateArchivedThreads(&activations_finder); |
+ return activations_finder.has_activations_; |
+} |
+ |
+MaybeHandle<Code> GetBaselineCode(Handle<JSFunction> function) { |
+ Isolate* isolate = function->GetIsolate(); |
+ VMState<COMPILER> state(isolate); |
+ PostponeInterruptsScope postpone(isolate); |
+ CompilationInfoWithZone info(function); |
+ |
+ // Reset profiler ticks, function is no longer considered hot. |
+ if (function->shared()->HasBytecodeArray()) { |
+ function->shared()->set_profiler_ticks(0); |
+ } |
+ |
+ // We do not switch to baseline code when the debugger might have created a |
+ // copy of the bytecode with break slots to be able to set break points. |
+ if (function->shared()->HasDebugInfo()) { |
+ return MaybeHandle<Code>(); |
+ } |
+ |
+ // TODO(4280): For now we do not switch generators to baseline code because |
+ // there might be suspended activations stored in generator objects on the |
+ // heap. We could eventually go directly to TurboFan in this case. |
+ if (function->shared()->is_generator()) { |
+ return MaybeHandle<Code>(); |
+ } |
+ |
+ // TODO(4280): For now we disable switching to baseline code in the presence |
+ // of interpreter activations of the given function. The reasons are: |
+ // 1) The debugger assumes each function is either full-code or bytecode. |
+ // 2) The underlying bytecode is cleared below, breaking stack unwinding. |
+ if (HasInterpreterActivations(isolate, function->shared())) { |
+ if (FLAG_trace_opt) { |
+ OFStream os(stdout); |
+ os << "[unable to switch " << Brief(*function) << " due to activations]" |
+ << std::endl; |
+ } |
+ return MaybeHandle<Code>(); |
+ } |
+ |
+ if (FLAG_trace_opt) { |
+ OFStream os(stdout); |
+ os << "[switching method " << Brief(*function) << " to baseline code]" |
+ << std::endl; |
+ } |
+ |
+ // Parse and update CompilationInfo with the results. |
+ if (!Parser::ParseStatic(info.parse_info())) return MaybeHandle<Code>(); |
+ Handle<SharedFunctionInfo> shared = info.shared_info(); |
+ DCHECK_EQ(shared->language_mode(), info.literal()->language_mode()); |
+ |
+ // Compile baseline code using the full code generator. |
+ if (!Compiler::Analyze(info.parse_info()) || |
+ !FullCodeGenerator::MakeCode(&info)) { |
+ if (!isolate->has_pending_exception()) isolate->StackOverflow(); |
+ return MaybeHandle<Code>(); |
+ } |
+ |
+ // TODO(4280): For now we play it safe and remove the bytecode array when we |
+ // switch to baseline code. We might consider keeping around the bytecode so |
+ // that it can be used as the "source of truth" eventually. |
+ shared->ClearBytecodeArray(); |
+ |
+ // Update the shared function info with the scope info. |
+ InstallSharedScopeInfo(&info, shared); |
+ |
+ // Install compilation result on the shared function info |
+ InstallSharedCompilationResult(&info, shared); |
+ |
+ // Record the function compilation event. |
+ RecordFunctionCompilation(Logger::LAZY_COMPILE_TAG, &info); |
+ |
+ return info.code(); |
+} |
+ |
MaybeHandle<Code> GetLazyCode(Handle<JSFunction> function) { |
Isolate* isolate = function->GetIsolate(); |
DCHECK(!isolate->has_pending_exception()); |
@@ -1089,6 +1188,29 @@ bool Compiler::Compile(Handle<JSFunction> function, ClearExceptionFlag flag) { |
return true; |
} |
+bool Compiler::CompileBaseline(Handle<JSFunction> function) { |
+ Isolate* isolate = function->GetIsolate(); |
+ DCHECK(AllowCompilation::IsAllowed(isolate)); |
+ |
+ // Start a compilation. |
+ Handle<Code> code; |
+ if (!GetBaselineCode(function).ToHandle(&code)) { |
+ // Baseline generation failed, get unoptimized code. |
+ DCHECK(function->shared()->is_compiled()); |
+ code = handle(function->shared()->code()); |
+ isolate->clear_pending_exception(); |
+ } |
+ |
+ // Install code on closure. |
+ function->ReplaceCode(*code); |
+ |
+ // Check postconditions on success. |
+ DCHECK(!isolate->has_pending_exception()); |
+ DCHECK(function->shared()->is_compiled()); |
+ DCHECK(function->is_compiled()); |
+ return true; |
+} |
+ |
bool Compiler::CompileOptimized(Handle<JSFunction> function, |
ConcurrencyMode mode) { |
if (function->IsOptimized()) return true; |