Do not look for the slot in the ScopeInfo's global range when it's not necessary.

This fixes the Runtime_DeclareGlobals performance regression caused by a huge number of global var declarations mentioned in chromium:517778.

BUG=chromium:517778
LOG=N

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

Cr-Commit-Position: refs/heads/master@{#30679}
This commit is contained in:
ishell 2015-09-10 05:54:53 -07:00 committed by Commit bot
parent 6da51b4b66
commit a1c1e2bd44
10 changed files with 83 additions and 92 deletions

View File

@ -44,10 +44,10 @@ bool ScriptContextTable::Lookup(Handle<ScriptContextTable> table,
DCHECK(context->IsScriptContext());
Handle<ScopeInfo> scope_info(context->scope_info());
int slot_index = ScopeInfo::ContextSlotIndex(
scope_info, name, &result->mode, &result->location, &result->init_flag,
scope_info, name, &result->mode, &result->init_flag,
&result->maybe_assigned_flag);
if (slot_index >= 0 && result->location == VariableLocation::CONTEXT) {
if (slot_index >= 0) {
result->context_index = i;
result->slot_index = slot_index;
return true;
@ -333,15 +333,14 @@ Handle<Object> Context::Lookup(Handle<String> name,
? context->closure()->shared()->scope_info()
: context->scope_info());
VariableMode mode;
VariableLocation location;
InitializationFlag init_flag;
// TODO(sigurds) Figure out whether maybe_assigned_flag should
// be used to compute binding_flags.
MaybeAssignedFlag maybe_assigned_flag;
int slot_index = ScopeInfo::ContextSlotIndex(
scope_info, name, &mode, &location, &init_flag, &maybe_assigned_flag);
scope_info, name, &mode, &init_flag, &maybe_assigned_flag);
DCHECK(slot_index < 0 || slot_index >= MIN_CONTEXT_SLOTS);
if (slot_index >= 0 && location == VariableLocation::CONTEXT) {
if (slot_index >= 0) {
if (FLAG_trace_contexts) {
PrintF("=> found local in context slot %d (mode = %d)\n",
slot_index, mode);

View File

@ -302,7 +302,6 @@ class ScriptContextTable : public FixedArray {
int context_index;
int slot_index;
VariableMode mode;
VariableLocation location;
InitializationFlag init_flag;
MaybeAssignedFlag maybe_assigned_flag;
};

View File

@ -280,15 +280,14 @@ Handle<Context> DebugEvaluate::ContextBuilder::MaterializeReceiver(
switch (scope_info->scope_type()) {
case FUNCTION_SCOPE: {
VariableMode mode;
VariableLocation location;
InitializationFlag init_flag;
MaybeAssignedFlag maybe_assigned_flag;
// Don't bother creating a fake context node if "this" is in the context
// already.
if (ScopeInfo::ContextSlotIndex(
scope_info, isolate_->factory()->this_string(), &mode, &location,
&init_flag, &maybe_assigned_flag) >= 0) {
if (ScopeInfo::ContextSlotIndex(scope_info,
isolate_->factory()->this_string(), &mode,
&init_flag, &maybe_assigned_flag) >= 0) {
return target;
}
receiver = handle(frame_->receiver(), isolate_);

View File

@ -180,11 +180,10 @@ void FrameInspector::UpdateStackLocalsFromMaterializedObject(
bool FrameInspector::ParameterIsShadowedByContextLocal(
Handle<ScopeInfo> info, Handle<String> parameter_name) {
VariableMode mode;
VariableLocation location;
InitializationFlag init_flag;
MaybeAssignedFlag maybe_assigned_flag;
return ScopeInfo::ContextSlotIndex(info, parameter_name, &mode, &location,
&init_flag, &maybe_assigned_flag) != -1;
return ScopeInfo::ContextSlotIndex(info, parameter_name, &mode, &init_flag,
&maybe_assigned_flag) != -1;
}

View File

@ -561,12 +561,10 @@ bool ScopeIterator::SetContextLocalValue(Handle<ScopeInfo> scope_info,
Handle<String> next_name(scope_info->ContextLocalName(i));
if (String::Equals(variable_name, next_name)) {
VariableMode mode;
VariableLocation location;
InitializationFlag init_flag;
MaybeAssignedFlag maybe_assigned_flag;
int context_index =
ScopeInfo::ContextSlotIndex(scope_info, next_name, &mode, &location,
&init_flag, &maybe_assigned_flag);
int context_index = ScopeInfo::ContextSlotIndex(
scope_info, next_name, &mode, &init_flag, &maybe_assigned_flag);
context->set(context_index, *new_value);
return true;
}

View File

@ -3898,16 +3898,25 @@ class ScopeInfo : public FixedArray {
// string.
int StackSlotIndex(String* name);
// Lookup support for serialized scope info. Returns the
// context slot index for a given slot name if the slot is present; otherwise
// Lookup support for serialized scope info. Returns the local context slot
// index for a given slot name if the slot is present; otherwise
// returns a value < 0. The name must be an internalized string.
// If the slot is present and mode != NULL, sets *mode to the corresponding
// mode for that variable.
static int ContextSlotIndex(Handle<ScopeInfo> scope_info, Handle<String> name,
VariableMode* mode, VariableLocation* location,
InitializationFlag* init_flag,
VariableMode* mode, InitializationFlag* init_flag,
MaybeAssignedFlag* maybe_assigned_flag);
// Similar to ContextSlotIndex() but this method searches only among
// global slots of the serialized scope info. Returns the context slot index
// for a given slot name if the slot is present; otherwise returns a
// value < 0. The name must be an internalized string. If the slot is present
// and mode != NULL, sets *mode to the corresponding mode for that variable.
static int ContextGlobalSlotIndex(Handle<ScopeInfo> scope_info,
Handle<String> name, VariableMode* mode,
InitializationFlag* init_flag,
MaybeAssignedFlag* maybe_assigned_flag);
// Lookup the name of a certain context slot by its index.
String* ContextSlotName(int slot_index);

View File

@ -568,13 +568,11 @@ RUNTIME_FUNCTION(Runtime_GetFrameDetails) {
if (scope_info->LocalIsSynthetic(i)) continue;
Handle<String> name(scope_info->LocalName(i));
VariableMode mode;
VariableLocation location;
InitializationFlag init_flag;
MaybeAssignedFlag maybe_assigned_flag;
locals->set(local * 2, *name);
int context_slot_index = ScopeInfo::ContextSlotIndex(
scope_info, name, &mode, &location, &init_flag, &maybe_assigned_flag);
DCHECK(VariableLocation::CONTEXT == location);
scope_info, name, &mode, &init_flag, &maybe_assigned_flag);
Object* value = context->get(context_slot_index);
locals->set(local * 2 + 1, value);
local++;

View File

@ -524,57 +524,73 @@ int ScopeInfo::StackSlotIndex(String* name) {
int ScopeInfo::ContextSlotIndex(Handle<ScopeInfo> scope_info,
Handle<String> name, VariableMode* mode,
VariableLocation* location,
InitializationFlag* init_flag,
MaybeAssignedFlag* maybe_assigned_flag) {
DCHECK(name->IsInternalizedString());
DCHECK(mode != NULL);
DCHECK(location != NULL);
DCHECK(init_flag != NULL);
if (scope_info->length() > 0) {
ContextSlotCache* context_slot_cache =
scope_info->GetIsolate()->context_slot_cache();
int result = context_slot_cache->Lookup(*scope_info, *name, mode, location,
init_flag, maybe_assigned_flag);
int result = context_slot_cache->Lookup(*scope_info, *name, mode, init_flag,
maybe_assigned_flag);
if (result != ContextSlotCache::kNotFound) {
DCHECK(result < scope_info->ContextLength());
return result;
}
DCHECK_EQ(scope_info->ContextGlobalNameEntriesIndex(),
scope_info->ContextLocalNameEntriesIndex() +
scope_info->ContextLocalCount());
int start = scope_info->ContextLocalNameEntriesIndex();
int end = scope_info->ContextGlobalNameEntriesIndex() +
scope_info->ContextGlobalCount();
int end = scope_info->ContextLocalNameEntriesIndex() +
scope_info->ContextLocalCount();
for (int i = start; i < end; ++i) {
if (*name == scope_info->get(i)) {
int var = i - start;
*mode = scope_info->ContextLocalMode(var);
*init_flag = scope_info->ContextLocalInitFlag(var);
*maybe_assigned_flag = scope_info->ContextLocalMaybeAssignedFlag(var);
result = Context::MIN_CONTEXT_SLOTS + var;
if (var < scope_info->ContextLocalCount()) {
*location = VariableLocation::CONTEXT;
result = Context::MIN_CONTEXT_SLOTS + var;
} else {
var -= scope_info->ContextLocalCount();
*location = VariableLocation::GLOBAL;
result = Context::MIN_CONTEXT_SLOTS +
scope_info->ContextLocalCount() + var;
}
context_slot_cache->Update(scope_info, name, *mode, *location,
*init_flag, *maybe_assigned_flag, result);
context_slot_cache->Update(scope_info, name, *mode, *init_flag,
*maybe_assigned_flag, result);
DCHECK(result < scope_info->ContextLength());
return result;
}
}
// Cache as not found. Mode, location, init flag and maybe assigned flag
// don't matter.
// Cache as not found. Mode, init flag and maybe assigned flag don't matter.
context_slot_cache->Update(scope_info, name, TEMPORARY,
VariableLocation::CONTEXT, kNeedsInitialization,
kNotAssigned, -1);
kNeedsInitialization, kNotAssigned, -1);
}
return -1;
}
int ScopeInfo::ContextGlobalSlotIndex(Handle<ScopeInfo> scope_info,
Handle<String> name, VariableMode* mode,
InitializationFlag* init_flag,
MaybeAssignedFlag* maybe_assigned_flag) {
DCHECK(name->IsInternalizedString());
DCHECK(mode != NULL);
DCHECK(init_flag != NULL);
if (scope_info->length() > 0) {
// This is to ensure that ContextLocalMode() and co. queries would work.
DCHECK_EQ(scope_info->ContextGlobalNameEntriesIndex(),
scope_info->ContextLocalNameEntriesIndex() +
scope_info->ContextLocalCount());
int base = scope_info->ContextLocalNameEntriesIndex();
int start = scope_info->ContextGlobalNameEntriesIndex();
int end = scope_info->ContextGlobalNameEntriesIndex() +
scope_info->ContextGlobalCount();
for (int i = start; i < end; ++i) {
if (*name == scope_info->get(i)) {
int var = i - base;
*mode = scope_info->ContextLocalMode(var);
*init_flag = scope_info->ContextLocalInitFlag(var);
*maybe_assigned_flag = scope_info->ContextLocalMaybeAssignedFlag(var);
int result = Context::MIN_CONTEXT_SLOTS + var;
DCHECK(result < scope_info->ContextLength());
return result;
}
}
}
return -1;
}
@ -701,7 +717,6 @@ int ContextSlotCache::Hash(Object* data, String* name) {
int ContextSlotCache::Lookup(Object* data, String* name, VariableMode* mode,
VariableLocation* location,
InitializationFlag* init_flag,
MaybeAssignedFlag* maybe_assigned_flag) {
int index = Hash(data, name);
@ -709,7 +724,6 @@ int ContextSlotCache::Lookup(Object* data, String* name, VariableMode* mode,
if ((key.data == data) && key.name->Equals(name)) {
Value result(values_[index]);
if (mode != NULL) *mode = result.mode();
if (location != NULL) *location = result.location();
if (init_flag != NULL) *init_flag = result.initialization_flag();
if (maybe_assigned_flag != NULL)
*maybe_assigned_flag = result.maybe_assigned_flag();
@ -720,8 +734,7 @@ int ContextSlotCache::Lookup(Object* data, String* name, VariableMode* mode,
void ContextSlotCache::Update(Handle<Object> data, Handle<String> name,
VariableMode mode, VariableLocation location,
InitializationFlag init_flag,
VariableMode mode, InitializationFlag init_flag,
MaybeAssignedFlag maybe_assigned_flag,
int slot_index) {
DisallowHeapAllocation no_gc;
@ -734,11 +747,10 @@ void ContextSlotCache::Update(Handle<Object> data, Handle<String> name,
key.data = *data;
key.name = *internalized_name;
// Please note value only takes a uint as index.
values_[index] = Value(mode, location, init_flag, maybe_assigned_flag,
values_[index] = Value(mode, init_flag, maybe_assigned_flag,
slot_index - kNotFound).raw();
#ifdef DEBUG
ValidateEntry(data, name, mode, location, init_flag, maybe_assigned_flag,
slot_index);
ValidateEntry(data, name, mode, init_flag, maybe_assigned_flag, slot_index);
#endif
}
}
@ -753,7 +765,6 @@ void ContextSlotCache::Clear() {
void ContextSlotCache::ValidateEntry(Handle<Object> data, Handle<String> name,
VariableMode mode,
VariableLocation location,
InitializationFlag init_flag,
MaybeAssignedFlag maybe_assigned_flag,
int slot_index) {
@ -767,7 +778,6 @@ void ContextSlotCache::ValidateEntry(Handle<Object> data, Handle<String> name,
DCHECK(key.name->Equals(*name));
Value result(values_[index]);
DCHECK(result.mode() == mode);
DCHECK(result.location() == location);
DCHECK(result.initialization_flag() == init_flag);
DCHECK(result.maybe_assigned_flag() == maybe_assigned_flag);
DCHECK(result.index() + kNotFound == slot_index);

View File

@ -21,12 +21,12 @@ class ContextSlotCache {
// Lookup context slot index for (data, name).
// If absent, kNotFound is returned.
int Lookup(Object* data, String* name, VariableMode* mode,
VariableLocation* location, InitializationFlag* init_flag,
InitializationFlag* init_flag,
MaybeAssignedFlag* maybe_assigned_flag);
// Update an element in the cache.
void Update(Handle<Object> data, Handle<String> name, VariableMode mode,
VariableLocation location, InitializationFlag init_flag,
InitializationFlag init_flag,
MaybeAssignedFlag maybe_assigned_flag, int slot_index);
// Clear the cache.
@ -47,8 +47,7 @@ class ContextSlotCache {
#ifdef DEBUG
void ValidateEntry(Handle<Object> data, Handle<String> name,
VariableMode mode, VariableLocation location,
InitializationFlag init_flag,
VariableMode mode, InitializationFlag init_flag,
MaybeAssignedFlag maybe_assigned_flag, int slot_index);
#endif
@ -59,26 +58,16 @@ class ContextSlotCache {
};
struct Value {
enum VariableLocationFlag { kContext, kGlobal };
Value(VariableMode mode, VariableLocation location,
InitializationFlag init_flag, MaybeAssignedFlag maybe_assigned_flag,
int index) {
DCHECK(location == VariableLocation::CONTEXT ||
location == VariableLocation::GLOBAL);
VariableLocationFlag location_flag =
location == VariableLocation::CONTEXT ? kContext : kGlobal;
Value(VariableMode mode, InitializationFlag init_flag,
MaybeAssignedFlag maybe_assigned_flag, int index) {
DCHECK(ModeField::is_valid(mode));
DCHECK(VariableLocationField::is_valid(location_flag));
DCHECK(InitField::is_valid(init_flag));
DCHECK(MaybeAssignedField::is_valid(maybe_assigned_flag));
DCHECK(IndexField::is_valid(index));
value_ = ModeField::encode(mode) | IndexField::encode(index) |
VariableLocationField::encode(location_flag) |
InitField::encode(init_flag) |
MaybeAssignedField::encode(maybe_assigned_flag);
DCHECK(mode == this->mode());
DCHECK(location == this->location());
DCHECK(init_flag == this->initialization_flag());
DCHECK(maybe_assigned_flag == this->maybe_assigned_flag());
DCHECK(index == this->index());
@ -90,17 +79,6 @@ class ContextSlotCache {
VariableMode mode() { return ModeField::decode(value_); }
VariableLocation location() {
switch (VariableLocationField::decode(value_)) {
case kContext:
return VariableLocation::CONTEXT;
case kGlobal:
return VariableLocation::GLOBAL;
}
UNREACHABLE();
return VariableLocation::CONTEXT;
}
InitializationFlag initialization_flag() {
return InitField::decode(value_);
}
@ -116,9 +94,7 @@ class ContextSlotCache {
class ModeField : public BitField<VariableMode, 0, 4> {};
class InitField : public BitField<InitializationFlag, 4, 1> {};
class MaybeAssignedField : public BitField<MaybeAssignedFlag, 5, 1> {};
class VariableLocationField : public BitField<VariableLocationFlag, 6, 1> {
};
class IndexField : public BitField<int, 7, 32 - 7> {};
class IndexField : public BitField<int, 6, 32 - 6> {};
private:
uint32_t value_;

View File

@ -394,12 +394,16 @@ Variable* Scope::LookupLocal(const AstRawString* name) {
// Check context slot lookup.
VariableMode mode;
VariableLocation location;
VariableLocation location = VariableLocation::CONTEXT;
InitializationFlag init_flag;
MaybeAssignedFlag maybe_assigned_flag;
int index =
ScopeInfo::ContextSlotIndex(scope_info_, name_handle, &mode, &location,
&init_flag, &maybe_assigned_flag);
int index = ScopeInfo::ContextSlotIndex(scope_info_, name_handle, &mode,
&init_flag, &maybe_assigned_flag);
if (index < 0) {
location = VariableLocation::GLOBAL;
index = ScopeInfo::ContextGlobalSlotIndex(scope_info_, name_handle, &mode,
&init_flag, &maybe_assigned_flag);
}
if (index < 0) {
// Check parameters.
index = scope_info_->ParameterIndex(*name_handle);