[snapshot] Support shared string table with --stress-snapshot

Bug: v8:12584, v8:12007
Change-Id: Iac3c8b1c5935142742dddc7e12293fd7640c06a3
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3419736
Auto-Submit: Shu-yu Guo <syg@chromium.org>
Reviewed-by: Leszek Swirski <leszeks@chromium.org>
Commit-Queue: Leszek Swirski <leszeks@chromium.org>
Cr-Commit-Position: refs/heads/main@{#78804}
This commit is contained in:
Shu-yu Guo 2022-01-26 20:04:18 -08:00 committed by V8 LUCI CQ
parent 3b233c9f25
commit 7437c69093
6 changed files with 53 additions and 17 deletions

View File

@ -74,7 +74,7 @@ void ReadOnlySerializer::SerializeReadOnlyRoots() {
ReadOnlyRoots(isolate()).Iterate(this); ReadOnlyRoots(isolate()).Iterate(this);
if (reconstruct_read_only_object_cache_for_testing()) { if (reconstruct_read_only_and_shared_object_caches_for_testing()) {
ReconstructReadOnlyObjectCacheForTesting(); ReconstructReadOnlyObjectCacheForTesting();
} }
} }

View File

@ -309,8 +309,9 @@ class Serializer : public SerializerDeserializer {
return (flags_ & Snapshot::kAllowActiveIsolateForTesting) != 0; return (flags_ & Snapshot::kAllowActiveIsolateForTesting) != 0;
} }
bool reconstruct_read_only_object_cache_for_testing() const { bool reconstruct_read_only_and_shared_object_caches_for_testing() const {
return (flags_ & Snapshot::kReconstructReadOnlyObjectCacheForTesting) != 0; return (flags_ &
Snapshot::kReconstructReadOnlyAndSharedObjectCachesForTesting) != 0;
} }
private: private:

View File

