[runtime] Use a hashtable in ScriptContextTable

Bug: v8:12315
Change-Id: If750c9528d4f20c6695a6b25f4d1abc8a14dba62
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3431486
Commit-Queue: Victor Gomes <victorgomes@chromium.org>
Auto-Submit: Victor Gomes <victorgomes@chromium.org>
Reviewed-by: Igor Sheludko <ishell@chromium.org>
Commit-Queue: Igor Sheludko <ishell@chromium.org>
Cr-Commit-Position: refs/heads/main@{#78983}
This commit is contained in:
Victor Gomes 2022-02-07 16:10:10 +01:00 committed by V8 LUCI CQ
parent 08544f06a7
commit 8cdd0bfbaa
8 changed files with 86 additions and 38 deletions

View File

@ -263,9 +263,12 @@ MaybeHandle<Context> NewScriptContext(Isolate* isolate,
isolate->factory()->NewScriptContext(native_context, scope_info);
result->Initialize(isolate);
// In REPL mode, we are allowed to add/modify let/const variables.
// We use the previous defined script context for those.
const bool ignore_duplicates = scope_info->IsReplModeScope();
Handle<ScriptContextTable> new_script_context_table =
ScriptContextTable::Extend(script_context, result);
ScriptContextTable::Extend(isolate, script_context, result,
ignore_duplicates);
native_context->synchronized_set_script_context_table(
*new_script_context_table);
return result;

View File

@ -1207,7 +1207,9 @@ Handle<ScriptContextTable> Factory::NewScriptContextTable() {
Handle<ScriptContextTable> context_table = Handle<ScriptContextTable>::cast(
NewFixedArrayWithMap(read_only_roots().script_context_table_map_handle(),
ScriptContextTable::kMinLength));
Handle<NameToIndexHashTable> names = NameToIndexHashTable::New(isolate(), 16);
context_table->set_used(0, kReleaseStore);
context_table->set_names_to_context_index(*names);
return context_table;
}

View File

@ -1243,7 +1243,7 @@ void Genesis::InstallGlobalThisBinding() {
context->set(slot, native_context()->global_proxy());
Handle<ScriptContextTable> new_script_contexts =
ScriptContextTable::Extend(script_contexts, context);
ScriptContextTable::Extend(isolate(), script_contexts, context);
native_context()->set_script_context_table(*new_script_contexts);
}

View File

@ -39,6 +39,9 @@ void ScriptContextTable::set_used(int used, ReleaseStoreTag tag) {
set(kUsedSlotIndex, Smi::FromInt(used), tag);
}
ACCESSORS(ScriptContextTable, names_to_context_index, NameToIndexHashTable,
kHashTableOffset)
// static
Handle<Context> ScriptContextTable::GetContext(Isolate* isolate,
Handle<ScriptContextTable> table,
@ -109,9 +112,7 @@ void NativeContext::set(int index, Object value, WriteBarrierMode mode,
Context::set(index, value, mode, tag);
}
void Context::set_scope_info(ScopeInfo scope_info, WriteBarrierMode mode) {
set(SCOPE_INFO_INDEX, scope_info, mode);
}
ACCESSORS(Context, scope_info, ScopeInfo, kScopeInfoOffset)
Object Context::unchecked_previous() const { return get(PREVIOUS_INDEX); }
@ -124,10 +125,6 @@ void Context::set_previous(Context context, WriteBarrierMode mode) {
set(PREVIOUS_INDEX, context, mode);
}
ScopeInfo Context::scope_info() const {
return ScopeInfo::cast(get(SCOPE_INFO_INDEX));
}
Object Context::next_context_link() const {
return get(Context::NEXT_CONTEXT_LINK);
}

View File

@ -14,15 +14,40 @@
namespace v8 {
namespace internal {
void ScriptContextTable::AddLocalNamesFromContext(
Isolate* isolate, Handle<ScriptContextTable> script_context_table,
Handle<Context> script_context, bool ignore_duplicates,
int script_context_index) {
ReadOnlyRoots roots(isolate);
PtrComprCageBase cage_base(isolate);
Handle<NameToIndexHashTable> names_table(
script_context_table->names_to_context_index(cage_base), isolate);
Handle<ScopeInfo> scope_info(script_context->scope_info(cage_base), isolate);
int local_count = scope_info->ContextLocalCount();
names_table = names_table->EnsureCapacity(isolate, names_table, local_count);
for (auto it : ScopeInfo::IterateLocalNames(scope_info)) {
Handle<Name> name(it->name(cage_base), isolate);
if (ignore_duplicates) {
int32_t hash = NameToIndexShape::Hash(roots, name);
if (names_table->FindEntry(cage_base, roots, name, hash).is_found()) {
continue;
}
}
names_table = NameToIndexHashTable::Add(isolate, names_table, name,
script_context_index);
}
script_context_table->set_names_to_context_index(*names_table);
}
Handle<ScriptContextTable> ScriptContextTable::Extend(
Handle<ScriptContextTable> table, Handle<Context> script_context) {
Isolate* isolate, Handle<ScriptContextTable> table,
Handle<Context> script_context, bool ignore_duplicates) {
Handle<ScriptContextTable> result;
int used = table->used(kAcquireLoad);
int length = table->length();
CHECK(used >= 0 && length > 0 && used < length);
if (used + kFirstContextSlotIndex == length) {
CHECK(length < Smi::kMaxValue / 2);
Isolate* isolate = script_context->GetIsolate();
Handle<FixedArray> copy =
isolate->factory()->CopyFixedArrayAndGrow(table, length);
copy->set_map(ReadOnlyRoots(isolate).script_context_table_map());
@ -31,6 +56,8 @@ Handle<ScriptContextTable> ScriptContextTable::Extend(
result = table;
}
DCHECK(script_context->IsScriptContext());
ScriptContextTable::AddLocalNamesFromContext(isolate, result, script_context,
ignore_duplicates, used);
result->set(used + kFirstContextSlotIndex, *script_context, kReleaseStore);
result->set_used(used + 1, kReleaseStore);
return result;
@ -49,16 +76,17 @@ void Context::Initialize(Isolate* isolate) {
bool ScriptContextTable::Lookup(Handle<String> name,
VariableLookupResult* result) {
DisallowGarbageCollection no_gc;
// Static variables cannot be in script contexts.
for (int i = 0; i < used(kAcquireLoad); i++) {
Context context = get_context(i);
DCHECK(context.IsScriptContext());
int slot_index = context.scope_info().ContextSlotIndex(name, result);
if (slot_index >= 0) {
result->context_index = i;
result->slot_index = slot_index;
return true;
}
int index = names_to_context_index().Lookup(name);
if (index == -1) return false;
DCHECK_LE(0, index);
DCHECK_LT(index, used(kAcquireLoad));
Context context = get_context(index);
DCHECK(context.IsScriptContext());
int slot_index = context.scope_info().ContextSlotIndex(name, result);
if (slot_index >= 0) {
result->context_index = index;
result->slot_index = slot_index;
return true;
}
return false;
}

View File

@ -386,6 +386,14 @@ class ScriptContextTable : public FixedArray {
inline Context get_context(int i) const;
inline Context get_context(int i, AcquireLoadTag tag) const;
DECL_ACCESSORS(names_to_context_index, NameToIndexHashTable)
// Adds local names from `script_context` to the hash table.
static void AddLocalNamesFromContext(
Isolate* isolate, Handle<ScriptContextTable> script_context_table,
Handle<Context> script_context, bool ignore_duplicates,
int script_context_index);
// Lookup a variable `name` in a ScriptContextTable.
// If it returns true, the variable is found and `result` contains
// valid information about its location.
@ -396,12 +404,16 @@ class ScriptContextTable : public FixedArray {
V8_WARN_UNUSED_RESULT
V8_EXPORT_PRIVATE static Handle<ScriptContextTable> Extend(
Handle<ScriptContextTable> table, Handle<Context> script_context);
Isolate* isolate, Handle<ScriptContextTable> table,
Handle<Context> script_context, bool ignore_duplicates = false);
static const int kUsedSlotIndex = 0;
static const int kFirstContextSlotIndex = 1;
static const int kHashTableIndex = 0;
static const int kUsedSlotIndex = 1;
static const int kFirstContextSlotIndex = 2;
static const int kMinLength = kFirstContextSlotIndex;
static const int kHashTableOffset = OffsetOfElementAt(kHashTableIndex);
OBJECT_CONSTRUCTORS(ScriptContextTable, FixedArray);
};
@ -562,8 +574,7 @@ class Context : public TorqueGeneratedContext<Context, HeapObject> {
static const int kInvalidContext = 1;
// Direct slot access.
inline void set_scope_info(ScopeInfo scope_info,
WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
DECL_ACCESSORS(scope_info, ScopeInfo)
inline Object unchecked_previous() const;
inline Context previous() const;
@ -576,7 +587,6 @@ class Context : public TorqueGeneratedContext<Context, HeapObject> {
HeapObject object, WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
JSObject extension_object() const;
JSReceiver extension_receiver() const;
V8_EXPORT_PRIVATE inline ScopeInfo scope_info() const;
// Find the module context (assuming there is one) and return the associated
// module object.

View File

@ -64,12 +64,18 @@ class ScopeInfo::LocalNamesRange {
return !(a == b);
}
String name() const {
String name(PtrComprCageBase cage_base) const {
DCHECK_LT(index_, range_->max_index());
if (range_->inlined()) {
return scope_info()->ContextInlinedLocalName(index_.as_int());
return scope_info()->ContextInlinedLocalName(cage_base,
index_.as_int());
}
return String::cast(table().KeyAt(index_));
return String::cast(table().KeyAt(cage_base, index_));
}
String name() const {
PtrComprCageBase cage_base = GetPtrComprCageBase(*scope_info());
return name(cage_base);
}
const Iterator* operator*() const { return this; }

View File

@ -98,6 +98,7 @@ TEST(ScriptContextTable_Extend) {
CcTest::InitializeVM();
v8::HandleScope scope(CcTest::isolate());
Isolate* isolate = CcTest::i_isolate();
const bool kIgnoreDuplicateNames = true;
Factory* factory = isolate->factory();
Handle<NativeContext> native_context = factory->NewNativeContext();
@ -116,8 +117,8 @@ TEST(ScriptContextTable_Extend) {
Handle<Context> script_context =
factory->NewScriptContext(native_context, scope_info);
script_context_table =
ScriptContextTable::Extend(script_context_table, script_context);
script_context_table = ScriptContextTable::Extend(
isolate, script_context_table, script_context, kIgnoreDuplicateNames);
}
std::unique_ptr<PersistentHandles> ph = isolate->NewPersistentHandles();
@ -137,8 +138,8 @@ TEST(ScriptContextTable_Extend) {
for (int i = 0; i < 100; ++i) {
Handle<Context> context =
factory->NewScriptContext(native_context, scope_info);
script_context_table =
ScriptContextTable::Extend(script_context_table, context);
script_context_table = ScriptContextTable::Extend(
isolate, script_context_table, context, kIgnoreDuplicateNames);
}
thread->Join();
@ -164,7 +165,7 @@ TEST(ScriptContextTable_AccessScriptContextTable) {
Handle<Context> context =
factory->NewScriptContext(native_context, scope_info);
script_context_table =
ScriptContextTable::Extend(script_context_table, context);
ScriptContextTable::Extend(isolate, script_context_table, context);
int initialized_entries = 1;
g_initialized_entries.store(initialized_entries, std::memory_order_release);
@ -183,11 +184,12 @@ TEST(ScriptContextTable_AccessScriptContextTable) {
sema_started.Wait();
const bool kIgnoreDuplicateNames = true;
for (; initialized_entries < 1000; ++initialized_entries) {
Handle<Context> new_context =
factory->NewScriptContext(native_context, scope_info);
script_context_table =
ScriptContextTable::Extend(script_context_table, new_context);
script_context_table = ScriptContextTable::Extend(
isolate, script_context_table, new_context, kIgnoreDuplicateNames);
native_context->synchronized_set_script_context_table(
*script_context_table);
// Update with relaxed semantics to not introduce ordering constraints.