Commit b0bcd45d authored by Maciej Goszczycki's avatar Maciej Goszczycki Committed by Commit Bot

[heap] Isolate read-only space creation

This provides a single point where read-only space sharing will be
controlled. Eventually ReadOnlyDeserializer will take ReadOnlyHeap
instead of Isolate, first steps include
https://chromium-review.googlesource.com/c/v8/v8/+/1483054

Bug: v8:7464
Change-Id: I213819aeca6fca335235025c9195edf474230eda
Reviewed-on: https://chromium-review.googlesource.com/c/1489087
Commit-Queue: Maciej Goszczycki <goszczycki@google.com>
Reviewed-by: 's avatarDan Elphick <delphick@chromium.org>
Reviewed-by: 's avatarMichael Lippautz <mlippautz@chromium.org>
Cr-Commit-Position: refs/heads/master@{#59954}
parent 506f79b8
......@@ -2108,6 +2108,8 @@ v8_source_set("v8_base") {
"src/heap/objects-visiting-inl.h",
"src/heap/objects-visiting.cc",
"src/heap/objects-visiting.h",
"src/heap/read-only-heap.cc",
"src/heap/read-only-heap.h",
"src/heap/remembered-set.h",
"src/heap/scavenge-job.cc",
"src/heap/scavenge-job.h",
......
......@@ -15,6 +15,7 @@ include_rules = [
"+src/heap/heap-inl.h",
"+src/heap/heap-write-barrier-inl.h",
"+src/heap/heap-write-barrier.h",
"+src/heap/read-only-heap.h",
"-src/inspector",
"-src/interpreter",
"+src/interpreter/bytecode-array-accessor.h",
......
......@@ -584,7 +584,7 @@ SnapshotCreator::SnapshotCreator(Isolate* isolate,
internal_isolate->set_snapshot_blob(blob);
i::Snapshot::Initialize(internal_isolate);
} else {
internal_isolate->Init(nullptr);
internal_isolate->InitWithoutSnapshot();
}
data_ = data;
}
......@@ -8209,7 +8209,7 @@ void Isolate::Initialize(Isolate* isolate,
}
base::ElapsedTimer timer;
if (i::FLAG_profile_deserialization) timer.Start();
i_isolate->Init(nullptr);
i_isolate->InitWithoutSnapshot();
if (i::FLAG_profile_deserialization) {
double ms = timer.Elapsed().InMillisecondsF();
i::PrintF("[Initializing isolate from scratch took %0.3f ms]\n", ms);
......
......@@ -663,6 +663,8 @@ enum AllocationSpace {
FIRST_SPACE = RO_SPACE,
LAST_SPACE = NEW_LO_SPACE,
FIRST_MUTABLE_SPACE = NEW_SPACE,
LAST_MUTABLE_SPACE = NEW_LO_SPACE,
FIRST_GROWABLE_PAGED_SPACE = OLD_SPACE,
LAST_GROWABLE_PAGED_SPACE = MAP_SPACE
};
......
......@@ -37,6 +37,7 @@
#include "src/heap/object-stats.h"
#include "src/heap/objects-visiting-inl.h"
#include "src/heap/objects-visiting.h"
#include "src/heap/read-only-heap.h"
#include "src/heap/remembered-set.h"
#include "src/heap/scavenge-job.h"
#include "src/heap/scavenger-inl.h"
......@@ -4493,7 +4494,7 @@ HeapObject Heap::AllocateRawCodeInLargeObjectSpace(int size) {
return HeapObject();
}
void Heap::SetUp() {
void Heap::SetUp(ReadOnlyHeap* ro_heap) {
#ifdef V8_ENABLE_ALLOCATION_TIMEOUT
allocation_timeout_ = NextAllocationTimeout();
#endif
......@@ -4506,6 +4507,9 @@ void Heap::SetUp() {
// and old_generation_size_ otherwise.
if (!configured_) ConfigureHeapDefault();
DCHECK_NOT_NULL(ro_heap);
read_only_heap_ = ro_heap;
mmap_region_base_ =
reinterpret_cast<uintptr_t>(v8::internal::GetRandomMmapAddr()) &
~kMmapRegionMask;
......@@ -4541,7 +4545,8 @@ void Heap::SetUp() {
space_[i] = nullptr;
}
space_[RO_SPACE] = read_only_space_ = new ReadOnlySpace(this);
space_[RO_SPACE] = read_only_space_ = ro_heap->read_only_space();
DCHECK_NOT_NULL(read_only_space_);
space_[NEW_SPACE] = new_space_ =
new NewSpace(this, memory_allocator_->data_page_allocator(),
initial_semispace_size_, max_semi_space_size_);
......@@ -4818,7 +4823,9 @@ void Heap::TearDown() {
tracer_.reset();
for (int i = FIRST_SPACE; i <= LAST_SPACE; i++) {
read_only_heap_->OnHeapTearDown();
space_[RO_SPACE] = read_only_space_ = nullptr;
for (int i = FIRST_MUTABLE_SPACE; i <= LAST_MUTABLE_SPACE; i++) {
delete space_[i];
space_[i] = nullptr;
}
......
......@@ -76,6 +76,7 @@ class ObjectIterator;
class ObjectStats;
class Page;
class PagedSpace;
class ReadOnlyHeap;
class RootVisitor;
class ScavengeJob;
class Scavenger;
......@@ -579,7 +580,7 @@ class Heap {
// Prepares the heap, setting up memory areas that are needed in the isolate
// without actually creating any objects.
void SetUp();
void SetUp(ReadOnlyHeap* ro_heap);
// (Re-)Initialize hash seed from flag or RNG.
void InitializeHashSeed();
......@@ -625,6 +626,8 @@ class Heap {
// Getters to other components. ==============================================
// ===========================================================================
ReadOnlyHeap* read_only_heap() const { return read_only_heap_; }
GCTracer* tracer() { return tracer_.get(); }
MemoryAllocator* memory_allocator() { return memory_allocator_.get(); }
......@@ -1788,6 +1791,8 @@ class Heap {
// and after context disposal.
int number_of_disposed_maps_ = 0;
ReadOnlyHeap* read_only_heap_ = nullptr;
NewSpace* new_space_ = nullptr;
OldSpace* old_space_ = nullptr;
CodeSpace* code_space_ = nullptr;
......
// Copyright 2019 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.
#include "src/heap/read-only-heap.h"
#include "src/heap/spaces.h"
namespace v8 {
namespace internal {
// static
ReadOnlyHeap* ReadOnlyHeap::GetOrCreateReadOnlyHeap(Heap* heap) {
return new ReadOnlyHeap(new ReadOnlySpace(heap));
}
void ReadOnlyHeap::MaybeDeserialize(Isolate* isolate,
ReadOnlyDeserializer* des) {
des->DeserializeInto(isolate);
}
void ReadOnlyHeap::OnHeapTearDown() {
delete read_only_space_;
delete this;
}
} // namespace internal
} // namespace v8
// Copyright 2019 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_HEAP_READ_ONLY_HEAP_H_
#define V8_HEAP_READ_ONLY_HEAP_H_
#include "src/base/macros.h"
#include "src/heap/heap.h"
#include "src/roots.h"
#include "src/snapshot/read-only-deserializer.h"
namespace v8 {
namespace internal {
class ReadOnlySpace;
// This class transparently manages read-only space, roots and cache creation
// and destruction. Eventually this will allow sharing these artifacts between
// isolates.
class ReadOnlyHeap {
public:
static ReadOnlyHeap* GetOrCreateReadOnlyHeap(Heap* heap);
// If necessary, deserialize read-only objects and set up read-only object
// cache.
void MaybeDeserialize(Isolate* isolate, ReadOnlyDeserializer* des);
// Frees ReadOnlySpace and itself when sharing is disabled. No-op otherwise.
// Read-only data should not be used within the current isolate after this is
// called.
void OnHeapTearDown();
std::vector<Object>* read_only_object_cache() {
return &read_only_object_cache_;
}
ReadOnlySpace* read_only_space() const { return read_only_space_; }
private:
ReadOnlySpace* read_only_space_ = nullptr;
std::vector<Object> read_only_object_cache_;
explicit ReadOnlyHeap(ReadOnlySpace* ro_space) : read_only_space_(ro_space) {}
DISALLOW_COPY_AND_ASSIGN(ReadOnlyHeap);
};
} // namespace internal
} // namespace v8
#endif // V8_HEAP_READ_ONLY_HEAP_H_
......@@ -1436,14 +1436,14 @@ class V8_EXPORT_PRIVATE MemoryAllocator {
Unmapper* unmapper() { return &unmapper_; }
private:
void InitializeCodePageAllocator(v8::PageAllocator* page_allocator,
size_t requested);
// PreFree logically frees the object, i.e., it takes care of the size
// bookkeeping and calls the allocation callback.
void PreFreeMemory(MemoryChunk* chunk);
private:
void InitializeCodePageAllocator(v8::PageAllocator* page_allocator,
size_t requested);
// FreeMemory can be called concurrently when PreFree was executed before.
void PerformFreeMemory(MemoryChunk* chunk);
......
......@@ -37,6 +37,7 @@
#include "src/frames-inl.h"
#include "src/hash-seed-inl.h"
#include "src/heap/heap-inl.h"
#include "src/heap/read-only-heap.h"
#include "src/ic/stub-cache.h"
#include "src/interpreter/interpreter.h"
#include "src/isolate-inl.h"
......@@ -64,6 +65,7 @@
#include "src/simulator.h"
#include "src/snapshot/embedded-data.h"
#include "src/snapshot/embedded-file-writer.h"
#include "src/snapshot/read-only-deserializer.h"
#include "src/snapshot/startup-deserializer.h"
#include "src/string-stream.h"
#include "src/tracing/tracing-category-observer.h"
......@@ -3262,11 +3264,24 @@ void Isolate::TearDownEmbeddedBlob() {
}
}
bool Isolate::Init(StartupDeserializer* des) {
bool Isolate::InitWithoutSnapshot() { return Init(nullptr, nullptr); }
bool Isolate::InitWithSnapshot(ReadOnlyDeserializer* read_only_deserializer,
StartupDeserializer* startup_deserializer) {
DCHECK_NOT_NULL(read_only_deserializer);
DCHECK_NOT_NULL(startup_deserializer);
return Init(read_only_deserializer, startup_deserializer);
}
bool Isolate::Init(ReadOnlyDeserializer* read_only_deserializer,
StartupDeserializer* startup_deserializer) {
TRACE_ISOLATE(init);
const bool create_heap_objects = (read_only_deserializer == nullptr);
// We either have both or neither.
DCHECK_EQ(create_heap_objects, startup_deserializer == nullptr);
base::ElapsedTimer timer;
if (des == nullptr && FLAG_profile_deserialization) timer.Start();
if (create_heap_objects && FLAG_profile_deserialization) timer.Start();
time_millis_at_init_ = heap_.MonotonicallyIncreasingTimeInMs();
......@@ -3320,7 +3335,8 @@ bool Isolate::Init(StartupDeserializer* des) {
// SetUp the object heap.
DCHECK(!heap_.HasBeenSetUp());
heap_.SetUp();
auto* read_only_heap = ReadOnlyHeap::GetOrCreateReadOnlyHeap(&heap_);
heap_.SetUp(read_only_heap);
isolate_data_.external_reference_table()->Init(this);
......@@ -3332,7 +3348,6 @@ bool Isolate::Init(StartupDeserializer* des) {
deoptimizer_data_ = new DeoptimizerData(heap());
const bool create_heap_objects = (des == nullptr);
if (setup_delegate_ == nullptr) {
setup_delegate_ = new SetupIsolateDelegate(create_heap_objects);
}
......@@ -3404,7 +3419,10 @@ bool Isolate::Init(StartupDeserializer* des) {
AlwaysAllocateScope always_allocate(this);
CodeSpaceMemoryModificationScope modification_scope(&heap_);
if (!create_heap_objects) des->DeserializeInto(this);
if (!create_heap_objects) {
read_only_heap->MaybeDeserialize(this, read_only_deserializer);
startup_deserializer->DeserializeInto(this);
}
load_stub_cache_->Initialize();
store_stub_cache_->Initialize();
interpreter_->Initialize();
......@@ -3463,7 +3481,7 @@ bool Isolate::Init(StartupDeserializer* des) {
ast_string_constants_ = new AstStringConstants(this, HashSeed(this));
}
initialized_from_snapshot_ = (des != nullptr);
initialized_from_snapshot_ = !create_heap_objects;
if (!FLAG_inline_new) heap_.DisableInlineAllocation();
......@@ -3476,7 +3494,7 @@ bool Isolate::Init(StartupDeserializer* des) {
sampling_flags);
}
if (des == nullptr && FLAG_profile_deserialization) {
if (create_heap_objects && FLAG_profile_deserialization) {
double ms = timer.Elapsed().InMillisecondsF();
PrintF("[Initializing isolate from scratch took %0.3f ms]\n", ms);
}
......@@ -3484,7 +3502,6 @@ bool Isolate::Init(StartupDeserializer* des) {
return true;
}
void Isolate::Enter() {
Isolate* current_isolate = nullptr;
PerIsolateThreadData* current_data = CurrentPerIsolateThreadData();
......
......@@ -84,6 +84,7 @@ class MaterializedObjectStore;
class Microtask;
class MicrotaskQueue;
class OptimizingCompileDispatcher;
class ReadOnlyDeserializer;
class RegExpStack;
class RootVisitor;
class RuntimeProfiler;
......@@ -518,7 +519,9 @@ class Isolate final : private HiddenFactory {
void InitializeLoggingAndCounters();
bool InitializeCounters(); // Returns false if already initialized.
bool Init(StartupDeserializer* des);
bool InitWithoutSnapshot();
bool InitWithSnapshot(ReadOnlyDeserializer* read_only_deserializer,
StartupDeserializer* startup_deserializer);
// True if at least one thread Enter'ed this isolate.
bool IsInUse() { return entry_stack_ != nullptr; }
......@@ -1349,10 +1352,6 @@ class Isolate final : private HiddenFactory {
void AddDetachedContext(Handle<Context> context);
void CheckDetachedContextsAfterGC();
std::vector<Object>* read_only_object_cache() {
return &read_only_object_cache_;
}
std::vector<Object>* partial_snapshot_cache() {
return &partial_snapshot_cache_;
}
......@@ -1498,6 +1497,9 @@ class Isolate final : private HiddenFactory {
explicit Isolate(std::unique_ptr<IsolateAllocator> isolate_allocator);
~Isolate();
bool Init(ReadOnlyDeserializer* read_only_deserializer,
StartupDeserializer* startup_deserializer);
void CheckIsolateLayout();
class ThreadDataTable {
......@@ -1751,7 +1753,6 @@ class Isolate final : private HiddenFactory {
v8::Isolate::UseCounterCallback use_counter_callback_ = nullptr;
std::vector<Object> read_only_object_cache_;
std::vector<Object> partial_snapshot_cache_;
// Used during builtins compilation to build the builtins constants table,
......
......@@ -7,6 +7,7 @@
#include "src/assembler-inl.h"
#include "src/heap/heap-inl.h"
#include "src/heap/heap-write-barrier-inl.h"
#include "src/heap/read-only-heap.h"
#include "src/interpreter/interpreter.h"
#include "src/isolate.h"
#include "src/log.h"
......@@ -794,8 +795,9 @@ TSlot Deserializer::ReadDataCase(Isolate* isolate, TSlot current,
hot_objects_.Add(heap_object);
} else if (bytecode == kReadOnlyObjectCache) {
int cache_index = source_.GetInt();
heap_object =
HeapObject::cast(isolate->read_only_object_cache()->at(cache_index));
heap_object = HeapObject::cast(
isolate->heap()->read_only_heap()->read_only_object_cache()->at(
cache_index));
DCHECK(!Heap::InYoungGeneration(heap_object));
emit_write_barrier = false;
} else if (bytecode == kPartialSnapshotCache) {
......
......@@ -6,6 +6,7 @@
#include "src/api.h"
#include "src/heap/heap-inl.h" // crbug.com/v8/8499
#include "src/heap/read-only-heap.h"
#include "src/objects/slots.h"
#include "src/snapshot/snapshot.h"
#include "src/v8threads.h"
......@@ -25,19 +26,24 @@ void ReadOnlyDeserializer::DeserializeInto(Isolate* isolate) {
// No active handles.
DCHECK(isolate->handle_scope_implementer()->blocks()->empty());
// Partial snapshot cache is not yet populated.
DCHECK(isolate->read_only_object_cache()->empty());
DCHECK(isolate->heap()->read_only_heap()->read_only_object_cache()->empty());
DCHECK(isolate->partial_snapshot_cache()->empty());
// Builtins are not yet created.
DCHECK(!isolate->builtins()->is_initialized());
{
DisallowHeapAllocation no_gc;
ReadOnlyRoots roots(isolate);
ReadOnlyRoots(isolate).Iterate(this);
isolate->heap()->read_only_space()->RepairFreeListsAfterDeserialization();
roots.Iterate(this);
isolate->heap()
->read_only_heap()
->read_only_space()
->RepairFreeListsAfterDeserialization();
// Deserialize the Read-only Object Cache.
std::vector<Object>* cache = isolate->read_only_object_cache();
std::vector<Object>* cache =
isolate->heap()->read_only_heap()->read_only_object_cache();
for (size_t i = 0;; ++i) {
// Extend the array ready to get a value when deserializing.
if (cache->size() <= i) cache->push_back(Smi::kZero);
......@@ -45,15 +51,15 @@ void ReadOnlyDeserializer::DeserializeInto(Isolate* isolate) {
// cache and eventually terminates the cache with undefined.
VisitRootPointer(Root::kReadOnlyObjectCache, nullptr,
FullObjectSlot(&cache->at(i)));
if (cache->at(i)->IsUndefined(isolate)) break;
if (cache->at(i)->IsUndefined(roots)) break;
}
DeserializeDeferredObjects();
}
}
void ReadOnlyDeserializer::RehashHeap() {
DCHECK(FLAG_rehash_snapshot && can_rehash());
Rehash();
if (FLAG_rehash_snapshot && can_rehash()) {
isolate_->heap()->InitializeHashSeed();
Rehash();
}
}
} // namespace internal
......
......@@ -20,12 +20,6 @@ class ReadOnlyDeserializer final : public Deserializer {
// Deserialize the snapshot into an empty heap.
void DeserializeInto(Isolate* isolate);
private:
friend class StartupDeserializer;
// Rehash after deserializing.
void RehashHeap();
};
} // namespace internal
......
......@@ -9,6 +9,7 @@
#include "src/base/platform/platform.h"
#include "src/counters.h"
#include "src/snapshot/partial-deserializer.h"
#include "src/snapshot/read-only-deserializer.h"
#include "src/snapshot/startup-deserializer.h"
#include "src/version.h"
......@@ -44,10 +45,12 @@ bool Snapshot::Initialize(Isolate* isolate) {
SnapshotData startup_snapshot_data(startup_data);
Vector<const byte> read_only_data = ExtractReadOnlyData(blob);
SnapshotData read_only_snapshot_data(read_only_data);
StartupDeserializer deserializer(&startup_snapshot_data,
&read_only_snapshot_data);
deserializer.SetRehashability(ExtractRehashability(blob));
bool success = isolate->Init(&deserializer);
StartupDeserializer startup_deserializer(&startup_snapshot_data);
ReadOnlyDeserializer read_only_deserializer(&read_only_snapshot_data);
startup_deserializer.SetRehashability(ExtractRehashability(blob));
read_only_deserializer.SetRehashability(ExtractRehashability(blob));
bool success =
isolate->InitWithSnapshot(&read_only_deserializer, &startup_deserializer);
if (FLAG_profile_deserialization) {
double ms = timer.Elapsed().InMillisecondsF();
int bytes = startup_data.length();
......
......@@ -67,6 +67,7 @@ class Snapshot : public AllStatic {
// ---------------- Helper methods ----------------
static bool HasContextSnapshot(Isolate* isolate, size_t index);
static bool EmbedsScript(Isolate* isolate);
// To be implemented by the snapshot source.
static const v8::StartupData* DefaultSnapshotBlob();
......
......@@ -7,7 +7,6 @@
#include "src/api.h"
#include "src/assembler-inl.h"
#include "src/heap/heap-inl.h"
#include "src/snapshot/read-only-deserializer.h"
#include "src/snapshot/snapshot.h"
#include "src/v8threads.h"
......@@ -17,10 +16,6 @@ namespace internal {
void StartupDeserializer::DeserializeInto(Isolate* isolate) {
Initialize(isolate);
ReadOnlyDeserializer read_only_deserializer(read_only_data_);
read_only_deserializer.SetRehashability(can_rehash());
read_only_deserializer.DeserializeInto(isolate);
if (!allocator()->ReserveSpace()) {
V8::FatalProcessOutOfMemory(isolate, "StartupDeserializer");
}
......@@ -64,8 +59,7 @@ void StartupDeserializer::DeserializeInto(Isolate* isolate) {
LogNewMapEvents();
if (FLAG_rehash_snapshot && can_rehash()) {
isolate->heap()->InitializeHashSeed();
read_only_deserializer.RehashHeap();
// Hash seed was initalized in ReadOnlyDeserializer.
Rehash();
}
}
......
......@@ -14,9 +14,8 @@ namespace internal {
// Initializes an isolate with context-independent data from a given snapshot.
class StartupDeserializer final : public Deserializer {
public:
StartupDeserializer(const SnapshotData* startup_data,
const SnapshotData* read_only_data)
: Deserializer(startup_data, false), read_only_data_(read_only_data) {}
explicit StartupDeserializer(const SnapshotData* startup_data)
: Deserializer(startup_data, false) {}
// Deserialize the snapshot into an empty heap.
void DeserializeInto(Isolate* isolate);
......@@ -24,8 +23,6 @@ class StartupDeserializer final : public Deserializer {
private:
void FlushICache();
void LogNewMapEvents();
const SnapshotData* read_only_data_;
};
} // namespace internal
......
......@@ -51,6 +51,7 @@
#include "src/snapshot/natives.h"
#include "src/snapshot/partial-deserializer.h"
#include "src/snapshot/partial-serializer.h"
#include "src/snapshot/read-only-deserializer.h"
#include "src/snapshot/read-only-serializer.h"
#include "src/snapshot/snapshot.h"
#include "src/snapshot/startup-deserializer.h"
......@@ -92,7 +93,7 @@ class TestSerializer {
v8::Isolate* v8_isolate = NewIsolate(kEnableSerializer, kGenerateHeap);
v8::Isolate::Scope isolate_scope(v8_isolate);
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
isolate->Init(nullptr);
isolate->Init(nullptr, nullptr);
isolate->heap()->read_only_space()->ClearStringPaddingIfNeeded();
return v8_isolate;
}
......@@ -100,13 +101,14 @@ class TestSerializer {
static v8::Isolate* NewIsolateFromBlob(StartupBlobs& blobs) {
SnapshotData startup_snapshot(blobs.startup);
SnapshotData read_only_snapshot(blobs.read_only);
StartupDeserializer deserializer(&startup_snapshot, &read_only_snapshot);
ReadOnlyDeserializer read_only_deserializer(&read_only_snapshot);
StartupDeserializer startup_deserializer(&startup_snapshot);
const bool kEnableSerializer = false;
const bool kGenerateHeap = false;
v8::Isolate* v8_isolate = NewIsolate(kEnableSerializer, kGenerateHeap);
v8::Isolate::Scope isolate_scope(v8_isolate);
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
isolate->Init(&deserializer);
isolate->Init(&read_only_deserializer, &startup_deserializer);
return v8_isolate;
}
......
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