[runtime] Use NameToIndexHashTable in ScopeInfo

- It changes ContextSlotIndex from static to non-static.
- Updates ContextSlotIndex and ScriptContextTable::Lookup to use
  handles, since it is necessary for the NameToIndexHashTable::Add
- Adds a NameToIndexHashTableLookup to CSA.
- Renames LocalNamesIterator to LocalNamesRange and iterates the
  hashtable when local names are not inlined.

Bug: v8:12315
Change-Id: I2c8c933002fe73f4def145bc207825823262d743
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3406751
Reviewed-by: Toon Verwaest <verwaest@chromium.org>
Reviewed-by: Igor Sheludko <ishell@chromium.org>
Commit-Queue: Victor Gomes <victorgomes@chromium.org>
Cr-Commit-Position: refs/heads/main@{#78818}
This commit is contained in:
Victor Gomes 2022-01-27 18:37:10 +01:00 committed by V8 LUCI CQ
parent e7ffb2570c
commit 94c490f795
22 changed files with 262 additions and 111 deletions

View File

@ -257,11 +257,9 @@ Scope::Scope(Zone* zone, ScopeType scope_type,
if (scope_type == BLOCK_SCOPE) {
// Set is_block_scope_for_object_literal_ based on the existince of the home
// object variable (we don't store it explicitly).
VariableLookupResult lookup_result;
DCHECK_NOT_NULL(ast_value_factory);
int home_object_index = ScopeInfo::ContextSlotIndex(
*scope_info, *(ast_value_factory->dot_home_object_string()->string()),
&lookup_result);
int home_object_index = scope_info->ContextSlotIndex(
ast_value_factory->dot_home_object_string()->string());
DCHECK_IMPLIES(home_object_index >= 0,
scope_type == CLASS_SCOPE || scope_type == BLOCK_SCOPE);
if (home_object_index >= 0) {
@ -961,8 +959,7 @@ Variable* Scope::LookupInScopeInfo(const AstRawString* name, Scope* cache) {
{
location = VariableLocation::CONTEXT;
index =
ScopeInfo::ContextSlotIndex(scope_info, name_handle, &lookup_result);
index = scope_info.ContextSlotIndex(name->string(), &lookup_result);
found = index >= 0;
}
@ -2727,8 +2724,7 @@ VariableProxy* Scope::NewHomeObjectVariableProxy(AstNodeFactory* factory,
Variable* home_object = variables_.Lookup(name);
if (home_object == nullptr) {
VariableLookupResult lookup_result;
int index = ScopeInfo::ContextSlotIndex(*scope_info_, *name->string(),
&lookup_result);
int index = scope_info_->ContextSlotIndex(name->string(), &lookup_result);
DCHECK_GE(index, 0);
bool was_added;
home_object = variables_.Declare(zone(), this, name, lookup_result.mode,
@ -2889,10 +2885,8 @@ Variable* ClassScope::LookupPrivateNameInScopeInfo(const AstRawString* name) {
DCHECK_NULL(LookupLocalPrivateName(name));
DisallowGarbageCollection no_gc;
String name_handle = *name->string();
VariableLookupResult lookup_result;
int index =
ScopeInfo::ContextSlotIndex(*scope_info_, name_handle, &lookup_result);
int index = scope_info_->ContextSlotIndex(name->string(), &lookup_result);
if (index < 0) {
return nullptr;
}

View File

@ -8522,12 +8522,34 @@ TNode<HeapObject> CodeStubAssembler::LoadName<GlobalDictionary>(
return CAST(LoadObjectField(property_cell, PropertyCell::kNameOffset));
}
template <>
TNode<HeapObject> CodeStubAssembler::LoadName<NameToIndexHashTable>(
TNode<HeapObject> key) {
CSA_DCHECK(this, IsName(key));
return key;
}
// The implementation should be in sync with NameToIndexHashTable::Lookup.
TNode<IntPtrT> CodeStubAssembler::NameToIndexHashTableLookup(
TNode<NameToIndexHashTable> table, TNode<Name> name, Label* not_found) {
TVARIABLE(IntPtrT, var_entry);
Label index_found(this, {&var_entry});
NameDictionaryLookup<NameToIndexHashTable>(table, name, &index_found,
&var_entry, not_found,
LookupMode::kFindExisting);
BIND(&index_found);
TNode<Smi> value =
CAST(LoadValueByKeyIndex<NameToIndexHashTable>(table, var_entry.value()));
return SmiToIntPtr(value);
}
template <typename Dictionary>
void CodeStubAssembler::NameDictionaryLookup(
TNode<Dictionary> dictionary, TNode<Name> unique_name, Label* if_found,
TVariable<IntPtrT>* var_name_index, Label* if_not_found, LookupMode mode) {
static_assert(std::is_same<Dictionary, NameDictionary>::value ||
std::is_same<Dictionary, GlobalDictionary>::value,
std::is_same<Dictionary, GlobalDictionary>::value ||
std::is_same<Dictionary, NameToIndexHashTable>::value,
"Unexpected NameDictionary");
DCHECK_EQ(MachineType::PointerRepresentation(), var_name_index->rep());
DCHECK_IMPLIES(mode == kFindInsertionIndex, if_found == nullptr);

View File

@ -3024,6 +3024,9 @@ class V8_EXPORT_PRIVATE CodeStubAssembler
// Calculate a valid size for the a hash table.
TNode<IntPtrT> HashTableComputeCapacity(TNode<IntPtrT> at_least_space_for);
TNode<IntPtrT> NameToIndexHashTableLookup(TNode<NameToIndexHashTable> table,
TNode<Name> name, Label* not_found);
template <class Dictionary>
TNode<Smi> GetNumberOfElements(TNode<Dictionary> dictionary);

View File

@ -94,9 +94,7 @@ bool FrameInspector::IsJavaScript() { return frame_->is_java_script(); }
bool FrameInspector::ParameterIsShadowedByContextLocal(
Handle<ScopeInfo> info, Handle<String> parameter_name) {
VariableLookupResult lookup_result;
return ScopeInfo::ContextSlotIndex(*info, *parameter_name, &lookup_result) !=
-1;
return info->ContextSlotIndex(parameter_name) != -1;
}
RedirectActiveFunctions::RedirectActiveFunctions(SharedFunctionInfo shared,

View File

@ -1062,11 +1062,8 @@ bool ScopeIterator::SetContextExtensionValue(Handle<String> variable_name,
bool ScopeIterator::SetContextVariableValue(Handle<String> variable_name,
Handle<Object> new_value) {
VariableLookupResult lookup_result;
int slot_index = ScopeInfo::ContextSlotIndex(context_->scope_info(),
*variable_name, &lookup_result);
int slot_index = context_->scope_info().ContextSlotIndex(variable_name);
if (slot_index < 0) return false;
context_->set(slot_index, *new_value);
return true;
}
@ -1098,8 +1095,7 @@ bool ScopeIterator::SetScriptVariableValue(Handle<String> variable_name,
context_->global_object().native_context().script_context_table(),
isolate_);
VariableLookupResult lookup_result;
if (ScriptContextTable::Lookup(isolate_, *script_contexts, *variable_name,
&lookup_result)) {
if (script_contexts->Lookup(variable_name, &lookup_result)) {
Handle<Context> script_context = ScriptContextTable::GetContext(
isolate_, script_contexts, lookup_result.context_index);
script_context->set(lookup_result.slot_index, *new_value);

View File

@ -101,10 +101,8 @@ v8::MaybeLocal<v8::Value> DebugStackTraceIterator::GetReceiver() const {
return v8::MaybeLocal<v8::Value>();
}
DisallowGarbageCollection no_gc;
VariableLookupResult lookup_result;
int slot_index = ScopeInfo::ContextSlotIndex(
context->scope_info(), ReadOnlyRoots(isolate_->heap()).this_string(),
&lookup_result);
int slot_index = context->scope_info().ContextSlotIndex(
ReadOnlyRoots(isolate_).this_string_handle());
if (slot_index < 0) return v8::MaybeLocal<v8::Value>();
Handle<Object> value = handle(context->get(slot_index), isolate_);
if (value->IsTheHole(isolate_)) return v8::MaybeLocal<v8::Value>();

View File

@ -2355,13 +2355,12 @@ void JSSegments::JSSegmentsPrint(std::ostream& os) {
namespace {
void PrintScopeInfoList(ScopeInfo scope_info, std::ostream& os,
const char* list_name, int length) {
DisallowGarbageCollection no_gc;
if (length <= 0) return;
os << "\n - " << list_name;
os << " {\n";
for (int i = 0; i < length; ++i) {
os << " - " << i << ": ";
scope_info.context_local_names(i).ShortPrint(os);
os << "\n";
for (auto it : ScopeInfo::IterateLocalNames(&scope_info, no_gc)) {
os << " - " << it->index() << ": " << it->name() << "\n";
}
os << " }";
}
@ -2377,6 +2376,12 @@ void ScopeInfo::ScopeInfoPrint(std::ostream& os) {
os << "\n - parameters: " << ParameterCount();
os << "\n - context locals : " << ContextLocalCount();
if (HasInlinedLocalNames()) {
os << "\n - inlined local names";
} else {
os << "\n - local names in a hashtable: "
<< Brief(context_local_names_hashtable());
}
os << "\n - scope type: " << scope_type();
if (SloppyEvalCanExtendVars()) os << "\n - sloppy eval";

View File

@ -211,7 +211,7 @@ MaybeHandle<Context> NewScriptContext(Isolate* isolate,
Handle<String> name(it->name(), isolate);
VariableMode mode = scope_info->ContextLocalMode(it->index());
VariableLookupResult lookup;
if (ScriptContextTable::Lookup(isolate, *script_context, *name, &lookup)) {
if (script_context->Lookup(name, &lookup)) {
if (IsLexicalVariableMode(mode) || IsLexicalVariableMode(lookup.mode)) {
Handle<Context> context = ScriptContextTable::GetContext(
isolate, script_context, lookup.context_index);

View File

@ -531,8 +531,7 @@ MaybeHandle<Object> LoadGlobalIC::Load(Handle<Name> name,
global->native_context().script_context_table(), isolate());
VariableLookupResult lookup_result;
if (ScriptContextTable::Lookup(isolate(), *script_contexts, *str_name,
&lookup_result)) {
if (script_contexts->Lookup(str_name, &lookup_result)) {
Handle<Context> script_context = ScriptContextTable::GetContext(
isolate(), script_contexts, lookup_result.context_index);
@ -1696,8 +1695,7 @@ MaybeHandle<Object> StoreGlobalIC::Store(Handle<Name> name,
global->native_context().script_context_table(), isolate());
VariableLookupResult lookup_result;
if (ScriptContextTable::Lookup(isolate(), *script_contexts, *str_name,
&lookup_result)) {
if (script_contexts->Lookup(str_name, &lookup_result)) {
Handle<Context> script_context = ScriptContextTable::GetContext(
isolate(), script_contexts, lookup_result.context_index);
if (lookup_result.mode == VariableMode::kConst) {
@ -2956,8 +2954,7 @@ RUNTIME_FUNCTION(Runtime_StoreGlobalIC_Slow) {
native_context->script_context_table(), isolate);
VariableLookupResult lookup_result;
if (ScriptContextTable::Lookup(isolate, *script_contexts, *name,
&lookup_result)) {
if (script_contexts->Lookup(name, &lookup_result)) {
Handle<Context> script_context = ScriptContextTable::GetContext(
isolate, script_contexts, lookup_result.context_index);
if (lookup_result.mode == VariableMode::kConst) {

View File

@ -46,16 +46,14 @@ void Context::Initialize(Isolate* isolate) {
}
}
bool ScriptContextTable::Lookup(Isolate* isolate, ScriptContextTable table,
String name, VariableLookupResult* result) {
bool ScriptContextTable::Lookup(Handle<String> name,
VariableLookupResult* result) {
DisallowGarbageCollection no_gc;
// Static variables cannot be in script contexts.
for (int i = 0; i < table.used(kAcquireLoad); i++) {
Context context = table.get_context(i);
for (int i = 0; i < used(kAcquireLoad); i++) {
Context context = get_context(i);
DCHECK(context.IsScriptContext());
int slot_index =
ScopeInfo::ContextSlotIndex(context.scope_info(), name, result);
int slot_index = context.scope_info().ContextSlotIndex(name, result);
if (slot_index >= 0) {
result->context_index = i;
result->slot_index = slot_index;
@ -217,7 +215,7 @@ Handle<Object> Context::Lookup(Handle<Context> context, Handle<String> name,
ScriptContextTable script_contexts =
context->global_object().native_context().script_context_table();
VariableLookupResult r;
if (ScriptContextTable::Lookup(isolate, script_contexts, *name, &r)) {
if (script_contexts.Lookup(name, &r)) {
Context script_context = script_contexts.get_context(r.context_index);
if (FLAG_trace_contexts) {
PrintF("=> found property in script context %d: %p\n",
@ -286,8 +284,7 @@ Handle<Object> Context::Lookup(Handle<Context> context, Handle<String> name,
// for the context index.
ScopeInfo scope_info = context->scope_info();
VariableLookupResult lookup_result;
int slot_index =
ScopeInfo::ContextSlotIndex(scope_info, *name, &lookup_result);
int slot_index = scope_info.ContextSlotIndex(name, &lookup_result);
DCHECK(slot_index < 0 || slot_index >= MIN_CONTEXT_SLOTS);
if (slot_index >= 0) {
// Re-direct lookup to the ScriptContextTable in case we find a hole in

View File

@ -391,9 +391,8 @@ class ScriptContextTable : public FixedArray {
// valid information about its location.
// If it returns false, `result` is untouched.
V8_WARN_UNUSED_RESULT
V8_EXPORT_PRIVATE static bool Lookup(Isolate* isolate,
ScriptContextTable table, String name,
VariableLookupResult* result);
V8_EXPORT_PRIVATE bool Lookup(Handle<String> name,
VariableLookupResult* result);
V8_WARN_UNUSED_RESULT
V8_EXPORT_PRIVATE static Handle<ScriptContextTable> Extend(

View File

@ -453,10 +453,14 @@ class NameToIndexShape : public BaseShape<Handle<Name>> {
class V8_EXPORT_PRIVATE NameToIndexHashTable
: public HashTable<NameToIndexHashTable, NameToIndexShape> {
public:
static const int kEntryValueIndex = NameToIndexShape::kEntryValueIndex;
inline static Handle<Map> GetMap(ReadOnlyRoots roots);
int32_t Lookup(Handle<Name> key);
int Lookup(Handle<Name> key);
// Returns the value at entry.
Object ValueAt(InternalIndex entry);
int IndexAt(InternalIndex entry);
template <typename IsolateT>
static Handle<NameToIndexHashTable> Add(IsolateT* isolate,

View File

@ -58,6 +58,10 @@ class InternalIndex {
return *this;
}
bool operator<(const InternalIndex& other) const {
return entry_ < other.entry_;
}
class Range {
public:
explicit Range(size_t max) : min_(0), max_(max) {}

View File

@ -6226,7 +6226,9 @@ Object ObjectHashTableBase<Derived, Shape>::Lookup(PtrComprCageBase cage_base,
return this->get(Derived::EntryToIndex(entry) + 1);
}
int32_t NameToIndexHashTable::Lookup(Handle<Name> key) {
// The implementation should be in sync with
// CodeStubAssembler::NameToIndexHashTableLookup.
int NameToIndexHashTable::Lookup(Handle<Name> key) {
DisallowGarbageCollection no_gc;
PtrComprCageBase cage_base = GetPtrComprCageBase(*this);
ReadOnlyRoots roots = this->GetReadOnlyRoots(cage_base);
@ -6267,6 +6269,16 @@ Object NameToIndexHashTable::ValueAt(InternalIndex entry) {
return this->get(EntryToValueIndex(entry));
}
int NameToIndexHashTable::IndexAt(InternalIndex entry) {
Object value = ValueAt(entry);
if (value.IsSmi()) {
int index = Smi::ToInt(value);
DCHECK_LE(0, index);
return index;
}
return -1;
}
template <typename Derived, typename Shape>
Handle<Derived> ObjectHashTableBase<Derived, Shape>::Put(Handle<Derived> table,
Handle<Object> key,

View File

@ -9,6 +9,7 @@
#include "src/objects/fixed-array-inl.h"
#include "src/objects/scope-info.h"
#include "src/objects/string.h"
#include "src/roots/roots-inl.h"
// Has to be the last include (doesn't have include guards):
#include "src/objects/object-macros.h"
@ -37,63 +38,102 @@ bool ScopeInfo::HasInlinedLocalNames() const {
}
template <typename ScopeInfoPtr>
class ScopeInfo::LocalNamesIterator {
class ScopeInfo::LocalNamesRange {
public:
class Iterator {
public:
Iterator(ScopeInfoPtr scope_info, int index)
: scope_info_(scope_info), index_(index) {}
Iterator(const LocalNamesRange* range, InternalIndex index)
: range_(range), index_(index) {
DCHECK_NOT_NULL(range);
if (!range_->inlined()) advance_hashtable_index();
}
Iterator& operator++() {
index_++;
DCHECK_LT(index_, range_->max_index());
++index_;
if (range_->inlined()) return *this;
advance_hashtable_index();
return *this;
}
friend bool operator==(const Iterator& a, const Iterator& b) {
return *a.scope_info_ == *b.scope_info_ && a.index_ == b.index_;
return a.range_ == b.range_ && a.index_ == b.index_;
}
friend bool operator!=(const Iterator& a, const Iterator& b) {
return !(a == b);
}
String name() const {
DCHECK_LT(index_, scope_info_->context_local_count());
return scope_info_->context_local_names(index_);
DCHECK_LT(index_, range_->max_index());
if (range_->inlined()) {
return scope_info()->ContextInlinedLocalName(index_.as_int());
}
return String::cast(table().KeyAt(index_));
}
const Iterator* operator*() const { return this; }
int index() const { return index_; }
int index() const {
if (range_->inlined()) return index_.as_int();
return table().IndexAt(index_);
}
private:
ScopeInfoPtr scope_info_;
int index_;
const LocalNamesRange* range_;
InternalIndex index_;
ScopeInfoPtr scope_info() const { return range_->scope_info_; }
NameToIndexHashTable table() const {
return scope_info()->context_local_names_hashtable();
}
void advance_hashtable_index() {
DisallowGarbageCollection no_gc;
ReadOnlyRoots roots = scope_info()->GetReadOnlyRoots();
InternalIndex max = range_->max_index();
// Increment until iterator points to a valid key or max.
while (index_ < max) {
Object key = table().KeyAt(index_);
if (table().IsKey(roots, key)) break;
++index_;
}
}
friend class LocalNamesRange;
};
explicit LocalNamesIterator(ScopeInfoPtr scope_info)
: scope_info_(scope_info) {}
bool inlined() const { return scope_info_->HasInlinedLocalNames(); }
inline Iterator begin() const { return Iterator(scope_info_, 0); }
inline Iterator end() const {
return Iterator(scope_info_, scope_info_->ContextLocalCount());
InternalIndex max_index() const {
int max = inlined()
? scope_info_->ContextLocalCount()
: scope_info_->context_local_names_hashtable().Capacity();
return InternalIndex(max);
}
explicit LocalNamesRange(ScopeInfoPtr scope_info) : scope_info_(scope_info) {}
inline Iterator begin() const { return Iterator(this, InternalIndex(0)); }
inline Iterator end() const { return Iterator(this, max_index()); }
private:
ScopeInfoPtr scope_info_;
};
// static
ScopeInfo::LocalNamesIterator<Handle<ScopeInfo>> ScopeInfo::IterateLocalNames(
ScopeInfo::LocalNamesRange<Handle<ScopeInfo>> ScopeInfo::IterateLocalNames(
Handle<ScopeInfo> scope_info) {
return LocalNamesIterator<Handle<ScopeInfo>>(scope_info);
return LocalNamesRange<Handle<ScopeInfo>>(scope_info);
}
// static
ScopeInfo::LocalNamesIterator<ScopeInfo*> ScopeInfo::IterateLocalNames(
ScopeInfo::LocalNamesRange<ScopeInfo*> ScopeInfo::IterateLocalNames(
ScopeInfo* scope_info, const DisallowGarbageCollection& no_gc) {
USE(no_gc);
return LocalNamesIterator<ScopeInfo*>(scope_info);
return LocalNamesRange<ScopeInfo*>(scope_info);
}
} // namespace internal

View File

@ -102,6 +102,11 @@ Handle<ScopeInfo> ScopeInfo::Create(IsolateT* isolate, Zone* zone, Scope* scope,
// Make sure we allocate the correct amount.
DCHECK_EQ(scope->ContextLocalCount(), context_local_count);
// If the number of locals is small, we inline directly
// in the scope info object.
bool has_inlined_local_names =
context_local_count < kScopeInfoMaxInlinedLocalNamesSize;
const bool has_new_target =
scope->is_declaration_scope() &&
scope->AsDeclarationScope()->new_target_var() != nullptr;
@ -161,7 +166,11 @@ Handle<ScopeInfo> ScopeInfo::Create(IsolateT* isolate, Zone* zone, Scope* scope,
FOR_EACH_SCOPE_INFO_NUMERIC_FIELD(ASSERT_MATCHED_FIELD)
#undef ASSERT_MATCHED_FIELD
const int length = kVariablePartIndex + 2 * context_local_count +
const int local_names_container_size =
has_inlined_local_names ? context_local_count : 1;
const int length = kVariablePartIndex + local_names_container_size +
context_local_count +
(should_save_class_variable_index ? 1 : 0) +
(has_function_name ? kFunctionNameEntries : 0) +
(has_inferred_function_name ? 1 : 0) +
@ -171,6 +180,13 @@ Handle<ScopeInfo> ScopeInfo::Create(IsolateT* isolate, Zone* zone, Scope* scope,
? 2 + kModuleVariableEntryLength * module_vars_count
: 0);
// Create hash table if local names are not inlined.
Handle<NameToIndexHashTable> local_names_hashtable;
if (!has_inlined_local_names) {
local_names_hashtable = NameToIndexHashTable::New(
isolate, context_local_count, AllocationType::kOld);
}
Handle<ScopeInfo> scope_info_handle =
isolate->factory()->NewScopeInfo(length);
int index = kVariablePartIndex;
@ -230,11 +246,15 @@ Handle<ScopeInfo> ScopeInfo::Create(IsolateT* isolate, Zone* zone, Scope* scope,
if (scope->is_module_scope()) {
scope_info.set_module_variable_count(module_vars_count);
}
if (!has_inlined_local_names) {
scope_info.set_context_local_names_hashtable(*local_names_hashtable);
}
// Add context locals' names and info, module variables' names and info.
// Context locals are added using their index.
int context_local_base = index;
int context_local_info_base = context_local_base + context_local_count;
int context_local_info_base =
context_local_base + local_names_container_size;
int module_var_entry = scope_info.ModuleVariableCountIndex() + 1;
for (Variable* var : *scope->locals()) {
@ -252,7 +272,14 @@ Handle<ScopeInfo> ScopeInfo::Create(IsolateT* isolate, Zone* zone, Scope* scope,
MaybeAssignedFlagBit::encode(var->maybe_assigned()) |
ParameterNumberBits::encode(ParameterNumberBits::kMax) |
IsStaticFlagBit::encode(var->is_static_flag());
scope_info.set(context_local_base + local_index, *var->name(), mode);
if (has_inlined_local_names) {
scope_info.set(context_local_base + local_index, *var->name(),
mode);
} else {
Handle<NameToIndexHashTable> new_table = NameToIndexHashTable::Add(
isolate, local_names_hashtable, var->name(), local_index);
DCHECK_EQ(*new_table, *local_names_hashtable);
}
scope_info.set(context_local_info_base + local_index,
Smi::FromInt(info));
break;
@ -305,7 +332,8 @@ Handle<ScopeInfo> ScopeInfo::Create(IsolateT* isolate, Zone* zone, Scope* scope,
}
}
index += 2 * context_local_count;
// Advance past local names and local names info.
index += local_names_container_size + context_local_count;
DCHECK_EQ(index, scope_info.SavedClassVariableInfoIndex());
// If the scope is a class scope and has used static private methods, save
@ -314,7 +342,15 @@ Handle<ScopeInfo> ScopeInfo::Create(IsolateT* isolate, Zone* zone, Scope* scope,
if (should_save_class_variable_index) {
Variable* class_variable = scope->AsClassScope()->class_variable();
DCHECK_EQ(class_variable->location(), VariableLocation::CONTEXT);
scope_info.set(index++, Smi::FromInt(class_variable->index()));
int local_index;
if (has_inlined_local_names) {
local_index = class_variable->index();
} else {
Handle<Name> name = class_variable->name();
InternalIndex entry = local_names_hashtable->FindEntry(isolate, name);
local_index = entry.as_int();
}
scope_info.set(index++, Smi::FromInt(local_index));
}
// If present, add the function variable name and its index.
@ -451,6 +487,8 @@ Handle<ScopeInfo> ScopeInfo::CreateForBootstrapping(Isolate* isolate,
is_empty_function || is_native_context ? 0 : 1;
const bool has_inferred_function_name = is_empty_function;
const bool has_position_info = true;
// NOTE: Local names are always inlined here, since context_local_count < 2.
DCHECK_LT(context_local_count, kScopeInfoMaxInlinedLocalNamesSize);
const int length = kVariablePartIndex + 2 * context_local_count +
(is_empty_function ? kFunctionNameEntries : 0) +
(has_inferred_function_name ? 1 : 0) +
@ -888,35 +926,47 @@ int ScopeInfo::ModuleIndex(String name, VariableMode* mode,
return 0;
}
// static
int ScopeInfo::ContextSlotIndex(ScopeInfo scope_info, String name,
int ScopeInfo::InlinedLocalNamesLookup(String name) {
int local_count = context_local_count();
for (int i = 0; i < local_count; ++i) {
if (name == ContextInlinedLocalName(i)) {
return i;
}
}
return -1;
}
int ScopeInfo::ContextSlotIndex(Handle<String> name,
VariableLookupResult* lookup_result) {
DisallowGarbageCollection no_gc;
DCHECK(name.IsInternalizedString());
DCHECK(name->IsInternalizedString());
DCHECK_NOT_NULL(lookup_result);
if (scope_info.IsEmpty()) return -1;
if (IsEmpty()) return -1;
int context_local_count = scope_info.context_local_count();
for (int var = 0; var < context_local_count; ++var) {
if (name != scope_info.context_local_names(var)) {
continue;
}
lookup_result->mode = scope_info.ContextLocalMode(var);
lookup_result->is_static_flag = scope_info.ContextLocalIsStaticFlag(var);
lookup_result->init_flag = scope_info.ContextLocalInitFlag(var);
lookup_result->maybe_assigned_flag =
scope_info.ContextLocalMaybeAssignedFlag(var);
lookup_result->is_repl_mode = scope_info.IsReplModeScope();
int result = scope_info.ContextHeaderLength() + var;
int index = HasInlinedLocalNames()
? InlinedLocalNamesLookup(*name)
: context_local_names_hashtable().Lookup(name);
DCHECK_LT(result, scope_info.ContextLength());
return result;
if (index != -1) {
lookup_result->mode = ContextLocalMode(index);
lookup_result->is_static_flag = ContextLocalIsStaticFlag(index);
lookup_result->init_flag = ContextLocalInitFlag(index);
lookup_result->maybe_assigned_flag = ContextLocalMaybeAssignedFlag(index);
lookup_result->is_repl_mode = IsReplModeScope();
int context_slot = ContextHeaderLength() + index;
DCHECK_LT(context_slot, ContextLength());
return context_slot;
}
return -1;
}
int ScopeInfo::ContextSlotIndex(Handle<String> name) {
VariableLookupResult lookup_result;
return ContextSlotIndex(name, &lookup_result);
}
std::pair<String, int> ScopeInfo::SavedClassVariable() const {
DCHECK(HasSavedClassVariableBit::decode(Flags()));
if (HasInlinedLocalNames()) {
@ -929,8 +979,11 @@ std::pair<String, int> ScopeInfo::SavedClassVariable() const {
} else {
// The saved class variable info corresponds to the offset in the hash
// table storage.
// TODO(victorgomes, v8:12315): Implement this once we have a hash table.
UNREACHABLE();
InternalIndex entry(saved_class_variable_info());
NameToIndexHashTable table = context_local_names_hashtable();
Object name = table.KeyAt(entry);
DCHECK(name.IsString());
return std::make_pair(String::cast(name), table.IndexAt(entry));
}
}

View File

@ -19,6 +19,9 @@
namespace v8 {
namespace internal {
// scope-info-tq.inc uses NameToIndexHashTable.
class NameToIndexHashTable;
#include "torque-generated/src/objects/scope-info-tq.inc"
template <typename T>
@ -144,12 +147,12 @@ class ScopeInfo : public TorqueGeneratedScopeInfo<ScopeInfo, HeapObject> {
inline bool HasInlinedLocalNames() const;
template <typename ScopeInfoPtr>
class LocalNamesIterator;
class LocalNamesRange;
static inline LocalNamesIterator<Handle<ScopeInfo>> IterateLocalNames(
static inline LocalNamesRange<Handle<ScopeInfo>> IterateLocalNames(
Handle<ScopeInfo> scope_info);
static inline LocalNamesIterator<ScopeInfo*> IterateLocalNames(
static inline LocalNamesRange<ScopeInfo*> IterateLocalNames(
ScopeInfo* scope_info, const DisallowGarbageCollection& no_gc);
// Return the name of a given context local.
@ -180,8 +183,9 @@ class ScopeInfo : public TorqueGeneratedScopeInfo<ScopeInfo, HeapObject> {
// returns a value < 0. The name must be an internalized string.
// If the slot is present and mode != nullptr, sets *mode to the corresponding
// mode for that variable.
static int ContextSlotIndex(ScopeInfo scope_info, String name,
VariableLookupResult* lookup_result);
int ContextSlotIndex(Handle<String> name);
int ContextSlotIndex(Handle<String> name,
VariableLookupResult* lookup_result);
// Lookup metadata of a MODULE-allocated variable. Return 0 if there is no
// module variable with the given name (the index value of a MODULE variable
@ -299,6 +303,8 @@ class ScopeInfo : public TorqueGeneratedScopeInfo<ScopeInfo, HeapObject> {
private:
friend class WebSnapshotDeserializer;
int InlinedLocalNamesLookup(String name);
int ContextLocalNamesIndex() const;
int ContextLocalInfosIndex() const;
int SavedClassVariableInfoIndex() const;

View File

@ -121,6 +121,12 @@ extern class ScopeInfo extends HeapObject {
context_local_names[Convert<intptr>(context_local_count) < kMaxInlinedLocalNamesSize ? context_local_count : 0]:
String;
// Contains a hash_map from local names to context slot index.
// This is only used when local names are not inlined in the scope info.
context_local_names_hashtable?
[kMaxInlinedLocalNamesSize <= Convert<intptr>(context_local_count)]:
NameToIndexHashTable;
// Contains the variable modes and initialization flags corresponding to
// the context locals in ContextLocalNames.
context_local_infos[context_local_count]: SmiTagged<VariableProperties>;
@ -170,11 +176,11 @@ extern class ScopeInfo extends HeapObject {
ModuleVariable;
}
// Returns the index of the named local in a ScopeInfo.
// Assumes that the given name is internalized; uses pointer comparisons.
@export
macro IndexOfLocalName(scopeInfo: ScopeInfo, name: Name):
intptr labels NotFound {
extern macro NameToIndexHashTableLookup(
NameToIndexHashTable, Name): intptr labels NotFound;
macro IndexOfInlinedLocalName(
scopeInfo: ScopeInfo, name: Name): intptr labels NotFound {
const count: intptr = Convert<intptr>(scopeInfo.context_local_count);
for (let i: intptr = 0; i < count; ++i) {
if (TaggedEqual(name, scopeInfo.context_local_names[i])) {
@ -183,3 +189,17 @@ macro IndexOfLocalName(scopeInfo: ScopeInfo, name: Name):
}
goto NotFound;
}
// Returns the index of the named local in a ScopeInfo.
// Assumes that the given name is internalized; uses pointer comparisons.
@export
macro IndexOfLocalName(scopeInfo: ScopeInfo, name: Name):
intptr labels NotFound {
const count: intptr = Convert<intptr>(scopeInfo.context_local_count);
if (count < kMaxInlinedLocalNamesSize) {
return IndexOfInlinedLocalName(scopeInfo, name) otherwise goto NotFound;
} else {
return NameToIndexHashTableLookup(
scopeInfo.context_local_names_hashtable, name) otherwise goto NotFound;
}
}

View File

@ -54,7 +54,7 @@ Object DeclareGlobal(Isolate* isolate, Handle<JSGlobalObject> global,
Handle<ScriptContextTable> script_contexts(
global->native_context().script_context_table(), isolate);
VariableLookupResult lookup;
if (ScriptContextTable::Lookup(isolate, *script_contexts, *name, &lookup) &&
if (script_contexts->Lookup(name, &lookup) &&
IsLexicalVariableMode(lookup.mode)) {
// ES#sec-globaldeclarationinstantiation 6.a:
// If envRec.HasLexicalDeclaration(name) is true, throw a SyntaxError
@ -877,8 +877,7 @@ RUNTIME_FUNCTION(Runtime_StoreGlobalNoHoleCheckForReplLetOrConst) {
native_context->script_context_table(), isolate);
VariableLookupResult lookup_result;
bool found = ScriptContextTable::Lookup(isolate, *script_contexts, *name,
&lookup_result);
bool found = script_contexts->Lookup(name, &lookup_result);
CHECK(found);
Handle<Context> script_context = ScriptContextTable::GetContext(
isolate, script_contexts, lookup_result.context_index);

View File

@ -24,6 +24,7 @@ inline uintptr_t ChangeUint32ToWord(uint32_t u) { return u; }
inline intptr_t IntPtrAdd(intptr_t a, intptr_t b) { return a + b; }
inline intptr_t IntPtrMul(intptr_t a, intptr_t b) { return a * b; }
inline bool IntPtrLessThan(intptr_t a, intptr_t b) { return a < b; }
inline bool IntPtrLessThanOrEqual(intptr_t a, intptr_t b) { return a <= b; }
inline intptr_t Signed(uintptr_t u) { return static_cast<intptr_t>(u); }
template <typename Smi>
inline int32_t SmiUntag(Smi s) {

View File

@ -46,8 +46,7 @@ Handle<T> GetLexical(const char* name) {
isolate->native_context()->script_context_table(), isolate);
VariableLookupResult lookup_result;
if (ScriptContextTable::Lookup(isolate, *script_contexts, *str_name,
&lookup_result)) {
if (script_contexts->Lookup(str_name, &lookup_result)) {
Handle<Context> script_context = ScriptContextTable::GetContext(
isolate, script_contexts, lookup_result.context_index);

View File

@ -71,6 +71,10 @@ inline Value<bool> IntPtrLessThan(d::MemoryAccessor accessor, intptr_t a,
intptr_t b) {
return {d::MemoryAccessResult::kOk, a < b};
}
inline Value<bool> IntPtrLessThanOrEqual(d::MemoryAccessor accessor, intptr_t a,
intptr_t b) {
return {d::MemoryAccessResult::kOk, a <= b};
}
inline Value<intptr_t> Signed(d::MemoryAccessor accessor, uintptr_t u) {
return {d::MemoryAccessResult::kOk, static_cast<intptr_t>(u)};
}