Commit ae8f2820 authored by mvstanton's avatar mvstanton Committed by Commit bot

This is a workaround for the fact that %SetCode can "lose" the script for a js...

This is a workaround for the fact that %SetCode can "lose" the script for a js native. If the js native is re-initialized (for a Realm or something), then the source SharedFunctionInfo won't have a script anymore. Nonetheless, we may want to optimize the function. If we've compiled bytecode, then we can compile optimized code without a script.

Here, we carve out a special exception for this case, so that we can turn on the --mark-shared-functions-for-tier-up.

BUG=v8:5946
R=leszeks@chromium.org

Review-Url: https://codereview.chromium.org/2684033007
Cr-Original-Commit-Position: refs/heads/master@{#43240}
Committed: https://chromium.googlesource.com/v8/v8/+/4123a3dd790495c40cf839990318a85c146e057d
Review-Url: https://codereview.chromium.org/2684033007
Cr-Commit-Position: refs/heads/master@{#43252}
parent 4b0edcf7
......@@ -348,10 +348,8 @@ bool UseTurboFan(Handle<SharedFunctionInfo> shared) {
passes_turbo_filter;
}
bool ShouldUseIgnition(CompilationInfo* info) {
DCHECK(info->has_shared_info());
Handle<SharedFunctionInfo> shared = info->shared_info();
bool ShouldUseIgnition(Handle<SharedFunctionInfo> shared,
bool marked_as_debug) {
// Code which can't be supported by the old pipeline should use Ignition.
if (shared->must_use_ignition_turbo()) return true;
......@@ -370,7 +368,7 @@ bool ShouldUseIgnition(CompilationInfo* info) {
// When requesting debug code as a replacement for existing code, we provide
// the same kind as the existing code (to prevent implicit tier-change).
if (info->is_debug() && shared->is_compiled()) {
if (marked_as_debug && shared->is_compiled()) {
return !shared->HasBaselineCode();
}
......@@ -381,6 +379,11 @@ bool ShouldUseIgnition(CompilationInfo* info) {
return FLAG_ignition;
}
bool ShouldUseIgnition(CompilationInfo* info) {
DCHECK(info->has_shared_info());
return ShouldUseIgnition(info->shared_info(), info->is_debug());
}
bool UseAsmWasm(DeclarationScope* scope, Handle<SharedFunctionInfo> shared_info,
bool is_debug) {
return FLAG_validate_asm && scope->asm_module() &&
......@@ -845,8 +848,12 @@ MaybeHandle<Code> GetOptimizedCode(Handle<JSFunction> function,
DCHECK(!isolate->has_pending_exception());
PostponeInterruptsScope postpone(isolate);
bool use_turbofan = UseTurboFan(shared) || ignition_osr;
bool has_script = shared->script()->IsScript();
// BUG(5946): This DCHECK is necessary to make certain that we won't tolerate
// the lack of a script without bytecode.
DCHECK_IMPLIES(!has_script, ShouldUseIgnition(shared, false));
std::unique_ptr<CompilationJob> job(
use_turbofan ? compiler::Pipeline::NewCompilationJob(function)
use_turbofan ? compiler::Pipeline::NewCompilationJob(function, has_script)
: new HCompilationJob(function));
CompilationInfo* info = job->info();
ParseInfo* parse_info = info->parse_info();
......@@ -1069,17 +1076,10 @@ MaybeHandle<Code> GetLazyCode(Handle<JSFunction> function) {
switch (Compiler::NextCompilationTier(*function)) {
case Compiler::BASELINE: {
if (FLAG_trace_opt) {
PrintF("[recompiling function ");
function->ShortPrint();
PrintF(
" to baseline eagerly (shared function marked for tier up)]\n");
}
Handle<Code> code;
if (GetBaselineCode(function).ToHandle(&code)) {
return code;
}
// We don't try to handle baseline here because GetBaselineCode()
// doesn't handle top-level code. We aren't supporting
// the hybrid pipeline going forward (where Ignition is a first
// tier followed by full-code).
break;
}
case Compiler::OPTIMIZED: {
......
......@@ -545,13 +545,13 @@ PipelineStatistics* CreatePipelineStatistics(CompilationInfo* info,
class PipelineCompilationJob final : public CompilationJob {
public:
PipelineCompilationJob(Isolate* isolate, Handle<JSFunction> function)
PipelineCompilationJob(ParseInfo* parse_info, Handle<JSFunction> function)
// Note that the CompilationInfo is not initialized at the time we pass it
// to the CompilationJob constructor, but it is not dereferenced there.
: CompilationJob(isolate, &info_, "TurboFan"),
parse_info_(handle(function->shared())),
zone_stats_(isolate->allocator()),
info_(parse_info_.zone(), &parse_info_, function),
: CompilationJob(parse_info->isolate(), &info_, "TurboFan"),
parse_info_(parse_info),
zone_stats_(parse_info->isolate()->allocator()),
info_(parse_info_.get()->zone(), parse_info_.get(), function),
pipeline_statistics_(CreatePipelineStatistics(info(), &zone_stats_)),
data_(&zone_stats_, info(), pipeline_statistics_.get()),
pipeline_(&data_),
......@@ -563,7 +563,7 @@ class PipelineCompilationJob final : public CompilationJob {
Status FinalizeJobImpl() final;
private:
ParseInfo parse_info_;
std::unique_ptr<ParseInfo> parse_info_;
ZoneStats zone_stats_;
CompilationInfo info_;
std::unique_ptr<PipelineStatistics> pipeline_statistics_;
......@@ -1750,8 +1750,16 @@ Handle<Code> Pipeline::GenerateCodeForTesting(
}
// static
CompilationJob* Pipeline::NewCompilationJob(Handle<JSFunction> function) {
return new PipelineCompilationJob(function->GetIsolate(), function);
CompilationJob* Pipeline::NewCompilationJob(Handle<JSFunction> function,
bool has_script) {
Handle<SharedFunctionInfo> shared = handle(function->shared());
ParseInfo* parse_info;
if (!has_script) {
parse_info = ParseInfo::AllocateWithoutScript(shared);
} else {
parse_info = new ParseInfo(shared);
}
return new PipelineCompilationJob(parse_info, function);
}
// static
......
......@@ -34,7 +34,8 @@ class SourcePositionTable;
class Pipeline : public AllStatic {
public:
// Returns a new compilation job for the given function.
static CompilationJob* NewCompilationJob(Handle<JSFunction> function);
static CompilationJob* NewCompilationJob(Handle<JSFunction> function,
bool has_script);
// Returns a new compilation job for the WebAssembly compilation info.
static CompilationJob* NewWasmCompilationJob(
......
......@@ -100,6 +100,46 @@ ParseInfo::~ParseInfo() {
ast_value_factory_ = nullptr;
}
// static
ParseInfo* ParseInfo::AllocateWithoutScript(Handle<SharedFunctionInfo> shared) {
Isolate* isolate = shared->GetIsolate();
ParseInfo* p = new ParseInfo(isolate->allocator());
p->isolate_ = isolate;
p->set_toplevel(shared->is_toplevel());
p->set_allow_lazy_parsing(FLAG_lazy_inner_functions);
p->set_hash_seed(isolate->heap()->HashSeed());
p->set_is_named_expression(shared->is_named_expression());
p->set_calls_eval(shared->scope_info()->CallsEval());
p->set_compiler_hints(shared->compiler_hints());
p->set_start_position(shared->start_position());
p->set_end_position(shared->end_position());
p->function_literal_id_ = shared->function_literal_id();
p->set_stack_limit(isolate->stack_guard()->real_climit());
p->set_unicode_cache(isolate->unicode_cache());
p->set_language_mode(shared->language_mode());
p->set_shared_info(shared);
p->set_module(shared->kind() == FunctionKind::kModule);
// BUG(5946): This function exists as a workaround until we can
// get rid of %SetCode in our native functions. The ParseInfo
// is explicitly set up for the case that:
// a) you have a native built-in,
// b) it's being run for the 2nd-Nth time in an isolate,
// c) we've already compiled bytecode and therefore don't need
// to parse.
// We tolerate a ParseInfo without a Script in this case.
p->set_native(true);
p->set_eval(false);
Handle<HeapObject> scope_info(shared->outer_scope_info());
if (!scope_info->IsTheHole(isolate) &&
Handle<ScopeInfo>::cast(scope_info)->length() > 0) {
p->set_outer_scope_info(Handle<ScopeInfo>::cast(scope_info));
}
return p;
}
DeclarationScope* ParseInfo::scope() const { return literal()->scope(); }
bool ParseInfo::is_declaration() const {
......
......@@ -42,6 +42,8 @@ class V8_EXPORT_PRIVATE ParseInfo {
~ParseInfo();
static ParseInfo* AllocateWithoutScript(Handle<SharedFunctionInfo> shared);
Zone* zone() const { return zone_.get(); }
std::shared_ptr<Zone> zone_shared() const { return zone_; }
......
......@@ -11,10 +11,16 @@ namespace internal {
std::ostream& operator<<(std::ostream& out, const SourcePositionInfo& pos) {
Handle<SharedFunctionInfo> function(pos.function);
Handle<Script> script(Script::cast(function->script()));
String* name = nullptr;
if (function->script()->IsScript()) {
Script* script = Script::cast(function->script());
if (script->name()->IsString()) {
name = String::cast(script->name());
}
}
out << "<";
if (script->name()->IsString()) {
out << String::cast(script->name())->ToCString(DISALLOW_NULLS).get();
if (name != nullptr) {
out << name->ToCString(DISALLOW_NULLS).get();
} else {
out << "unknown";
}
......@@ -78,12 +84,15 @@ std::vector<SourcePositionInfo> SourcePosition::InliningStack(
void SourcePosition::Print(std::ostream& out,
SharedFunctionInfo* function) const {
Script* script = Script::cast(function->script());
Object* source_name = script->name();
Script::PositionInfo pos;
script->GetPositionInfo(ScriptOffset(), &pos, Script::WITH_OFFSET);
Object* source_name = nullptr;
if (function->script()->IsScript()) {
Script* script = Script::cast(function->script());
source_name = script->name();
script->GetPositionInfo(ScriptOffset(), &pos, Script::WITH_OFFSET);
}
out << "<";
if (source_name->IsString()) {
if (source_name != nullptr && source_name->IsString()) {
out << String::cast(source_name)
->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL)
.get();
......@@ -117,12 +126,14 @@ void SourcePosition::Print(std::ostream& out, Code* code) const {
SourcePositionInfo::SourcePositionInfo(SourcePosition pos,
Handle<SharedFunctionInfo> f)
: position(pos), function(f) {
Handle<Script> script(Script::cast(function->script()));
Script::PositionInfo info;
if (Script::GetPositionInfo(script, pos.ScriptOffset(), &info,
Script::WITH_OFFSET)) {
line = info.line;
column = info.column;
if (function->script()->IsScript()) {
Handle<Script> script(Script::cast(function->script()));
Script::PositionInfo info;
if (Script::GetPositionInfo(script, pos.ScriptOffset(), &info,
Script::WITH_OFFSET)) {
line = info.line;
column = info.column;
}
}
}
......
......@@ -544,7 +544,6 @@
# Forced optimisation path tests.
'shared-function-tier-up-default': [SKIP],
'shared-function-tier-up-ignition': [SKIP],
'shared-function-tier-up-turbo': [SKIP],
# Fails deopt_fuzzer due to --deopt_every_n_times or
......
// Copyright 2016 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// Flags: --mark-shared-functions-for-tier-up --allow-natives-syntax
// Flags: --ignition-staging --no-turbo
// Flags: --crankshaft --no-always-opt
// If we are always or never optimizing it is useless.
assertFalse(isAlwaysOptimize());
assertFalse(isNeverOptimize());
(function() {
var sum = 0;
var i = 0;
for (var i = 0; i < 5; ++i) {
var f = function(x) {
return 2 * x;
}
sum += f(i);
if (i == 1) {
// f must be interpreted code.
assertTrue(isInterpreted(f));
// Allow it to run twice (i = 0, 1), then tier-up to baseline.
%BaselineFunctionOnNextCall(f);
} else if (i == 2) {
// Tier-up at i = 2 should only go up to baseline.
assertTrue(isBaselined(f));
} else if (i == 3) {
// Now f must be baseline code.
assertTrue(isBaselined(f));
// Run two more times (i = 2, 3), then tier-up to optimized.
%OptimizeFunctionOnNextCall(f);
} else if (i == 4) {
// Tier-up at i = 4 should now go up to crankshaft.
assertTrue(isCrankshafted(f));
}
}
})()
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