Change the CompilerDispatcherJob to take a SharedFunctionInfo

This means we can no longer take the closure's context to parse, but
need to rely on the outer scope info.

Since it's not possible to get that, however, for lazy functions, we
introduce a new field to SharedFunctionInfo that stores the outer scope
info whenever available.

BUG=v8:5215
R=marja@chromium.org,verwaest@chromium.org,jgruber@chromium.org

Review-Url: https://codereview.chromium.org/2358503002
Cr-Commit-Position: refs/heads/master@{#39548}
This commit is contained in:
jochen 2016-09-20 05:07:52 -07:00 committed by Commit bot
parent 4f5695229e
commit 0f0912dd23
15 changed files with 122 additions and 57 deletions

View File

@ -396,7 +396,7 @@ Handle<ScopeInfo> ScopeInfo::CreateGlobalThisBinding(Isolate* isolate) {
ScopeInfo* ScopeInfo::Empty(Isolate* isolate) {
return reinterpret_cast<ScopeInfo*>(isolate->heap()->empty_fixed_array());
return isolate->heap()->empty_scope_info();
}

View File

@ -533,6 +533,13 @@ void DeclarationScope::Analyze(ParseInfo* info, AnalyzeMode mode) {
scope->AllocateVariables(info, mode);
// Ensuring that the outer script scope has a scope info avoids having
// special case for native contexts vs other contexts.
if (info->script_scope()->scope_info_.is_null()) {
info->script_scope()->scope_info_ =
handle(ScopeInfo::Empty(info->isolate()));
}
#ifdef DEBUG
if (info->script_is_native() ? FLAG_print_builtin_scopes
: FLAG_print_scopes) {
@ -1147,6 +1154,14 @@ DeclarationScope* Scope::GetReceiverScope() {
return scope->AsDeclarationScope();
}
Scope* Scope::GetOuterScopeWithContext() {
Scope* scope = outer_scope_;
while (scope && !scope->NeedsContext()) {
scope = scope->outer_scope();
}
return scope;
}
Handle<StringSet> DeclarationScope::CollectNonLocals(
ParseInfo* info, Handle<StringSet> non_locals) {
VariableProxy* free_variables = FetchFreeVariables(this, info);

View File

@ -374,6 +374,9 @@ class Scope: public ZoneObject {
// Find the module scope, assuming there is one.
ModuleScope* GetModuleScope();
// Find the innermost outer scope that needs a context.
Scope* GetOuterScopeWithContext();
// Analyze() must have been called once to create the ScopeInfo.
Handle<ScopeInfo> scope_info() {
DCHECK(!scope_info_.is_null());

View File

@ -20,16 +20,16 @@ namespace v8 {
namespace internal {
CompilerDispatcherJob::CompilerDispatcherJob(Isolate* isolate,
Handle<JSFunction> function,
Handle<SharedFunctionInfo> shared,
size_t max_stack_size)
: isolate_(isolate),
function_(Handle<JSFunction>::cast(
isolate_->global_handles()->Create(*function))),
shared_(Handle<SharedFunctionInfo>::cast(
isolate_->global_handles()->Create(*shared))),
max_stack_size_(max_stack_size),
can_compile_on_background_thread_(false) {
HandleScope scope(isolate_);
Handle<SharedFunctionInfo> shared(function_->shared(), isolate_);
Handle<Script> script(Script::cast(shared->script()), isolate_);
DCHECK(!shared_->outer_scope_info()->IsTheHole(isolate_));
Handle<Script> script(Script::cast(shared_->script()), isolate_);
Handle<String> source(String::cast(script->source()), isolate_);
can_parse_on_background_thread_ =
source->IsExternalTwoByteString() || source->IsExternalOneByteString();
@ -39,7 +39,7 @@ CompilerDispatcherJob::~CompilerDispatcherJob() {
DCHECK(ThreadId::Current().Equals(isolate_->thread_id()));
DCHECK(status_ == CompileJobStatus::kInitial ||
status_ == CompileJobStatus::kDone);
i::GlobalHandles::Destroy(Handle<Object>::cast(function_).location());
i::GlobalHandles::Destroy(Handle<Object>::cast(shared_).location());
}
void CompilerDispatcherJob::PrepareToParseOnMainThread() {
@ -48,44 +48,42 @@ void CompilerDispatcherJob::PrepareToParseOnMainThread() {
HandleScope scope(isolate_);
unicode_cache_.reset(new UnicodeCache());
zone_.reset(new Zone(isolate_->allocator()));
Handle<SharedFunctionInfo> shared(function_->shared(), isolate_);
Handle<Script> script(Script::cast(shared->script()), isolate_);
Handle<Script> script(Script::cast(shared_->script()), isolate_);
DCHECK(script->type() != Script::TYPE_NATIVE);
Handle<String> source(String::cast(script->source()), isolate_);
if (source->IsExternalTwoByteString() || source->IsExternalOneByteString()) {
character_stream_.reset(ScannerStream::For(source, shared->start_position(),
shared->end_position()));
character_stream_.reset(ScannerStream::For(
source, shared_->start_position(), shared_->end_position()));
} else {
source = String::Flatten(source);
// Have to globalize the reference here, so it survives between function
// calls.
source_ = Handle<String>::cast(isolate_->global_handles()->Create(*source));
character_stream_.reset(ScannerStream::For(
source_, shared->start_position(), shared->end_position()));
source_, shared_->start_position(), shared_->end_position()));
}
parse_info_.reset(new ParseInfo(zone_.get()));
parse_info_->set_isolate(isolate_);
parse_info_->set_character_stream(character_stream_.get());
parse_info_->set_lazy();
parse_info_->set_hash_seed(isolate_->heap()->HashSeed());
parse_info_->set_is_named_expression(shared->is_named_expression());
parse_info_->set_calls_eval(shared->scope_info()->CallsEval());
parse_info_->set_compiler_hints(shared->compiler_hints());
parse_info_->set_start_position(shared->start_position());
parse_info_->set_end_position(shared->end_position());
parse_info_->set_is_named_expression(shared_->is_named_expression());
parse_info_->set_compiler_hints(shared_->compiler_hints());
parse_info_->set_start_position(shared_->start_position());
parse_info_->set_end_position(shared_->end_position());
parse_info_->set_unicode_cache(unicode_cache_.get());
parse_info_->set_language_mode(shared->language_mode());
parse_info_->set_language_mode(shared_->language_mode());
parser_.reset(new Parser(parse_info_.get()));
parser_->DeserializeScopeChain(
parse_info_.get(),
function_->context()->IsNativeContext()
? MaybeHandle<ScopeInfo>()
: MaybeHandle<ScopeInfo>(function_->context()->scope_info(),
isolate_));
Handle<ScopeInfo> outer_scope_info(
handle(ScopeInfo::cast(shared_->outer_scope_info())));
parser_->DeserializeScopeChain(parse_info_.get(),
outer_scope_info->length() > 0
? MaybeHandle<ScopeInfo>(outer_scope_info)
: MaybeHandle<ScopeInfo>());
Handle<String> name(String::cast(shared->name()));
Handle<String> name(String::cast(shared_->name()));
parse_info_->set_function_name(
parse_info_->ast_value_factory()->GetString(name));
status_ = CompileJobStatus::kReadyToParse;
@ -136,15 +134,15 @@ bool CompilerDispatcherJob::FinalizeParsingOnMainThread() {
DeferredHandleScope scope(isolate_);
{
Handle<SharedFunctionInfo> shared(function_->shared(), isolate_);
Handle<Script> script(Script::cast(shared->script()), isolate_);
Handle<Script> script(Script::cast(shared_->script()), isolate_);
parse_info_->set_script(script);
if (!function_->context()->IsNativeContext()) {
parse_info_->set_outer_scope_info(
handle(function_->context()->scope_info(), isolate_));
Handle<ScopeInfo> outer_scope_info(
handle(ScopeInfo::cast(shared_->outer_scope_info())));
if (outer_scope_info->length() > 0) {
parse_info_->set_outer_scope_info(outer_scope_info);
}
parse_info_->set_shared_info(handle(function_->shared(), isolate_));
parse_info_->set_shared_info(shared_);
{
// Create a canonical handle scope if compiling ignition bytecode. This is
@ -174,7 +172,8 @@ bool CompilerDispatcherJob::PrepareToCompileOnMainThread() {
DCHECK(ThreadId::Current().Equals(isolate_->thread_id()));
DCHECK(status() == CompileJobStatus::kReadyToAnalyse);
compile_info_.reset(new CompilationInfo(parse_info_.get(), function_));
compile_info_.reset(
new CompilationInfo(parse_info_.get(), Handle<JSFunction>::null()));
DeferredHandleScope scope(isolate_);
if (Compiler::Analyze(parse_info_.get())) {

View File

@ -17,9 +17,9 @@ namespace internal {
class CompilationInfo;
class CompilationJob;
class Isolate;
class JSFunction;
class ParseInfo;
class Parser;
class SharedFunctionInfo;
class String;
class UnicodeCache;
class Utf16CharacterStream;
@ -38,7 +38,7 @@ enum class CompileJobStatus {
class CompilerDispatcherJob {
public:
CompilerDispatcherJob(Isolate* isolate, Handle<JSFunction> function,
CompilerDispatcherJob(Isolate* isolate, Handle<SharedFunctionInfo> shared,
size_t max_stack_size);
~CompilerDispatcherJob();
@ -81,7 +81,7 @@ class CompilerDispatcherJob {
CompileJobStatus status_ = CompileJobStatus::kInitial;
Isolate* isolate_;
Handle<JSFunction> function_; // Global handle.
Handle<SharedFunctionInfo> shared_; // Global handle.
Handle<String> source_; // Global handle.
size_t max_stack_size_;

View File

@ -396,6 +396,10 @@ void InstallSharedScopeInfo(CompilationInfo* info,
Handle<SharedFunctionInfo> shared) {
Handle<ScopeInfo> scope_info = info->scope()->scope_info();
shared->set_scope_info(*scope_info);
Scope* outer_scope = info->scope()->GetOuterScopeWithContext();
if (outer_scope) {
shared->set_outer_scope_info(*outer_scope->scope_info());
}
}
void InstallSharedCompilationResult(CompilationInfo* info,
@ -1799,6 +1803,10 @@ Handle<SharedFunctionInfo> Compiler::GetSharedFunctionInfo(
if (lazy) {
info.SetCode(isolate->builtins()->CompileLazy());
Scope* outer_scope = literal->scope()->GetOuterScopeWithContext();
if (outer_scope) {
result->set_outer_scope_info(*outer_scope->scope_info());
}
} else if (Renumber(info.parse_info()) && GenerateUnoptimizedCode(&info)) {
// Code generation will ensure that the feedback vector is present and
// appropriately sized.
@ -1842,6 +1850,7 @@ Handle<SharedFunctionInfo> Compiler::GetSharedFunctionInfoForNative(
Handle<SharedFunctionInfo> shared = isolate->factory()->NewSharedFunctionInfo(
name, fun->shared()->num_literals(), FunctionKind::kNormalFunction, code,
Handle<ScopeInfo>(fun->shared()->scope_info()));
shared->set_outer_scope_info(fun->shared()->outer_scope_info());
shared->SetConstructStub(*construct_stub);
shared->set_feedback_metadata(fun->shared()->feedback_metadata());

View File

@ -1016,6 +1016,7 @@ void LiveEdit::ReplaceFunctionCode(
handle(shared_info->GetDebugInfo()));
}
shared_info->set_scope_info(new_shared_info->scope_info());
shared_info->set_outer_scope_info(new_shared_info->outer_scope_info());
shared_info->DisableOptimization(kLiveEdit);
// Update the type feedback vector, if needed.
Handle<TypeFeedbackMetadata> new_feedback_metadata(

View File

@ -2110,6 +2110,7 @@ Handle<SharedFunctionInfo> Factory::NewSharedFunctionInfo(
Handle<SharedFunctionInfo> shared = NewSharedFunctionInfo(
name, code, IsConstructable(kind, scope_info->language_mode()));
shared->set_scope_info(*scope_info);
shared->set_outer_scope_info(*the_hole_value());
shared->set_kind(kind);
shared->set_num_literals(number_of_literals);
if (IsGeneratorFunction(kind)) {
@ -2156,6 +2157,7 @@ Handle<SharedFunctionInfo> Factory::NewSharedFunctionInfo(
share->set_code(*code);
share->set_optimized_code_map(*cleared_optimized_code_map());
share->set_scope_info(ScopeInfo::Empty(isolate()));
share->set_outer_scope_info(*the_hole_value());
Handle<Code> construct_stub =
is_constructor ? isolate()->builtins()->JSConstructStubGeneric()
: isolate()->builtins()->ConstructedNonConstructable();

View File

@ -2409,6 +2409,12 @@ bool Heap::CreateInitialMaps() {
#undef ALLOCATE_MAP
}
{
AllocationResult allocation = AllocateEmptyScopeInfo();
if (!allocation.To(&obj)) return false;
}
set_empty_scope_info(ScopeInfo::cast(obj));
{
AllocationResult allocation = Allocate(boolean_map(), OLD_SPACE);
if (!allocation.To(&obj)) return false;
@ -3809,6 +3815,18 @@ AllocationResult Heap::AllocateEmptyFixedArray() {
return result;
}
AllocationResult Heap::AllocateEmptyScopeInfo() {
int size = FixedArray::SizeFor(0);
HeapObject* result = nullptr;
{
AllocationResult allocation = AllocateRaw(size, OLD_SPACE);
if (!allocation.To(&result)) return allocation;
}
// Initialize the object.
result->set_map_no_write_barrier(scope_info_map());
FixedArray::cast(result)->set_length(0);
return result;
}
AllocationResult Heap::CopyAndTenureFixedCOWArray(FixedArray* src) {
if (!InNewSpace(src)) {

View File

@ -62,6 +62,7 @@ using v8::MemoryPressureLevel;
V(FixedArray, empty_literals_array, EmptyLiteralsArray) \
V(FixedArray, empty_type_feedback_vector, EmptyTypeFeedbackVector) \
V(FixedArray, empty_fixed_array, EmptyFixedArray) \
V(ScopeInfo, empty_scope_info, EmptyScopeInfo) \
V(FixedArray, cleared_optimized_code_map, ClearedOptimizedCodeMap) \
V(DescriptorArray, empty_descriptor_array, EmptyDescriptorArray) \
/* Entries beyond the first 32 */ \
@ -2039,6 +2040,9 @@ class Heap {
// Allocate empty fixed array.
MUST_USE_RESULT AllocationResult AllocateEmptyFixedArray();
// Allocate empty scope info.
MUST_USE_RESULT AllocationResult AllocateEmptyScopeInfo();
// Allocate empty fixed typed array of given type.
MUST_USE_RESULT AllocationResult
AllocateEmptyFixedTypedArray(ExternalArrayType array_type);

View File

@ -562,6 +562,7 @@ void SharedFunctionInfo::SharedFunctionInfoVerify() {
VerifyObjectField(kOptimizedCodeMapOffset);
VerifyObjectField(kFeedbackMetadataOffset);
VerifyObjectField(kScopeInfoOffset);
VerifyObjectField(kOuterScopeInfoOffset);
VerifyObjectField(kInstanceClassNameOffset);
CHECK(function_data()->IsUndefined(GetIsolate()) || IsApiFunction() ||
HasBytecodeArray() || HasAsmWasmData());

View File

@ -6198,6 +6198,9 @@ void SharedFunctionInfo::set_scope_info(ScopeInfo* value,
mode);
}
ACCESSORS(SharedFunctionInfo, outer_scope_info, HeapObject,
kOuterScopeInfoOffset)
bool SharedFunctionInfo::is_compiled() const {
Builtins* builtins = GetIsolate()->builtins();
DCHECK(code() != builtins->builtin(Builtins::kCompileOptimizedConcurrent));

View File

@ -7158,6 +7158,10 @@ class SharedFunctionInfo: public HeapObject {
// [scope_info]: Scope info.
DECL_ACCESSORS(scope_info, ScopeInfo)
// The outer scope info for the purpose of parsing this function, or the hole
// value if it isn't yet known.
DECL_ACCESSORS(outer_scope_info, HeapObject)
// [construct stub]: Code stub for constructing instances of this function.
DECL_ACCESSORS(construct_stub, Code)
@ -7515,7 +7519,8 @@ class SharedFunctionInfo: public HeapObject {
static const int kCodeOffset = kNameOffset + kPointerSize;
static const int kOptimizedCodeMapOffset = kCodeOffset + kPointerSize;
static const int kScopeInfoOffset = kOptimizedCodeMapOffset + kPointerSize;
static const int kConstructStubOffset = kScopeInfoOffset + kPointerSize;
static const int kOuterScopeInfoOffset = kScopeInfoOffset + kPointerSize;
static const int kConstructStubOffset = kOuterScopeInfoOffset + kPointerSize;
static const int kInstanceClassNameOffset =
kConstructStubOffset + kPointerSize;
static const int kFunctionDataOffset =

View File

@ -174,6 +174,7 @@ RUNTIME_FUNCTION(Runtime_SetCode) {
target_shared->set_bytecode_array(source_shared->bytecode_array());
}
target_shared->set_scope_info(source_shared->scope_info());
target_shared->set_outer_scope_info(source_shared->outer_scope_info());
target_shared->set_length(source_shared->length());
target_shared->set_num_literals(source_shared->num_literals());
target_shared->set_feedback_metadata(source_shared->feedback_metadata());

View File

@ -30,6 +30,7 @@ class IgnitionCompilerDispatcherJobTest : public TestWithContext {
static void SetUpTestCase() {
old_flag_ = i::FLAG_ignition;
i::FLAG_ignition = true;
i::FLAG_never_compact = true;
TestWithContext::SetUpTestCase();
}
@ -65,7 +66,7 @@ class ScriptResource : public v8::String::ExternalOneByteStringResource {
DISALLOW_COPY_AND_ASSIGN(ScriptResource);
};
Handle<JSFunction> CreateFunction(
Handle<SharedFunctionInfo> CreateSharedFunctionInfo(
Isolate* isolate, ExternalOneByteString::Resource* maybe_resource) {
HandleScope scope(isolate);
Handle<String> source;
@ -82,10 +83,8 @@ Handle<JSFunction> CreateFunction(
isolate->builtins()->CompileLazy(), false);
SharedFunctionInfo::SetScript(shared, script);
shared->set_end_position(source->length());
Handle<JSFunction> function =
isolate->factory()->NewFunctionFromSharedFunctionInfo(
shared, handle(isolate->context(), isolate));
return scope.CloseAndEscape(function);
shared->set_outer_scope_info(ScopeInfo::Empty(isolate));
return scope.CloseAndEscape(shared);
}
Handle<Object> RunJS(v8::Isolate* isolate, const char* script) {
@ -103,26 +102,30 @@ Handle<Object> RunJS(v8::Isolate* isolate, const char* script) {
TEST_F(CompilerDispatcherJobTest, Construct) {
std::unique_ptr<CompilerDispatcherJob> job(new CompilerDispatcherJob(
i_isolate(), CreateFunction(i_isolate(), nullptr), FLAG_stack_size));
i_isolate(), CreateSharedFunctionInfo(i_isolate(), nullptr),
FLAG_stack_size));
}
TEST_F(CompilerDispatcherJobTest, CanParseOnBackgroundThread) {
{
std::unique_ptr<CompilerDispatcherJob> job(new CompilerDispatcherJob(
i_isolate(), CreateFunction(i_isolate(), nullptr), FLAG_stack_size));
i_isolate(), CreateSharedFunctionInfo(i_isolate(), nullptr),
FLAG_stack_size));
ASSERT_FALSE(job->can_parse_on_background_thread());
}
{
ScriptResource script(test_script, strlen(test_script));
std::unique_ptr<CompilerDispatcherJob> job(new CompilerDispatcherJob(
i_isolate(), CreateFunction(i_isolate(), &script), FLAG_stack_size));
i_isolate(), CreateSharedFunctionInfo(i_isolate(), &script),
FLAG_stack_size));
ASSERT_TRUE(job->can_parse_on_background_thread());
}
}
TEST_F(CompilerDispatcherJobTest, StateTransitions) {
std::unique_ptr<CompilerDispatcherJob> job(new CompilerDispatcherJob(
i_isolate(), CreateFunction(i_isolate(), nullptr), FLAG_stack_size));
i_isolate(), CreateSharedFunctionInfo(i_isolate(), nullptr),
FLAG_stack_size));
ASSERT_TRUE(job->status() == CompileJobStatus::kInitial);
job->PrepareToParseOnMainThread();
@ -144,7 +147,8 @@ TEST_F(CompilerDispatcherJobTest, StateTransitions) {
TEST_F(CompilerDispatcherJobTest, SyntaxError) {
ScriptResource script("^^^", strlen("^^^"));
std::unique_ptr<CompilerDispatcherJob> job(new CompilerDispatcherJob(
i_isolate(), CreateFunction(i_isolate(), &script), FLAG_stack_size));
i_isolate(), CreateSharedFunctionInfo(i_isolate(), &script),
FLAG_stack_size));
job->PrepareToParseOnMainThread();
job->Parse();
@ -160,12 +164,12 @@ TEST_F(CompilerDispatcherJobTest, SyntaxError) {
TEST_F(CompilerDispatcherJobTest, ScopeChain) {
const char script[] =
"function g() { var g = 1; function f(x) { return x * g }; return f; } "
"function g() { var y = 1; function f(x) { return x * y }; return f; } "
"g();";
Handle<JSFunction> f = Handle<JSFunction>::cast(RunJS(isolate(), script));
std::unique_ptr<CompilerDispatcherJob> job(
new CompilerDispatcherJob(i_isolate(), f, FLAG_stack_size));
std::unique_ptr<CompilerDispatcherJob> job(new CompilerDispatcherJob(
i_isolate(), handle(f->shared()), FLAG_stack_size));
job->PrepareToParseOnMainThread();
job->Parse();
@ -179,9 +183,9 @@ TEST_F(CompilerDispatcherJobTest, ScopeChain) {
ASSERT_TRUE(var);
ASSERT_TRUE(var->IsParameter());
const AstRawString* var_g =
job->parse_info_->ast_value_factory()->GetOneByteString("g");
var = job->parse_info_->literal()->scope()->Lookup(var_g);
const AstRawString* var_y =
job->parse_info_->ast_value_factory()->GetOneByteString("y");
var = job->parse_info_->literal()->scope()->Lookup(var_y);
ASSERT_TRUE(var);
ASSERT_TRUE(var->IsContextSlot());
@ -200,8 +204,8 @@ TEST_F(CompilerDispatcherJobTest, CompileAndRun) {
"}\n"
"g();";
Handle<JSFunction> f = Handle<JSFunction>::cast(RunJS(isolate(), script));
std::unique_ptr<CompilerDispatcherJob> job(
new CompilerDispatcherJob(i_isolate(), f, FLAG_stack_size));
std::unique_ptr<CompilerDispatcherJob> job(new CompilerDispatcherJob(
i_isolate(), handle(f->shared()), FLAG_stack_size));
job->PrepareToParseOnMainThread();
job->Parse();
@ -226,7 +230,7 @@ TEST_F(CompilerDispatcherJobTest, CompileFailureToPrepare) {
raw_script += " 'x'; }";
ScriptResource script(raw_script.c_str(), strlen(raw_script.c_str()));
std::unique_ptr<CompilerDispatcherJob> job(new CompilerDispatcherJob(
i_isolate(), CreateFunction(i_isolate(), &script), 100));
i_isolate(), CreateSharedFunctionInfo(i_isolate(), &script), 100));
job->PrepareToParseOnMainThread();
job->Parse();
@ -248,7 +252,7 @@ TEST_F(CompilerDispatcherJobTest, CompileFailureToFinalize) {
raw_script += " 'x'; }";
ScriptResource script(raw_script.c_str(), strlen(raw_script.c_str()));
std::unique_ptr<CompilerDispatcherJob> job(new CompilerDispatcherJob(
i_isolate(), CreateFunction(i_isolate(), &script), 50));
i_isolate(), CreateSharedFunctionInfo(i_isolate(), &script), 50));
job->PrepareToParseOnMainThread();
job->Parse();
@ -291,7 +295,7 @@ TEST_F(IgnitionCompilerDispatcherJobTest, CompileOnBackgroundThread) {
"}";
ScriptResource script(raw_script, strlen(raw_script));
std::unique_ptr<CompilerDispatcherJob> job(new CompilerDispatcherJob(
i_isolate(), CreateFunction(i_isolate(), &script), 100));
i_isolate(), CreateSharedFunctionInfo(i_isolate(), &script), 100));
job->PrepareToParseOnMainThread();
job->Parse();