Commit 3fc0224c authored by mstarzinger's avatar mstarzinger Committed by Commit bot

[compiler] Add baseline tier to compilation pipeline.

This adds a baseline tier to the compilation pipeline. Currently this
tier is used to model a path from the interpreter to optimized code via
full-codegen code (to ensure sufficient type feedback). Switching from
the unoptimized tier to the baseline tier is limited to happen only when
there are no activations of the given function on the stack.

R=rmcilroy@chromium.org,bmeurer@chromium.org

Review URL: https://codereview.chromium.org/1903273004

Cr-Commit-Position: refs/heads/master@{#35757}
parent 692eec39
......@@ -1401,6 +1401,9 @@ void Builtins::Generate_CompileLazy(MacroAssembler* masm) {
GenerateTailCallToReturnedCode(masm, Runtime::kCompileLazy);
}
void Builtins::Generate_CompileBaseline(MacroAssembler* masm) {
GenerateTailCallToReturnedCode(masm, Runtime::kCompileBaseline);
}
void Builtins::Generate_CompileOptimized(MacroAssembler* masm) {
GenerateTailCallToReturnedCode(masm,
......
......@@ -1324,6 +1324,9 @@ void Builtins::Generate_CompileLazy(MacroAssembler* masm) {
GenerateTailCallToReturnedCode(masm, Runtime::kCompileLazy);
}
void Builtins::Generate_CompileBaseline(MacroAssembler* masm) {
GenerateTailCallToReturnedCode(masm, Runtime::kCompileBaseline);
}
void Builtins::Generate_CompileOptimized(MacroAssembler* masm) {
GenerateTailCallToReturnedCode(masm,
......
......@@ -215,6 +215,7 @@ inline bool operator&(BuiltinExtraArguments lhs, BuiltinExtraArguments rhs) {
V(JSConstructEntryTrampoline, BUILTIN, UNINITIALIZED, kNoExtraICState) \
V(ResumeGeneratorTrampoline, BUILTIN, UNINITIALIZED, kNoExtraICState) \
V(CompileLazy, BUILTIN, UNINITIALIZED, kNoExtraICState) \
V(CompileBaseline, BUILTIN, UNINITIALIZED, kNoExtraICState) \
V(CompileOptimized, BUILTIN, UNINITIALIZED, kNoExtraICState) \
V(CompileOptimizedConcurrent, BUILTIN, UNINITIALIZED, kNoExtraICState) \
V(NotifyDeoptimized, BUILTIN, UNINITIALIZED, kNoExtraICState) \
......@@ -438,6 +439,7 @@ class Builtins {
BuiltinExtraArguments extra_args);
static void Generate_ConstructedNonConstructable(MacroAssembler* masm);
static void Generate_CompileLazy(MacroAssembler* masm);
static void Generate_CompileBaseline(MacroAssembler* masm);
static void Generate_InOptimizationQueue(MacroAssembler* masm);
static void Generate_CompileOptimized(MacroAssembler* masm);
static void Generate_CompileOptimizedConcurrent(MacroAssembler* masm);
......
......@@ -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;
......
......@@ -44,6 +44,7 @@ class Compiler : public AllStatic {
// given function holds (except for live-edit, which compiles the world).
static bool Compile(Handle<JSFunction> function, ClearExceptionFlag flag);
static bool CompileBaseline(Handle<JSFunction> function);
static bool CompileOptimized(Handle<JSFunction> function, ConcurrencyMode);
static bool CompileDebugCode(Handle<JSFunction> function);
static bool CompileDebugCode(Handle<SharedFunctionInfo> shared);
......
......@@ -997,6 +997,9 @@ void Builtins::Generate_CompileLazy(MacroAssembler* masm) {
GenerateTailCallToReturnedCode(masm, Runtime::kCompileLazy);
}
void Builtins::Generate_CompileBaseline(MacroAssembler* masm) {
GenerateTailCallToReturnedCode(masm, Runtime::kCompileBaseline);
}
void Builtins::Generate_CompileOptimized(MacroAssembler* masm) {
GenerateTailCallToReturnedCode(masm,
......
......@@ -1393,6 +1393,9 @@ void Builtins::Generate_CompileLazy(MacroAssembler* masm) {
GenerateTailCallToReturnedCode(masm, Runtime::kCompileLazy);
}
void Builtins::Generate_CompileBaseline(MacroAssembler* masm) {
GenerateTailCallToReturnedCode(masm, Runtime::kCompileBaseline);
}
void Builtins::Generate_CompileOptimized(MacroAssembler* masm) {
GenerateTailCallToReturnedCode(masm,
......
......@@ -1382,6 +1382,9 @@ void Builtins::Generate_CompileLazy(MacroAssembler* masm) {
GenerateTailCallToReturnedCode(masm, Runtime::kCompileLazy);
}
void Builtins::Generate_CompileBaseline(MacroAssembler* masm) {
GenerateTailCallToReturnedCode(masm, Runtime::kCompileBaseline);
}
void Builtins::Generate_CompileOptimized(MacroAssembler* masm) {
GenerateTailCallToReturnedCode(masm,
......
......@@ -5861,6 +5861,7 @@ bool SharedFunctionInfo::is_compiled() {
Builtins* builtins = GetIsolate()->builtins();
DCHECK(code() != builtins->builtin(Builtins::kCompileOptimizedConcurrent));
DCHECK(code() != builtins->builtin(Builtins::kCompileOptimized));
DCHECK(code() != builtins->builtin(Builtins::kCompileBaseline));
return code() != builtins->builtin(Builtins::kCompileLazy);
}
......@@ -6056,6 +6057,10 @@ bool JSFunction::IsOptimized() {
return code()->kind() == Code::OPTIMIZED_FUNCTION;
}
bool JSFunction::IsMarkedForBaseline() {
return code() ==
GetIsolate()->builtins()->builtin(Builtins::kCompileBaseline);
}
bool JSFunction::IsMarkedForOptimization() {
return code() == GetIsolate()->builtins()->builtin(
......@@ -6221,6 +6226,7 @@ Object* JSFunction::prototype() {
bool JSFunction::is_compiled() {
Builtins* builtins = GetIsolate()->builtins();
return code() != builtins->builtin(Builtins::kCompileLazy) &&
code() != builtins->builtin(Builtins::kCompileBaseline) &&
code() != builtins->builtin(Builtins::kCompileOptimized) &&
code() != builtins->builtin(Builtins::kCompileOptimizedConcurrent);
}
......
......@@ -11769,6 +11769,12 @@ bool JSFunction::Inlines(SharedFunctionInfo* candidate) {
return false;
}
void JSFunction::MarkForBaseline() {
Isolate* isolate = GetIsolate();
set_code_no_write_barrier(
isolate->builtins()->builtin(Builtins::kCompileBaseline));
// No write barrier required, since the builtin is part of the root set.
}
void JSFunction::MarkForOptimization() {
Isolate* isolate = GetIsolate();
......
......@@ -7478,13 +7478,14 @@ class JSFunction: public JSObject {
// Tells whether or not this function has been optimized.
inline bool IsOptimized();
// Mark this function for lazy recompilation. The function will be
// recompiled the next time it is executed.
// Mark this function for lazy recompilation. The function will be recompiled
// the next time it is executed.
void MarkForBaseline();
void MarkForOptimization();
void AttemptConcurrentOptimization();
// Tells whether or not the function is already marked for lazy
// recompilation.
// Tells whether or not the function is already marked for lazy recompilation.
inline bool IsMarkedForBaseline();
inline bool IsMarkedForOptimization();
inline bool IsMarkedForConcurrentOptimization();
......
......@@ -1398,6 +1398,9 @@ void Builtins::Generate_CompileLazy(MacroAssembler* masm) {
GenerateTailCallToReturnedCode(masm, Runtime::kCompileLazy);
}
void Builtins::Generate_CompileBaseline(MacroAssembler* masm) {
GenerateTailCallToReturnedCode(masm, Runtime::kCompileBaseline);
}
void Builtins::Generate_CompileOptimized(MacroAssembler* masm) {
GenerateTailCallToReturnedCode(masm,
......
......@@ -106,7 +106,11 @@ void RuntimeProfiler::Optimize(JSFunction* function, const char* reason) {
PrintF("]\n");
}
function->AttemptConcurrentOptimization();
if (function->shared()->HasBytecodeArray()) {
function->MarkForBaseline();
} else {
function->AttemptConcurrentOptimization();
}
}
......@@ -247,7 +251,8 @@ void RuntimeProfiler::MaybeOptimizeIgnition(JSFunction* function,
// TODO(rmcilroy): Consider whether we should optimize small functions when
// they are first seen on the stack (e.g., kMaxSizeEarlyOpt).
if (!frame_optimized && (function->IsMarkedForOptimization() ||
if (!frame_optimized && (function->IsMarkedForBaseline() ||
function->IsMarkedForOptimization() ||
function->IsMarkedForConcurrentOptimization() ||
function->IsOptimized())) {
// TODO(rmcilroy): Support OSR in these cases.
......@@ -320,7 +325,7 @@ void RuntimeProfiler::MarkCandidatesForOptimization() {
}
}
if (FLAG_ignition) {
if (frame->is_interpreted()) {
MaybeOptimizeIgnition(function, frame->is_optimized());
} else {
MaybeOptimizeFullCodegen(function, frame_count, frame->is_optimized());
......
......@@ -8,16 +8,10 @@
#include "src/allocation.h"
namespace v8 {
namespace base {
class Semaphore;
}
namespace internal {
class Isolate;
class JSFunction;
class Object;
class RuntimeProfiler {
public:
......
......@@ -19,7 +19,7 @@ namespace internal {
RUNTIME_FUNCTION(Runtime_CompileLazy) {
HandleScope scope(isolate);
DCHECK(args.length() == 1);
DCHECK_EQ(1, args.length());
CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
#ifdef DEBUG
......@@ -39,10 +39,22 @@ RUNTIME_FUNCTION(Runtime_CompileLazy) {
return function->code();
}
RUNTIME_FUNCTION(Runtime_CompileBaseline) {
HandleScope scope(isolate);
DCHECK_EQ(1, args.length());
CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
StackLimitCheck check(isolate);
if (check.JsHasOverflowed(1 * KB)) return isolate->StackOverflow();
if (!Compiler::CompileBaseline(function)) {
return isolate->heap()->exception();
}
DCHECK(function->is_compiled());
return function->code();
}
RUNTIME_FUNCTION(Runtime_CompileOptimized_Concurrent) {
HandleScope scope(isolate);
DCHECK(args.length() == 1);
DCHECK_EQ(1, args.length());
CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
StackLimitCheck check(isolate);
if (check.JsHasOverflowed(1 * KB)) return isolate->StackOverflow();
......@@ -56,7 +68,7 @@ RUNTIME_FUNCTION(Runtime_CompileOptimized_Concurrent) {
RUNTIME_FUNCTION(Runtime_CompileOptimized_NotConcurrent) {
HandleScope scope(isolate);
DCHECK(args.length() == 1);
DCHECK_EQ(1, args.length());
CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
StackLimitCheck check(isolate);
if (check.JsHasOverflowed(1 * KB)) return isolate->StackOverflow();
......
......@@ -122,6 +122,7 @@ namespace internal {
#define FOR_EACH_INTRINSIC_COMPILER(F) \
F(CompileLazy, 1, 1) \
F(CompileBaseline, 1, 1) \
F(CompileOptimized_Concurrent, 1, 1) \
F(CompileOptimized_NotConcurrent, 1, 1) \
F(NotifyStubFailure, 0, 1) \
......
......@@ -1362,6 +1362,10 @@ void Builtins::Generate_CompileLazy(MacroAssembler* masm) {
GenerateTailCallToReturnedCode(masm, Runtime::kCompileLazy);
}
void Builtins::Generate_CompileBaseline(MacroAssembler* masm) {
GenerateTailCallToReturnedCode(masm, Runtime::kCompileBaseline);
}
void Builtins::Generate_CompileOptimized(MacroAssembler* masm) {
GenerateTailCallToReturnedCode(masm,
Runtime::kCompileOptimized_NotConcurrent);
......
......@@ -1048,6 +1048,9 @@ void Builtins::Generate_CompileLazy(MacroAssembler* masm) {
GenerateTailCallToReturnedCode(masm, Runtime::kCompileLazy);
}
void Builtins::Generate_CompileBaseline(MacroAssembler* masm) {
GenerateTailCallToReturnedCode(masm, Runtime::kCompileBaseline);
}
void Builtins::Generate_CompileOptimized(MacroAssembler* masm) {
GenerateTailCallToReturnedCode(masm,
......
......@@ -998,6 +998,9 @@ void Builtins::Generate_CompileLazy(MacroAssembler* masm) {
GenerateTailCallToReturnedCode(masm, Runtime::kCompileLazy);
}
void Builtins::Generate_CompileBaseline(MacroAssembler* masm) {
GenerateTailCallToReturnedCode(masm, Runtime::kCompileBaseline);
}
void Builtins::Generate_CompileOptimized(MacroAssembler* masm) {
GenerateTailCallToReturnedCode(masm,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment