[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:
parent
08544f06a7
commit
8cdd0bfbaa
@ -263,9 +263,12 @@ MaybeHandle<Context> NewScriptContext(Isolate* isolate,
|
|||||||
isolate->factory()->NewScriptContext(native_context, scope_info);
|
isolate->factory()->NewScriptContext(native_context, scope_info);
|
||||||
|
|
||||||
result->Initialize(isolate);
|
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 =
|
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(
|
native_context->synchronized_set_script_context_table(
|
||||||
*new_script_context_table);
|
*new_script_context_table);
|
||||||
return result;
|
return result;
|
||||||
|
@ -1207,7 +1207,9 @@ Handle<ScriptContextTable> Factory::NewScriptContextTable() {
|
|||||||
Handle<ScriptContextTable> context_table = Handle<ScriptContextTable>::cast(
|
Handle<ScriptContextTable> context_table = Handle<ScriptContextTable>::cast(
|
||||||
NewFixedArrayWithMap(read_only_roots().script_context_table_map_handle(),
|
NewFixedArrayWithMap(read_only_roots().script_context_table_map_handle(),
|
||||||
ScriptContextTable::kMinLength));
|
ScriptContextTable::kMinLength));
|
||||||
|
Handle<NameToIndexHashTable> names = NameToIndexHashTable::New(isolate(), 16);
|
||||||
context_table->set_used(0, kReleaseStore);
|
context_table->set_used(0, kReleaseStore);
|
||||||
|
context_table->set_names_to_context_index(*names);
|
||||||
return context_table;
|
return context_table;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1243,7 +1243,7 @@ void Genesis::InstallGlobalThisBinding() {
|
|||||||
context->set(slot, native_context()->global_proxy());
|
context->set(slot, native_context()->global_proxy());
|
||||||
|
|
||||||
Handle<ScriptContextTable> new_script_contexts =
|
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);
|
native_context()->set_script_context_table(*new_script_contexts);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,6 +39,9 @@ void ScriptContextTable::set_used(int used, ReleaseStoreTag tag) {
|
|||||||
set(kUsedSlotIndex, Smi::FromInt(used), tag);
|
set(kUsedSlotIndex, Smi::FromInt(used), tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ACCESSORS(ScriptContextTable, names_to_context_index, NameToIndexHashTable,
|
||||||
|
kHashTableOffset)
|
||||||
|
|
||||||
// static
|
// static
|
||||||
Handle<Context> ScriptContextTable::GetContext(Isolate* isolate,
|
Handle<Context> ScriptContextTable::GetContext(Isolate* isolate,
|
||||||
Handle<ScriptContextTable> table,
|
Handle<ScriptContextTable> table,
|
||||||
@ -109,9 +112,7 @@ void NativeContext::set(int index, Object value, WriteBarrierMode mode,
|
|||||||
Context::set(index, value, mode, tag);
|
Context::set(index, value, mode, tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Context::set_scope_info(ScopeInfo scope_info, WriteBarrierMode mode) {
|
ACCESSORS(Context, scope_info, ScopeInfo, kScopeInfoOffset)
|
||||||
set(SCOPE_INFO_INDEX, scope_info, mode);
|
|
||||||
}
|
|
||||||
|
|
||||||
Object Context::unchecked_previous() const { return get(PREVIOUS_INDEX); }
|
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);
|
set(PREVIOUS_INDEX, context, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
ScopeInfo Context::scope_info() const {
|
|
||||||
return ScopeInfo::cast(get(SCOPE_INFO_INDEX));
|
|
||||||
}
|
|
||||||
|
|
||||||
Object Context::next_context_link() const {
|
Object Context::next_context_link() const {
|
||||||
return get(Context::NEXT_CONTEXT_LINK);
|
return get(Context::NEXT_CONTEXT_LINK);
|
||||||
}
|
}
|
||||||
|
@ -14,15 +14,40 @@
|
|||||||
namespace v8 {
|
namespace v8 {
|
||||||
namespace internal {
|
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> ScriptContextTable::Extend(
|
||||||
Handle<ScriptContextTable> table, Handle<Context> script_context) {
|
Isolate* isolate, Handle<ScriptContextTable> table,
|
||||||
|
Handle<Context> script_context, bool ignore_duplicates) {
|
||||||
Handle<ScriptContextTable> result;
|
Handle<ScriptContextTable> result;
|
||||||
int used = table->used(kAcquireLoad);
|
int used = table->used(kAcquireLoad);
|
||||||
int length = table->length();
|
int length = table->length();
|
||||||
CHECK(used >= 0 && length > 0 && used < length);
|
CHECK(used >= 0 && length > 0 && used < length);
|
||||||
if (used + kFirstContextSlotIndex == length) {
|
if (used + kFirstContextSlotIndex == length) {
|
||||||
CHECK(length < Smi::kMaxValue / 2);
|
CHECK(length < Smi::kMaxValue / 2);
|
||||||
Isolate* isolate = script_context->GetIsolate();
|
|
||||||
Handle<FixedArray> copy =
|
Handle<FixedArray> copy =
|
||||||
isolate->factory()->CopyFixedArrayAndGrow(table, length);
|
isolate->factory()->CopyFixedArrayAndGrow(table, length);
|
||||||
copy->set_map(ReadOnlyRoots(isolate).script_context_table_map());
|
copy->set_map(ReadOnlyRoots(isolate).script_context_table_map());
|
||||||
@ -31,6 +56,8 @@ Handle<ScriptContextTable> ScriptContextTable::Extend(
|
|||||||
result = table;
|
result = table;
|
||||||
}
|
}
|
||||||
DCHECK(script_context->IsScriptContext());
|
DCHECK(script_context->IsScriptContext());
|
||||||
|
ScriptContextTable::AddLocalNamesFromContext(isolate, result, script_context,
|
||||||
|
ignore_duplicates, used);
|
||||||
result->set(used + kFirstContextSlotIndex, *script_context, kReleaseStore);
|
result->set(used + kFirstContextSlotIndex, *script_context, kReleaseStore);
|
||||||
result->set_used(used + 1, kReleaseStore);
|
result->set_used(used + 1, kReleaseStore);
|
||||||
return result;
|
return result;
|
||||||
@ -49,16 +76,17 @@ void Context::Initialize(Isolate* isolate) {
|
|||||||
bool ScriptContextTable::Lookup(Handle<String> name,
|
bool ScriptContextTable::Lookup(Handle<String> name,
|
||||||
VariableLookupResult* result) {
|
VariableLookupResult* result) {
|
||||||
DisallowGarbageCollection no_gc;
|
DisallowGarbageCollection no_gc;
|
||||||
// Static variables cannot be in script contexts.
|
int index = names_to_context_index().Lookup(name);
|
||||||
for (int i = 0; i < used(kAcquireLoad); i++) {
|
if (index == -1) return false;
|
||||||
Context context = get_context(i);
|
DCHECK_LE(0, index);
|
||||||
DCHECK(context.IsScriptContext());
|
DCHECK_LT(index, used(kAcquireLoad));
|
||||||
int slot_index = context.scope_info().ContextSlotIndex(name, result);
|
Context context = get_context(index);
|
||||||
if (slot_index >= 0) {
|
DCHECK(context.IsScriptContext());
|
||||||
result->context_index = i;
|
int slot_index = context.scope_info().ContextSlotIndex(name, result);
|
||||||
result->slot_index = slot_index;
|
if (slot_index >= 0) {
|
||||||
return true;
|
result->context_index = index;
|
||||||
}
|
result->slot_index = slot_index;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -386,6 +386,14 @@ class ScriptContextTable : public FixedArray {
|
|||||||
inline Context get_context(int i) const;
|
inline Context get_context(int i) const;
|
||||||
inline Context get_context(int i, AcquireLoadTag tag) 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.
|
// Lookup a variable `name` in a ScriptContextTable.
|
||||||
// If it returns true, the variable is found and `result` contains
|
// If it returns true, the variable is found and `result` contains
|
||||||
// valid information about its location.
|
// valid information about its location.
|
||||||
@ -396,12 +404,16 @@ class ScriptContextTable : public FixedArray {
|
|||||||
|
|
||||||
V8_WARN_UNUSED_RESULT
|
V8_WARN_UNUSED_RESULT
|
||||||
V8_EXPORT_PRIVATE static Handle<ScriptContextTable> Extend(
|
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 kHashTableIndex = 0;
|
||||||
static const int kFirstContextSlotIndex = 1;
|
static const int kUsedSlotIndex = 1;
|
||||||
|
static const int kFirstContextSlotIndex = 2;
|
||||||
static const int kMinLength = kFirstContextSlotIndex;
|
static const int kMinLength = kFirstContextSlotIndex;
|
||||||
|
|
||||||
|
static const int kHashTableOffset = OffsetOfElementAt(kHashTableIndex);
|
||||||
|
|
||||||
OBJECT_CONSTRUCTORS(ScriptContextTable, FixedArray);
|
OBJECT_CONSTRUCTORS(ScriptContextTable, FixedArray);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -562,8 +574,7 @@ class Context : public TorqueGeneratedContext<Context, HeapObject> {
|
|||||||
static const int kInvalidContext = 1;
|
static const int kInvalidContext = 1;
|
||||||
|
|
||||||
// Direct slot access.
|
// Direct slot access.
|
||||||
inline void set_scope_info(ScopeInfo scope_info,
|
DECL_ACCESSORS(scope_info, ScopeInfo)
|
||||||
WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
|
|
||||||
|
|
||||||
inline Object unchecked_previous() const;
|
inline Object unchecked_previous() const;
|
||||||
inline Context previous() const;
|
inline Context previous() const;
|
||||||
@ -576,7 +587,6 @@ class Context : public TorqueGeneratedContext<Context, HeapObject> {
|
|||||||
HeapObject object, WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
|
HeapObject object, WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
|
||||||
JSObject extension_object() const;
|
JSObject extension_object() const;
|
||||||
JSReceiver extension_receiver() 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
|
// Find the module context (assuming there is one) and return the associated
|
||||||
// module object.
|
// module object.
|
||||||
|
@ -64,12 +64,18 @@ class ScopeInfo::LocalNamesRange {
|
|||||||
return !(a == b);
|
return !(a == b);
|
||||||
}
|
}
|
||||||
|
|
||||||
String name() const {
|
String name(PtrComprCageBase cage_base) const {
|
||||||
DCHECK_LT(index_, range_->max_index());
|
DCHECK_LT(index_, range_->max_index());
|
||||||
if (range_->inlined()) {
|
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; }
|
const Iterator* operator*() const { return this; }
|
||||||
|
@ -98,6 +98,7 @@ TEST(ScriptContextTable_Extend) {
|
|||||||
CcTest::InitializeVM();
|
CcTest::InitializeVM();
|
||||||
v8::HandleScope scope(CcTest::isolate());
|
v8::HandleScope scope(CcTest::isolate());
|
||||||
Isolate* isolate = CcTest::i_isolate();
|
Isolate* isolate = CcTest::i_isolate();
|
||||||
|
const bool kIgnoreDuplicateNames = true;
|
||||||
|
|
||||||
Factory* factory = isolate->factory();
|
Factory* factory = isolate->factory();
|
||||||
Handle<NativeContext> native_context = factory->NewNativeContext();
|
Handle<NativeContext> native_context = factory->NewNativeContext();
|
||||||
@ -116,8 +117,8 @@ TEST(ScriptContextTable_Extend) {
|
|||||||
Handle<Context> script_context =
|
Handle<Context> script_context =
|
||||||
factory->NewScriptContext(native_context, scope_info);
|
factory->NewScriptContext(native_context, scope_info);
|
||||||
|
|
||||||
script_context_table =
|
script_context_table = ScriptContextTable::Extend(
|
||||||
ScriptContextTable::Extend(script_context_table, script_context);
|
isolate, script_context_table, script_context, kIgnoreDuplicateNames);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<PersistentHandles> ph = isolate->NewPersistentHandles();
|
std::unique_ptr<PersistentHandles> ph = isolate->NewPersistentHandles();
|
||||||
@ -137,8 +138,8 @@ TEST(ScriptContextTable_Extend) {
|
|||||||
for (int i = 0; i < 100; ++i) {
|
for (int i = 0; i < 100; ++i) {
|
||||||
Handle<Context> context =
|
Handle<Context> context =
|
||||||
factory->NewScriptContext(native_context, scope_info);
|
factory->NewScriptContext(native_context, scope_info);
|
||||||
script_context_table =
|
script_context_table = ScriptContextTable::Extend(
|
||||||
ScriptContextTable::Extend(script_context_table, context);
|
isolate, script_context_table, context, kIgnoreDuplicateNames);
|
||||||
}
|
}
|
||||||
|
|
||||||
thread->Join();
|
thread->Join();
|
||||||
@ -164,7 +165,7 @@ TEST(ScriptContextTable_AccessScriptContextTable) {
|
|||||||
Handle<Context> context =
|
Handle<Context> context =
|
||||||
factory->NewScriptContext(native_context, scope_info);
|
factory->NewScriptContext(native_context, scope_info);
|
||||||
script_context_table =
|
script_context_table =
|
||||||
ScriptContextTable::Extend(script_context_table, context);
|
ScriptContextTable::Extend(isolate, script_context_table, context);
|
||||||
int initialized_entries = 1;
|
int initialized_entries = 1;
|
||||||
g_initialized_entries.store(initialized_entries, std::memory_order_release);
|
g_initialized_entries.store(initialized_entries, std::memory_order_release);
|
||||||
|
|
||||||
@ -183,11 +184,12 @@ TEST(ScriptContextTable_AccessScriptContextTable) {
|
|||||||
|
|
||||||
sema_started.Wait();
|
sema_started.Wait();
|
||||||
|
|
||||||
|
const bool kIgnoreDuplicateNames = true;
|
||||||
for (; initialized_entries < 1000; ++initialized_entries) {
|
for (; initialized_entries < 1000; ++initialized_entries) {
|
||||||
Handle<Context> new_context =
|
Handle<Context> new_context =
|
||||||
factory->NewScriptContext(native_context, scope_info);
|
factory->NewScriptContext(native_context, scope_info);
|
||||||
script_context_table =
|
script_context_table = ScriptContextTable::Extend(
|
||||||
ScriptContextTable::Extend(script_context_table, new_context);
|
isolate, script_context_table, new_context, kIgnoreDuplicateNames);
|
||||||
native_context->synchronized_set_script_context_table(
|
native_context->synchronized_set_script_context_table(
|
||||||
*script_context_table);
|
*script_context_table);
|
||||||
// Update with relaxed semantics to not introduce ordering constraints.
|
// Update with relaxed semantics to not introduce ordering constraints.
|
||||||
|
Loading…
Reference in New Issue
Block a user