@ -65,10 +65,6 @@ void SharedHeapSerializer::FinalizeSerialization() {
Pad(); Pad();
#ifdef DEBUG #ifdef DEBUG
// During snapshotting there is no shared heap.
CHECK(!isolate()->is_shared());
CHECK_NULL(isolate()->shared_isolate());
// Check that all serialized object are in shared heap and not RO. RO objects // Check that all serialized object are in shared heap and not RO. RO objects
// should be in the RO snapshot. // should be in the RO snapshot.
IdentityMap<int, base::DefaultAllocationPolicy>::IteratableScope it_scope( IdentityMap<int, base::DefaultAllocationPolicy>::IteratableScope it_scope(
@ -90,6 +86,20 @@ bool SharedHeapSerializer::SerializeUsingSharedHeapObjectCache(
SnapshotByteSink* sink, Handle<HeapObject> obj) { SnapshotByteSink* sink, Handle<HeapObject> obj) {
if (!ShouldBeInSharedHeapObjectCache(*obj)) return false; if (!ShouldBeInSharedHeapObjectCache(*obj)) return false;
int cache_index = SerializeInObjectCache(obj); int cache_index = SerializeInObjectCache(obj);
// When testing deserialization of a snapshot from a live isolate, the shared
// object cache needs to be extended because the live isolate may have had new
// internalized strings that were not present in the startup snapshot to be
// serialized.
if (reconstruct_read_only_and_shared_object_caches_for_testing()) {
const size_t existing_cache_size =
isolate()->shared_heap_object_cache()->size();
DCHECK_LE(base::checked_cast<size_t>(cache_index), existing_cache_size);
if (base::checked_cast<size_t>(cache_index) == existing_cache_size) {
isolate()->shared_heap_object_cache()->push_back(*obj);
}
}
sink->Put(kSharedHeapObjectCache, "SharedHeapObjectCache"); sink->Put(kSharedHeapObjectCache, "SharedHeapObjectCache");
sink->PutInt(cache_index, "shared_heap_object_cache_index"); sink->PutInt(cache_index, "shared_heap_object_cache_index");
return true; return true;
@ -170,5 +180,18 @@ void SharedHeapSerializer::SerializeObjectImpl(Handle<HeapObject> obj) {
#endif #endif
} }
void SharedHeapSerializer::
ReconstructSharedHeapObjectCacheForTestingIfNeeded() {
if (!reconstruct_read_only_and_shared_object_caches_for_testing()) return;
std::vector<Object>* cache = isolate()->shared_heap_object_cache();
DCHECK_EQ(isolate()->shared_isolate()->shared_heap_object_cache(), cache);
for (size_t i = 0, size = cache->size(); i < size; i++) {
Handle<HeapObject> obj(HeapObject::cast(cache->at(i)), isolate());
int cache_index = SerializeInObjectCache(obj);
USE(cache_index);
DCHECK_EQ(cache_index, i);
}
}
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8

View File

@ -43,6 +43,8 @@ class V8_EXPORT_PRIVATE SharedHeapSerializer : public RootsSerializer {
bool SerializeUsingSharedHeapObjectCache(SnapshotByteSink* sink, bool SerializeUsingSharedHeapObjectCache(SnapshotByteSink* sink,
Handle<HeapObject> obj); Handle<HeapObject> obj);
void ReconstructSharedHeapObjectCacheForTestingIfNeeded();
static bool CanBeInSharedOldSpace(HeapObject obj); static bool CanBeInSharedOldSpace(HeapObject obj);
static bool ShouldBeInSharedHeapObjectCache(HeapObject obj); static bool ShouldBeInSharedHeapObjectCache(HeapObject obj);

View File

@ -313,13 +313,17 @@ void Snapshot::SerializeDeserializeAndVerifyForTesting(
// Test serialization. // Test serialization.
{ {
GlobalSafepointScope global_safepoint(isolate); GlobalSafepointScope global_safepoint(isolate);
base::Optional<SafepointScope> shared_isolate_safepoint_scope;
if (Isolate* shared_isolate = isolate->shared_isolate()) {
shared_isolate_safepoint_scope.emplace(shared_isolate->heap());
}
DisallowGarbageCollection no_gc; DisallowGarbageCollection no_gc;
Snapshot::SerializerFlags flags( Snapshot::SerializerFlags flags(
Snapshot::kAllowUnknownExternalReferencesForTesting | Snapshot::kAllowUnknownExternalReferencesForTesting |
Snapshot::kAllowActiveIsolateForTesting | Snapshot::kAllowActiveIsolateForTesting |
(ReadOnlyHeap::IsReadOnlySpaceShared() ((isolate->shared_isolate() || ReadOnlyHeap::IsReadOnlySpaceShared())
? Snapshot::kReconstructReadOnlyObjectCacheForTesting ? Snapshot::kReconstructReadOnlyAndSharedObjectCachesForTesting
: 0)); : 0));
serialized_data = Snapshot::Create(isolate, *default_context, serialized_data = Snapshot::Create(isolate, *default_context,
global_safepoint, no_gc, flags); global_safepoint, no_gc, flags);
@ -337,6 +341,9 @@ void Snapshot::SerializeDeserializeAndVerifyForTesting(
new_isolate->set_snapshot_blob(&serialized_data); new_isolate->set_snapshot_blob(&serialized_data);
new_isolate->set_array_buffer_allocator( new_isolate->set_array_buffer_allocator(
v8::ArrayBuffer::Allocator::NewDefaultAllocator()); v8::ArrayBuffer::Allocator::NewDefaultAllocator());
if (Isolate* shared_isolate = isolate->shared_isolate()) {
new_isolate->set_shared_isolate(shared_isolate);
}
CHECK(Snapshot::Initialize(new_isolate)); CHECK(Snapshot::Initialize(new_isolate));
HandleScope scope(new_isolate); HandleScope scope(new_isolate);
@ -376,6 +383,7 @@ v8::StartupData Snapshot::Create(
SharedHeapSerializer shared_heap_serializer(isolate, flags, SharedHeapSerializer shared_heap_serializer(isolate, flags,
&read_only_serializer); &read_only_serializer);
shared_heap_serializer.ReconstructSharedHeapObjectCacheForTestingIfNeeded();
StartupSerializer startup_serializer(isolate, flags, &read_only_serializer, StartupSerializer startup_serializer(isolate, flags, &read_only_serializer,
&shared_heap_serializer); &shared_heap_serializer);

View File

@ -39,15 +39,17 @@ class Snapshot : public AllStatic {
// after deserialization. // after deserialization.
// If unset, we assert that these previously mentioned areas are empty. // If unset, we assert that these previously mentioned areas are empty.
kAllowActiveIsolateForTesting = 1 << 1, kAllowActiveIsolateForTesting = 1 << 1,
// If set, the ReadOnlySerializer reconstructs the read-only object cache // If set, the ReadOnlySerializer and the SharedHeapSerializer reconstructs
// from the existing ReadOnlyHeap's read-only object cache so the same // their respective object caches from the existing ReadOnlyHeap's read-only
// object cache or the existing shared heap's object cache so the same
// mapping is used. This mode is used for testing deserialization of a // mapping is used. This mode is used for testing deserialization of a
// snapshot from a live isolate that's using a shared // snapshot from a live isolate that's using a shared ReadOnlyHeap or is
// ReadOnlyHeap. Otherwise during deserialization the indices will mismatch, // attached to a shared isolate. Otherwise during deserialization the
// causing deserialization crashes when e.g. types mismatch. // indices will mismatch, causing deserialization crashes when e.g. types
// If unset, the read-only object cache is populated as read-only objects // mismatch. If unset, the read-only object cache is populated as read-only
// are serialized. // objects are serialized, and the shared heap object cache is populated as
kReconstructReadOnlyObjectCacheForTesting = 1 << 2, // shared heap objects are serialized.
kReconstructReadOnlyAndSharedObjectCachesForTesting = 1 << 2,
}; };
using SerializerFlags = base::Flags<SerializerFlag>; using SerializerFlags = base::Flags<SerializerFlag>;
V8_EXPORT_PRIVATE static constexpr SerializerFlags kDefaultSerializerFlags = V8_EXPORT_PRIVATE static constexpr SerializerFlags kDefaultSerializerFlags =