Commit b6030dba authored by Shu-yu Guo's avatar Shu-yu Guo Committed by V8 LUCI CQ

[string] Make String::MakeThin threadsafe for shared strings

For shared strings, String::MakeThin is protected by using the map word
of the string being migrated as a spinlock.

Note that this CL does not make it safe yet to access character data
from multiple threads. The spinlock here only protects write-write races
in String::MakeThin.

For more information, see the following two design docs:

https://docs.google.com/document/d/1c5i8f2EfKIQygGZ23hNiGxouvRISjUMnJjNsOodj6z0/edit
https://docs.google.com/document/d/1Drzigf17t4ofy0evDmaIL5p0MDZuAl95c9fSeX-QjVg/edit

Bug: v8:12007
Change-Id: I9c47412c6ec7360a672b65a8576b4f6156ee5846
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3313429
Commit-Queue: Shu-yu Guo <syg@chromium.org>
Reviewed-by: 's avatarLeszek Swirski <leszeks@chromium.org>
Reviewed-by: 's avatarMarja Hölttä <marja@chromium.org>
Reviewed-by: 's avatarMichael Lippautz <mlippautz@chromium.org>
Reviewed-by: 's avatarPatrick Thier <pthier@chromium.org>
Reviewed-by: 's avatarCamillo Bruni <cbruni@chromium.org>
Cr-Commit-Position: refs/heads/main@{#78257}
parent 480a917d
// Copyright 2021 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_BASE_PLATFORM_YIELD_PROCESSOR_H_
#define V8_BASE_PLATFORM_YIELD_PROCESSOR_H_
// The YIELD_PROCESSOR macro wraps an architecture specific-instruction that
// informs the processor we're in a busy wait, so it can handle the branch more
// intelligently and e.g. reduce power to our core or give more resources to the
// other hyper-thread on this core. See the following for context:
// https://software.intel.com/en-us/articles/benefitting-power-and-performance-sleep-loops
#if defined(V8_HOST_ARCH_IA32) || defined(V8_HOST_ARCH_X64)
#define YIELD_PROCESSOR __asm__ __volatile__("pause")
#elif defined(V8_HOST_ARCH_ARM64) || \
(defined(V8_HOST_ARCH_ARM) && __ARM_ARCH >= 6)
#define YIELD_PROCESSOR __asm__ __volatile__("yield")
#elif defined(V8_HOST_ARCH_MIPS)
// The MIPS32 docs state that the PAUSE instruction is a no-op on older
// architectures (first added in MIPS32r2). To avoid assembler errors when
// targeting pre-r2, we must encode the instruction manually.
#define YIELD_PROCESSOR __asm__ __volatile__(".word 0x00000140")
#elif defined(V8_HOST_ARCH_MIPS64EL) && __mips_isa_rev >= 2
// Don't bother doing using .word here since r2 is the lowest supported mips64
// that Chromium supports.
#define YIELD_PROCESSOR __asm__ __volatile__("pause")
#elif defined(V8_HOST_ARCH_PPC64)
#define YIELD_PROCESSOR __asm__ __volatile__("or 31,31,31")
#endif // V8_HOST_ARCH
#ifndef YIELD_PROCESSOR
#define YIELD_PROCESSOR ((void)0)
#endif
#endif // V8_BASE_PLATFORM_YIELD_PROCESSOR_H_
...@@ -270,6 +270,8 @@ void HeapObject::HeapObjectPrint(std::ostream& os) { ...@@ -270,6 +270,8 @@ void HeapObject::HeapObjectPrint(std::ostream& os) {
case UNCACHED_EXTERNAL_ONE_BYTE_STRING_TYPE: case UNCACHED_EXTERNAL_ONE_BYTE_STRING_TYPE:
case SHARED_STRING_TYPE: case SHARED_STRING_TYPE:
case SHARED_ONE_BYTE_STRING_TYPE: case SHARED_ONE_BYTE_STRING_TYPE:
case SHARED_THIN_STRING_TYPE:
case SHARED_THIN_ONE_BYTE_STRING_TYPE:
case JS_LAST_DUMMY_API_OBJECT_TYPE: case JS_LAST_DUMMY_API_OBJECT_TYPE:
// TODO(all): Handle these types too. // TODO(all): Handle these types too.
os << "UNKNOWN TYPE " << map().instance_type(); os << "UNKNOWN TYPE " << map().instance_type();
......
...@@ -998,9 +998,11 @@ MaybeHandle<Map> FactoryBase<Impl>::GetInPlaceInternalizedStringMap( ...@@ -998,9 +998,11 @@ MaybeHandle<Map> FactoryBase<Impl>::GetInPlaceInternalizedStringMap(
MaybeHandle<Map> map; MaybeHandle<Map> map;
switch (instance_type) { switch (instance_type) {
case STRING_TYPE: case STRING_TYPE:
case SHARED_STRING_TYPE:
map = read_only_roots().internalized_string_map_handle(); map = read_only_roots().internalized_string_map_handle();
break; break;
case ONE_BYTE_STRING_TYPE: case ONE_BYTE_STRING_TYPE:
case SHARED_ONE_BYTE_STRING_TYPE:
map = read_only_roots().one_byte_internalized_string_map_handle(); map = read_only_roots().one_byte_internalized_string_map_handle();
break; break;
case EXTERNAL_STRING_TYPE: case EXTERNAL_STRING_TYPE:
...@@ -1017,6 +1019,25 @@ MaybeHandle<Map> FactoryBase<Impl>::GetInPlaceInternalizedStringMap( ...@@ -1017,6 +1019,25 @@ MaybeHandle<Map> FactoryBase<Impl>::GetInPlaceInternalizedStringMap(
return map; return map;
} }
template <typename Impl>
Handle<Map> FactoryBase<Impl>::GetStringMigrationSentinelMap(
InstanceType from_string_type) {
Handle<Map> map;
switch (from_string_type) {
case SHARED_STRING_TYPE:
map = read_only_roots().seq_string_migration_sentinel_map_handle();
break;
case SHARED_ONE_BYTE_STRING_TYPE:
map =
read_only_roots().one_byte_seq_string_migration_sentinel_map_handle();
break;
default:
UNREACHABLE();
}
DCHECK_EQ(map->instance_type(), from_string_type);
return map;
}
template <typename Impl> template <typename Impl>
AllocationType AllocationType
FactoryBase<Impl>::RefineAllocationTypeForInPlaceInternalizableString( FactoryBase<Impl>::RefineAllocationTypeForInPlaceInternalizableString(
......
...@@ -252,6 +252,8 @@ class EXPORT_TEMPLATE_DECLARE(V8_EXPORT_PRIVATE) FactoryBase ...@@ -252,6 +252,8 @@ class EXPORT_TEMPLATE_DECLARE(V8_EXPORT_PRIVATE) FactoryBase
MaybeHandle<Map> GetInPlaceInternalizedStringMap(Map from_string_map); MaybeHandle<Map> GetInPlaceInternalizedStringMap(Map from_string_map);
Handle<Map> GetStringMigrationSentinelMap(InstanceType from_string_type);
AllocationType RefineAllocationTypeForInPlaceInternalizableString( AllocationType RefineAllocationTypeForInPlaceInternalizableString(
AllocationType allocation, Map string_map); AllocationType allocation, Map string_map);
......
...@@ -407,6 +407,9 @@ bool Heap::CreateInitialMaps() { ...@@ -407,6 +407,9 @@ bool Heap::CreateInitialMaps() {
if (StringShape(entry.type).IsCons()) map.mark_unstable(); if (StringShape(entry.type).IsCons()) map.mark_unstable();
roots_table()[entry.index] = map.ptr(); roots_table()[entry.index] = map.ptr();
} }
ALLOCATE_VARSIZE_MAP(SHARED_STRING_TYPE, seq_string_migration_sentinel);
ALLOCATE_VARSIZE_MAP(SHARED_ONE_BYTE_STRING_TYPE,
one_byte_seq_string_migration_sentinel);
ALLOCATE_VARSIZE_MAP(FIXED_DOUBLE_ARRAY_TYPE, fixed_double_array) ALLOCATE_VARSIZE_MAP(FIXED_DOUBLE_ARRAY_TYPE, fixed_double_array)
roots.fixed_double_array_map().set_elements_kind(HOLEY_DOUBLE_ELEMENTS); roots.fixed_double_array_map().set_elements_kind(HOLEY_DOUBLE_ELEMENTS);
......
...@@ -141,6 +141,9 @@ enum InstanceType : uint16_t { ...@@ -141,6 +141,9 @@ enum InstanceType : uint16_t {
kOneByteStringTag | kThinStringTag | kNotInternalizedTag, kOneByteStringTag | kThinStringTag | kNotInternalizedTag,
SHARED_STRING_TYPE = STRING_TYPE | kSharedStringTag, SHARED_STRING_TYPE = STRING_TYPE | kSharedStringTag,
SHARED_ONE_BYTE_STRING_TYPE = ONE_BYTE_STRING_TYPE | kSharedStringTag, SHARED_ONE_BYTE_STRING_TYPE = ONE_BYTE_STRING_TYPE | kSharedStringTag,
SHARED_THIN_STRING_TYPE = THIN_STRING_TYPE | kSharedStringTag,
SHARED_THIN_ONE_BYTE_STRING_TYPE =
THIN_ONE_BYTE_STRING_TYPE | kSharedStringTag,
// Most instance types are defined in Torque, with the exception of the string // Most instance types are defined in Torque, with the exception of the string
// types above. They are ordered by inheritance hierarchy so that we can easily // types above. They are ordered by inheritance hierarchy so that we can easily
......
...@@ -51,7 +51,9 @@ namespace internal { ...@@ -51,7 +51,9 @@ namespace internal {
V(UNCACHED_EXTERNAL_STRING_TYPE) \ V(UNCACHED_EXTERNAL_STRING_TYPE) \
V(UNCACHED_EXTERNAL_ONE_BYTE_STRING_TYPE) \ V(UNCACHED_EXTERNAL_ONE_BYTE_STRING_TYPE) \
V(SHARED_STRING_TYPE) \ V(SHARED_STRING_TYPE) \
V(SHARED_ONE_BYTE_STRING_TYPE) V(SHARED_THIN_STRING_TYPE) \
V(SHARED_ONE_BYTE_STRING_TYPE) \
V(SHARED_THIN_ONE_BYTE_STRING_TYPE)
#define INSTANCE_TYPE_LIST(V) \ #define INSTANCE_TYPE_LIST(V) \
INSTANCE_TYPE_LIST_BASE(V) \ INSTANCE_TYPE_LIST_BASE(V) \
...@@ -100,7 +102,11 @@ namespace internal { ...@@ -100,7 +102,11 @@ namespace internal {
\ \
V(SHARED_STRING_TYPE, kVariableSizeSentinel, shared_string, SharedString) \ V(SHARED_STRING_TYPE, kVariableSizeSentinel, shared_string, SharedString) \
V(SHARED_ONE_BYTE_STRING_TYPE, kVariableSizeSentinel, \ V(SHARED_ONE_BYTE_STRING_TYPE, kVariableSizeSentinel, \
shared_one_byte_string, SharedOneByteString) shared_one_byte_string, SharedOneByteString) \
V(SHARED_THIN_STRING_TYPE, ThinString::kSize, shared_thin_string, \
SharedThinString) \
V(SHARED_THIN_ONE_BYTE_STRING_TYPE, ThinString::kSize, \
shared_thin_one_byte_string, SharedThinOneByteString)
// A struct is a simple object a set of object-valued fields. Including an // A struct is a simple object a set of object-valued fields. Including an
// object type in this causes the compiler to generate most of the boilerplate // object type in this causes the compiler to generate most of the boilerplate
......
...@@ -1424,6 +1424,8 @@ bool String::IsInPlaceInternalizable(InstanceType instance_type) { ...@@ -1424,6 +1424,8 @@ bool String::IsInPlaceInternalizable(InstanceType instance_type) {
switch (instance_type) { switch (instance_type) {
case STRING_TYPE: case STRING_TYPE:
case ONE_BYTE_STRING_TYPE: case ONE_BYTE_STRING_TYPE:
case SHARED_STRING_TYPE:
case SHARED_ONE_BYTE_STRING_TYPE:
case EXTERNAL_STRING_TYPE: case EXTERNAL_STRING_TYPE:
case EXTERNAL_ONE_BYTE_STRING_TYPE: case EXTERNAL_ONE_BYTE_STRING_TYPE:
return true; return true;
......
...@@ -437,13 +437,11 @@ Handle<String> StringTable::LookupString(Isolate* isolate, ...@@ -437,13 +437,11 @@ Handle<String> StringTable::LookupString(Isolate* isolate,
// correctly ordered by LookupKey's write mutex and see the updated map // correctly ordered by LookupKey's write mutex and see the updated map
// during the re-lookup. // during the re-lookup.
// //
// For lookup misses, the internalized string map is the same map in RO // For lookup misses, the internalized string map is the same map in RO space
// space regardless of which thread is doing the lookup. // regardless of which thread is doing the lookup.
// //
// For lookup hits, String::MakeThin is not threadsafe but is currently // For lookup hits, String::MakeThin is threadsafe and spinlocks on
// only called on strings that are not accessible from multiple threads, // migrating into a ThinString.
// even if in the shared heap. TODO(v8:12007) Make String::MakeThin
// threadsafe so old- generation flat strings can be shared across threads.
string = String::Flatten(isolate, string); string = String::Flatten(isolate, string);
if (string->IsInternalizedString()) return string; if (string->IsInternalizedString()) return string;
...@@ -454,6 +452,7 @@ Handle<String> StringTable::LookupString(Isolate* isolate, ...@@ -454,6 +452,7 @@ Handle<String> StringTable::LookupString(Isolate* isolate,
if (!string->IsInternalizedString()) { if (!string->IsInternalizedString()) {
string->MakeThin(isolate, *result); string->MakeThin(isolate, *result);
} }
return result; return result;
} }
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#include "src/objects/string.h" #include "src/objects/string.h"
#include "src/base/platform/yield-processor.h"
#include "src/common/assert-scope.h" #include "src/common/assert-scope.h"
#include "src/common/globals.h" #include "src/common/globals.h"
#include "src/execution/isolate-utils.h" #include "src/execution/isolate-utils.h"
...@@ -177,6 +178,147 @@ void MigrateExternalString(Isolate* isolate, String string, ...@@ -177,6 +178,147 @@ void MigrateExternalString(Isolate* isolate, String string,
} }
} }
template <typename IsolateT>
Map ComputeThinStringMap(IsolateT* isolate, StringShape from_string_shape,
bool one_byte) {
ReadOnlyRoots roots(isolate);
if (from_string_shape.IsShared()) {
return one_byte ? roots.shared_thin_one_byte_string_map()
: roots.shared_thin_string_map();
}
return one_byte ? roots.thin_one_byte_string_map() : roots.thin_string_map();
}
enum class StringMigrationResult {
kThisThreadMigrated,
kAnotherThreadMigrated
};
// This function must be used when migrating strings whose
// StringShape::CanMigrateInParallel() is true. It encapsulates the
// synchronization needed for parallel migrations from multiple threads. The
// user passes a lambda to perform to update the representation.
//
// Returns whether this thread successfully migrated the string or another
// thread did so.
//
// The locking algorithm to migrate a String uses its map word as a migration
// lock:
//
// map = string.map(kAcquireLoad);
// if (map != SENTINEL_MAP &&
// string.compare_and_swap_map(map, SENTINEL_MAP)) {
// // Lock acquired, i.e. the string's map is SENTINEL_MAP.
// } else {
// // Lock not acquired. Another thread set the sentinel. Spin until the
// // map is no longer the sentinel, i.e. until the other thread
// // releases the lock.
// Map reloaded_map;
// do {
// reloaded_map = string.map(kAcquireLoad);
// } while (reloaded_map == SENTINEL_MAP);
// }
//
// Some notes on usage:
// - The initial map must be loaded with kAcquireLoad for synchronization.
// - Avoid loading the map multiple times. Load the map once and branch
// on that.
// - The lambda is passed the string and its initial (pre-migration)
// StringShape.
// - The lambda may be executed under a spinlock, so it should be as short
// as possible.
// - Currently only SeqString -> ThinString migrations can happen in
// parallel. If kAnotherThreadMigrated is returned, then the caller doesn't
// need to do any other work. In the future, if additional migrations can
// happen in parallel, then restarts may be needed if the parallel migration
// was to a different type (e.g. SeqString -> External).
//
// Example:
//
// DisallowGarbageCollection no_gc;
// Map initial_map = string.map(kAcquireLoad);
// switch (MigrateStringMapUnderLockIfNeeded(
// isolate, string, initial_map, target_map,
// [](Isolate* isolate, String string, StringShape initial_shape) {
// auto t = TargetStringType::unchecked_cast(string);
// t.set_field(foo);
// t.set_another_field(bar);
// }, no_gc);
//
template <typename IsolateT, typename Callback>
StringMigrationResult MigrateStringMapUnderLockIfNeeded(
IsolateT* isolate, String string, Map initial_map, Map target_map,
Callback update_representation, const DisallowGarbageCollection& no_gc) {
USE(no_gc);
InstanceType initial_type = initial_map.instance_type();
StringShape initial_shape(initial_type);
if (initial_shape.CanMigrateInParallel()) {
// A string whose map is a sentinel map means that it is in the critical
// section for being migrated to a different map. There are multiple
// sentinel maps: one for each InstanceType that may be migrated from.
Map sentinel_map =
*isolate->factory()->GetStringMigrationSentinelMap(initial_type);
// Try to acquire the migration lock by setting the string's map to the
// sentinel map. Note that it's possible that we've already witnessed a
// sentinel map.
if (initial_map == sentinel_map ||
!string.release_compare_and_swap_map_word(
MapWord::FromMap(initial_map), MapWord::FromMap(sentinel_map))) {
// If the lock couldn't be acquired, another thread must be migrating this
// string. The string's map will be the sentinel map until the migration
// is finished. Spin until the map is no longer the sentinel map.
//
// TODO(v8:12007): Replace this spin lock with a ParkingLot-like
// primitive.
Map reloaded_map = string.map(kAcquireLoad);
while (reloaded_map == sentinel_map) {
YIELD_PROCESSOR;
reloaded_map = string.map(kAcquireLoad);
}
// Another thread must have migrated once the map is no longer the
// sentinel map.
//
// TODO(v8:12007): At time of writing there is only a single kind of
// migration that can happen in parallel: SeqString -> ThinString. If
// other parallel migrations are added, this DCHECK will fail, and users
// of MigrateStringMapUnderLockIfNeeded would need to restart if the
// string was migrated to a different map than target_map.
DCHECK_EQ(reloaded_map, target_map);
return StringMigrationResult::kAnotherThreadMigrated;
}
}
// With the lock held for cases where it's needed, do the work to update the
// representation before storing the map word. In addition to parallel
// migrations, this also ensures that the concurrent marker will read the
// updated representation when visiting migrated strings.
update_representation(isolate, string, initial_shape);
// Do the store on the map word.
//
// In debug mode, do a compare-and-swap that is checked to succeed, to check
// that all string map migrations are using this function, since to be in the
// migration critical section, the string's current map must be the sentinel
// map.
//
// Otherwise do a normal release store.
if (DEBUG_BOOL && initial_shape.CanMigrateInParallel()) {
DCHECK_NE(initial_map, target_map);
Map sentinel_map =
*isolate->factory()->GetStringMigrationSentinelMap(initial_type);
CHECK(string.release_compare_and_swap_map_word(
MapWord::FromMap(sentinel_map), MapWord::FromMap(target_map)));
} else {
string.set_map(target_map, kReleaseStore);
}
return StringMigrationResult::kThisThreadMigrated;
}
} // namespace } // namespace
template <typename IsolateT> template <typename IsolateT>
...@@ -184,29 +326,45 @@ void String::MakeThin(IsolateT* isolate, String internalized) { ...@@ -184,29 +326,45 @@ void String::MakeThin(IsolateT* isolate, String internalized) {
DisallowGarbageCollection no_gc; DisallowGarbageCollection no_gc;
DCHECK_NE(*this, internalized); DCHECK_NE(*this, internalized);
DCHECK(internalized.IsInternalizedString()); DCHECK(internalized.IsInternalizedString());
// TODO(v8:12007): Make this method threadsafe.
DCHECK(!IsShared());
DCHECK_IMPLIES(
InSharedWritableHeap(),
ThreadId::Current() == GetIsolateFromWritableObject(*this)->thread_id());
if (this->IsExternalString()) { // Load the map once at the beginning and use it to query for the shape of the
MigrateExternalString(isolate->AsIsolate(), *this, internalized); // string to avoid reloading the map in case of parallel migrations. See
// comment above for MigrateStringMapUnderLockIfNeeded.
Map initial_map = this->map(kAcquireLoad);
StringShape initial_shape(initial_map);
// Another thread may have already migrated the string.
if (initial_shape.IsThin()) {
DCHECK(initial_shape.IsShared());
return;
} }
bool has_pointers = StringShape(*this).IsIndirect(); bool has_pointers = initial_shape.IsIndirect();
int old_size = this->SizeFromMap(initial_map);
Map target_map = ComputeThinStringMap(isolate, initial_shape,
internalized.IsOneByteRepresentation());
switch (MigrateStringMapUnderLockIfNeeded(
isolate, *this, initial_map, target_map,
[=](IsolateT* isolate, String string, StringShape initial_shape) {
if (initial_shape.IsExternal()) {
// TODO(v8:12007): Support external strings.
DCHECK(!initial_shape.IsShared());
MigrateExternalString(isolate->AsIsolate(), string, internalized);
}
ThinString::unchecked_cast(string).set_actual(internalized);
DCHECK_GE(old_size, ThinString::kSize);
},
no_gc)) {
case StringMigrationResult::kThisThreadMigrated:
// Overwrite character data with the filler below.
break;
case StringMigrationResult::kAnotherThreadMigrated:
// Nothing to do.
return;
}
int old_size = this->Size(); ThinString thin = ThinString::cast(*this);
bool one_byte = internalized.IsOneByteRepresentation();
Handle<Map> map = one_byte ? isolate->factory()->thin_one_byte_string_map()
: isolate->factory()->thin_string_map();
// Update actual first and then do release store on the map word. This ensures
// that the concurrent marker will read the pointer when visiting a
// ThinString.
ThinString thin = ThinString::unchecked_cast(*this);
thin.set_actual(internalized);
DCHECK_GE(old_size, ThinString::kSize);
this->set_map(*map, kReleaseStore);
Address thin_end = thin.address() + ThinString::kSize; Address thin_end = thin.address() + ThinString::kSize;
int size_delta = old_size - ThinString::kSize; int size_delta = old_size - ThinString::kSize;
if (size_delta != 0) { if (size_delta != 0) {
...@@ -222,8 +380,10 @@ void String::MakeThin(IsolateT* isolate, String internalized) { ...@@ -222,8 +380,10 @@ void String::MakeThin(IsolateT* isolate, String internalized) {
} }
} }
template void String::MakeThin(Isolate* isolate, String internalized); template EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE) void String::MakeThin(
template void String::MakeThin(LocalIsolate* isolate, String internalized); Isolate* isolate, String internalized);
template EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE) void String::MakeThin(
LocalIsolate* isolate, String internalized);
bool String::MakeExternal(v8::String::ExternalStringResource* resource) { bool String::MakeExternal(v8::String::ExternalStringResource* resource) {
// Disallow garbage collection to avoid possible GC vs string access deadlock. // Disallow garbage collection to avoid possible GC vs string access deadlock.
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include "src/base/strings.h" #include "src/base/strings.h"
#include "src/common/globals.h" #include "src/common/globals.h"
#include "src/objects/instance-type.h" #include "src/objects/instance-type.h"
#include "src/objects/map.h"
#include "src/objects/name.h" #include "src/objects/name.h"
#include "src/objects/smi.h" #include "src/objects/smi.h"
#include "src/strings/unicode-decoder.h" #include "src/strings/unicode-decoder.h"
...@@ -180,6 +181,7 @@ class String : public TorqueGeneratedString<String, Name> { ...@@ -180,6 +181,7 @@ class String : public TorqueGeneratedString<String, Name> {
}; };
template <typename IsolateT> template <typename IsolateT>
EXPORT_TEMPLATE_DECLARE(V8_EXPORT_PRIVATE)
void MakeThin(IsolateT* isolate, String canonical); void MakeThin(IsolateT* isolate, String canonical);
template <typename Char> template <typename Char>
......
...@@ -145,6 +145,12 @@ class Symbol; ...@@ -145,6 +145,12 @@ class Symbol;
UncachedExternalOneByteStringMap) \ UncachedExternalOneByteStringMap) \
V(Map, shared_one_byte_string_map, SharedOneByteStringMap) \ V(Map, shared_one_byte_string_map, SharedOneByteStringMap) \
V(Map, shared_string_map, SharedStringMap) \ V(Map, shared_string_map, SharedStringMap) \
V(Map, shared_thin_one_byte_string_map, SharedThinOneByteStringMap) \
V(Map, shared_thin_string_map, SharedThinStringMap) \
V(Map, seq_string_migration_sentinel_map, \
TwoByteSeqStringMigrationSentinelMap) \
V(Map, one_byte_seq_string_migration_sentinel_map, \
OneByteSeqStringMigrationSentinelMap) \
/* Oddball maps */ \ /* Oddball maps */ \
V(Map, undefined_map, UndefinedMap) \ V(Map, undefined_map, UndefinedMap) \
V(Map, the_hole_map, TheHoleMap) \ V(Map, the_hole_map, TheHoleMap) \
......
...@@ -431,6 +431,7 @@ void Deserializer<IsolateT>::PostProcessNewObject(Handle<Map> map, ...@@ -431,6 +431,7 @@ void Deserializer<IsolateT>::PostProcessNewObject(Handle<Map> map,
isolate()->string_table()->LookupKey(isolate(), &key); isolate()->string_table()->LookupKey(isolate(), &key);
if (*result != *string) { if (*result != *string) {
DCHECK(!string->IsShared());
string->MakeThin(isolate(), *result); string->MakeThin(isolate(), *result);
// Mutate the given object handle so that the backreference entry is // Mutate the given object handle so that the backreference entry is
// also updated. // also updated.
......
...@@ -235,10 +235,13 @@ UNINITIALIZED_TEST(YoungInternalization) { ...@@ -235,10 +235,13 @@ UNINITIALIZED_TEST(YoungInternalization) {
CHECK_EQ(*two_byte_intern1, *two_byte_intern2); CHECK_EQ(*two_byte_intern1, *two_byte_intern2);
} }
enum TestHitOrMiss { kTestMiss, kTestHit };
class ConcurrentInternalizationThread final : public v8::base::Thread { class ConcurrentInternalizationThread final : public v8::base::Thread {
public: public:
ConcurrentInternalizationThread(MultiClientIsolateTest* test, ConcurrentInternalizationThread(MultiClientIsolateTest* test,
Handle<FixedArray> shared_strings, Handle<FixedArray> shared_strings,
TestHitOrMiss hit_or_miss,
base::Semaphore* sema_ready, base::Semaphore* sema_ready,
base::Semaphore* sema_execute_start, base::Semaphore* sema_execute_start,
base::Semaphore* sema_execute_complete) base::Semaphore* sema_execute_complete)
...@@ -246,6 +249,7 @@ class ConcurrentInternalizationThread final : public v8::base::Thread { ...@@ -246,6 +249,7 @@ class ConcurrentInternalizationThread final : public v8::base::Thread {
base::Thread::Options("ConcurrentInternalizationThread")), base::Thread::Options("ConcurrentInternalizationThread")),
test_(test), test_(test),
shared_strings_(shared_strings), shared_strings_(shared_strings),
hit_or_miss_(hit_or_miss),
sema_ready_(sema_ready), sema_ready_(sema_ready),
sema_execute_start_(sema_execute_start), sema_execute_start_(sema_execute_start),
sema_execute_complete_(sema_execute_complete) {} sema_execute_complete_(sema_execute_complete) {}
...@@ -260,12 +264,22 @@ class ConcurrentInternalizationThread final : public v8::base::Thread { ...@@ -260,12 +264,22 @@ class ConcurrentInternalizationThread final : public v8::base::Thread {
HandleScope scope(i_isolate); HandleScope scope(i_isolate);
Handle<String> manual_thin_actual =
factory->InternalizeString(factory->NewStringFromAsciiChecked("TODO"));
for (int i = 0; i < shared_strings_->length(); i++) { for (int i = 0; i < shared_strings_->length(); i++) {
Handle<String> input_string(String::cast(shared_strings_->get(i)), Handle<String> input_string(String::cast(shared_strings_->get(i)),
i_isolate); i_isolate);
CHECK(input_string->InSharedHeap()); CHECK(input_string->IsShared());
Handle<String> interned = factory->InternalizeString(input_string); if (hit_or_miss_ == kTestMiss) {
CHECK_EQ(*input_string, *interned); Handle<String> interned = factory->InternalizeString(input_string);
CHECK_EQ(*input_string, *interned);
} else {
// TODO(v8:12007): Make this branch also test InternalizeString. But
// LookupString needs to be made threadsafe first and restart-aware.
input_string->MakeThin(i_isolate, *manual_thin_actual);
CHECK(input_string->IsThinString());
}
} }
sema_execute_complete_->Signal(); sema_execute_complete_->Signal();
...@@ -274,12 +288,14 @@ class ConcurrentInternalizationThread final : public v8::base::Thread { ...@@ -274,12 +288,14 @@ class ConcurrentInternalizationThread final : public v8::base::Thread {
private: private:
MultiClientIsolateTest* test_; MultiClientIsolateTest* test_;
Handle<FixedArray> shared_strings_; Handle<FixedArray> shared_strings_;
TestHitOrMiss hit_or_miss_;
base::Semaphore* sema_ready_; base::Semaphore* sema_ready_;
base::Semaphore* sema_execute_start_; base::Semaphore* sema_execute_start_;
base::Semaphore* sema_execute_complete_; base::Semaphore* sema_execute_complete_;
}; };
UNINITIALIZED_TEST(ConcurrentInternalization) { namespace {
void TestConcurrentInternalization(TestHitOrMiss hit_or_miss) {
if (!ReadOnlyHeap::IsReadOnlySpaceShared()) return; if (!ReadOnlyHeap::IsReadOnlySpaceShared()) return;
if (!COMPRESS_POINTERS_IN_SHARED_CAGE_BOOL) return; if (!COMPRESS_POINTERS_IN_SHARED_CAGE_BOOL) return;
...@@ -298,12 +314,20 @@ UNINITIALIZED_TEST(ConcurrentInternalization) { ...@@ -298,12 +314,20 @@ UNINITIALIZED_TEST(ConcurrentInternalization) {
Handle<FixedArray> shared_strings = Handle<FixedArray> shared_strings =
factory->NewFixedArray(kStrings, AllocationType::kSharedOld); factory->NewFixedArray(kStrings, AllocationType::kSharedOld);
for (int i = 0; i < kStrings; i++) { for (int i = 0; i < kStrings; i++) {
char* ascii = new char[i + 2]; char* ascii = new char[i + 3];
for (int j = 0; j < i + 1; j++) ascii[j] = 'a'; // Don't make single character strings, which might will end up
ascii[i + 1] = '\0'; // deduplicating to an RO string and mess up the string table hit test.
Handle<String> string = for (int j = 0; j < i + 2; j++) ascii[j] = 'a';
factory->NewStringFromAsciiChecked(ascii, AllocationType::kOld); ascii[i + 2] = '\0';
CHECK(string->InSharedHeap()); if (hit_or_miss == kTestHit) {
// When testing concurrent string table hits, pre-internalize a string of
// the same contents so all subsequent internalizations are hits.
factory->InternalizeString(factory->NewStringFromAsciiChecked(ascii));
}
Handle<String> string = String::Share(
i_isolate,
factory->NewStringFromAsciiChecked(ascii, AllocationType::kOld));
CHECK(string->IsShared());
string->EnsureHash(); string->EnsureHash();
shared_strings->set(i, *string); shared_strings->set(i, *string);
delete[] ascii; delete[] ascii;
...@@ -315,7 +339,7 @@ UNINITIALIZED_TEST(ConcurrentInternalization) { ...@@ -315,7 +339,7 @@ UNINITIALIZED_TEST(ConcurrentInternalization) {
std::vector<std::unique_ptr<ConcurrentInternalizationThread>> threads; std::vector<std::unique_ptr<ConcurrentInternalizationThread>> threads;
for (int i = 0; i < kThreads; i++) { for (int i = 0; i < kThreads; i++) {
auto thread = std::make_unique<ConcurrentInternalizationThread>( auto thread = std::make_unique<ConcurrentInternalizationThread>(
&test, shared_strings, &sema_ready, &sema_execute_start, &test, shared_strings, hit_or_miss, &sema_ready, &sema_execute_start,
&sema_execute_complete); &sema_execute_complete);
CHECK(thread->Start()); CHECK(thread->Start());
threads.push_back(std::move(thread)); threads.push_back(std::move(thread));
...@@ -329,6 +353,15 @@ UNINITIALIZED_TEST(ConcurrentInternalization) { ...@@ -329,6 +353,15 @@ UNINITIALIZED_TEST(ConcurrentInternalization) {
thread->Join(); thread->Join();
} }
} }
} // namespace
UNINITIALIZED_TEST(ConcurrentInternalizationMiss) {
TestConcurrentInternalization(kTestMiss);
}
UNINITIALIZED_TEST(ConcurrentInternalizationHit) {
TestConcurrentInternalization(kTestHit);
}
namespace { namespace {
void CheckSharedStringIsEqualCopy(Handle<String> shared, void CheckSharedStringIsEqualCopy(Handle<String> shared,
......
...@@ -26,7 +26,9 @@ INSTANCE_TYPES = { ...@@ -26,7 +26,9 @@ INSTANCE_TYPES = {
50: "UNCACHED_EXTERNAL_STRING_TYPE", 50: "UNCACHED_EXTERNAL_STRING_TYPE",
58: "UNCACHED_EXTERNAL_ONE_BYTE_STRING_TYPE", 58: "UNCACHED_EXTERNAL_ONE_BYTE_STRING_TYPE",
96: "SHARED_STRING_TYPE", 96: "SHARED_STRING_TYPE",
101: "SHARED_THIN_STRING_TYPE",
104: "SHARED_ONE_BYTE_STRING_TYPE", 104: "SHARED_ONE_BYTE_STRING_TYPE",
109: "SHARED_THIN_ONE_BYTE_STRING_TYPE",
128: "SYMBOL_TYPE", 128: "SYMBOL_TYPE",
129: "BIG_INT_BASE_TYPE", 129: "BIG_INT_BASE_TYPE",
130: "HEAP_NUMBER_TYPE", 130: "HEAP_NUMBER_TYPE",
...@@ -352,76 +354,80 @@ KNOWN_MAPS = { ...@@ -352,76 +354,80 @@ KNOWN_MAPS = {
("read_only_space", 0x03219): (58, "UncachedExternalOneByteStringMap"), ("read_only_space", 0x03219): (58, "UncachedExternalOneByteStringMap"),
("read_only_space", 0x03241): (104, "SharedOneByteStringMap"), ("read_only_space", 0x03241): (104, "SharedOneByteStringMap"),
("read_only_space", 0x03269): (96, "SharedStringMap"), ("read_only_space", 0x03269): (96, "SharedStringMap"),
("read_only_space", 0x03291): (131, "SelfReferenceMarkerMap"), ("read_only_space", 0x03291): (109, "SharedThinOneByteStringMap"),
("read_only_space", 0x032b9): (131, "BasicBlockCountersMarkerMap"), ("read_only_space", 0x032b9): (101, "SharedThinStringMap"),
("read_only_space", 0x032fd): (147, "ArrayBoilerplateDescriptionMap"), ("read_only_space", 0x032e1): (96, "TwoByteSeqStringMigrationSentinelMap"),
("read_only_space", 0x033fd): (159, "InterceptorInfoMap"), ("read_only_space", 0x03309): (104, "OneByteSeqStringMigrationSentinelMap"),
("read_only_space", 0x05c71): (132, "PromiseFulfillReactionJobTaskMap"), ("read_only_space", 0x03331): (131, "SelfReferenceMarkerMap"),
("read_only_space", 0x05c99): (133, "PromiseRejectReactionJobTaskMap"), ("read_only_space", 0x03359): (131, "BasicBlockCountersMarkerMap"),
("read_only_space", 0x05cc1): (134, "CallableTaskMap"), ("read_only_space", 0x0339d): (147, "ArrayBoilerplateDescriptionMap"),
("read_only_space", 0x05ce9): (135, "CallbackTaskMap"), ("read_only_space", 0x0349d): (159, "InterceptorInfoMap"),
("read_only_space", 0x05d11): (136, "PromiseResolveThenableJobTaskMap"), ("read_only_space", 0x05d11): (132, "PromiseFulfillReactionJobTaskMap"),
("read_only_space", 0x05d39): (139, "FunctionTemplateInfoMap"), ("read_only_space", 0x05d39): (133, "PromiseRejectReactionJobTaskMap"),
("read_only_space", 0x05d61): (140, "ObjectTemplateInfoMap"), ("read_only_space", 0x05d61): (134, "CallableTaskMap"),
("read_only_space", 0x05d89): (141, "AccessCheckInfoMap"), ("read_only_space", 0x05d89): (135, "CallbackTaskMap"),
("read_only_space", 0x05db1): (142, "AccessorInfoMap"), ("read_only_space", 0x05db1): (136, "PromiseResolveThenableJobTaskMap"),
("read_only_space", 0x05dd9): (143, "AccessorPairMap"), ("read_only_space", 0x05dd9): (139, "FunctionTemplateInfoMap"),
("read_only_space", 0x05e01): (144, "AliasedArgumentsEntryMap"), ("read_only_space", 0x05e01): (140, "ObjectTemplateInfoMap"),
("read_only_space", 0x05e29): (145, "AllocationMementoMap"), ("read_only_space", 0x05e29): (141, "AccessCheckInfoMap"),
("read_only_space", 0x05e51): (148, "AsmWasmDataMap"), ("read_only_space", 0x05e51): (142, "AccessorInfoMap"),
("read_only_space", 0x05e79): (149, "AsyncGeneratorRequestMap"), ("read_only_space", 0x05e79): (143, "AccessorPairMap"),
("read_only_space", 0x05ea1): (150, "BreakPointMap"), ("read_only_space", 0x05ea1): (144, "AliasedArgumentsEntryMap"),
("read_only_space", 0x05ec9): (151, "BreakPointInfoMap"), ("read_only_space", 0x05ec9): (145, "AllocationMementoMap"),
("read_only_space", 0x05ef1): (152, "CachedTemplateObjectMap"), ("read_only_space", 0x05ef1): (148, "AsmWasmDataMap"),
("read_only_space", 0x05f19): (154, "ClassPositionsMap"), ("read_only_space", 0x05f19): (149, "AsyncGeneratorRequestMap"),
("read_only_space", 0x05f41): (155, "DebugInfoMap"), ("read_only_space", 0x05f41): (150, "BreakPointMap"),
("read_only_space", 0x05f69): (158, "FunctionTemplateRareDataMap"), ("read_only_space", 0x05f69): (151, "BreakPointInfoMap"),
("read_only_space", 0x05f91): (160, "InterpreterDataMap"), ("read_only_space", 0x05f91): (152, "CachedTemplateObjectMap"),
("read_only_space", 0x05fb9): (161, "ModuleRequestMap"), ("read_only_space", 0x05fb9): (154, "ClassPositionsMap"),
("read_only_space", 0x05fe1): (162, "PromiseCapabilityMap"), ("read_only_space", 0x05fe1): (155, "DebugInfoMap"),
("read_only_space", 0x06009): (163, "PromiseReactionMap"), ("read_only_space", 0x06009): (158, "FunctionTemplateRareDataMap"),
("read_only_space", 0x06031): (164, "PropertyDescriptorObjectMap"), ("read_only_space", 0x06031): (160, "InterpreterDataMap"),
("read_only_space", 0x06059): (165, "PrototypeInfoMap"), ("read_only_space", 0x06059): (161, "ModuleRequestMap"),
("read_only_space", 0x06081): (166, "RegExpBoilerplateDescriptionMap"), ("read_only_space", 0x06081): (162, "PromiseCapabilityMap"),
("read_only_space", 0x060a9): (167, "ScriptMap"), ("read_only_space", 0x060a9): (163, "PromiseReactionMap"),
("read_only_space", 0x060d1): (168, "ScriptOrModuleMap"), ("read_only_space", 0x060d1): (164, "PropertyDescriptorObjectMap"),
("read_only_space", 0x060f9): (169, "SourceTextModuleInfoEntryMap"), ("read_only_space", 0x060f9): (165, "PrototypeInfoMap"),
("read_only_space", 0x06121): (170, "StackFrameInfoMap"), ("read_only_space", 0x06121): (166, "RegExpBoilerplateDescriptionMap"),
("read_only_space", 0x06149): (171, "TemplateObjectDescriptionMap"), ("read_only_space", 0x06149): (167, "ScriptMap"),
("read_only_space", 0x06171): (172, "Tuple2Map"), ("read_only_space", 0x06171): (168, "ScriptOrModuleMap"),
("read_only_space", 0x06199): (173, "WasmContinuationObjectMap"), ("read_only_space", 0x06199): (169, "SourceTextModuleInfoEntryMap"),
("read_only_space", 0x061c1): (174, "WasmExceptionTagMap"), ("read_only_space", 0x061c1): (170, "StackFrameInfoMap"),
("read_only_space", 0x061e9): (175, "WasmIndirectFunctionTableMap"), ("read_only_space", 0x061e9): (171, "TemplateObjectDescriptionMap"),
("read_only_space", 0x06211): (193, "SloppyArgumentsElementsMap"), ("read_only_space", 0x06211): (172, "Tuple2Map"),
("read_only_space", 0x06239): (224, "DescriptorArrayMap"), ("read_only_space", 0x06239): (173, "WasmContinuationObjectMap"),
("read_only_space", 0x06261): (229, "UncompiledDataWithoutPreparseDataMap"), ("read_only_space", 0x06261): (174, "WasmExceptionTagMap"),
("read_only_space", 0x06289): (228, "UncompiledDataWithPreparseDataMap"), ("read_only_space", 0x06289): (175, "WasmIndirectFunctionTableMap"),
("read_only_space", 0x062b1): (245, "OnHeapBasicBlockProfilerDataMap"), ("read_only_space", 0x062b1): (193, "SloppyArgumentsElementsMap"),
("read_only_space", 0x062d9): (207, "TurbofanBitsetTypeMap"), ("read_only_space", 0x062d9): (224, "DescriptorArrayMap"),
("read_only_space", 0x06301): (211, "TurbofanUnionTypeMap"), ("read_only_space", 0x06301): (229, "UncompiledDataWithoutPreparseDataMap"),
("read_only_space", 0x06329): (210, "TurbofanRangeTypeMap"), ("read_only_space", 0x06329): (228, "UncompiledDataWithPreparseDataMap"),
("read_only_space", 0x06351): (208, "TurbofanHeapConstantTypeMap"), ("read_only_space", 0x06351): (245, "OnHeapBasicBlockProfilerDataMap"),
("read_only_space", 0x06379): (209, "TurbofanOtherNumberConstantTypeMap"), ("read_only_space", 0x06379): (207, "TurbofanBitsetTypeMap"),
("read_only_space", 0x063a1): (241, "InternalClassMap"), ("read_only_space", 0x063a1): (211, "TurbofanUnionTypeMap"),
("read_only_space", 0x063c9): (252, "SmiPairMap"), ("read_only_space", 0x063c9): (210, "TurbofanRangeTypeMap"),
("read_only_space", 0x063f1): (251, "SmiBoxMap"), ("read_only_space", 0x063f1): (208, "TurbofanHeapConstantTypeMap"),
("read_only_space", 0x06419): (216, "ExportedSubClassBaseMap"), ("read_only_space", 0x06419): (209, "TurbofanOtherNumberConstantTypeMap"),
("read_only_space", 0x06441): (217, "ExportedSubClassMap"), ("read_only_space", 0x06441): (241, "InternalClassMap"),
("read_only_space", 0x06469): (222, "AbstractInternalClassSubclass1Map"), ("read_only_space", 0x06469): (252, "SmiPairMap"),
("read_only_space", 0x06491): (223, "AbstractInternalClassSubclass2Map"), ("read_only_space", 0x06491): (251, "SmiBoxMap"),
("read_only_space", 0x064b9): (192, "InternalClassWithSmiElementsMap"), ("read_only_space", 0x064b9): (216, "ExportedSubClassBaseMap"),
("read_only_space", 0x064e1): (242, "InternalClassWithStructElementsMap"), ("read_only_space", 0x064e1): (217, "ExportedSubClassMap"),
("read_only_space", 0x06509): (218, "ExportedSubClass2Map"), ("read_only_space", 0x06509): (222, "AbstractInternalClassSubclass1Map"),
("read_only_space", 0x06531): (253, "SortStateMap"), ("read_only_space", 0x06531): (223, "AbstractInternalClassSubclass2Map"),
("read_only_space", 0x06559): (146, "AllocationSiteWithWeakNextMap"), ("read_only_space", 0x06559): (192, "InternalClassWithSmiElementsMap"),
("read_only_space", 0x06581): (146, "AllocationSiteWithoutWeakNextMap"), ("read_only_space", 0x06581): (242, "InternalClassWithStructElementsMap"),
("read_only_space", 0x065a9): (137, "LoadHandler1Map"), ("read_only_space", 0x065a9): (218, "ExportedSubClass2Map"),
("read_only_space", 0x065d1): (137, "LoadHandler2Map"), ("read_only_space", 0x065d1): (253, "SortStateMap"),
("read_only_space", 0x065f9): (137, "LoadHandler3Map"), ("read_only_space", 0x065f9): (146, "AllocationSiteWithWeakNextMap"),
("read_only_space", 0x06621): (138, "StoreHandler0Map"), ("read_only_space", 0x06621): (146, "AllocationSiteWithoutWeakNextMap"),
("read_only_space", 0x06649): (138, "StoreHandler1Map"), ("read_only_space", 0x06649): (137, "LoadHandler1Map"),
("read_only_space", 0x06671): (138, "StoreHandler2Map"), ("read_only_space", 0x06671): (137, "LoadHandler2Map"),
("read_only_space", 0x06699): (138, "StoreHandler3Map"), ("read_only_space", 0x06699): (137, "LoadHandler3Map"),
("read_only_space", 0x066c1): (138, "StoreHandler0Map"),
("read_only_space", 0x066e9): (138, "StoreHandler1Map"),
("read_only_space", 0x06711): (138, "StoreHandler2Map"),
("read_only_space", 0x06739): (138, "StoreHandler3Map"),
("map_space", 0x02119): (1057, "ExternalMap"), ("map_space", 0x02119): (1057, "ExternalMap"),
("map_space", 0x02141): (2114, "JSMessageObjectMap"), ("map_space", 0x02141): (2114, "JSMessageObjectMap"),
} }
...@@ -447,32 +453,32 @@ KNOWN_OBJECTS = { ...@@ -447,32 +453,32 @@ KNOWN_OBJECTS = {
("read_only_space", 0x02831): "TerminationException", ("read_only_space", 0x02831): "TerminationException",
("read_only_space", 0x02899): "OptimizedOut", ("read_only_space", 0x02899): "OptimizedOut",
("read_only_space", 0x028f9): "StaleRegister", ("read_only_space", 0x028f9): "StaleRegister",
("read_only_space", 0x032e1): "EmptyPropertyArray", ("read_only_space", 0x03381): "EmptyPropertyArray",
("read_only_space", 0x032e9): "EmptyByteArray", ("read_only_space", 0x03389): "EmptyByteArray",
("read_only_space", 0x032f1): "EmptyObjectBoilerplateDescription", ("read_only_space", 0x03391): "EmptyObjectBoilerplateDescription",
("read_only_space", 0x03325): "EmptyArrayBoilerplateDescription", ("read_only_space", 0x033c5): "EmptyArrayBoilerplateDescription",
("read_only_space", 0x03331): "EmptyClosureFeedbackCellArray", ("read_only_space", 0x033d1): "EmptyClosureFeedbackCellArray",
("read_only_space", 0x03339): "EmptySlowElementDictionary", ("read_only_space", 0x033d9): "EmptySlowElementDictionary",
("read_only_space", 0x0335d): "EmptyOrderedHashMap", ("read_only_space", 0x033fd): "EmptyOrderedHashMap",
("read_only_space", 0x03371): "EmptyOrderedHashSet", ("read_only_space", 0x03411): "EmptyOrderedHashSet",
("read_only_space", 0x03385): "EmptyFeedbackMetadata", ("read_only_space", 0x03425): "EmptyFeedbackMetadata",
("read_only_space", 0x03391): "EmptyPropertyDictionary", ("read_only_space", 0x03431): "EmptyPropertyDictionary",
("read_only_space", 0x033b9): "EmptyOrderedPropertyDictionary", ("read_only_space", 0x03459): "EmptyOrderedPropertyDictionary",
("read_only_space", 0x033d1): "EmptySwissPropertyDictionary", ("read_only_space", 0x03471): "EmptySwissPropertyDictionary",
("read_only_space", 0x03425): "NoOpInterceptorInfo", ("read_only_space", 0x034c5): "NoOpInterceptorInfo",
("read_only_space", 0x0344d): "EmptyWeakFixedArray", ("read_only_space", 0x034ed): "EmptyWeakFixedArray",
("read_only_space", 0x03455): "InfinityValue", ("read_only_space", 0x034f5): "InfinityValue",
("read_only_space", 0x03461): "MinusZeroValue", ("read_only_space", 0x03501): "MinusZeroValue",
("read_only_space", 0x0346d): "MinusInfinityValue", ("read_only_space", 0x0350d): "MinusInfinityValue",
("read_only_space", 0x03479): "SelfReferenceMarker", ("read_only_space", 0x03519): "SelfReferenceMarker",
("read_only_space", 0x034b9): "BasicBlockCountersMarker", ("read_only_space", 0x03559): "BasicBlockCountersMarker",
("read_only_space", 0x034fd): "OffHeapTrampolineRelocationInfo", ("read_only_space", 0x0359d): "OffHeapTrampolineRelocationInfo",
("read_only_space", 0x03509): "TrampolineTrivialCodeDataContainer", ("read_only_space", 0x035a9): "TrampolineTrivialCodeDataContainer",
("read_only_space", 0x03515): "TrampolinePromiseRejectionCodeDataContainer", ("read_only_space", 0x035b5): "TrampolinePromiseRejectionCodeDataContainer",
("read_only_space", 0x03521): "GlobalThisBindingScopeInfo", ("read_only_space", 0x035c1): "GlobalThisBindingScopeInfo",
("read_only_space", 0x03551): "EmptyFunctionScopeInfo", ("read_only_space", 0x035f1): "EmptyFunctionScopeInfo",
("read_only_space", 0x03575): "NativeScopeInfo", ("read_only_space", 0x03615): "NativeScopeInfo",
("read_only_space", 0x0358d): "HashSeed", ("read_only_space", 0x0362d): "HashSeed",
("old_space", 0x04211): "ArgumentsIteratorAccessor", ("old_space", 0x04211): "ArgumentsIteratorAccessor",
("old_space", 0x04255): "ArrayLengthAccessor", ("old_space", 0x04255): "ArrayLengthAccessor",
("old_space", 0x04299): "BoundFunctionLengthAccessor", ("old_space", 0x04299): "BoundFunctionLengthAccessor",
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment