Commit 595609fb authored by Leszek Swirski's avatar Leszek Swirski Committed by Commit Bot

[offthread] Add off thread deserialization

Add a new OffThreadObjectDeserializer, which can deserialize a snapshot
into an OffThreadIsolate.

This involves templating the Deserializer base class on Isolate, and
amending OffThreadHeap to be able to create Reservations same as the
main-thread Heap can. Various off-thread incompatible methods are
stubbed out as UNREACHABLE in OffThreadIsolate overloads.

There is currently no API entry into the off-thread deserialization, but
under --stress-background-compile it now runs the CodeDeserializer (i.e.
code cache deserialization) in a background thread.

Bug: chromium:1075999

Change-Id: I2453f51ae31df4d4b6aa94b0804a9d6d3a03781e
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2172741
Commit-Queue: Leszek Swirski <leszeks@chromium.org>
Reviewed-by: 's avatarJakob Gruber <jgruber@chromium.org>
Reviewed-by: 's avatarIgor Sheludko <ishell@chromium.org>
Reviewed-by: 's avatarUlan Degenbaev <ulan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#67799}
parent 4dabba12
// Copyright 2020 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_EXECUTION_LOCAL_ISOLATE_WRAPPER_INL_H_
#define V8_EXECUTION_LOCAL_ISOLATE_WRAPPER_INL_H_
#include "src/execution/isolate.h"
#include "src/execution/local-isolate-wrapper.h"
#include "src/execution/off-thread-isolate.h"
#include "src/heap/heap-inl.h"
#include "src/heap/off-thread-heap.h"
#include "src/logging/log.h"
#include "src/logging/off-thread-logger.h"
namespace v8 {
namespace internal {
class HeapMethodCaller {
public:
explicit HeapMethodCaller(LocalHeapWrapper* heap) : heap_(heap) {}
ReadOnlySpace* read_only_space() {
return heap_->is_off_thread() ? heap_->off_thread()->read_only_space()
: heap_->main_thread()->read_only_space();
}
void OnAllocationEvent(HeapObject obj, int size) {
return heap_->is_off_thread()
? heap_->off_thread()->OnAllocationEvent(obj, size)
: heap_->main_thread()->OnAllocationEvent(obj, size);
}
bool Contains(HeapObject obj) {
return heap_->is_off_thread() ? heap_->off_thread()->Contains(obj)
: heap_->main_thread()->Contains(obj);
}
private:
LocalHeapWrapper* heap_;
};
class LoggerMethodCaller {
public:
explicit LoggerMethodCaller(LocalLoggerWrapper* logger) : logger_(logger) {}
bool is_logging() const {
return logger_->is_off_thread() ? logger_->off_thread()->is_logging()
: logger_->main_thread()->is_logging();
}
void ScriptEvent(Logger::ScriptEventType type, int script_id) {
return logger_->is_off_thread()
? logger_->off_thread()->ScriptEvent(type, script_id)
: logger_->main_thread()->ScriptEvent(type, script_id);
}
void ScriptDetails(Script script) {
return logger_->is_off_thread()
? logger_->off_thread()->ScriptDetails(script)
: logger_->main_thread()->ScriptDetails(script);
}
private:
LocalLoggerWrapper* logger_;
};
class IsolateMethodCaller {
public:
explicit IsolateMethodCaller(LocalIsolateWrapper* isolate)
: isolate_(isolate) {}
LocalLoggerWrapper logger() {
return isolate_->is_off_thread()
? LocalLoggerWrapper(isolate_->off_thread()->logger())
: LocalLoggerWrapper(isolate_->main_thread()->logger());
}
LocalHeapWrapper heap() {
return isolate_->is_off_thread()
? LocalHeapWrapper(isolate_->off_thread()->heap())
: LocalHeapWrapper(isolate_->main_thread()->heap());
}
ReadOnlyHeap* read_only_heap() {
return isolate_->is_off_thread()
? isolate_->off_thread()->read_only_heap()
: isolate_->main_thread()->read_only_heap();
}
Object root(RootIndex index) {
return isolate_->is_off_thread() ? isolate_->off_thread()->root(index)
: isolate_->main_thread()->root(index);
}
int GetNextScriptId() {
return isolate_->is_off_thread()
? isolate_->off_thread()->GetNextScriptId()
: isolate_->main_thread()->GetNextScriptId();
}
private:
LocalIsolateWrapper* isolate_;
};
// Helper wrapper for HandleScope behaviour with a LocalIsolateWrapper.
class LocalHandleScopeWrapper {
public:
explicit LocalHandleScopeWrapper(LocalIsolateWrapper local_isolate)
: is_off_thread_(local_isolate.is_off_thread()) {
if (is_off_thread_) {
new (off_thread()) OffThreadHandleScope(local_isolate.off_thread());
} else {
new (main_thread()) HandleScope(local_isolate.main_thread());
}
}
~LocalHandleScopeWrapper() {
if (is_off_thread_) {
off_thread()->~OffThreadHandleScope();
} else {
main_thread()->~HandleScope();
}
}
template <typename T>
Handle<T> CloseAndEscape(Handle<T> handle) {
if (is_off_thread_) {
return off_thread()->CloseAndEscape(handle);
} else {
return main_thread()->CloseAndEscape(handle);
}
}
private:
HandleScope* main_thread() {
return reinterpret_cast<HandleScope*>(&scope_storage_);
}
OffThreadHandleScope* off_thread() {
return reinterpret_cast<OffThreadHandleScope*>(&scope_storage_);
}
std::aligned_union_t<0, HandleScope, OffThreadHandleScope> scope_storage_;
bool is_off_thread_;
};
} // namespace internal
} // namespace v8
#endif // V8_EXECUTION_LOCAL_ISOLATE_WRAPPER_INL_H_
// Copyright 2020 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_EXECUTION_LOCAL_ISOLATE_WRAPPER_H_
#define V8_EXECUTION_LOCAL_ISOLATE_WRAPPER_H_
#include "src/utils/pointer-with-payload.h"
namespace v8 {
namespace internal {
// LocalWrapperBase is the base-class for wrapper classes around a main-thread
// and off-thread type, e.g. Isolate and OffThreadIsolate, and a bit stating
// which of the two the wrapper wraps.
//
// The shared methods are defined on MethodCaller, which will dispatch to the
// right type depending on the state of the wrapper. The reason for a separate
// MethodCaller is to
//
// a) Move the method definitions into an -inl.h so that this header can have
// minimal dependencies, and
// b) To allow the type methods to be called with operator-> (e.g.
// isolate_wrapper->heap()), while forcing the wrapper methods to be called
// with a dot (e.g. isolate_wrapper.is_main_thread()).
template <typename MainThreadType, typename OffThreadType,
typename MethodCaller>
class LocalWrapperBase {
public:
// Helper for returning a MethodCaller* by value from operator->.
class MethodCallerRef {
public:
MethodCaller* operator->() { return &caller_; }
private:
friend class LocalWrapperBase;
explicit MethodCallerRef(LocalWrapperBase* wrapper) : caller_(wrapper) {}
MethodCaller caller_;
};
explicit LocalWrapperBase(std::nullptr_t) : pointer_and_tag_(nullptr) {}
explicit LocalWrapperBase(MainThreadType* pointer)
: pointer_and_tag_(pointer, false) {}
explicit LocalWrapperBase(OffThreadType* pointer)
: pointer_and_tag_(pointer, true) {}
MainThreadType* main_thread() {
DCHECK(is_main_thread());
return static_cast<MainThreadType*>(
pointer_and_tag_.GetPointerWithKnownPayload(false));
}
OffThreadType* off_thread() {
DCHECK(is_off_thread());
return static_cast<OffThreadType*>(
pointer_and_tag_.GetPointerWithKnownPayload(true));
}
bool is_main_thread() const {
return !is_null() && !pointer_and_tag_.GetPayload();
}
bool is_off_thread() const {
return !is_null() && pointer_and_tag_.GetPayload();
}
bool is_null() const { return pointer_and_tag_.GetPointer() == nullptr; }
// Access the methods via wrapper->Method.
MethodCallerRef operator->() { return MethodCallerRef(this); }
private:
PointerWithPayload<void, bool, 1> pointer_and_tag_;
};
using LocalHeapWrapper =
LocalWrapperBase<class Heap, class OffThreadHeap, class HeapMethodCaller>;
using LocalLoggerWrapper = LocalWrapperBase<class Logger, class OffThreadLogger,
class LoggerMethodCaller>;
using LocalIsolateWrapper =
LocalWrapperBase<class Isolate, class OffThreadIsolate,
class IsolateMethodCaller>;
} // namespace internal
} // namespace v8
#endif // V8_EXECUTION_LOCAL_ISOLATE_WRAPPER_H_
...@@ -15,6 +15,14 @@ namespace internal { ...@@ -15,6 +15,14 @@ namespace internal {
Address OffThreadIsolate::isolate_root() const { Address OffThreadIsolate::isolate_root() const {
return isolate_->isolate_root(); return isolate_->isolate_root();
} }
ReadOnlyHeap* OffThreadIsolate::read_only_heap() {
return isolate_->read_only_heap();
}
Object OffThreadIsolate::root(RootIndex index) {
DCHECK(RootsTable::IsImmortalImmovable(index));
return isolate_->root(index);
}
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
......
...@@ -86,6 +86,8 @@ class V8_EXPORT_PRIVATE OffThreadIsolate final ...@@ -86,6 +86,8 @@ class V8_EXPORT_PRIVATE OffThreadIsolate final
OffThreadHeap* heap() { return &heap_; } OffThreadHeap* heap() { return &heap_; }
inline Address isolate_root() const; inline Address isolate_root() const;
inline ReadOnlyHeap* read_only_heap();
inline Object root(RootIndex index);
v8::internal::OffThreadFactory* factory() { v8::internal::OffThreadFactory* factory() {
// Upcast to the privately inherited base-class using c-style casts to avoid // Upcast to the privately inherited base-class using c-style casts to avoid
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#define V8_HANDLES_HANDLES_INL_H_ #define V8_HANDLES_HANDLES_INL_H_
#include "src/execution/isolate.h" #include "src/execution/isolate.h"
#include "src/execution/local-isolate-wrapper.h"
#include "src/execution/off-thread-isolate.h" #include "src/execution/off-thread-isolate.h"
#include "src/handles/handles.h" #include "src/handles/handles.h"
#include "src/handles/local-handles-inl.h" #include "src/handles/local-handles-inl.h"
...@@ -66,19 +67,11 @@ V8_INLINE Handle<T> handle(T object, LocalHeap* local_heap) { ...@@ -66,19 +67,11 @@ V8_INLINE Handle<T> handle(T object, LocalHeap* local_heap) {
return Handle<T>(object, local_heap); return Handle<T>(object, local_heap);
} }
// Convenience overloads for when we already have a Handle, but want
// either a Handle or an Handle.
template <typename T> template <typename T>
V8_INLINE Handle<T> handle(Handle<T> handle, Isolate* isolate) { V8_INLINE Handle<T> handle(T object, LocalIsolateWrapper local_isolate) {
return handle; return local_isolate.is_off_thread()
} ? handle(object, local_isolate.off_thread())
template <typename T> : handle(object, local_isolate.main_thread());
V8_INLINE Handle<T> handle(Handle<T> handle, OffThreadIsolate* isolate) {
return Handle<T>(*handle);
}
template <typename T>
V8_INLINE Handle<T> handle(Handle<T> handle, LocalHeap* local_heap) {
return Handle<T>(*handle, local_heap);
} }
template <typename T> template <typename T>
......
...@@ -199,6 +199,11 @@ class HandleScope { ...@@ -199,6 +199,11 @@ class HandleScope {
explicit inline HandleScope(Isolate* isolate); explicit inline HandleScope(Isolate* isolate);
inline HandleScope(HandleScope&& other) V8_NOEXCEPT; inline HandleScope(HandleScope&& other) V8_NOEXCEPT;
// Allow placement new.
void* operator new(size_t size, void* storage) {
return ::operator new(size, storage);
}
inline ~HandleScope(); inline ~HandleScope();
inline HandleScope& operator=(HandleScope&& other) V8_NOEXCEPT; inline HandleScope& operator=(HandleScope&& other) V8_NOEXCEPT;
...@@ -235,8 +240,8 @@ class HandleScope { ...@@ -235,8 +240,8 @@ class HandleScope {
private: private:
// Prevent heap allocation or illegal handle scopes. // Prevent heap allocation or illegal handle scopes.
void* operator new(size_t size); void* operator new(size_t size) = delete;
void operator delete(void* size_t); void operator delete(void* size_t) = delete;
Isolate* isolate_; Isolate* isolate_;
Address* prev_next_; Address* prev_next_;
......
...@@ -4,10 +4,12 @@ ...@@ -4,10 +4,12 @@
#include "src/heap/off-thread-heap.h" #include "src/heap/off-thread-heap.h"
#include "src/common/globals.h"
#include "src/heap/spaces-inl.h" #include "src/heap/spaces-inl.h"
#include "src/heap/spaces.h" #include "src/heap/spaces.h"
#include "src/objects/objects-body-descriptors-inl.h" #include "src/objects/objects-body-descriptors-inl.h"
#include "src/roots/roots.h" #include "src/roots/roots.h"
#include "src/snapshot/references.h"
// Has to be the last include (doesn't have include guards) // Has to be the last include (doesn't have include guards)
#include "src/objects/object-macros.h" #include "src/objects/object-macros.h"
...@@ -17,6 +19,10 @@ namespace internal { ...@@ -17,6 +19,10 @@ namespace internal {
OffThreadHeap::OffThreadHeap(Heap* heap) : space_(heap), lo_space_(heap) {} OffThreadHeap::OffThreadHeap(Heap* heap) : space_(heap), lo_space_(heap) {}
bool OffThreadHeap::Contains(HeapObject obj) {
return space_.Contains(obj) || lo_space_.Contains(obj);
}
class OffThreadHeap::StringSlotCollectingVisitor : public ObjectVisitor { class OffThreadHeap::StringSlotCollectingVisitor : public ObjectVisitor {
public: public:
void VisitPointers(HeapObject host, ObjectSlot start, void VisitPointers(HeapObject host, ObjectSlot start,
...@@ -223,7 +229,37 @@ HeapObject OffThreadHeap::AllocateRaw(int size, AllocationType allocation, ...@@ -223,7 +229,37 @@ HeapObject OffThreadHeap::AllocateRaw(int size, AllocationType allocation,
} else { } else {
result = space_.AllocateRaw(size, alignment); result = space_.AllocateRaw(size, alignment);
} }
return result.ToObjectChecked(); HeapObject obj = result.ToObjectChecked();
OnAllocationEvent(obj, size);
return obj;
}
bool OffThreadHeap::ReserveSpace(Heap::Reservation* reservations) {
#ifdef DEBUG
for (int space = FIRST_SPACE;
space < static_cast<int>(SnapshotSpace::kNumberOfHeapSpaces); space++) {
if (space == OLD_SPACE || space == LO_SPACE) continue;
Heap::Reservation* reservation = &reservations[space];
DCHECK_EQ(reservation->size(), 1);
DCHECK_EQ(reservation->at(0).size, 0);
}
#endif
for (auto& chunk : reservations[OLD_SPACE]) {
int size = chunk.size;
AllocationResult allocation = space_.AllocateRawUnaligned(size);
HeapObject free_space = allocation.ToObjectChecked();
// Mark with a free list node, in case we have a GC before
// deserializing.
Address free_space_address = free_space.address();
CreateFillerObjectAt(free_space_address, size,
ClearFreedMemoryMode::kDontClearFreedMemory);
chunk.start = free_space_address;
chunk.end = free_space_address + size;
}
return true;
} }
HeapObject OffThreadHeap::CreateFillerObjectAt( HeapObject OffThreadHeap::CreateFillerObjectAt(
......
...@@ -6,9 +6,11 @@ ...@@ -6,9 +6,11 @@
#define V8_HEAP_OFF_THREAD_HEAP_H_ #define V8_HEAP_OFF_THREAD_HEAP_H_
#include <vector> #include <vector>
#include "src/common/globals.h" #include "src/common/globals.h"
#include "src/heap/large-spaces.h" #include "src/heap/large-spaces.h"
#include "src/heap/spaces.h" #include "src/heap/spaces.h"
#include "src/objects/heap-object.h"
namespace v8 { namespace v8 {
namespace internal { namespace internal {
...@@ -21,6 +23,19 @@ class V8_EXPORT_PRIVATE OffThreadHeap { ...@@ -21,6 +23,19 @@ class V8_EXPORT_PRIVATE OffThreadHeap {
AllocationAlignment alignment = kWordAligned); AllocationAlignment alignment = kWordAligned);
void AddToScriptList(Handle<Script> shared); void AddToScriptList(Handle<Script> shared);
void OnAllocationEvent(HeapObject obj, int size) {
// TODO(leszeks): Do something here.
}
ReadOnlySpace* read_only_space() const {
// Access the main-thread heap via the spaces.
return space_.heap()->read_only_space();
}
bool Contains(HeapObject obj);
bool ReserveSpace(Heap::Reservation* reservations);
HeapObject CreateFillerObjectAt(Address addr, int size, HeapObject CreateFillerObjectAt(Address addr, int size,
ClearFreedMemoryMode clear_memory_mode); ClearFreedMemoryMode clear_memory_mode);
...@@ -28,6 +43,8 @@ class V8_EXPORT_PRIVATE OffThreadHeap { ...@@ -28,6 +43,8 @@ class V8_EXPORT_PRIVATE OffThreadHeap {
void Publish(Heap* heap); void Publish(Heap* heap);
private: private:
friend class DeserializerAllocator;
class StringSlotCollectingVisitor; class StringSlotCollectingVisitor;
struct RelativeSlot { struct RelativeSlot {
......
...@@ -72,13 +72,13 @@ class Ticker; ...@@ -72,13 +72,13 @@ class Ticker;
#undef LOG #undef LOG
#define LOG(isolate, Call) \ #define LOG(isolate, Call) \
do { \ do { \
auto* logger = (isolate)->logger(); \ auto&& logger = (isolate)->logger(); \
if (logger->is_logging()) logger->Call; \ if (logger->is_logging()) logger->Call; \
} while (false) } while (false)
#define LOG_CODE_EVENT(isolate, Call) \ #define LOG_CODE_EVENT(isolate, Call) \
do { \ do { \
auto* logger = (isolate)->logger(); \ auto&& logger = (isolate)->logger(); \
if (logger->is_listening_to_code_events()) logger->Call; \ if (logger->is_listening_to_code_events()) logger->Call; \
} while (false) } while (false)
......
...@@ -19,6 +19,7 @@ class OffThreadLogger { ...@@ -19,6 +19,7 @@ class OffThreadLogger {
void ScriptEvent(Logger::ScriptEventType type, int script_id) { void ScriptEvent(Logger::ScriptEventType type, int script_id) {
UNREACHABLE(); UNREACHABLE();
} }
void ScriptDetails(Script script) { UNREACHABLE(); }
void CodeLinePosInfoRecordEvent(Address code_start, void CodeLinePosInfoRecordEvent(Address code_start,
ByteArray source_position_table) { ByteArray source_position_table) {
UNREACHABLE(); UNREACHABLE();
......
...@@ -191,7 +191,7 @@ class HeapObject : public Object { ...@@ -191,7 +191,7 @@ class HeapObject : public Object {
bool CanBeRehashed() const; bool CanBeRehashed() const;
// Rehash the object based on the layout inferred from its map. // Rehash the object based on the layout inferred from its map.
void RehashBasedOnMap(ReadOnlyRoots root); void RehashBasedOnMap(LocalIsolateWrapper isolate);
// Layout description. // Layout description.
#define HEAP_OBJECT_FIELDS(V) \ #define HEAP_OBJECT_FIELDS(V) \
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#define V8_OBJECTS_MAYBE_OBJECT_INL_H_ #define V8_OBJECTS_MAYBE_OBJECT_INL_H_
#include "src/common/ptr-compr-inl.h" #include "src/common/ptr-compr-inl.h"
#include "src/execution/local-isolate-wrapper.h"
#include "src/objects/maybe-object.h" #include "src/objects/maybe-object.h"
#include "src/objects/smi-inl.h" #include "src/objects/smi-inl.h"
#include "src/objects/tagged-impl-inl.h" #include "src/objects/tagged-impl-inl.h"
...@@ -88,6 +89,13 @@ HeapObjectReference HeapObjectReference::ClearedValue( ...@@ -88,6 +89,13 @@ HeapObjectReference HeapObjectReference::ClearedValue(
return HeapObjectReference(raw_value); return HeapObjectReference(raw_value);
} }
// static
HeapObjectReference HeapObjectReference::ClearedValue(
LocalIsolateWrapper isolate) {
return isolate.is_off_thread() ? ClearedValue(isolate.off_thread())
: ClearedValue(isolate.main_thread());
}
template <typename THeapObjectSlot> template <typename THeapObjectSlot>
void HeapObjectReference::Update(THeapObjectSlot slot, HeapObject value) { void HeapObjectReference::Update(THeapObjectSlot slot, HeapObject value) {
static_assert(std::is_same<THeapObjectSlot, FullHeapObjectSlot>::value || static_assert(std::is_same<THeapObjectSlot, FullHeapObjectSlot>::value ||
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#ifndef V8_OBJECTS_MAYBE_OBJECT_H_ #ifndef V8_OBJECTS_MAYBE_OBJECT_H_
#define V8_OBJECTS_MAYBE_OBJECT_H_ #define V8_OBJECTS_MAYBE_OBJECT_H_
#include "src/execution/local-isolate-wrapper.h"
#include "src/objects/tagged-impl.h" #include "src/objects/tagged-impl.h"
namespace v8 { namespace v8 {
...@@ -52,6 +53,9 @@ class HeapObjectReference : public MaybeObject { ...@@ -52,6 +53,9 @@ class HeapObjectReference : public MaybeObject {
V8_INLINE static HeapObjectReference ClearedValue( V8_INLINE static HeapObjectReference ClearedValue(
const OffThreadIsolate* isolate); const OffThreadIsolate* isolate);
V8_INLINE static HeapObjectReference ClearedValue(
LocalIsolateWrapper isolate);
template <typename THeapObjectSlot> template <typename THeapObjectSlot>
V8_INLINE static void Update(THeapObjectSlot slot, HeapObject value); V8_INLINE static void Update(THeapObjectSlot slot, HeapObject value);
}; };
......
...@@ -2354,7 +2354,8 @@ bool HeapObject::CanBeRehashed() const { ...@@ -2354,7 +2354,8 @@ bool HeapObject::CanBeRehashed() const {
return false; return false;
} }
void HeapObject::RehashBasedOnMap(ReadOnlyRoots roots) { void HeapObject::RehashBasedOnMap(LocalIsolateWrapper isolate) {
ReadOnlyRoots roots = ReadOnlyRoots(isolate);
switch (map().instance_type()) { switch (map().instance_type()) {
case HASH_TABLE_TYPE: case HASH_TABLE_TYPE:
UNREACHABLE(); UNREACHABLE();
......
...@@ -5,9 +5,8 @@ ...@@ -5,9 +5,8 @@
#ifndef V8_ROOTS_ROOTS_INL_H_ #ifndef V8_ROOTS_ROOTS_INL_H_
#define V8_ROOTS_ROOTS_INL_H_ #define V8_ROOTS_ROOTS_INL_H_
#include "src/roots/roots.h"
#include "src/execution/isolate.h" #include "src/execution/isolate.h"
#include "src/execution/local-isolate-wrapper.h"
#include "src/execution/off-thread-isolate.h" #include "src/execution/off-thread-isolate.h"
#include "src/handles/handles.h" #include "src/handles/handles.h"
#include "src/heap/read-only-heap.h" #include "src/heap/read-only-heap.h"
...@@ -23,6 +22,7 @@ ...@@ -23,6 +22,7 @@
#include "src/objects/scope-info.h" #include "src/objects/scope-info.h"
#include "src/objects/slots.h" #include "src/objects/slots.h"
#include "src/objects/string.h" #include "src/objects/string.h"
#include "src/roots/roots.h"
namespace v8 { namespace v8 {
namespace internal { namespace internal {
...@@ -72,7 +72,14 @@ ReadOnlyRoots::ReadOnlyRoots(Isolate* isolate) ...@@ -72,7 +72,14 @@ ReadOnlyRoots::ReadOnlyRoots(Isolate* isolate)
ReadOnlyRoots::ReadOnlyRoots(OffThreadIsolate* isolate) ReadOnlyRoots::ReadOnlyRoots(OffThreadIsolate* isolate)
: ReadOnlyRoots(isolate->factory()->read_only_roots()) {} : ReadOnlyRoots(isolate->factory()->read_only_roots()) {}
ReadOnlyRoots::ReadOnlyRoots(Address* ro_roots) : read_only_roots_(ro_roots) {} ReadOnlyRoots::ReadOnlyRoots(LocalHeapWrapper heap)
: ReadOnlyRoots(heap.is_off_thread() ? ReadOnlyRoots(heap.off_thread())
: ReadOnlyRoots(heap.main_thread())) {}
ReadOnlyRoots::ReadOnlyRoots(LocalIsolateWrapper isolate)
: ReadOnlyRoots(isolate.is_off_thread()
? ReadOnlyRoots(isolate.off_thread())
: ReadOnlyRoots(isolate.main_thread())) {}
// We use unchecked_cast below because we trust our read-only roots to // We use unchecked_cast below because we trust our read-only roots to
// have the right type, and to avoid the heavy #includes that would be // have the right type, and to avoid the heavy #includes that would be
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include "src/base/macros.h" #include "src/base/macros.h"
#include "src/builtins/accessors.h" #include "src/builtins/accessors.h"
#include "src/common/globals.h" #include "src/common/globals.h"
#include "src/execution/local-isolate-wrapper.h"
#include "src/handles/handles.h" #include "src/handles/handles.h"
#include "src/init/heap-symbols.h" #include "src/init/heap-symbols.h"
#include "src/objects/objects-definitions.h" #include "src/objects/objects-definitions.h"
...@@ -527,6 +528,8 @@ class ReadOnlyRoots { ...@@ -527,6 +528,8 @@ class ReadOnlyRoots {
V8_INLINE explicit ReadOnlyRoots(OffThreadHeap* heap); V8_INLINE explicit ReadOnlyRoots(OffThreadHeap* heap);
V8_INLINE explicit ReadOnlyRoots(Isolate* isolate); V8_INLINE explicit ReadOnlyRoots(Isolate* isolate);
V8_INLINE explicit ReadOnlyRoots(OffThreadIsolate* isolate); V8_INLINE explicit ReadOnlyRoots(OffThreadIsolate* isolate);
V8_INLINE explicit ReadOnlyRoots(LocalIsolateWrapper wrapper);
V8_INLINE explicit ReadOnlyRoots(LocalHeapWrapper wrapper);
#define ROOT_ACCESSOR(Type, name, CamelName) \ #define ROOT_ACCESSOR(Type, name, CamelName) \
V8_INLINE class Type name() const; \ V8_INLINE class Type name() const; \
...@@ -553,13 +556,15 @@ class ReadOnlyRoots { ...@@ -553,13 +556,15 @@ class ReadOnlyRoots {
#undef ROOT_TYPE_CHECK #undef ROOT_TYPE_CHECK
#endif #endif
V8_INLINE explicit ReadOnlyRoots(Address* ro_roots); V8_INLINE explicit ReadOnlyRoots(Address* ro_roots)
: read_only_roots_(ro_roots) {}
V8_INLINE Address* GetLocation(RootIndex root_index) const; V8_INLINE Address* GetLocation(RootIndex root_index) const;
Address* read_only_roots_; Address* read_only_roots_;
friend class ReadOnlyHeap; friend class ReadOnlyHeap;
friend class DeserializerAllocator;
}; };
} // namespace internal } // namespace internal
......
...@@ -4,9 +4,12 @@ ...@@ -4,9 +4,12 @@
#include "src/snapshot/code-serializer.h" #include "src/snapshot/code-serializer.h"
#include "src/base/platform/platform.h"
#include "src/codegen/macro-assembler.h" #include "src/codegen/macro-assembler.h"
#include "src/common/globals.h"
#include "src/debug/debug.h" #include "src/debug/debug.h"
#include "src/heap/heap-inl.h" #include "src/heap/heap-inl.h"
#include "src/heap/off-thread-factory-inl.h"
#include "src/logging/counters.h" #include "src/logging/counters.h"
#include "src/logging/log.h" #include "src/logging/log.h"
#include "src/objects/objects-inl.h" #include "src/objects/objects-inl.h"
...@@ -259,6 +262,39 @@ void CreateInterpreterDataForDeserializedCode(Isolate* isolate, ...@@ -259,6 +262,39 @@ void CreateInterpreterDataForDeserializedCode(Isolate* isolate,
} }
#endif // V8_TARGET_ARCH_ARM #endif // V8_TARGET_ARCH_ARM
namespace {
class StressOffThreadDeserializeThread final : public base::Thread {
public:
explicit StressOffThreadDeserializeThread(
OffThreadIsolate* off_thread_isolate, const SerializedCodeData* scd)
: Thread(
base::Thread::Options("StressOffThreadDeserializeThread", 2 * MB)),
off_thread_isolate_(off_thread_isolate),
scd_(scd) {}
MaybeHandle<SharedFunctionInfo> maybe_result() const {
return maybe_result_.ToHandle();
}
void Run() final {
off_thread_isolate_->PinToCurrentThread();
MaybeHandle<SharedFunctionInfo> off_thread_maybe_result =
ObjectDeserializer::DeserializeSharedFunctionInfoOffThread(
off_thread_isolate_, scd_,
off_thread_isolate_->factory()->empty_string());
maybe_result_ =
off_thread_isolate_->TransferHandle(off_thread_maybe_result);
}
private:
OffThreadIsolate* off_thread_isolate_;
const SerializedCodeData* scd_;
OffThreadTransferMaybeHandle<SharedFunctionInfo> maybe_result_;
};
} // namespace
MaybeHandle<SharedFunctionInfo> CodeSerializer::Deserialize( MaybeHandle<SharedFunctionInfo> CodeSerializer::Deserialize(
Isolate* isolate, ScriptData* cached_data, Handle<String> source, Isolate* isolate, ScriptData* cached_data, Handle<String> source,
ScriptOriginOptions origin_options) { ScriptOriginOptions origin_options) {
...@@ -281,8 +317,29 @@ MaybeHandle<SharedFunctionInfo> CodeSerializer::Deserialize( ...@@ -281,8 +317,29 @@ MaybeHandle<SharedFunctionInfo> CodeSerializer::Deserialize(
} }
// Deserialize. // Deserialize.
MaybeHandle<SharedFunctionInfo> maybe_result = MaybeHandle<SharedFunctionInfo> maybe_result;
ObjectDeserializer::DeserializeSharedFunctionInfo(isolate, &scd, source); if (FLAG_stress_background_compile) {
Zone zone(isolate->allocator(), "Deserialize");
OffThreadIsolate off_thread_isolate(isolate, &zone);
StressOffThreadDeserializeThread thread(&off_thread_isolate, &scd);
CHECK(thread.Start());
thread.Join();
off_thread_isolate.FinishOffThread();
off_thread_isolate.Publish(isolate);
maybe_result = thread.maybe_result();
// Fix-up result script source.
Handle<SharedFunctionInfo> result;
if (maybe_result.ToHandle(&result)) {
Script::cast(result->script()).set_source(*source);
}
} else {
maybe_result = ObjectDeserializer::DeserializeSharedFunctionInfo(
isolate, &scd, source);
}
Handle<SharedFunctionInfo> result; Handle<SharedFunctionInfo> result;
if (!maybe_result.ToHandle(&result)) { if (!maybe_result.ToHandle(&result)) {
...@@ -356,7 +413,6 @@ MaybeHandle<SharedFunctionInfo> CodeSerializer::Deserialize( ...@@ -356,7 +413,6 @@ MaybeHandle<SharedFunctionInfo> CodeSerializer::Deserialize(
return scope.CloseAndEscape(result); return scope.CloseAndEscape(result);
} }
SerializedCodeData::SerializedCodeData(const std::vector<byte>* payload, SerializedCodeData::SerializedCodeData(const std::vector<byte>* payload,
const CodeSerializer* cs) { const CodeSerializer* cs) {
DisallowHeapAllocation no_gc; DisallowHeapAllocation no_gc;
......
...@@ -6,10 +6,17 @@ ...@@ -6,10 +6,17 @@
#include "src/heap/heap-inl.h" // crbug.com/v8/8499 #include "src/heap/heap-inl.h" // crbug.com/v8/8499
#include "src/heap/memory-chunk.h" #include "src/heap/memory-chunk.h"
#include "src/roots/roots.h"
namespace v8 { namespace v8 {
namespace internal { namespace internal {
void DeserializerAllocator::Initialize(LocalHeapWrapper heap) {
heap_ = heap;
roots_ = heap.is_off_thread() ? ReadOnlyRoots(heap.off_thread())
: ReadOnlyRoots(heap.main_thread());
}
// We know the space requirements before deserialization and can // We know the space requirements before deserialization and can
// pre-allocate that reserved space. During deserialization, all we need // pre-allocate that reserved space. During deserialization, all we need
// to do is to bump up the pointer for each space in the reserved // to do is to bump up the pointer for each space in the reserved
...@@ -24,12 +31,18 @@ namespace internal { ...@@ -24,12 +31,18 @@ namespace internal {
Address DeserializerAllocator::AllocateRaw(SnapshotSpace space, int size) { Address DeserializerAllocator::AllocateRaw(SnapshotSpace space, int size) {
const int space_number = static_cast<int>(space); const int space_number = static_cast<int>(space);
if (space == SnapshotSpace::kLargeObject) { if (space == SnapshotSpace::kLargeObject) {
AlwaysAllocateScope scope(heap_);
// Note that we currently do not support deserialization of large code // Note that we currently do not support deserialization of large code
// objects. // objects.
OldLargeObjectSpace* lo_space = heap_->lo_space(); HeapObject obj;
AllocationResult result = lo_space->AllocateRaw(size); if (heap_.is_off_thread()) {
HeapObject obj = result.ToObjectChecked(); obj = heap_.off_thread()->lo_space_.AllocateRaw(size).ToObjectChecked();
} else {
Heap* heap = heap_.main_thread();
AlwaysAllocateScope scope(heap);
OldLargeObjectSpace* lo_space = heap->lo_space();
AllocationResult result = lo_space->AllocateRaw(size);
obj = result.ToObjectChecked();
}
deserialized_large_objects_.push_back(obj); deserialized_large_objects_.push_back(obj);
return obj.address(); return obj.address();
} else if (space == SnapshotSpace::kMap) { } else if (space == SnapshotSpace::kMap) {
...@@ -82,11 +95,10 @@ Address DeserializerAllocator::Allocate(SnapshotSpace space, int size) { ...@@ -82,11 +95,10 @@ Address DeserializerAllocator::Allocate(SnapshotSpace space, int size) {
// If one of the following assertions fails, then we are deserializing an // If one of the following assertions fails, then we are deserializing an
// aligned object when the filler maps have not been deserialized yet. // aligned object when the filler maps have not been deserialized yet.
// We require filler maps as padding to align the object. // We require filler maps as padding to align the object.
DCHECK(ReadOnlyRoots(heap_).free_space_map().IsMap()); DCHECK(roots_.free_space_map().IsMap());
DCHECK(ReadOnlyRoots(heap_).one_pointer_filler_map().IsMap()); DCHECK(roots_.one_pointer_filler_map().IsMap());
DCHECK(ReadOnlyRoots(heap_).two_pointer_filler_map().IsMap()); DCHECK(roots_.two_pointer_filler_map().IsMap());
obj = Heap::AlignWithFiller(ReadOnlyRoots(heap_), obj, size, reserved, obj = Heap::AlignWithFiller(roots_, obj, size, reserved, next_alignment_);
next_alignment_);
address = obj.address(); address = obj.address();
next_alignment_ = kWordAligned; next_alignment_ = kWordAligned;
return address; return address;
...@@ -109,6 +121,7 @@ void DeserializerAllocator::MoveToNextChunk(SnapshotSpace space) { ...@@ -109,6 +121,7 @@ void DeserializerAllocator::MoveToNextChunk(SnapshotSpace space) {
} }
HeapObject DeserializerAllocator::GetMap(uint32_t index) { HeapObject DeserializerAllocator::GetMap(uint32_t index) {
DCHECK(!heap_.is_off_thread());
DCHECK_LT(index, next_map_index_); DCHECK_LT(index, next_map_index_);
return HeapObject::FromAddress(allocated_maps_[index]); return HeapObject::FromAddress(allocated_maps_[index]);
} }
...@@ -156,10 +169,16 @@ bool DeserializerAllocator::ReserveSpace() { ...@@ -156,10 +169,16 @@ bool DeserializerAllocator::ReserveSpace() {
} }
#endif // DEBUG #endif // DEBUG
DCHECK(allocated_maps_.empty()); DCHECK(allocated_maps_.empty());
// TODO(v8:7464): Allocate using the off-heap ReadOnlySpace here once if (heap_.is_off_thread()) {
// implemented. if (!heap_.off_thread()->ReserveSpace(reservations_)) {
if (!heap_->ReserveSpace(reservations_, &allocated_maps_)) { return false;
return false; }
} else {
// TODO(v8:7464): Allocate using the off-heap ReadOnlySpace here once
// implemented.
if (!heap_.main_thread()->ReserveSpace(reservations_, &allocated_maps_)) {
return false;
}
} }
for (int i = 0; i < kNumberOfPreallocatedSpaces; i++) { for (int i = 0; i < kNumberOfPreallocatedSpaces; i++) {
high_water_[i] = reservations_[i][0].start; high_water_[i] = reservations_[i][0].start;
...@@ -181,7 +200,8 @@ bool DeserializerAllocator::ReservationsAreFullyUsed() const { ...@@ -181,7 +200,8 @@ bool DeserializerAllocator::ReservationsAreFullyUsed() const {
} }
void DeserializerAllocator::RegisterDeserializedObjectsForBlackAllocation() { void DeserializerAllocator::RegisterDeserializedObjectsForBlackAllocation() {
heap_->RegisterDeserializedObjectsForBlackAllocation( DCHECK(!heap_.is_off_thread());
heap_.main_thread()->RegisterDeserializedObjectsForBlackAllocation(
reservations_, deserialized_large_objects_, allocated_maps_); reservations_, deserialized_large_objects_, allocated_maps_);
} }
......
...@@ -6,8 +6,10 @@ ...@@ -6,8 +6,10 @@
#define V8_SNAPSHOT_DESERIALIZER_ALLOCATOR_H_ #define V8_SNAPSHOT_DESERIALIZER_ALLOCATOR_H_
#include "src/common/globals.h" #include "src/common/globals.h"
#include "src/execution/local-isolate-wrapper.h"
#include "src/heap/heap.h" #include "src/heap/heap.h"
#include "src/objects/heap-object.h" #include "src/objects/heap-object.h"
#include "src/roots/roots.h"
#include "src/snapshot/references.h" #include "src/snapshot/references.h"
#include "src/snapshot/snapshot-data.h" #include "src/snapshot/snapshot-data.h"
...@@ -16,12 +18,13 @@ namespace internal { ...@@ -16,12 +18,13 @@ namespace internal {
class Deserializer; class Deserializer;
class StartupDeserializer; class StartupDeserializer;
class OffThreadHeap;
class DeserializerAllocator final { class DeserializerAllocator final {
public: public:
DeserializerAllocator() = default; DeserializerAllocator() = default;
void Initialize(Heap* heap) { heap_ = heap; } void Initialize(LocalHeapWrapper heap);
// ------- Allocation Methods ------- // ------- Allocation Methods -------
// Methods related to memory allocation during deserialization. // Methods related to memory allocation during deserialization.
...@@ -99,7 +102,9 @@ class DeserializerAllocator final { ...@@ -99,7 +102,9 @@ class DeserializerAllocator final {
// back-references. // back-references.
std::vector<HeapObject> deserialized_large_objects_; std::vector<HeapObject> deserialized_large_objects_;
Heap* heap_; // ReadOnlyRoots and heap are null until Initialize is called.
LocalHeapWrapper heap_ = LocalHeapWrapper(nullptr);
ReadOnlyRoots roots_ = ReadOnlyRoots(static_cast<Address*>(nullptr));
DISALLOW_COPY_AND_ASSIGN(DeserializerAllocator); DISALLOW_COPY_AND_ASSIGN(DeserializerAllocator);
}; };
......
This diff is collapsed.
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include <utility> #include <utility>
#include <vector> #include <vector>
#include "src/execution/local-isolate-wrapper.h"
#include "src/objects/allocation-site.h" #include "src/objects/allocation-site.h"
#include "src/objects/api-callbacks.h" #include "src/objects/api-callbacks.h"
#include "src/objects/backing-store.h" #include "src/objects/backing-store.h"
...@@ -47,7 +48,7 @@ class V8_EXPORT_PRIVATE Deserializer : public SerializerDeserializer { ...@@ -47,7 +48,7 @@ class V8_EXPORT_PRIVATE Deserializer : public SerializerDeserializer {
// Create a deserializer from a snapshot byte source. // Create a deserializer from a snapshot byte source.
template <class Data> template <class Data>
Deserializer(Data* data, bool deserializing_user_code) Deserializer(Data* data, bool deserializing_user_code)
: isolate_(nullptr), : local_isolate_(nullptr),
source_(data->Payload()), source_(data->Payload()),
magic_number_(data->GetMagicNumber()), magic_number_(data->GetMagicNumber()),
deserializing_user_code_(deserializing_user_code), deserializing_user_code_(deserializing_user_code),
...@@ -58,7 +59,10 @@ class V8_EXPORT_PRIVATE Deserializer : public SerializerDeserializer { ...@@ -58,7 +59,10 @@ class V8_EXPORT_PRIVATE Deserializer : public SerializerDeserializer {
backing_stores_.push_back({}); backing_stores_.push_back({});
} }
void Initialize(Isolate* isolate); void Initialize(Isolate* isolate) {
Initialize(LocalIsolateWrapper(isolate));
}
void Initialize(LocalIsolateWrapper isolate);
void DeserializeDeferredObjects(); void DeserializeDeferredObjects();
// Create Log events for newly deserialized objects. // Create Log events for newly deserialized objects.
...@@ -80,7 +84,11 @@ class V8_EXPORT_PRIVATE Deserializer : public SerializerDeserializer { ...@@ -80,7 +84,11 @@ class V8_EXPORT_PRIVATE Deserializer : public SerializerDeserializer {
CHECK_EQ(new_off_heap_array_buffers().size(), 0); CHECK_EQ(new_off_heap_array_buffers().size(), 0);
} }
Isolate* isolate() const { return isolate_; } LocalIsolateWrapper local_isolate() const { return local_isolate_; }
Isolate* isolate() const { return local_isolate().main_thread(); }
bool is_main_thread() const { return local_isolate().is_main_thread(); }
bool is_off_thread() const { return local_isolate().is_off_thread(); }
SnapshotByteSource* source() { return &source_; } SnapshotByteSource* source() { return &source_; }
const std::vector<AllocationSite>& new_allocation_sites() const { const std::vector<AllocationSite>& new_allocation_sites() const {
return new_allocation_sites_; return new_allocation_sites_;
...@@ -117,9 +125,6 @@ class V8_EXPORT_PRIVATE Deserializer : public SerializerDeserializer { ...@@ -117,9 +125,6 @@ class V8_EXPORT_PRIVATE Deserializer : public SerializerDeserializer {
void Rehash(); void Rehash();
// Cached current isolate.
Isolate* isolate_;
private: private:
void VisitRootPointers(Root root, const char* description, void VisitRootPointers(Root root, const char* description,
FullObjectSlot start, FullObjectSlot end) override; FullObjectSlot start, FullObjectSlot end) override;
...@@ -148,9 +153,8 @@ class V8_EXPORT_PRIVATE Deserializer : public SerializerDeserializer { ...@@ -148,9 +153,8 @@ class V8_EXPORT_PRIVATE Deserializer : public SerializerDeserializer {
// Returns the new value of {current}. // Returns the new value of {current}.
template <typename TSlot, Bytecode bytecode, template <typename TSlot, Bytecode bytecode,
SnapshotSpace space_number_if_any> SnapshotSpace space_number_if_any>
inline TSlot ReadDataCase(Isolate* isolate, TSlot current, inline TSlot ReadDataCase(TSlot current, Address current_object_address,
Address current_object_address, byte data, byte data, bool write_barrier_needed);
bool write_barrier_needed);
// A helper function for ReadData for reading external references. // A helper function for ReadData for reading external references.
inline Address ReadExternalReferenceCase(); inline Address ReadExternalReferenceCase();
...@@ -175,6 +179,9 @@ class V8_EXPORT_PRIVATE Deserializer : public SerializerDeserializer { ...@@ -175,6 +179,9 @@ class V8_EXPORT_PRIVATE Deserializer : public SerializerDeserializer {
// Special handling for serialized code like hooking up internalized strings. // Special handling for serialized code like hooking up internalized strings.
HeapObject PostProcessNewObject(HeapObject obj, SnapshotSpace space); HeapObject PostProcessNewObject(HeapObject obj, SnapshotSpace space);
// Cached current isolate.
LocalIsolateWrapper local_isolate_;
// Objects from the attached object descriptions in the serialized user code. // Objects from the attached object descriptions in the serialized user code.
std::vector<Handle<HeapObject>> attached_objects_; std::vector<Handle<HeapObject>> attached_objects_;
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include "src/codegen/assembler-inl.h" #include "src/codegen/assembler-inl.h"
#include "src/execution/isolate.h" #include "src/execution/isolate.h"
#include "src/execution/local-isolate-wrapper-inl.h"
#include "src/heap/heap-inl.h" #include "src/heap/heap-inl.h"
#include "src/objects/allocation-site-inl.h" #include "src/objects/allocation-site-inl.h"
#include "src/objects/objects.h" #include "src/objects/objects.h"
...@@ -26,75 +27,91 @@ ObjectDeserializer::DeserializeSharedFunctionInfo( ...@@ -26,75 +27,91 @@ ObjectDeserializer::DeserializeSharedFunctionInfo(
d.AddAttachedObject(source); d.AddAttachedObject(source);
Handle<HeapObject> result; Handle<HeapObject> result;
return d.Deserialize(isolate).ToHandle(&result) return d.Deserialize(LocalIsolateWrapper(isolate)).ToHandle(&result)
? Handle<SharedFunctionInfo>::cast(result) ? Handle<SharedFunctionInfo>::cast(result)
: MaybeHandle<SharedFunctionInfo>(); : MaybeHandle<SharedFunctionInfo>();
} }
MaybeHandle<HeapObject> ObjectDeserializer::Deserialize(Isolate* isolate) { MaybeHandle<SharedFunctionInfo>
Initialize(isolate); ObjectDeserializer::DeserializeSharedFunctionInfoOffThread(
OffThreadIsolate* isolate, const SerializedCodeData* data,
Handle<String> source) {
DCHECK(ReadOnlyHeap::Contains(*source) || Heap::InOffThreadSpace(*source));
ObjectDeserializer d(data);
d.AddAttachedObject(source);
Handle<HeapObject> result;
return d.Deserialize(LocalIsolateWrapper(isolate)).ToHandle(&result)
? Handle<SharedFunctionInfo>::cast(result)
: MaybeHandle<SharedFunctionInfo>();
}
MaybeHandle<HeapObject> ObjectDeserializer::Deserialize(
LocalIsolateWrapper local_isolate) {
Initialize(local_isolate);
if (!allocator()->ReserveSpace()) return MaybeHandle<HeapObject>(); if (!allocator()->ReserveSpace()) return MaybeHandle<HeapObject>();
DCHECK(deserializing_user_code()); DCHECK(deserializing_user_code());
HandleScope scope(isolate); LocalHandleScopeWrapper scope(local_isolate);
Handle<HeapObject> result; Handle<HeapObject> result;
{ {
DisallowHeapAllocation no_gc; DisallowHeapAllocation no_gc;
Object root; Object root;
VisitRootPointer(Root::kStartupObjectCache, nullptr, FullObjectSlot(&root)); VisitRootPointer(Root::kStartupObjectCache, nullptr, FullObjectSlot(&root));
DeserializeDeferredObjects(); DeserializeDeferredObjects();
FlushICache(); CHECK(new_code_objects().empty());
LinkAllocationSites(); if (is_main_thread()) {
LogNewMapEvents(); LinkAllocationSites();
result = handle(HeapObject::cast(root), isolate); LogNewMapEvents();
}
result = handle(HeapObject::cast(root), local_isolate);
Rehash(); Rehash();
allocator()->RegisterDeserializedObjectsForBlackAllocation(); if (is_main_thread()) {
allocator()->RegisterDeserializedObjectsForBlackAllocation();
}
} }
CommitPostProcessedObjects(); CommitPostProcessedObjects();
return scope.CloseAndEscape(result); return scope.CloseAndEscape(result);
} }
void ObjectDeserializer::FlushICache() {
DCHECK(deserializing_user_code());
for (Code code : new_code_objects()) {
// Record all references to embedded objects in the new code object.
#ifndef V8_DISABLE_WRITE_BARRIERS
WriteBarrierForCode(code);
#endif
FlushInstructionCache(code.raw_instruction_start(),
code.raw_instruction_size());
}
}
void ObjectDeserializer::CommitPostProcessedObjects() { void ObjectDeserializer::CommitPostProcessedObjects() {
CHECK_LE(new_internalized_strings().size(), kMaxInt); if (is_main_thread()) {
StringTable::EnsureCapacityForDeserialization( CHECK_LE(new_internalized_strings().size(), kMaxInt);
isolate(), static_cast<int>(new_internalized_strings().size())); StringTable::EnsureCapacityForDeserialization(
for (Handle<String> string : new_internalized_strings()) { isolate(), static_cast<int>(new_internalized_strings().size()));
DisallowHeapAllocation no_gc; for (Handle<String> string : new_internalized_strings()) {
StringTableInsertionKey key(*string); DisallowHeapAllocation no_gc;
StringTable::AddKeyNoResize(isolate(), &key); StringTableInsertionKey key(*string);
StringTable::AddKeyNoResize(isolate(), &key);
}
for (Handle<JSArrayBuffer> buffer : new_off_heap_array_buffers()) {
uint32_t store_index = buffer->GetBackingStoreRefForDeserialization();
auto bs = backing_store(store_index);
SharedFlag shared =
bs && bs->is_shared() ? SharedFlag::kShared : SharedFlag::kNotShared;
buffer->Setup(shared, bs);
}
} else {
CHECK_EQ(new_internalized_strings().size(), 0);
CHECK_EQ(new_off_heap_array_buffers().size(), 0);
} }
Heap* heap = isolate()->heap();
Factory* factory = isolate()->factory();
for (Handle<Script> script : new_scripts()) { for (Handle<Script> script : new_scripts()) {
// Assign a new script id to avoid collision. // Assign a new script id to avoid collision.
script->set_id(isolate()->GetNextScriptId()); script->set_id(local_isolate()->GetNextScriptId());
LogScriptEvents(*script); LogScriptEvents(*script);
// Add script to list. // Add script to list.
Handle<WeakArrayList> list = factory->script_list(); if (is_main_thread()) {
list = WeakArrayList::AddToEnd(isolate(), list, Handle<WeakArrayList> list = isolate()->factory()->script_list();
MaybeObjectHandle::Weak(script)); list = WeakArrayList::AddToEnd(isolate(), list,
heap->SetRootScriptList(*list); MaybeObjectHandle::Weak(script));
} isolate()->heap()->SetRootScriptList(*list);
} else {
for (Handle<JSArrayBuffer> buffer : new_off_heap_array_buffers()) { local_isolate().off_thread()->heap()->AddToScriptList(script);
uint32_t store_index = buffer->GetBackingStoreRefForDeserialization(); }
auto bs = backing_store(store_index);
SharedFlag shared =
bs && bs->is_shared() ? SharedFlag::kShared : SharedFlag::kNotShared;
buffer->Setup(shared, bs);
} }
} }
......
...@@ -18,14 +18,16 @@ class ObjectDeserializer final : public Deserializer { ...@@ -18,14 +18,16 @@ class ObjectDeserializer final : public Deserializer {
public: public:
static MaybeHandle<SharedFunctionInfo> DeserializeSharedFunctionInfo( static MaybeHandle<SharedFunctionInfo> DeserializeSharedFunctionInfo(
Isolate* isolate, const SerializedCodeData* data, Handle<String> source); Isolate* isolate, const SerializedCodeData* data, Handle<String> source);
static MaybeHandle<SharedFunctionInfo> DeserializeSharedFunctionInfoOffThread(
OffThreadIsolate* isolate, const SerializedCodeData* data,
Handle<String> source);
private: private:
explicit ObjectDeserializer(const SerializedCodeData* data); explicit ObjectDeserializer(const SerializedCodeData* data);
// Deserialize an object graph. Fail gracefully. // Deserialize an object graph. Fail gracefully.
MaybeHandle<HeapObject> Deserialize(Isolate* isolate); MaybeHandle<HeapObject> Deserialize(LocalIsolateWrapper isolate);
void FlushICache();
void LinkAllocationSites(); void LinkAllocationSites();
void CommitPostProcessedObjects(); void CommitPostProcessedObjects();
}; };
......
...@@ -55,7 +55,7 @@ void ReadOnlyDeserializer::DeserializeInto(Isolate* isolate) { ...@@ -55,7 +55,7 @@ void ReadOnlyDeserializer::DeserializeInto(Isolate* isolate) {
} }
if (FLAG_rehash_snapshot && can_rehash()) { if (FLAG_rehash_snapshot && can_rehash()) {
isolate_->heap()->InitializeHashSeed(); isolate->heap()->InitializeHashSeed();
Rehash(); Rehash();
} }
} }
......
...@@ -74,7 +74,7 @@ void StartupDeserializer::DeserializeInto(Isolate* isolate) { ...@@ -74,7 +74,7 @@ void StartupDeserializer::DeserializeInto(Isolate* isolate) {
} }
void StartupDeserializer::LogNewMapEvents() { void StartupDeserializer::LogNewMapEvents() {
if (FLAG_trace_maps) LOG(isolate_, LogAllMaps()); if (FLAG_trace_maps) LOG(isolate(), LogAllMaps());
} }
void StartupDeserializer::FlushICache() { void StartupDeserializer::FlushICache() {
......
...@@ -20,6 +20,12 @@ struct PointerWithPayloadTraits { ...@@ -20,6 +20,12 @@ struct PointerWithPayloadTraits {
alignof(PointerType) >= 8 ? 3 : alignof(PointerType) >= 4 ? 2 : 1; alignof(PointerType) >= 8 ? 3 : alignof(PointerType) >= 4 ? 2 : 1;
}; };
// Assume void* has the same payloads as void**, under the assumption that it's
// used for classes that contain at least one pointer.
template <>
struct PointerWithPayloadTraits<void> : public PointerWithPayloadTraits<void*> {
};
// PointerWithPayload combines a PointerType* an a small PayloadType into // PointerWithPayload combines a PointerType* an a small PayloadType into
// one. The bits of the storage type get packed into the lower bits of the // one. The bits of the storage type get packed into the lower bits of the
// pointer that are free due to alignment. The user needs to specify how many // pointer that are free due to alignment. The user needs to specify how many
...@@ -42,7 +48,8 @@ class PointerWithPayload { ...@@ -42,7 +48,8 @@ class PointerWithPayload {
"Ptr does not have sufficient alignment for the selected amount of " "Ptr does not have sufficient alignment for the selected amount of "
"storage bits."); "storage bits.");
static constexpr uintptr_t kPayloadMask = (uintptr_t{1} << kAvailBits) - 1; static constexpr uintptr_t kPayloadMask =
(uintptr_t{1} << NumPayloadBits) - 1;
static constexpr uintptr_t kPointerMask = ~kPayloadMask; static constexpr uintptr_t kPointerMask = ~kPayloadMask;
public: public:
...@@ -68,6 +75,13 @@ class PointerWithPayload { ...@@ -68,6 +75,13 @@ class PointerWithPayload {
return reinterpret_cast<PointerType*>(pointer_ & kPointerMask); return reinterpret_cast<PointerType*>(pointer_ & kPointerMask);
} }
// An optimized version of GetPointer for when we know the payload value.
V8_INLINE PointerType* GetPointerWithKnownPayload(PayloadType payload) const {
DCHECK_EQ(GetPayload(), payload);
return reinterpret_cast<PointerType*>(pointer_ -
static_cast<uintptr_t>(payload));
}
V8_INLINE PointerType* operator->() const { return GetPointer(); } V8_INLINE PointerType* operator->() const { return GetPointer(); }
V8_INLINE void update(PointerType* new_pointer, PayloadType new_payload) { V8_INLINE void update(PointerType* new_pointer, PayloadType new_payload) {
......
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