Commit ce3f46b1 authored by jochen's avatar jochen Committed by Commit bot

Chain ScopeInfos together

This will allow getting the entire scope chain from a SharedFunctionInfo
which in turn will allow for generating bytecode when we just have the
SFI

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

Review-Url: https://codereview.chromium.org/2271993002
Cr-Commit-Position: refs/heads/master@{#39243}
parent 7ac19fe5
......@@ -2083,7 +2083,12 @@ MaybeLocal<Function> ScriptCompiler::CompileFunctionInContext(
if (!extension->IsJSObject()) return Local<Function>();
i::Handle<i::JSFunction> closure(context->closure(), isolate);
context = factory->NewWithContext(
closure, context, i::ScopeInfo::CreateForWithScope(isolate), extension);
closure, context,
i::ScopeInfo::CreateForWithScope(
isolate, context->IsNativeContext()
? i::Handle<i::ScopeInfo>::null()
: i::Handle<i::ScopeInfo>(context->scope_info())),
extension);
}
i::Handle<i::Object> name_obj;
......
......@@ -19,8 +19,43 @@ enum ModuleVariableEntryOffset {
kModuleVariableEntryLength // Sentinel value.
};
Handle<ScopeInfo> ScopeInfo::Create(Isolate* isolate, Zone* zone,
Scope* scope) {
#ifdef DEBUG
bool ScopeInfo::Equals(ScopeInfo* other) const {
if (length() != other->length()) return false;
for (int index = 0; index < length(); ++index) {
Object* entry = get(index);
Object* other_entry = other->get(index);
if (entry->IsSmi()) {
if (entry != other_entry) return false;
} else {
if (HeapObject::cast(entry)->map()->instance_type() !=
HeapObject::cast(other_entry)->map()->instance_type()) {
return false;
}
if (entry->IsString()) {
if (!String::cast(entry)->Equals(String::cast(other_entry))) {
return false;
}
} else if (entry->IsScopeInfo()) {
if (!ScopeInfo::cast(entry)->Equals(ScopeInfo::cast(other_entry))) {
return false;
}
} else if (entry->IsModuleInfo()) {
if (!ModuleInfo::cast(entry)->Equals(ModuleInfo::cast(other_entry))) {
return false;
}
} else {
UNREACHABLE();
return false;
}
}
}
return true;
}
#endif
Handle<ScopeInfo> ScopeInfo::Create(Isolate* isolate, Zone* zone, Scope* scope,
MaybeHandle<ScopeInfo> outer_scope) {
// Collect variables.
ZoneList<Variable*>* locals = scope->locals();
int stack_local_count = 0;
......@@ -94,9 +129,11 @@ Handle<ScopeInfo> ScopeInfo::Create(Isolate* isolate, Zone* zone,
const bool has_function_name = function_name_info != NONE;
const bool has_receiver = receiver_info == STACK || receiver_info == CONTEXT;
const int parameter_count = scope->num_parameters();
const bool has_outer_scope_info = !outer_scope.is_null();
const int length = kVariablePartIndex + parameter_count +
(1 + stack_local_count) + 2 * context_local_count +
(has_receiver ? 1 : 0) + (has_function_name ? 2 : 0) +
(has_outer_scope_info ? 1 : 0) +
(scope->is_module_scope()
? 2 + kModuleVariableEntryLength * module_vars_count
: 0);
......@@ -127,7 +164,8 @@ Handle<ScopeInfo> ScopeInfo::Create(Isolate* isolate, Zone* zone,
AsmModuleField::encode(asm_module) |
AsmFunctionField::encode(asm_function) |
HasSimpleParametersField::encode(has_simple_parameters) |
FunctionKindField::encode(function_kind);
FunctionKindField::encode(function_kind) |
HasOuterScopeInfoField::encode(has_outer_scope_info);
scope_info->SetFlags(flags);
scope_info->SetParameterCount(parameter_count);
......@@ -222,6 +260,12 @@ Handle<ScopeInfo> ScopeInfo::Create(Isolate* isolate, Zone* zone,
var_index == scope_info->ContextLength() - 1);
}
// If present, add the outer scope info.
DCHECK(index == scope_info->OuterScopeInfoEntryIndex());
if (has_outer_scope_info) {
scope_info->set(index++, *outer_scope.ToHandleChecked());
}
// Module-specific information (only for module scopes).
if (scope->is_module_scope()) {
Handle<ModuleInfo> module_info =
......@@ -241,8 +285,10 @@ Handle<ScopeInfo> ScopeInfo::Create(Isolate* isolate, Zone* zone,
return scope_info;
}
Handle<ScopeInfo> ScopeInfo::CreateForWithScope(Isolate* isolate) {
const int length = kVariablePartIndex + 1;
Handle<ScopeInfo> ScopeInfo::CreateForWithScope(
Isolate* isolate, MaybeHandle<ScopeInfo> outer_scope) {
const bool has_outer_scope_info = !outer_scope.is_null();
const int length = kVariablePartIndex + 1 + (has_outer_scope_info ? 1 : 0);
Factory* factory = isolate->factory();
Handle<ScopeInfo> scope_info = factory->NewScopeInfo(length);
......@@ -254,7 +300,8 @@ Handle<ScopeInfo> ScopeInfo::CreateForWithScope(Isolate* isolate) {
ReceiverVariableField::encode(NONE) | HasNewTargetField::encode(false) |
FunctionVariableField::encode(NONE) | AsmModuleField::encode(false) |
AsmFunctionField::encode(false) | HasSimpleParametersField::encode(true) |
FunctionKindField::encode(kNormalFunction);
FunctionKindField::encode(kNormalFunction) |
HasOuterScopeInfoField::encode(has_outer_scope_info);
scope_info->SetFlags(flags);
scope_info->SetParameterCount(0);
......@@ -268,6 +315,10 @@ Handle<ScopeInfo> ScopeInfo::CreateForWithScope(Isolate* isolate) {
DCHECK_EQ(index, scope_info->StackLocalEntriesIndex());
DCHECK_EQ(index, scope_info->ReceiverEntryIndex());
DCHECK_EQ(index, scope_info->FunctionNameEntryIndex());
DCHECK(index == scope_info->OuterScopeInfoEntryIndex());
if (has_outer_scope_info) {
scope_info->set(index++, *outer_scope.ToHandleChecked());
}
DCHECK_EQ(index, scope_info->length());
DCHECK_EQ(0, scope_info->ParameterCount());
DCHECK_EQ(Context::MIN_CONTEXT_SLOTS, scope_info->ContextLength());
......@@ -284,24 +335,26 @@ Handle<ScopeInfo> ScopeInfo::CreateGlobalThisBinding(Isolate* isolate) {
const VariableAllocationInfo function_name_info = NONE;
const bool has_function_name = false;
const bool has_receiver = true;
const bool has_outer_scope_info = false;
const int parameter_count = 0;
const int length = kVariablePartIndex + parameter_count +
(1 + stack_local_count) + 2 * context_local_count +
(has_receiver ? 1 : 0) + (has_function_name ? 2 : 0);
(has_receiver ? 1 : 0) + (has_function_name ? 2 : 0) +
(has_outer_scope_info ? 1 : 0);
Factory* factory = isolate->factory();
Handle<ScopeInfo> scope_info = factory->NewScopeInfo(length);
// Encode the flags.
int flags = ScopeTypeField::encode(SCRIPT_SCOPE) |
CallsEvalField::encode(false) |
LanguageModeField::encode(SLOPPY) |
DeclarationScopeField::encode(true) |
ReceiverVariableField::encode(receiver_info) |
FunctionVariableField::encode(function_name_info) |
AsmModuleField::encode(false) | AsmFunctionField::encode(false) |
HasSimpleParametersField::encode(has_simple_parameters) |
FunctionKindField::encode(FunctionKind::kNormalFunction);
int flags =
ScopeTypeField::encode(SCRIPT_SCOPE) | CallsEvalField::encode(false) |
LanguageModeField::encode(SLOPPY) | DeclarationScopeField::encode(true) |
ReceiverVariableField::encode(receiver_info) |
FunctionVariableField::encode(function_name_info) |
AsmModuleField::encode(false) | AsmFunctionField::encode(false) |
HasSimpleParametersField::encode(has_simple_parameters) |
FunctionKindField::encode(FunctionKind::kNormalFunction) |
HasOuterScopeInfoField::encode(has_outer_scope_info);
scope_info->SetFlags(flags);
scope_info->SetParameterCount(parameter_count);
scope_info->SetStackLocalCount(stack_local_count);
......@@ -328,6 +381,7 @@ Handle<ScopeInfo> ScopeInfo::CreateGlobalThisBinding(Isolate* isolate) {
scope_info->set(index++, Smi::FromInt(receiver_index));
DCHECK_EQ(index, scope_info->FunctionNameEntryIndex());
DCHECK_EQ(index, scope_info->OuterScopeInfoEntryIndex());
DCHECK_EQ(index, scope_info->length());
DCHECK_EQ(scope_info->ParameterCount(), 0);
......@@ -429,6 +483,13 @@ bool ScopeInfo::HasFunctionName() {
}
}
bool ScopeInfo::HasOuterScopeInfo() {
if (length() > 0) {
return HasOuterScopeInfoField::decode(Flags());
} else {
return false;
}
}
bool ScopeInfo::HasHeapAllocatedLocals() {
if (length() > 0) {
......@@ -449,6 +510,11 @@ String* ScopeInfo::FunctionName() {
return String::cast(get(FunctionNameEntryIndex()));
}
ScopeInfo* ScopeInfo::OuterScopeInfo() {
DCHECK(HasOuterScopeInfo());
return ScopeInfo::cast(get(OuterScopeInfoEntryIndex()));
}
ModuleInfo* ScopeInfo::ModuleDescriptorInfo() {
DCHECK(scope_type() == MODULE_SCOPE);
return static_cast<ModuleInfo*>(get(ModuleInfoEntryIndex()));
......@@ -700,10 +766,14 @@ int ScopeInfo::FunctionNameEntryIndex() {
return ReceiverEntryIndex() + (HasAllocatedReceiver() ? 1 : 0);
}
int ScopeInfo::ModuleInfoEntryIndex() {
int ScopeInfo::OuterScopeInfoEntryIndex() {
return FunctionNameEntryIndex() + (HasFunctionName() ? 2 : 0);
}
int ScopeInfo::ModuleInfoEntryIndex() {
return OuterScopeInfoEntryIndex() + (HasOuterScopeInfo() ? 1 : 0);
}
int ScopeInfo::ModuleVariableCountIndex() { return ModuleInfoEntryIndex() + 1; }
int ScopeInfo::ModuleVariableEntriesIndex() {
......
......@@ -337,8 +337,7 @@ Scope* Scope::DeserializeScopeChain(Isolate* isolate, Zone* zone,
DCHECK(context->previous()->IsNativeContext());
break;
} else if (context->IsFunctionContext()) {
Handle<ScopeInfo> scope_info(context->closure()->shared()->scope_info(),
isolate);
Handle<ScopeInfo> scope_info(context->scope_info(), isolate);
// TODO(neis): For an eval scope, we currently create an ordinary function
// context. This is wrong and needs to be fixed.
// https://bugs.chromium.org/p/v8/issues/detail?id=5295
......@@ -360,7 +359,7 @@ Scope* Scope::DeserializeScopeChain(Isolate* isolate, Zone* zone,
outer_scope = new (zone) Scope(zone, BLOCK_SCOPE, scope_info);
}
} else if (context->IsModuleContext()) {
ScopeInfo* scope_info = context->closure()->shared()->scope_info();
ScopeInfo* scope_info = context->scope_info();
DCHECK_EQ(scope_info->scope_type(), MODULE_SCOPE);
outer_scope = new (zone) ModuleScope(
isolate, Handle<ScopeInfo>(scope_info), ast_value_factory);
......@@ -373,6 +372,13 @@ Scope* Scope::DeserializeScopeChain(Isolate* isolate, Zone* zone,
}
if (current_scope != nullptr) {
outer_scope->AddInnerScope(current_scope);
DCHECK_IMPLIES(
deserialization_mode == DeserializationMode::kKeepScopeInfo,
current_scope->scope_info_->HasOuterScopeInfo());
DCHECK_IMPLIES(
deserialization_mode == DeserializationMode::kKeepScopeInfo,
outer_scope->scope_info_->Equals(
current_scope->scope_info_->OuterScopeInfo()));
}
current_scope = outer_scope;
if (deserialization_mode == DeserializationMode::kDeserializeOffHeap) {
......@@ -384,6 +390,17 @@ Scope* Scope::DeserializeScopeChain(Isolate* isolate, Zone* zone,
if (innermost_scope == nullptr) return script_scope;
script_scope->AddInnerScope(current_scope);
#if DEBUG
if (deserialization_mode == DeserializationMode::kKeepScopeInfo) {
if (script_scope->scope_info_.is_null()) {
DCHECK(!current_scope->scope_info_->HasOuterScopeInfo());
} else {
DCHECK(!script_scope->scope_info_->HasOuterScopeInfo());
DCHECK(script_scope->scope_info_->Equals(
current_scope->scope_info_->OuterScopeInfo()));
}
}
#endif
return innermost_scope;
}
......@@ -1066,7 +1083,14 @@ Declaration* Scope::CheckLexDeclarationsConflictingWith(
void DeclarationScope::AllocateVariables(ParseInfo* info, AnalyzeMode mode) {
ResolveVariablesRecursively(info);
AllocateVariablesRecursively();
AllocateScopeInfosRecursively(info->isolate(), mode);
MaybeHandle<ScopeInfo> outer_scope;
for (const Scope* s = outer_scope_; s != nullptr; s = s->outer_scope_) {
if (s->scope_info_.is_null()) continue;
outer_scope = s->scope_info_;
break;
}
AllocateScopeInfosRecursively(info->isolate(), mode, outer_scope);
}
bool Scope::AllowsLazyParsing() const {
......@@ -1794,15 +1818,21 @@ void Scope::AllocateVariablesRecursively() {
DCHECK(num_heap_slots_ == 0 || num_heap_slots_ >= Context::MIN_CONTEXT_SLOTS);
}
void Scope::AllocateScopeInfosRecursively(Isolate* isolate, AnalyzeMode mode) {
void Scope::AllocateScopeInfosRecursively(Isolate* isolate, AnalyzeMode mode,
MaybeHandle<ScopeInfo> outer_scope) {
DCHECK(scope_info_.is_null());
if (mode == AnalyzeMode::kDebugger || NeedsScopeInfo()) {
scope_info_ = ScopeInfo::Create(isolate, zone(), this);
scope_info_ = ScopeInfo::Create(isolate, zone(), this, outer_scope);
}
// The ScopeInfo chain should mirror the context chain, so we only link to
// the next outer scope that needs a context.
MaybeHandle<ScopeInfo> next_outer_scope = outer_scope;
if (NeedsContext()) next_outer_scope = scope_info_;
// Allocate ScopeInfos for inner scopes.
for (Scope* scope = inner_scope_; scope != nullptr; scope = scope->sibling_) {
scope->AllocateScopeInfosRecursively(isolate, mode);
scope->AllocateScopeInfosRecursively(isolate, mode, next_outer_scope);
}
}
......
......@@ -538,7 +538,8 @@ class Scope: public ZoneObject {
void AllocateNonParameterLocalsAndDeclaredGlobals();
void AllocateVariablesRecursively();
void AllocateScopeInfosRecursively(Isolate* isolate, AnalyzeMode mode);
void AllocateScopeInfosRecursively(Isolate* isolate, AnalyzeMode mode,
MaybeHandle<ScopeInfo> outer_scope);
// Construct a scope based on the scope info.
Scope(Zone* zone, ScopeType type, Handle<ScopeInfo> scope_info);
......
......@@ -110,8 +110,10 @@ JSReceiver* Context::extension_receiver() {
}
ScopeInfo* Context::scope_info() {
DCHECK(IsModuleContext() || IsScriptContext() || IsBlockContext() ||
IsCatchContext() || IsWithContext() || IsDebugEvaluateContext());
DCHECK(!IsNativeContext());
if (IsFunctionContext() || IsModuleContext()) {
return closure()->shared()->scope_info();
}
HeapObject* object = extension();
if (object->IsContextExtension()) {
DCHECK(IsBlockContext() || IsCatchContext() || IsWithContext() ||
......
......@@ -95,7 +95,12 @@ MaybeHandle<Object> DebugEvaluate::Evaluate(
Handle<JSObject> extension = Handle<JSObject>::cast(context_extension);
Handle<JSFunction> closure(context->closure(), isolate);
context = isolate->factory()->NewWithContext(
closure, context, ScopeInfo::CreateForWithScope(isolate), extension);
closure, context,
ScopeInfo::CreateForWithScope(
isolate, context->IsNativeContext()
? Handle<ScopeInfo>::null()
: Handle<ScopeInfo>(context->scope_info())),
extension);
}
Handle<JSFunction> eval_fun;
......@@ -205,7 +210,12 @@ DebugEvaluate::ContextBuilder::ContextBuilder(Isolate* isolate,
for (int i = context_chain_.length() - 1; i >= 0; i--) {
evaluation_context_ = factory->NewDebugEvaluateContext(
evaluation_context_, ScopeInfo::CreateForWithScope(isolate),
evaluation_context_,
ScopeInfo::CreateForWithScope(
isolate,
evaluation_context_->IsNativeContext()
? Handle<ScopeInfo>::null()
: Handle<ScopeInfo>(evaluation_context_->scope_info())),
context_chain_[i].materialized_object,
context_chain_[i].wrapped_context, context_chain_[i].whitelist);
}
......
......@@ -7928,6 +7928,13 @@ FixedArray* ModuleInfo::regular_exports() const {
return FixedArray::cast(get(kRegularExportsIndex));
}
#ifdef DEBUG
bool ModuleInfo::Equals(ModuleInfo* other) const {
return get(kSpecialExportsIndex) == other->get(kSpecialExportsIndex) &&
get(kRegularExportsIndex) == other->get(kRegularExportsIndex);
}
#endif
void Map::ClearCodeCache(Heap* heap) {
// No write barrier is needed since empty_fixed_array is not in new space.
// Please note this function is used during marking:
......
......@@ -4391,8 +4391,20 @@ class ScopeInfo : public FixedArray {
FunctionKind function_kind();
static Handle<ScopeInfo> Create(Isolate* isolate, Zone* zone, Scope* scope);
static Handle<ScopeInfo> CreateForWithScope(Isolate* isolate);
// Returns true if this ScopeInfo is linked to a outer ScopeInfo.
bool HasOuterScopeInfo();
// Return the outer ScopeInfo if present.
ScopeInfo* OuterScopeInfo();
#ifdef DEBUG
bool Equals(ScopeInfo* other) const;
#endif
static Handle<ScopeInfo> Create(Isolate* isolate, Zone* zone, Scope* scope,
MaybeHandle<ScopeInfo> outer_scope);
static Handle<ScopeInfo> CreateForWithScope(
Isolate* isolate, MaybeHandle<ScopeInfo> outer_scope);
static Handle<ScopeInfo> CreateGlobalThisBinding(Isolate* isolate);
// Serializes empty scope info.
......@@ -4463,7 +4475,9 @@ class ScopeInfo : public FixedArray {
// information about the function variable. It always occupies two array
// slots: a. The name of the function variable.
// b. The context or stack slot index for the variable.
// 8. ModuleInfoEntry, ModuleVariableCount, and ModuleVariableEntries:
// 8. OuterScopeInfoEntryIndex:
// The outer scope's ScopeInfo or the hole if there's none.
// 9. ModuleInfoEntry, ModuleVariableCount, and ModuleVariableEntries:
// For a module scope, this part contains the ModuleInfo, the number of
// MODULE-allocated variables, and the metadata of those variables. For
// non-module scopes it is empty.
......@@ -4474,6 +4488,7 @@ class ScopeInfo : public FixedArray {
int ContextLocalInfoEntriesIndex();
int ReceiverEntryIndex();
int FunctionNameEntryIndex();
int OuterScopeInfoEntryIndex();
int ModuleInfoEntryIndex();
int ModuleVariableCountIndex();
int ModuleVariableEntriesIndex();
......@@ -4508,6 +4523,8 @@ class ScopeInfo : public FixedArray {
: public BitField<bool, AsmFunctionField::kNext, 1> {};
class FunctionKindField
: public BitField<FunctionKind, HasSimpleParametersField::kNext, 9> {};
class HasOuterScopeInfoField
: public BitField<bool, FunctionKindField::kNext, 1> {};
// Properties of variables.
class VariableModeField : public BitField<VariableMode, 0, 3> {};
......@@ -4525,6 +4542,10 @@ class ModuleInfo : public FixedArray {
inline FixedArray* special_exports() const;
inline FixedArray* regular_exports() const;
#ifdef DEBUG
inline bool Equals(ModuleInfo* other) const;
#endif
private:
friend class Factory;
enum { kSpecialExportsIndex, kRegularExportsIndex, kLength };
......
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