[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:
parent
e7ffb2570c
commit
94c490f795
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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>();
|
||||
|
@ -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";
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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(
|
||||
|
@ -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,
|
||||
|
@ -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) {}
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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)};
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user