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

[heap] Add read-only heap sharing behind a flag

Piggybacking of splitting heap setup, this change adds a shared
read-only heap and a flag to enable it.

Also makes CallOnce use std::function instead of a raw function
pointer so the CL can use lambdas with CallOnce.

Bug: v8:7464
Change-Id: I9a97fb1baa6badca39a7381de3fd9e01f5969340
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1518180Reviewed-by: 's avatarHannes Payer <hpayer@chromium.org>
Reviewed-by: 's avatarDan Elphick <delphick@chromium.org>
Commit-Queue: Maciej Goszczycki <goszczycki@google.com>
Cr-Commit-Position: refs/heads/master@{#60241}
parent 04bb707e
...@@ -171,6 +171,9 @@ declare_args() { ...@@ -171,6 +171,9 @@ declare_args() {
# setting the "check_v8_header_includes" gclient variable to run a # setting the "check_v8_header_includes" gclient variable to run a
# specific hook). # specific hook).
v8_check_header_includes = false v8_check_header_includes = false
# Enable sharing read-only space across isolates.
v8_enable_shared_ro_heap = false
} }
# We reuse the snapshot toolchain for building torque and other generators to # We reuse the snapshot toolchain for building torque and other generators to
...@@ -214,6 +217,9 @@ assert(!v8_enable_lite_mode || v8_enable_embedded_builtins, ...@@ -214,6 +217,9 @@ assert(!v8_enable_lite_mode || v8_enable_embedded_builtins,
assert(!v8_enable_lite_mode || v8_use_snapshot, assert(!v8_enable_lite_mode || v8_use_snapshot,
"Lite mode requires a snapshot build") "Lite mode requires a snapshot build")
assert(v8_use_snapshot || !v8_enable_shared_ro_heap,
"Nosnapshot builds are not supported with shared read-only heap enabled")
v8_random_seed = "314159265" v8_random_seed = "314159265"
v8_toolset_for_shell = "host" v8_toolset_for_shell = "host"
...@@ -404,6 +410,9 @@ config("features") { ...@@ -404,6 +410,9 @@ config("features") {
if (v8_use_siphash) { if (v8_use_siphash) {
defines += [ "V8_USE_SIPHASH" ] defines += [ "V8_USE_SIPHASH" ]
} }
if (v8_enable_shared_ro_heap) {
defines += [ "V8_SHARED_RO_HEAP" ]
}
} }
config("toolchain") { config("toolchain") {
......
...@@ -74,7 +74,6 @@ enum : uint8_t { ...@@ -74,7 +74,6 @@ enum : uint8_t {
ONCE_STATE_DONE = 2 ONCE_STATE_DONE = 2
}; };
typedef void (*NoArgFunction)();
typedef void (*PointerArgFunction)(void* arg); typedef void (*PointerArgFunction)(void* arg);
template <typename T> template <typename T>
...@@ -85,13 +84,12 @@ struct OneArgFunction { ...@@ -85,13 +84,12 @@ struct OneArgFunction {
V8_BASE_EXPORT void CallOnceImpl(OnceType* once, V8_BASE_EXPORT void CallOnceImpl(OnceType* once,
std::function<void()> init_func); std::function<void()> init_func);
inline void CallOnce(OnceType* once, NoArgFunction init_func) { inline void CallOnce(OnceType* once, std::function<void()> init_func) {
if (once->load(std::memory_order_acquire) != ONCE_STATE_DONE) { if (once->load(std::memory_order_acquire) != ONCE_STATE_DONE) {
CallOnceImpl(once, init_func); CallOnceImpl(once, init_func);
} }
} }
template <typename Arg> template <typename Arg>
inline void CallOnce(OnceType* once, inline void CallOnce(OnceType* once,
typename OneArgFunction<Arg*>::type init_func, Arg* arg) { typename OneArgFunction<Arg*>::type init_func, Arg* arg) {
......
...@@ -3550,14 +3550,21 @@ const char* Heap::GarbageCollectionReasonToString( ...@@ -3550,14 +3550,21 @@ const char* Heap::GarbageCollectionReasonToString(
} }
bool Heap::Contains(HeapObject value) { bool Heap::Contains(HeapObject value) {
// Check RO_SPACE first because IsOutsideAllocatedSpace cannot account for a
// shared RO_SPACE.
// TODO(goszczycki): Exclude read-only space. Use ReadOnlyHeap::Contains where
// appropriate.
if (read_only_space_ != nullptr && read_only_space_->Contains(value)) {
return true;
}
if (memory_allocator()->IsOutsideAllocatedSpace(value->address())) { if (memory_allocator()->IsOutsideAllocatedSpace(value->address())) {
return false; return false;
} }
return HasBeenSetUp() && return HasBeenSetUp() &&
(new_space_->ToSpaceContains(value) || old_space_->Contains(value) || (new_space_->ToSpaceContains(value) || old_space_->Contains(value) ||
code_space_->Contains(value) || map_space_->Contains(value) || code_space_->Contains(value) || map_space_->Contains(value) ||
lo_space_->Contains(value) || read_only_space_->Contains(value) || lo_space_->Contains(value) || code_lo_space_->Contains(value) ||
code_lo_space_->Contains(value) || new_lo_space_->Contains(value)); new_lo_space_->Contains(value));
} }
bool Heap::InSpace(HeapObject value, AllocationSpace space) { bool Heap::InSpace(HeapObject value, AllocationSpace space) {
...@@ -4550,8 +4557,9 @@ void Heap::SetUp() { ...@@ -4550,8 +4557,9 @@ void Heap::SetUp() {
} }
void Heap::SetUpFromReadOnlyHeap(ReadOnlyHeap* ro_heap) { void Heap::SetUpFromReadOnlyHeap(ReadOnlyHeap* ro_heap) {
DCHECK_NULL(read_only_space_);
DCHECK_NOT_NULL(ro_heap); DCHECK_NOT_NULL(ro_heap);
DCHECK_IMPLIES(read_only_space_ != nullptr,
read_only_space_ == ro_heap->read_only_space());
read_only_heap_ = ro_heap; read_only_heap_ = ro_heap;
space_[RO_SPACE] = read_only_space_ = ro_heap->read_only_space(); space_[RO_SPACE] = read_only_space_ = ro_heap->read_only_space();
} }
......
...@@ -4,29 +4,72 @@ ...@@ -4,29 +4,72 @@
#include "src/heap/read-only-heap.h" #include "src/heap/read-only-heap.h"
#include <cstring>
#include "src/base/once.h"
#include "src/heap/heap-inl.h"
#include "src/heap/spaces.h" #include "src/heap/spaces.h"
#include "src/snapshot/read-only-deserializer.h" #include "src/snapshot/read-only-deserializer.h"
namespace v8 { namespace v8 {
namespace internal { namespace internal {
#ifdef V8_SHARED_RO_HEAP
V8_DECLARE_ONCE(setup_ro_heap_once);
ReadOnlyHeap* shared_ro_heap = nullptr;
#endif
// static // static
void ReadOnlyHeap::SetUp(Isolate* isolate, ReadOnlyDeserializer* des) { void ReadOnlyHeap::SetUp(Isolate* isolate, ReadOnlyDeserializer* des) {
auto* ro_heap = new ReadOnlyHeap(new ReadOnlySpace(isolate->heap())); #ifdef V8_SHARED_RO_HEAP
isolate->heap()->SetUpFromReadOnlyHeap(ro_heap); void* isolate_ro_roots = reinterpret_cast<void*>(
isolate->roots_table().read_only_roots_begin().address());
base::CallOnce(&setup_ro_heap_once, [isolate, des, isolate_ro_roots]() {
shared_ro_heap = Init(isolate, des);
if (des != nullptr) {
std::memcpy(shared_ro_heap->read_only_roots_, isolate_ro_roots,
kEntriesCount * sizeof(Address));
}
});
isolate->heap()->SetUpFromReadOnlyHeap(shared_ro_heap);
if (des != nullptr) { if (des != nullptr) {
des->DeserializeInto(isolate); std::memcpy(isolate_ro_roots, shared_ro_heap->read_only_roots_,
ro_heap->read_only_space_->MarkAsReadOnly(); kEntriesCount * sizeof(Address));
} }
#else
Init(isolate, des);
#endif // V8_SHARED_RO_HEAP
} }
void ReadOnlyHeap::OnCreateHeapObjectsComplete() { void ReadOnlyHeap::OnCreateHeapObjectsComplete() {
DCHECK(!deserializing_);
#ifdef V8_SHARED_RO_HEAP
read_only_space_->Forget();
#endif
read_only_space_->MarkAsReadOnly(); read_only_space_->MarkAsReadOnly();
} }
// static
ReadOnlyHeap* ReadOnlyHeap::Init(Isolate* isolate, ReadOnlyDeserializer* des) {
auto* ro_heap = new ReadOnlyHeap(new ReadOnlySpace(isolate->heap()));
isolate->heap()->SetUpFromReadOnlyHeap(ro_heap);
if (des != nullptr) {
des->DeserializeInto(isolate);
ro_heap->deserializing_ = true;
#ifdef V8_SHARED_RO_HEAP
ro_heap->read_only_space_->Forget();
#endif
ro_heap->read_only_space_->MarkAsReadOnly();
}
return ro_heap;
}
void ReadOnlyHeap::OnHeapTearDown() { void ReadOnlyHeap::OnHeapTearDown() {
#ifndef V8_SHARED_RO_HEAP
delete read_only_space_; delete read_only_space_;
delete this; delete this;
#endif
} }
// static // static
......
...@@ -9,7 +9,6 @@ ...@@ -9,7 +9,6 @@
#include "src/heap/heap.h" #include "src/heap/heap.h"
#include "src/objects.h" #include "src/objects.h"
#include "src/roots.h" #include "src/roots.h"
#include "src/snapshot/read-only-deserializer.h"
namespace v8 { namespace v8 {
namespace internal { namespace internal {
...@@ -18,16 +17,19 @@ class ReadOnlySpace; ...@@ -18,16 +17,19 @@ class ReadOnlySpace;
class ReadOnlyDeserializer; class ReadOnlyDeserializer;
// This class transparently manages read-only space, roots and cache creation // This class transparently manages read-only space, roots and cache creation
// and destruction. Eventually this will allow sharing these artifacts between // and destruction.
// isolates.
class ReadOnlyHeap final { class ReadOnlyHeap final {
public: public:
static constexpr size_t kEntriesCount =
static_cast<size_t>(RootIndex::kReadOnlyRootsCount);
// If necessary create read-only heap and initialize its artifacts (if the // If necessary create read-only heap and initialize its artifacts (if the
// deserializer is provided). // deserializer is provided).
// TODO(goszczycki): Ideally we'd create this without needing a heap. // TODO(goszczycki): Ideally we'd create this without needing a heap.
static void SetUp(Isolate* isolate, ReadOnlyDeserializer* des); static void SetUp(Isolate* isolate, ReadOnlyDeserializer* des);
// Indicate that all read-only space objects have been created and will not // Indicate that all read-only space objects have been created and will not
// be written to. // be written to. This is not thread safe, and should really only be used as
// part of mksnapshot or when read-only heap sharing is disabled.
void OnCreateHeapObjectsComplete(); void OnCreateHeapObjectsComplete();
// Indicate that the current isolate no longer requires the read-only heap and // Indicate that the current isolate no longer requires the read-only heap and
// it may be safely disposed of. // it may be safely disposed of.
...@@ -42,9 +44,16 @@ class ReadOnlyHeap final { ...@@ -42,9 +44,16 @@ class ReadOnlyHeap final {
ReadOnlySpace* read_only_space() const { return read_only_space_; } ReadOnlySpace* read_only_space() const { return read_only_space_; }
private: private:
static ReadOnlyHeap* Init(Isolate* isolate, ReadOnlyDeserializer* des);
bool deserializing_ = false;
ReadOnlySpace* read_only_space_ = nullptr; ReadOnlySpace* read_only_space_ = nullptr;
std::vector<Object> read_only_object_cache_; std::vector<Object> read_only_object_cache_;
#ifdef V8_SHARED_RO_HEAP
Address read_only_roots_[kEntriesCount];
#endif
explicit ReadOnlyHeap(ReadOnlySpace* ro_space) : read_only_space_(ro_space) {} explicit ReadOnlyHeap(ReadOnlySpace* ro_space) : read_only_space_(ro_space) {}
DISALLOW_COPY_AND_ASSIGN(ReadOnlyHeap); DISALLOW_COPY_AND_ASSIGN(ReadOnlyHeap);
}; };
......
...@@ -3305,6 +3305,12 @@ void ReadOnlyPage::MakeHeaderRelocatable() { ...@@ -3305,6 +3305,12 @@ void ReadOnlyPage::MakeHeaderRelocatable() {
} }
} }
void ReadOnlySpace::Forget() {
for (Page* p : *this) {
heap()->memory_allocator()->PreFreeMemory(p);
}
}
void ReadOnlySpace::SetPermissionsForPages(PageAllocator::Permission access) { void ReadOnlySpace::SetPermissionsForPages(PageAllocator::Permission access) {
MemoryAllocator* memory_allocator = heap()->memory_allocator(); MemoryAllocator* memory_allocator = heap()->memory_allocator();
for (Page* p : *this) { for (Page* p : *this) {
......
...@@ -2992,6 +2992,9 @@ class ReadOnlySpace : public PagedSpace { ...@@ -2992,6 +2992,9 @@ class ReadOnlySpace : public PagedSpace {
void ClearStringPaddingIfNeeded(); void ClearStringPaddingIfNeeded();
void MarkAsReadOnly(); void MarkAsReadOnly();
// Make the heap forget the space for memory bookkeeping purposes
// (e.g. prevent space's memory from registering as leaked).
void Forget();
// During boot the free_space_map is created, and afterwards we may need // During boot the free_space_map is created, and afterwards we may need
// to write it into the free list nodes that were already created. // to write it into the free list nodes that were already created.
......
...@@ -497,6 +497,7 @@ class RootsTable { ...@@ -497,6 +497,7 @@ class RootsTable {
friend class Isolate; friend class Isolate;
friend class Heap; friend class Heap;
friend class Factory; friend class Factory;
friend class ReadOnlyHeap;
friend class ReadOnlyRoots; friend class ReadOnlyRoots;
friend class RootsSerializer; friend class RootsSerializer;
}; };
......
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