Chromium Code Reviews| Index: src/compiler.cc |
| diff --git a/src/compiler.cc b/src/compiler.cc |
| index 750d822a5177df7083fde2648d8e34f32c4baae6..33bd1aa455bf9fe54ac16265f011b15dd9eb9066 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(); it.Advance()) { |
|
rmcilroy
2016/04/22 10:02:57
Also done when "has_activations_" ?
Michael Starzinger
2016/04/22 10:47:45
Done.
|
| + 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); |
| + } |
| + |
| + // TODO(4280): For now we do not switch to baseline code when the debugger |
| + // might have created a copy of the bytecode with break slots. |
|
rmcilroy
2016/04/22 10:02:57
Is this a TODO - I though we were planning to alwa
Michael Starzinger
2016/04/22 10:47:45
Done. I don't have a concrete answer on whether we
|
| + 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 unoptimized code using the full code generator. |
|
rmcilroy
2016/04/22 10:02:57
/s/unoptimzed/baseline
Michael Starzinger
2016/04/22 10:47:45
Done.
|
| + 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; |