[offthread] Template deserializer on Isolate
Make the deserializer class templated on Isolate/LocalIsolate. This allows the ObjectSerializer to be split into a main-thread and offthread variant, with the latter taking a LocalIsolate. Eventually, we probably want to anyway split off the code-cache de/serializer to a separate implementation (for various reasons), and this the only one that wants off-thread finalization, and at this point the deserializer can revert back to being un-templated, used only for bootstrapping. However, this is the simplest way, for now, to enable off-thread deserialization. Bug: chromium:1075999 Change-Id: I49c0d2c5409f0aa58183673785296756c3714f22 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2562254 Reviewed-by: Jakob Gruber <jgruber@chromium.org> Reviewed-by: Dominik Inführ <dinfuehr@chromium.org> Commit-Queue: Leszek Swirski <leszeks@chromium.org> Cr-Commit-Position: refs/heads/master@{#75834}
This commit is contained in:
parent
7179c71e12
commit
e24fa91327
@ -1768,6 +1768,7 @@ class V8_EXPORT_PRIVATE Isolate final : private HiddenFactory {
|
||||
return main_thread_local_isolate_.get();
|
||||
}
|
||||
|
||||
Isolate* AsIsolate() { return this; }
|
||||
LocalIsolate* AsLocalIsolate() { return main_thread_local_isolate(); }
|
||||
|
||||
LocalHeap* main_thread_local_heap();
|
||||
|
@ -22,6 +22,11 @@ Object LocalIsolate::root(RootIndex index) const {
|
||||
return isolate_->root(index);
|
||||
}
|
||||
|
||||
Handle<Object> LocalIsolate::root_handle(RootIndex index) const {
|
||||
DCHECK(RootsTable::IsImmortalImmovable(index));
|
||||
return isolate_->root_handle(index);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
||||
|
@ -26,6 +26,13 @@ LocalIsolate::LocalIsolate(Isolate* isolate, ThreadKind kind,
|
||||
|
||||
LocalIsolate::~LocalIsolate() = default;
|
||||
|
||||
void LocalIsolate::RegisterDeserializerStarted() {
|
||||
return isolate_->RegisterDeserializerStarted();
|
||||
}
|
||||
void LocalIsolate::RegisterDeserializerFinished() {
|
||||
return isolate_->RegisterDeserializerFinished();
|
||||
}
|
||||
|
||||
int LocalIsolate::GetNextScriptId() { return isolate_->GetNextScriptId(); }
|
||||
|
||||
#if V8_SFI_HAS_UNIQUE_ID
|
||||
|
@ -48,11 +48,14 @@ class V8_EXPORT_PRIVATE LocalIsolate final : private HiddenLocalFactory {
|
||||
OFFSET_OF(LocalIsolate, heap_));
|
||||
}
|
||||
|
||||
bool is_main_thread() { return heap()->is_main_thread(); }
|
||||
|
||||
LocalHeap* heap() { return &heap_; }
|
||||
|
||||
inline Address cage_base() const;
|
||||
inline ReadOnlyHeap* read_only_heap() const;
|
||||
inline Object root(RootIndex index) const;
|
||||
inline Handle<Object> root_handle(RootIndex index) const;
|
||||
|
||||
StringTable* string_table() const { return isolate_->string_table(); }
|
||||
base::SharedMutex* internalized_string_access() {
|
||||
@ -67,6 +70,9 @@ class V8_EXPORT_PRIVATE LocalIsolate final : private HiddenLocalFactory {
|
||||
|
||||
bool has_pending_exception() const { return false; }
|
||||
|
||||
void RegisterDeserializerStarted();
|
||||
void RegisterDeserializerFinished();
|
||||
|
||||
template <typename T>
|
||||
Handle<T> Throw(Handle<Object> exception) {
|
||||
UNREACHABLE();
|
||||
@ -89,6 +95,12 @@ class V8_EXPORT_PRIVATE LocalIsolate final : private HiddenLocalFactory {
|
||||
|
||||
bool is_main_thread() const { return heap_.is_main_thread(); }
|
||||
|
||||
// AsIsolate is only allowed on the main-thread.
|
||||
Isolate* AsIsolate() {
|
||||
DCHECK(is_main_thread());
|
||||
DCHECK_EQ(ThreadId::Current(), isolate_->thread_id());
|
||||
return isolate_;
|
||||
}
|
||||
LocalIsolate* AsLocalIsolate() { return this; }
|
||||
|
||||
private:
|
||||
|
@ -335,14 +335,11 @@ HeapObject Heap::AllocateRawWith(int size, AllocationType allocation,
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
Address Heap::DeserializerAllocate(AllocationType type, int size_in_bytes) {
|
||||
if (V8_ENABLE_THIRD_PARTY_HEAP_BOOL) {
|
||||
AllocationResult allocation = tp_heap_->Allocate(
|
||||
size_in_bytes, type, AllocationAlignment::kDoubleAligned);
|
||||
return allocation.ToObjectChecked().ptr();
|
||||
} else {
|
||||
UNIMPLEMENTED(); // unimplemented
|
||||
}
|
||||
Address Heap::AllocateRawOrFail(int size, AllocationType allocation,
|
||||
AllocationOrigin origin,
|
||||
AllocationAlignment alignment) {
|
||||
return AllocateRawWith<kRetryOrFail>(size, allocation, origin, alignment)
|
||||
.address();
|
||||
}
|
||||
|
||||
void Heap::OnAllocationEvent(HeapObject object, int size_in_bytes) {
|
||||
|
@ -567,11 +567,6 @@ class Heap {
|
||||
|
||||
V8_EXPORT_PRIVATE static bool IsLargeObject(HeapObject object);
|
||||
|
||||
// This method supports the deserialization allocator. All allocations
|
||||
// are word-aligned. The method should never fail to allocate since the
|
||||
// total space requirements of the deserializer are known at build time.
|
||||
inline Address DeserializerAllocate(AllocationType type, int size_in_bytes);
|
||||
|
||||
// Trim the given array from the left. Note that this relocates the object
|
||||
// start and hence is only valid if there is only a single reference to it.
|
||||
V8_EXPORT_PRIVATE FixedArrayBase LeftTrimFixedArray(FixedArrayBase obj,
|
||||
@ -2105,6 +2100,12 @@ class Heap {
|
||||
AllocationOrigin origin = AllocationOrigin::kRuntime,
|
||||
AllocationAlignment alignment = kWordAligned);
|
||||
|
||||
// Call AllocateRawWith with kRetryOrFail. Matches the method in LocalHeap.
|
||||
V8_WARN_UNUSED_RESULT inline Address AllocateRawOrFail(
|
||||
int size, AllocationType allocation,
|
||||
AllocationOrigin origin = AllocationOrigin::kRuntime,
|
||||
AllocationAlignment alignment = kWordAligned);
|
||||
|
||||
// This method will try to perform an allocation of a given size of a given
|
||||
// AllocationType. If the allocation fails, a regular full garbage collection
|
||||
// is triggered and the allocation is retried. This is performed multiple
|
||||
@ -2527,6 +2528,7 @@ class Heap {
|
||||
|
||||
// The allocator interface.
|
||||
friend class Factory;
|
||||
template <typename IsolateT>
|
||||
friend class Deserializer;
|
||||
|
||||
// The Isolate constructs us.
|
||||
@ -2580,8 +2582,6 @@ class V8_NODISCARD AlwaysAllocateScope {
|
||||
|
||||
private:
|
||||
friend class AlwaysAllocateScopeForTesting;
|
||||
friend class Deserializer;
|
||||
friend class DeserializerAllocator;
|
||||
friend class Evacuator;
|
||||
friend class Heap;
|
||||
friend class Isolate;
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "src/common/assert-scope.h"
|
||||
#include "src/handles/persistent-handles.h"
|
||||
#include "src/heap/concurrent-allocator-inl.h"
|
||||
#include "src/heap/heap.h"
|
||||
#include "src/heap/local-heap.h"
|
||||
|
||||
namespace v8 {
|
||||
@ -53,6 +54,13 @@ Address LocalHeap::AllocateRawOrFail(int object_size, AllocationType type,
|
||||
alignment);
|
||||
}
|
||||
|
||||
void LocalHeap::CreateFillerObjectAt(Address addr, int size,
|
||||
ClearRecordedSlots clear_slots_mode) {
|
||||
DCHECK_EQ(clear_slots_mode, ClearRecordedSlots::kNo);
|
||||
heap()->CreateFillerObjectAtBackground(
|
||||
addr, size, ClearFreedMemoryMode::kDontClearFreedMemory);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
||||
|
@ -130,7 +130,14 @@ class V8_EXPORT_PRIVATE LocalHeap {
|
||||
AllocationOrigin origin = AllocationOrigin::kRuntime,
|
||||
AllocationAlignment alignment = kWordAligned);
|
||||
|
||||
inline void CreateFillerObjectAt(Address addr, int size,
|
||||
ClearRecordedSlots clear_slots_mode);
|
||||
|
||||
bool is_main_thread() const { return is_main_thread_; }
|
||||
bool deserialization_complete() const {
|
||||
return heap_->deserialization_complete();
|
||||
}
|
||||
ReadOnlySpace* read_only_space() { return heap_->read_only_space(); }
|
||||
|
||||
// Requests GC and blocks until the collection finishes.
|
||||
bool TryPerformCollection();
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include "src/logging/local-logger.h"
|
||||
|
||||
#include "src/execution/isolate.h"
|
||||
#include "src/objects/map.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
@ -27,5 +28,9 @@ void LocalLogger::CodeLinePosInfoRecordEvent(Address code_start,
|
||||
logger_->CodeLinePosInfoRecordEvent(code_start, source_position_table);
|
||||
}
|
||||
|
||||
void LocalLogger::MapCreate(Map map) { logger_->MapCreate(map); }
|
||||
|
||||
void LocalLogger::MapDetails(Map map) { logger_->MapDetails(map); }
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
@ -25,6 +25,9 @@ class LocalLogger {
|
||||
void CodeLinePosInfoRecordEvent(Address code_start,
|
||||
ByteArray source_position_table);
|
||||
|
||||
void MapCreate(Map map);
|
||||
void MapDetails(Map map);
|
||||
|
||||
private:
|
||||
Logger* logger_;
|
||||
bool is_logging_;
|
||||
|
@ -195,7 +195,8 @@ class HeapObject : public Object {
|
||||
bool CanBeRehashed() const;
|
||||
|
||||
// Rehash the object based on the layout inferred from its map.
|
||||
void RehashBasedOnMap(Isolate* isolate);
|
||||
template <typename IsolateT>
|
||||
void RehashBasedOnMap(IsolateT* isolate);
|
||||
|
||||
// Layout description.
|
||||
#define HEAP_OBJECT_FIELDS(V) \
|
||||
|
@ -364,6 +364,7 @@ class JSTypedArray
|
||||
#endif
|
||||
|
||||
private:
|
||||
template <typename IsolateT>
|
||||
friend class Deserializer;
|
||||
friend class Factory;
|
||||
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "src/objects/map-inl.h"
|
||||
#include "src/objects/name.h"
|
||||
#include "src/objects/primitive-heap-object-inl.h"
|
||||
#include "src/objects/string-inl.h"
|
||||
|
||||
// Has to be the last include (doesn't have include guards):
|
||||
#include "src/objects/object-macros.h"
|
||||
@ -97,6 +98,14 @@ uint32_t Name::EnsureHash() {
|
||||
return String::cast(*this).ComputeAndSetHash();
|
||||
}
|
||||
|
||||
uint32_t Name::EnsureHash(const SharedStringAccessGuardIfNeeded& access_guard) {
|
||||
// Fast case: has hash code already been computed?
|
||||
uint32_t field = raw_hash_field();
|
||||
if (IsHashFieldComputed(field)) return field >> kHashShift;
|
||||
// Slow case: compute hash code and set it. Has to be a string.
|
||||
return String::cast(*this).ComputeAndSetHash(access_guard);
|
||||
}
|
||||
|
||||
uint32_t Name::hash() const {
|
||||
uint32_t field = raw_hash_field();
|
||||
DCHECK(IsHashFieldComputed(field));
|
||||
|
@ -18,6 +18,8 @@ namespace internal {
|
||||
|
||||
#include "torque-generated/src/objects/name-tq.inc"
|
||||
|
||||
class SharedStringAccessGuardIfNeeded;
|
||||
|
||||
// The Name abstract class captures anything that can be used as a property
|
||||
// name, i.e., strings and symbols. All names store a hash value.
|
||||
class Name : public TorqueGeneratedName<Name, PrimitiveHeapObject> {
|
||||
@ -27,7 +29,11 @@ class Name : public TorqueGeneratedName<Name, PrimitiveHeapObject> {
|
||||
|
||||
// Returns a hash value used for the property table. Ensures that the hash
|
||||
// value is computed.
|
||||
//
|
||||
// The overload without SharedStringAccessGuardIfNeeded can only be called on
|
||||
// the main thread.
|
||||
inline uint32_t EnsureHash();
|
||||
inline uint32_t EnsureHash(const SharedStringAccessGuardIfNeeded&);
|
||||
|
||||
// Returns a hash value used for the property table (same as Hash()), assumes
|
||||
// the hash is already computed.
|
||||
|
@ -2363,7 +2363,8 @@ bool HeapObject::CanBeRehashed() const {
|
||||
}
|
||||
}
|
||||
|
||||
void HeapObject::RehashBasedOnMap(Isolate* isolate) {
|
||||
template <typename IsolateT>
|
||||
void HeapObject::RehashBasedOnMap(IsolateT* isolate) {
|
||||
switch (map().instance_type()) {
|
||||
case HASH_TABLE_TYPE:
|
||||
UNREACHABLE();
|
||||
@ -2399,11 +2400,11 @@ void HeapObject::RehashBasedOnMap(Isolate* isolate) {
|
||||
case ORDERED_HASH_SET_TYPE:
|
||||
UNREACHABLE(); // We'll rehash from the JSMap or JSSet referencing them.
|
||||
case JS_MAP_TYPE: {
|
||||
JSMap::cast(*this).Rehash(isolate);
|
||||
JSMap::cast(*this).Rehash(isolate->AsIsolate());
|
||||
break;
|
||||
}
|
||||
case JS_SET_TYPE: {
|
||||
JSSet::cast(*this).Rehash(isolate);
|
||||
JSSet::cast(*this).Rehash(isolate->AsIsolate());
|
||||
break;
|
||||
}
|
||||
case SMALL_ORDERED_NAME_DICTIONARY_TYPE:
|
||||
@ -2419,6 +2420,8 @@ void HeapObject::RehashBasedOnMap(Isolate* isolate) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
template void HeapObject::RehashBasedOnMap(Isolate* isolate);
|
||||
template void HeapObject::RehashBasedOnMap(LocalIsolate* isolate);
|
||||
|
||||
bool HeapObject::IsExternal(Isolate* isolate) const {
|
||||
return map().FindRootMap(isolate) == isolate->heap()->external_map();
|
||||
|
@ -9,17 +9,19 @@
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
void StringComparator::State::Init(String string) {
|
||||
ConsString cons_string = String::VisitFlat(this, string);
|
||||
void StringComparator::State::Init(
|
||||
String string, const SharedStringAccessGuardIfNeeded& access_guard) {
|
||||
ConsString cons_string = String::VisitFlat(this, string, 0, access_guard);
|
||||
iter_.Reset(cons_string);
|
||||
if (!cons_string.is_null()) {
|
||||
int offset;
|
||||
string = iter_.Next(&offset);
|
||||
String::VisitFlat(this, string, offset);
|
||||
String::VisitFlat(this, string, offset, access_guard);
|
||||
}
|
||||
}
|
||||
|
||||
void StringComparator::State::Advance(int consumed) {
|
||||
void StringComparator::State::Advance(
|
||||
int consumed, const SharedStringAccessGuardIfNeeded& access_guard) {
|
||||
DCHECK(consumed <= length_);
|
||||
// Still in buffer.
|
||||
if (length_ != consumed) {
|
||||
@ -36,13 +38,15 @@ void StringComparator::State::Advance(int consumed) {
|
||||
String next = iter_.Next(&offset);
|
||||
DCHECK_EQ(0, offset);
|
||||
DCHECK(!next.is_null());
|
||||
String::VisitFlat(this, next);
|
||||
String::VisitFlat(this, next, 0, access_guard);
|
||||
}
|
||||
|
||||
bool StringComparator::Equals(String string_1, String string_2) {
|
||||
bool StringComparator::Equals(
|
||||
String string_1, String string_2,
|
||||
const SharedStringAccessGuardIfNeeded& access_guard) {
|
||||
int length = string_1.length();
|
||||
state_1_.Init(string_1);
|
||||
state_2_.Init(string_2);
|
||||
state_1_.Init(string_1, access_guard);
|
||||
state_2_.Init(string_2, access_guard);
|
||||
while (true) {
|
||||
int to_check = std::min(state_1_.length_, state_2_.length_);
|
||||
DCHECK(to_check > 0 && to_check <= length);
|
||||
@ -65,8 +69,8 @@ bool StringComparator::Equals(String string_1, String string_2) {
|
||||
length -= to_check;
|
||||
// Exit condition. Strings are equal.
|
||||
if (length == 0) return true;
|
||||
state_1_.Advance(to_check);
|
||||
state_2_.Advance(to_check);
|
||||
state_1_.Advance(to_check, access_guard);
|
||||
state_2_.Advance(to_check, access_guard);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -20,7 +20,8 @@ class StringComparator {
|
||||
State(const State&) = delete;
|
||||
State& operator=(const State&) = delete;
|
||||
|
||||
void Init(String string);
|
||||
void Init(String string,
|
||||
const SharedStringAccessGuardIfNeeded& access_guard);
|
||||
|
||||
inline void VisitOneByteString(const uint8_t* chars, int length) {
|
||||
is_one_byte_ = true;
|
||||
@ -34,7 +35,8 @@ class StringComparator {
|
||||
length_ = length;
|
||||
}
|
||||
|
||||
void Advance(int consumed);
|
||||
void Advance(int consumed,
|
||||
const SharedStringAccessGuardIfNeeded& access_guard);
|
||||
|
||||
ConsStringIterator iter_;
|
||||
bool is_one_byte_;
|
||||
@ -57,7 +59,8 @@ class StringComparator {
|
||||
return CompareCharsEqual(a, b, to_check);
|
||||
}
|
||||
|
||||
bool Equals(String string_1, String string_2);
|
||||
bool Equals(String string_1, String string_2,
|
||||
const SharedStringAccessGuardIfNeeded& access_guard);
|
||||
|
||||
private:
|
||||
State state_1_;
|
||||
|
@ -510,6 +510,8 @@ template Handle<String> StringTable::LookupKey(LocalIsolate* isolate,
|
||||
|
||||
template Handle<String> StringTable::LookupKey(Isolate* isolate,
|
||||
StringTableInsertionKey* key);
|
||||
template Handle<String> StringTable::LookupKey(LocalIsolate* isolate,
|
||||
StringTableInsertionKey* key);
|
||||
|
||||
StringTable::Data* StringTable::EnsureCapacity(PtrComprCageBase cage_base,
|
||||
int additional_elements) {
|
||||
|
@ -10,6 +10,8 @@
|
||||
#include "src/execution/thread-id.h"
|
||||
#include "src/handles/handles-inl.h"
|
||||
#include "src/heap/heap-inl.h"
|
||||
#include "src/heap/local-factory-inl.h"
|
||||
#include "src/heap/local-heap-inl.h"
|
||||
#include "src/heap/memory-chunk.h"
|
||||
#include "src/heap/read-only-heap.h"
|
||||
#include "src/numbers/conversions.h"
|
||||
@ -93,26 +95,32 @@ void MigrateExternalStringResource(Isolate* isolate, ExternalString from,
|
||||
}
|
||||
}
|
||||
|
||||
void MigrateExternalString(Isolate* isolate, String string,
|
||||
String internalized) {
|
||||
if (internalized.IsExternalOneByteString()) {
|
||||
MigrateExternalStringResource(isolate, ExternalString::cast(string),
|
||||
ExternalOneByteString::cast(internalized));
|
||||
} else if (internalized.IsExternalTwoByteString()) {
|
||||
MigrateExternalStringResource(isolate, ExternalString::cast(string),
|
||||
ExternalTwoByteString::cast(internalized));
|
||||
} else {
|
||||
// If the external string is duped into an existing non-external
|
||||
// internalized string, free its resource (it's about to be rewritten
|
||||
// into a ThinString below).
|
||||
isolate->heap()->FinalizeExternalString(string);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void String::MakeThin(Isolate* isolate, String internalized) {
|
||||
template <typename IsolateT>
|
||||
void String::MakeThin(IsolateT* isolate, String internalized) {
|
||||
DisallowGarbageCollection no_gc;
|
||||
DCHECK_NE(*this, internalized);
|
||||
DCHECK(internalized.IsInternalizedString());
|
||||
|
||||
if (this->IsExternalString()) {
|
||||
if (internalized.IsExternalOneByteString()) {
|
||||
MigrateExternalStringResource(isolate, ExternalString::cast(*this),
|
||||
ExternalOneByteString::cast(internalized));
|
||||
} else if (internalized.IsExternalTwoByteString()) {
|
||||
MigrateExternalStringResource(isolate, ExternalString::cast(*this),
|
||||
ExternalTwoByteString::cast(internalized));
|
||||
} else {
|
||||
// If the external string is duped into an existing non-external
|
||||
// internalized string, free its resource (it's about to be rewritten
|
||||
// into a ThinString below).
|
||||
isolate->heap()->FinalizeExternalString(*this);
|
||||
}
|
||||
MigrateExternalString(isolate->AsIsolate(), *this, internalized);
|
||||
}
|
||||
|
||||
bool has_pointers = StringShape(*this).IsIndirect();
|
||||
@ -131,9 +139,8 @@ void String::MakeThin(Isolate* isolate, String internalized) {
|
||||
Address thin_end = thin.address() + ThinString::kSize;
|
||||
int size_delta = old_size - ThinString::kSize;
|
||||
if (size_delta != 0) {
|
||||
Heap* heap = isolate->heap();
|
||||
if (!heap->IsLargeObject(thin)) {
|
||||
heap->CreateFillerObjectAt(
|
||||
if (!Heap::IsLargeObject(thin)) {
|
||||
isolate->heap()->CreateFillerObjectAt(
|
||||
thin_end, size_delta,
|
||||
has_pointers ? ClearRecordedSlots::kYes : ClearRecordedSlots::kNo);
|
||||
} else {
|
||||
@ -144,6 +151,9 @@ void String::MakeThin(Isolate* isolate, String internalized) {
|
||||
}
|
||||
}
|
||||
|
||||
template void String::MakeThin(Isolate* isolate, String internalized);
|
||||
template void String::MakeThin(LocalIsolate* isolate, String internalized);
|
||||
|
||||
bool String::MakeExternal(v8::String::ExternalStringResource* resource) {
|
||||
// Disallow garbage collection to avoid possible GC vs string access deadlock.
|
||||
DisallowGarbageCollection no_gc;
|
||||
@ -633,6 +643,7 @@ std::unique_ptr<char[]> String::ToCString(AllowNullsFlag allow_nulls,
|
||||
return ToCString(allow_nulls, robust_flag, 0, -1, length_return);
|
||||
}
|
||||
|
||||
// static
|
||||
template <typename sinkchar>
|
||||
void String::WriteToFlat(String source, sinkchar* sink, int from, int to) {
|
||||
DCHECK(!SharedStringAccessGuardIfNeeded::IsNeeded(source));
|
||||
@ -640,6 +651,7 @@ void String::WriteToFlat(String source, sinkchar* sink, int from, int to) {
|
||||
SharedStringAccessGuardIfNeeded::NotNeeded());
|
||||
}
|
||||
|
||||
// static
|
||||
template <typename sinkchar>
|
||||
void String::WriteToFlat(String source, sinkchar* sink, int from, int to,
|
||||
const SharedStringAccessGuardIfNeeded& access_guard) {
|
||||
@ -794,6 +806,13 @@ template Handle<FixedArray> String::CalculateLineEnds(LocalIsolate* isolate,
|
||||
bool include_ending_line);
|
||||
|
||||
bool String::SlowEquals(String other) const {
|
||||
DCHECK(!SharedStringAccessGuardIfNeeded::IsNeeded(*this));
|
||||
DCHECK(!SharedStringAccessGuardIfNeeded::IsNeeded(other));
|
||||
return SlowEquals(other, SharedStringAccessGuardIfNeeded::NotNeeded());
|
||||
}
|
||||
|
||||
bool String::SlowEquals(
|
||||
String other, const SharedStringAccessGuardIfNeeded& access_guard) const {
|
||||
DisallowGarbageCollection no_gc;
|
||||
// Fast check: negative check with lengths.
|
||||
int len = length();
|
||||
@ -833,16 +852,18 @@ bool String::SlowEquals(String other) const {
|
||||
|
||||
// We know the strings are both non-empty. Compare the first chars
|
||||
// before we try to flatten the strings.
|
||||
if (this->Get(0) != other.Get(0)) return false;
|
||||
if (this->Get(0, access_guard) != other.Get(0, access_guard)) return false;
|
||||
|
||||
if (IsSeqOneByteString() && other.IsSeqOneByteString()) {
|
||||
const uint8_t* str1 = SeqOneByteString::cast(*this).GetChars(no_gc);
|
||||
const uint8_t* str2 = SeqOneByteString::cast(other).GetChars(no_gc);
|
||||
const uint8_t* str1 =
|
||||
SeqOneByteString::cast(*this).GetChars(no_gc, access_guard);
|
||||
const uint8_t* str2 =
|
||||
SeqOneByteString::cast(other).GetChars(no_gc, access_guard);
|
||||
return CompareCharsEqual(str1, str2, len);
|
||||
}
|
||||
|
||||
StringComparator comparator;
|
||||
return comparator.Equals(*this, other);
|
||||
return comparator.Equals(*this, other, access_guard);
|
||||
}
|
||||
|
||||
// static
|
||||
@ -1326,7 +1347,8 @@ bool String::HasOneBytePrefix(base::Vector<const char> str) {
|
||||
namespace {
|
||||
|
||||
template <typename Char>
|
||||
uint32_t HashString(String string, size_t start, int length, uint64_t seed) {
|
||||
uint32_t HashString(String string, size_t start, int length, uint64_t seed,
|
||||
const SharedStringAccessGuardIfNeeded& access_guard) {
|
||||
DisallowGarbageCollection no_gc;
|
||||
|
||||
if (length > String::kMaxHashCalcLength) {
|
||||
@ -1340,10 +1362,10 @@ uint32_t HashString(String string, size_t start, int length, uint64_t seed) {
|
||||
DCHECK_EQ(0, start);
|
||||
DCHECK(!string.IsFlat());
|
||||
buffer.reset(new Char[length]);
|
||||
String::WriteToFlat(string, buffer.get(), 0, length);
|
||||
String::WriteToFlat(string, buffer.get(), 0, length, access_guard);
|
||||
chars = buffer.get();
|
||||
} else {
|
||||
chars = string.GetChars<Char>(no_gc) + start;
|
||||
chars = string.GetChars<Char>(no_gc, access_guard) + start;
|
||||
}
|
||||
|
||||
return StringHasher::HashSequentialString<Char>(chars, length, seed);
|
||||
@ -1352,6 +1374,11 @@ uint32_t HashString(String string, size_t start, int length, uint64_t seed) {
|
||||
} // namespace
|
||||
|
||||
uint32_t String::ComputeAndSetHash() {
|
||||
DCHECK(!SharedStringAccessGuardIfNeeded::IsNeeded(*this));
|
||||
return ComputeAndSetHash(SharedStringAccessGuardIfNeeded::NotNeeded());
|
||||
}
|
||||
uint32_t String::ComputeAndSetHash(
|
||||
const SharedStringAccessGuardIfNeeded& access_guard) {
|
||||
DisallowGarbageCollection no_gc;
|
||||
// Should only be called if hash code has not yet been computed.
|
||||
DCHECK(!HasHashCode());
|
||||
@ -1377,8 +1404,8 @@ uint32_t String::ComputeAndSetHash() {
|
||||
}
|
||||
uint32_t raw_hash_field =
|
||||
string.IsOneByteRepresentation()
|
||||
? HashString<uint8_t>(string, start, length(), seed)
|
||||
: HashString<uint16_t>(string, start, length(), seed);
|
||||
? HashString<uint8_t>(string, start, length(), seed, access_guard)
|
||||
: HashString<uint16_t>(string, start, length(), seed, access_guard);
|
||||
set_raw_hash_field(raw_hash_field);
|
||||
|
||||
// Check the hash code is there.
|
||||
|
@ -172,7 +172,8 @@ class String : public TorqueGeneratedString<String, Name> {
|
||||
friend class IterableSubString;
|
||||
};
|
||||
|
||||
void MakeThin(Isolate* isolate, String canonical);
|
||||
template <typename IsolateT>
|
||||
void MakeThin(IsolateT* isolate, String canonical);
|
||||
|
||||
template <typename Char>
|
||||
V8_INLINE base::Vector<const Char> GetCharVector(
|
||||
@ -570,6 +571,8 @@ class String : public TorqueGeneratedString<String, Name> {
|
||||
// Slow case of String::Equals. This implementation works on any strings
|
||||
// but it is most efficient on strings that are almost flat.
|
||||
V8_EXPORT_PRIVATE bool SlowEquals(String other) const;
|
||||
V8_EXPORT_PRIVATE bool SlowEquals(
|
||||
String other, const SharedStringAccessGuardIfNeeded&) const;
|
||||
|
||||
V8_EXPORT_PRIVATE static bool SlowEquals(Isolate* isolate, Handle<String> one,
|
||||
Handle<String> two);
|
||||
@ -580,6 +583,8 @@ class String : public TorqueGeneratedString<String, Name> {
|
||||
|
||||
// Compute and set the hash code.
|
||||
V8_EXPORT_PRIVATE uint32_t ComputeAndSetHash();
|
||||
V8_EXPORT_PRIVATE uint32_t
|
||||
ComputeAndSetHash(const SharedStringAccessGuardIfNeeded&);
|
||||
|
||||
TQ_OBJECT_CONSTRUCTORS(String)
|
||||
};
|
||||
|
@ -207,7 +207,8 @@ Handle<SwissNameDictionary> SwissNameDictionary::Shrink(
|
||||
// storing it somewhere in the main table or the meta table, for those
|
||||
// SwissNameDictionaries that we know will be in-place rehashed, most notably
|
||||
// those stored in the snapshot.
|
||||
void SwissNameDictionary::Rehash(Isolate* isolate) {
|
||||
template <typename IsolateT>
|
||||
void SwissNameDictionary::Rehash(IsolateT* isolate) {
|
||||
DisallowHeapAllocation no_gc;
|
||||
|
||||
struct Entry {
|
||||
@ -307,6 +308,10 @@ template V8_EXPORT_PRIVATE Handle<SwissNameDictionary>
|
||||
SwissNameDictionary::Rehash(Isolate* isolate, Handle<SwissNameDictionary> table,
|
||||
int new_capacity);
|
||||
|
||||
template V8_EXPORT_PRIVATE void SwissNameDictionary::Rehash(
|
||||
LocalIsolate* isolate);
|
||||
template V8_EXPORT_PRIVATE void SwissNameDictionary::Rehash(Isolate* isolate);
|
||||
|
||||
constexpr int SwissNameDictionary::kInitialCapacity;
|
||||
constexpr int SwissNameDictionary::kGroupWidth;
|
||||
|
||||
|
@ -133,7 +133,8 @@ class V8_EXPORT_PRIVATE SwissNameDictionary : public HeapObject {
|
||||
static Handle<SwissNameDictionary> Rehash(IsolateT* isolate,
|
||||
Handle<SwissNameDictionary> table,
|
||||
int new_capacity);
|
||||
void Rehash(Isolate* isolate);
|
||||
template <typename IsolateT>
|
||||
void Rehash(IsolateT* isolate);
|
||||
|
||||
inline void SetHash(int hash);
|
||||
inline int Hash();
|
||||
|
@ -4,12 +4,16 @@
|
||||
|
||||
#include "src/snapshot/code-serializer.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "src/base/platform/platform.h"
|
||||
#include "src/codegen/macro-assembler.h"
|
||||
#include "src/common/globals.h"
|
||||
#include "src/debug/debug.h"
|
||||
#include "src/handles/persistent-handles.h"
|
||||
#include "src/heap/heap-inl.h"
|
||||
#include "src/heap/local-factory-inl.h"
|
||||
#include "src/heap/parked-scope.h"
|
||||
#include "src/logging/counters.h"
|
||||
#include "src/logging/log.h"
|
||||
#include "src/logging/runtime-call-stats-scope.h"
|
||||
@ -277,18 +281,39 @@ class StressOffThreadDeserializeThread final : public base::Thread {
|
||||
|
||||
void Run() final {
|
||||
LocalIsolate local_isolate(isolate_, ThreadKind::kBackground);
|
||||
UnparkedScope unparked_scope(&local_isolate);
|
||||
LocalHandleScope handle_scope(&local_isolate);
|
||||
|
||||
MaybeHandle<SharedFunctionInfo> local_maybe_result =
|
||||
ObjectDeserializer::DeserializeSharedFunctionInfoOffThread(
|
||||
&local_isolate, scd_, local_isolate.factory()->empty_string());
|
||||
OffThreadObjectDeserializer::DeserializeSharedFunctionInfo(
|
||||
&local_isolate, scd_, &scripts_);
|
||||
|
||||
maybe_result_ =
|
||||
local_isolate.heap()->NewPersistentMaybeHandle(local_maybe_result);
|
||||
|
||||
persistent_handles_ = local_isolate.heap()->DetachPersistentHandles();
|
||||
}
|
||||
|
||||
void Finalize(Isolate* isolate) {
|
||||
Handle<WeakArrayList> list = isolate->factory()->script_list();
|
||||
for (Handle<Script> script : scripts_) {
|
||||
DCHECK(persistent_handles_->Contains(script.location()));
|
||||
list = WeakArrayList::AddToEnd(isolate, list,
|
||||
MaybeObjectHandle::Weak(script));
|
||||
}
|
||||
isolate->heap()->SetRootScriptList(*list);
|
||||
Handle<SharedFunctionInfo> result;
|
||||
if (maybe_result_.ToHandle(&result)) {
|
||||
maybe_result_ = handle(*result, isolate);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
Isolate* isolate_;
|
||||
const SerializedCodeData* scd_;
|
||||
MaybeHandle<SharedFunctionInfo> maybe_result_;
|
||||
std::vector<Handle<Script>> scripts_;
|
||||
std::unique_ptr<PersistentHandles> persistent_handles_;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
@ -315,12 +340,12 @@ MaybeHandle<SharedFunctionInfo> CodeSerializer::Deserialize(
|
||||
|
||||
// Deserialize.
|
||||
MaybeHandle<SharedFunctionInfo> maybe_result;
|
||||
// TODO(leszeks): Add LocalHeap support to deserializer
|
||||
if (false && FLAG_stress_background_compile) {
|
||||
if (FLAG_stress_background_compile) {
|
||||
StressOffThreadDeserializeThread thread(isolate, &scd);
|
||||
CHECK(thread.Start());
|
||||
thread.Join();
|
||||
|
||||
thread.Finalize(isolate);
|
||||
maybe_result = thread.maybe_result();
|
||||
|
||||
// Fix-up result script source.
|
||||
|
@ -17,7 +17,8 @@ class Isolate;
|
||||
|
||||
// Deserializes the context-dependent object graph rooted at a given object.
|
||||
// The ContextDeserializer is not expected to deserialize any code objects.
|
||||
class V8_EXPORT_PRIVATE ContextDeserializer final : public Deserializer {
|
||||
class V8_EXPORT_PRIVATE ContextDeserializer final
|
||||
: public Deserializer<Isolate> {
|
||||
public:
|
||||
static MaybeHandle<Context> DeserializeContext(
|
||||
Isolate* isolate, const SnapshotData* data, bool can_rehash,
|
||||
|
@ -14,10 +14,14 @@
|
||||
#include "src/heap/heap-inl.h"
|
||||
#include "src/heap/heap-write-barrier-inl.h"
|
||||
#include "src/heap/heap-write-barrier.h"
|
||||
#include "src/heap/heap.h"
|
||||
#include "src/heap/local-heap-inl.h"
|
||||
#include "src/heap/read-only-heap.h"
|
||||
#include "src/interpreter/interpreter.h"
|
||||
#include "src/logging/local-logger.h"
|
||||
#include "src/logging/log.h"
|
||||
#include "src/objects/api-callbacks.h"
|
||||
#include "src/objects/backing-store.h"
|
||||
#include "src/objects/cell-inl.h"
|
||||
#include "src/objects/embedder-data-array-inl.h"
|
||||
#include "src/objects/hash-table.h"
|
||||
@ -149,9 +153,10 @@ class SlotAccessorForRootSlots {
|
||||
|
||||
// A SlotAccessor for creating a Handle, which saves a Handle allocation when
|
||||
// a Handle already exists.
|
||||
template <typename IsolateT>
|
||||
class SlotAccessorForHandle {
|
||||
public:
|
||||
SlotAccessorForHandle(Handle<HeapObject>* handle, Isolate* isolate)
|
||||
SlotAccessorForHandle(Handle<HeapObject>* handle, IsolateT* isolate)
|
||||
: handle_(handle), isolate_(isolate) {}
|
||||
|
||||
MaybeObjectSlot slot() const { UNREACHABLE(); }
|
||||
@ -185,36 +190,62 @@ class SlotAccessorForHandle {
|
||||
|
||||
private:
|
||||
Handle<HeapObject>* handle_;
|
||||
Isolate* isolate_;
|
||||
IsolateT* isolate_;
|
||||
};
|
||||
|
||||
template <typename IsolateT>
|
||||
template <typename TSlot>
|
||||
int Deserializer::WriteAddress(TSlot dest, Address value) {
|
||||
int Deserializer<IsolateT>::WriteAddress(TSlot dest, Address value) {
|
||||
DCHECK(!next_reference_is_weak_);
|
||||
memcpy(dest.ToVoidPtr(), &value, kSystemPointerSize);
|
||||
STATIC_ASSERT(IsAligned(kSystemPointerSize, TSlot::kSlotDataSize));
|
||||
return (kSystemPointerSize / TSlot::kSlotDataSize);
|
||||
}
|
||||
|
||||
template <typename IsolateT>
|
||||
template <typename TSlot>
|
||||
int Deserializer::WriteExternalPointer(TSlot dest, Address value,
|
||||
ExternalPointerTag tag) {
|
||||
int Deserializer<IsolateT>::WriteExternalPointer(TSlot dest, Address value,
|
||||
ExternalPointerTag tag) {
|
||||
DCHECK(!next_reference_is_weak_);
|
||||
InitExternalPointerField(dest.address(), isolate(), value, tag);
|
||||
InitExternalPointerField(dest.address(), main_thread_isolate(), value, tag);
|
||||
STATIC_ASSERT(IsAligned(kExternalPointerSize, TSlot::kSlotDataSize));
|
||||
return (kExternalPointerSize / TSlot::kSlotDataSize);
|
||||
}
|
||||
|
||||
Deserializer::Deserializer(Isolate* isolate, base::Vector<const byte> payload,
|
||||
uint32_t magic_number, bool deserializing_user_code,
|
||||
bool can_rehash)
|
||||
namespace {
|
||||
#ifdef DEBUG
|
||||
int GetNumApiReferences(Isolate* isolate) {
|
||||
int num_api_references = 0;
|
||||
// The read-only deserializer is run by read-only heap set-up before the
|
||||
// heap is fully set up. External reference table relies on a few parts of
|
||||
// this set-up (like old-space), so it may be uninitialized at this point.
|
||||
if (isolate->isolate_data()->external_reference_table()->is_initialized()) {
|
||||
// Count the number of external references registered through the API.
|
||||
if (isolate->api_external_references() != nullptr) {
|
||||
while (isolate->api_external_references()[num_api_references] != 0) {
|
||||
num_api_references++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return num_api_references;
|
||||
}
|
||||
int GetNumApiReferences(LocalIsolate* isolate) { return 0; }
|
||||
#endif
|
||||
} // namespace
|
||||
|
||||
template <typename IsolateT>
|
||||
Deserializer<IsolateT>::Deserializer(IsolateT* isolate,
|
||||
base::Vector<const byte> payload,
|
||||
uint32_t magic_number,
|
||||
bool deserializing_user_code,
|
||||
bool can_rehash)
|
||||
: isolate_(isolate),
|
||||
source_(payload),
|
||||
magic_number_(magic_number),
|
||||
deserializing_user_code_(deserializing_user_code),
|
||||
can_rehash_(can_rehash) {
|
||||
DCHECK_NOT_NULL(isolate);
|
||||
isolate_->RegisterDeserializerStarted();
|
||||
isolate->RegisterDeserializerStarted();
|
||||
|
||||
// We start the indices here at 1, so that we can distinguish between an
|
||||
// actual index and a nullptr (serialized as kNullRefSentinel) in a
|
||||
@ -223,30 +254,21 @@ Deserializer::Deserializer(Isolate* isolate, base::Vector<const byte> payload,
|
||||
backing_stores_.push_back({});
|
||||
|
||||
#ifdef DEBUG
|
||||
num_api_references_ = 0;
|
||||
// The read-only deserializer is run by read-only heap set-up before the
|
||||
// heap is fully set up. External reference table relies on a few parts of
|
||||
// this set-up (like old-space), so it may be uninitialized at this point.
|
||||
if (isolate->isolate_data()->external_reference_table()->is_initialized()) {
|
||||
// Count the number of external references registered through the API.
|
||||
if (isolate->api_external_references() != nullptr) {
|
||||
while (isolate->api_external_references()[num_api_references_] != 0) {
|
||||
num_api_references_++;
|
||||
}
|
||||
}
|
||||
}
|
||||
num_api_references_ = GetNumApiReferences(isolate);
|
||||
#endif // DEBUG
|
||||
CHECK_EQ(magic_number_, SerializedData::kMagicNumber);
|
||||
}
|
||||
|
||||
void Deserializer::Rehash() {
|
||||
template <typename IsolateT>
|
||||
void Deserializer<IsolateT>::Rehash() {
|
||||
DCHECK(can_rehash() || deserializing_user_code());
|
||||
for (Handle<HeapObject> item : to_rehash_) {
|
||||
item->RehashBasedOnMap(isolate());
|
||||
}
|
||||
}
|
||||
|
||||
Deserializer::~Deserializer() {
|
||||
template <typename IsolateT>
|
||||
Deserializer<IsolateT>::~Deserializer() {
|
||||
#ifdef DEBUG
|
||||
// Do not perform checks if we aborted deserialization.
|
||||
if (source_.position() == 0) return;
|
||||
@ -261,24 +283,30 @@ Deserializer::~Deserializer() {
|
||||
|
||||
// This is called on the roots. It is the driver of the deserialization
|
||||
// process. It is also called on the body of each function.
|
||||
void Deserializer::VisitRootPointers(Root root, const char* description,
|
||||
FullObjectSlot start, FullObjectSlot end) {
|
||||
template <typename IsolateT>
|
||||
void Deserializer<IsolateT>::VisitRootPointers(Root root,
|
||||
const char* description,
|
||||
FullObjectSlot start,
|
||||
FullObjectSlot end) {
|
||||
ReadData(FullMaybeObjectSlot(start), FullMaybeObjectSlot(end));
|
||||
}
|
||||
|
||||
void Deserializer::Synchronize(VisitorSynchronization::SyncTag tag) {
|
||||
template <typename IsolateT>
|
||||
void Deserializer<IsolateT>::Synchronize(VisitorSynchronization::SyncTag tag) {
|
||||
static const byte expected = kSynchronize;
|
||||
CHECK_EQ(expected, source_.Get());
|
||||
}
|
||||
|
||||
void Deserializer::DeserializeDeferredObjects() {
|
||||
template <typename IsolateT>
|
||||
void Deserializer<IsolateT>::DeserializeDeferredObjects() {
|
||||
for (int code = source_.Get(); code != kSynchronize; code = source_.Get()) {
|
||||
SnapshotSpace space = NewObject::Decode(code);
|
||||
ReadObject(space);
|
||||
}
|
||||
}
|
||||
|
||||
void Deserializer::LogNewMapEvents() {
|
||||
template <typename IsolateT>
|
||||
void Deserializer<IsolateT>::LogNewMapEvents() {
|
||||
DisallowGarbageCollection no_gc;
|
||||
for (Handle<Map> map : new_maps_) {
|
||||
DCHECK(FLAG_log_maps);
|
||||
@ -287,7 +315,8 @@ void Deserializer::LogNewMapEvents() {
|
||||
}
|
||||
}
|
||||
|
||||
void Deserializer::WeakenDescriptorArrays() {
|
||||
template <typename IsolateT>
|
||||
void Deserializer<IsolateT>::WeakenDescriptorArrays() {
|
||||
DisallowGarbageCollection no_gc;
|
||||
for (Handle<DescriptorArray> descriptor_array : new_descriptor_arrays_) {
|
||||
DCHECK(descriptor_array->IsStrongDescriptorArray());
|
||||
@ -297,36 +326,66 @@ void Deserializer::WeakenDescriptorArrays() {
|
||||
}
|
||||
}
|
||||
|
||||
void Deserializer::LogScriptEvents(Script script) {
|
||||
template <typename IsolateT>
|
||||
void Deserializer<IsolateT>::LogScriptEvents(Script script) {
|
||||
DisallowGarbageCollection no_gc;
|
||||
LOG(isolate(),
|
||||
ScriptEvent(Logger::ScriptEventType::kDeserialize, script.id()));
|
||||
LOG(isolate(), ScriptDetails(script));
|
||||
}
|
||||
|
||||
StringTableInsertionKey::StringTableInsertionKey(Handle<String> string)
|
||||
: StringTableKey(ComputeRawHashField(*string), string->length()),
|
||||
namespace {
|
||||
template <typename IsolateT>
|
||||
uint32_t ComputeRawHashField(IsolateT* isolate, String string) {
|
||||
// Make sure raw_hash_field() is computed.
|
||||
string.EnsureHash(SharedStringAccessGuardIfNeeded(isolate));
|
||||
return string.raw_hash_field();
|
||||
}
|
||||
} // namespace
|
||||
|
||||
StringTableInsertionKey::StringTableInsertionKey(Isolate* isolate,
|
||||
Handle<String> string)
|
||||
: StringTableKey(ComputeRawHashField(isolate, *string), string->length()),
|
||||
string_(string) {
|
||||
DCHECK(string->IsInternalizedString());
|
||||
}
|
||||
|
||||
bool StringTableInsertionKey::IsMatch(Isolate* isolate, String string) {
|
||||
StringTableInsertionKey::StringTableInsertionKey(LocalIsolate* isolate,
|
||||
Handle<String> string)
|
||||
: StringTableKey(ComputeRawHashField(isolate, *string), string->length()),
|
||||
string_(string) {
|
||||
DCHECK(string->IsInternalizedString());
|
||||
}
|
||||
|
||||
template <typename IsolateT>
|
||||
bool StringTableInsertionKey::IsMatch(IsolateT* isolate, String string) {
|
||||
// We want to compare the content of two strings here.
|
||||
return string_->SlowEquals(string);
|
||||
return string_->SlowEquals(string, SharedStringAccessGuardIfNeeded(isolate));
|
||||
}
|
||||
template bool StringTableInsertionKey::IsMatch(Isolate* isolate, String string);
|
||||
template bool StringTableInsertionKey::IsMatch(LocalIsolate* isolate,
|
||||
String string);
|
||||
|
||||
namespace {
|
||||
|
||||
void PostProcessExternalString(Handle<ExternalString> string,
|
||||
Isolate* isolate) {
|
||||
uint32_t index = string->GetResourceRefForDeserialization();
|
||||
Address address =
|
||||
static_cast<Address>(isolate->api_external_references()[index]);
|
||||
string->AllocateExternalPointerEntries(isolate);
|
||||
string->set_address_as_resource(isolate, address);
|
||||
isolate->heap()->UpdateExternalString(*string, 0,
|
||||
string->ExternalPayloadSize());
|
||||
isolate->heap()->RegisterExternalString(*string);
|
||||
}
|
||||
|
||||
Handle<String> StringTableInsertionKey::AsHandle(Isolate* isolate) {
|
||||
return string_;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
uint32_t StringTableInsertionKey::ComputeRawHashField(String string) {
|
||||
// Make sure raw_hash_field() is computed.
|
||||
string.EnsureHash();
|
||||
return string.raw_hash_field();
|
||||
}
|
||||
|
||||
void Deserializer::PostProcessNewObject(Handle<Map> map, Handle<HeapObject> obj,
|
||||
SnapshotSpace space) {
|
||||
template <typename IsolateT>
|
||||
void Deserializer<IsolateT>::PostProcessNewObject(Handle<Map> map,
|
||||
Handle<HeapObject> obj,
|
||||
SnapshotSpace space) {
|
||||
DCHECK_EQ(*map, obj->map());
|
||||
DisallowGarbageCollection no_gc;
|
||||
InstanceType instance_type = map->instance_type();
|
||||
@ -349,15 +408,20 @@ void Deserializer::PostProcessNewObject(Handle<Map> map, Handle<HeapObject> obj,
|
||||
if (deserializing_user_code()) {
|
||||
if (InstanceTypeChecker::IsInternalizedString(instance_type)) {
|
||||
// Canonicalize the internalized string. If it already exists in the
|
||||
// string table, set it to forward to the existing one.
|
||||
// string table, patch the deserialized string handle to point to the
|
||||
// existing one.
|
||||
// TODO(leszeks): This handle patching is ugly, consider adding an
|
||||
// explicit internalized string bytecode.
|
||||
Handle<String> string = Handle<String>::cast(obj);
|
||||
|
||||
StringTableInsertionKey key(string);
|
||||
StringTableInsertionKey key(isolate(), string);
|
||||
Handle<String> result =
|
||||
isolate()->string_table()->LookupKey(isolate(), &key);
|
||||
|
||||
if (*result != *string) {
|
||||
string->MakeThin(isolate(), *result);
|
||||
// Invalidate the original string.
|
||||
isolate()->heap()->CreateFillerObjectAt(
|
||||
string->address(), string->Size(), ClearRecordedSlots::kNo);
|
||||
// Mutate the given object handle so that the backreference entry is
|
||||
// also updated.
|
||||
obj.PatchValue(*result);
|
||||
@ -388,8 +452,8 @@ void Deserializer::PostProcessNewObject(Handle<Map> map, Handle<HeapObject> obj,
|
||||
} else if (V8_EXTERNAL_CODE_SPACE_BOOL &&
|
||||
InstanceTypeChecker::IsCodeDataContainer(instance_type)) {
|
||||
auto code_data_container = Handle<CodeDataContainer>::cast(obj);
|
||||
code_data_container->AllocateExternalPointerEntries(isolate());
|
||||
code_data_container->UpdateCodeEntryPoint(isolate(),
|
||||
code_data_container->AllocateExternalPointerEntries(main_thread_isolate());
|
||||
code_data_container->UpdateCodeEntryPoint(main_thread_isolate(),
|
||||
code_data_container->code());
|
||||
} else if (InstanceTypeChecker::IsMap(instance_type)) {
|
||||
if (FLAG_log_maps) {
|
||||
@ -406,15 +470,8 @@ void Deserializer::PostProcessNewObject(Handle<Map> map, Handle<HeapObject> obj,
|
||||
call_handler_infos_.push_back(Handle<CallHandlerInfo>::cast(obj));
|
||||
#endif
|
||||
} else if (InstanceTypeChecker::IsExternalString(instance_type)) {
|
||||
Handle<ExternalString> string = Handle<ExternalString>::cast(obj);
|
||||
uint32_t index = string->GetResourceRefForDeserialization();
|
||||
Address address =
|
||||
static_cast<Address>(isolate()->api_external_references()[index]);
|
||||
string->AllocateExternalPointerEntries(isolate());
|
||||
string->set_address_as_resource(isolate(), address);
|
||||
isolate()->heap()->UpdateExternalString(*string, 0,
|
||||
string->ExternalPayloadSize());
|
||||
isolate()->heap()->RegisterExternalString(*string);
|
||||
PostProcessExternalString(Handle<ExternalString>::cast(obj),
|
||||
main_thread_isolate());
|
||||
} else if (InstanceTypeChecker::IsJSDataView(instance_type)) {
|
||||
Handle<JSDataView> data_view = Handle<JSDataView>::cast(obj);
|
||||
JSArrayBuffer buffer = JSArrayBuffer::cast(data_view->buffer());
|
||||
@ -426,18 +483,18 @@ void Deserializer::PostProcessNewObject(Handle<Map> map, Handle<HeapObject> obj,
|
||||
// a numbered reference to an already deserialized backing store.
|
||||
backing_store = backing_stores_[store_index]->buffer_start();
|
||||
}
|
||||
data_view->AllocateExternalPointerEntries(isolate());
|
||||
data_view->AllocateExternalPointerEntries(main_thread_isolate());
|
||||
data_view->set_data_pointer(
|
||||
isolate(),
|
||||
main_thread_isolate(),
|
||||
reinterpret_cast<uint8_t*>(backing_store) + data_view->byte_offset());
|
||||
} else if (InstanceTypeChecker::IsJSTypedArray(instance_type)) {
|
||||
Handle<JSTypedArray> typed_array = Handle<JSTypedArray>::cast(obj);
|
||||
// Fixup typed array pointers.
|
||||
if (typed_array->is_on_heap()) {
|
||||
Address raw_external_pointer = typed_array->external_pointer_raw();
|
||||
typed_array->AllocateExternalPointerEntries(isolate());
|
||||
typed_array->AllocateExternalPointerEntries(main_thread_isolate());
|
||||
typed_array->SetOnHeapDataPtr(
|
||||
isolate(), HeapObject::cast(typed_array->base_pointer()),
|
||||
main_thread_isolate(), HeapObject::cast(typed_array->base_pointer()),
|
||||
raw_external_pointer);
|
||||
} else {
|
||||
// Serializer writes backing store ref as a DataPtr() value.
|
||||
@ -447,8 +504,8 @@ void Deserializer::PostProcessNewObject(Handle<Map> map, Handle<HeapObject> obj,
|
||||
auto start = backing_store
|
||||
? reinterpret_cast<byte*>(backing_store->buffer_start())
|
||||
: nullptr;
|
||||
typed_array->AllocateExternalPointerEntries(isolate());
|
||||
typed_array->SetOffHeapDataPtr(isolate(), start,
|
||||
typed_array->AllocateExternalPointerEntries(main_thread_isolate());
|
||||
typed_array->SetOffHeapDataPtr(main_thread_isolate(), start,
|
||||
typed_array->byte_offset());
|
||||
}
|
||||
} else if (InstanceTypeChecker::IsJSArrayBuffer(instance_type)) {
|
||||
@ -457,8 +514,8 @@ void Deserializer::PostProcessNewObject(Handle<Map> map, Handle<HeapObject> obj,
|
||||
if (buffer->GetBackingStoreRefForDeserialization() != kNullRefSentinel) {
|
||||
new_off_heap_array_buffers_.push_back(buffer);
|
||||
} else {
|
||||
buffer->AllocateExternalPointerEntries(isolate());
|
||||
buffer->set_backing_store(isolate(), nullptr);
|
||||
buffer->AllocateExternalPointerEntries(main_thread_isolate());
|
||||
buffer->set_backing_store(main_thread_isolate(), nullptr);
|
||||
}
|
||||
} else if (InstanceTypeChecker::IsBytecodeArray(instance_type)) {
|
||||
// TODO(mythria): Remove these once we store the default values for these
|
||||
@ -471,7 +528,7 @@ void Deserializer::PostProcessNewObject(Handle<Map> map, Handle<HeapObject> obj,
|
||||
new_descriptor_arrays_.push_back(descriptors);
|
||||
} else if (InstanceTypeChecker::IsNativeContext(instance_type)) {
|
||||
Handle<NativeContext> context = Handle<NativeContext>::cast(obj);
|
||||
context->AllocateExternalPointerEntries(isolate());
|
||||
context->AllocateExternalPointerEntries(main_thread_isolate());
|
||||
}
|
||||
|
||||
// Check alignment.
|
||||
@ -479,7 +536,8 @@ void Deserializer::PostProcessNewObject(Handle<Map> map, Handle<HeapObject> obj,
|
||||
HeapObject::RequiredAlignment(*map)));
|
||||
}
|
||||
|
||||
HeapObjectReferenceType Deserializer::GetAndResetNextReferenceType() {
|
||||
template <typename IsolateT>
|
||||
HeapObjectReferenceType Deserializer<IsolateT>::GetAndResetNextReferenceType() {
|
||||
HeapObjectReferenceType type = next_reference_is_weak_
|
||||
? HeapObjectReferenceType::WEAK
|
||||
: HeapObjectReferenceType::STRONG;
|
||||
@ -487,7 +545,8 @@ HeapObjectReferenceType Deserializer::GetAndResetNextReferenceType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
Handle<HeapObject> Deserializer::GetBackReferencedObject() {
|
||||
template <typename IsolateT>
|
||||
Handle<HeapObject> Deserializer<IsolateT>::GetBackReferencedObject() {
|
||||
Handle<HeapObject> obj = back_refs_[source_.GetInt()];
|
||||
|
||||
// We don't allow ThinStrings in backreferences -- if internalization produces
|
||||
@ -499,15 +558,17 @@ Handle<HeapObject> Deserializer::GetBackReferencedObject() {
|
||||
return obj;
|
||||
}
|
||||
|
||||
Handle<HeapObject> Deserializer::ReadObject() {
|
||||
template <typename IsolateT>
|
||||
Handle<HeapObject> Deserializer<IsolateT>::ReadObject() {
|
||||
Handle<HeapObject> ret;
|
||||
CHECK_EQ(ReadSingleBytecodeData(source_.Get(),
|
||||
SlotAccessorForHandle(&ret, isolate())),
|
||||
CHECK_EQ(ReadSingleBytecodeData(
|
||||
source_.Get(), SlotAccessorForHandle<IsolateT>(&ret, isolate())),
|
||||
1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
Handle<HeapObject> Deserializer::ReadObject(SnapshotSpace space) {
|
||||
template <typename IsolateT>
|
||||
Handle<HeapObject> Deserializer<IsolateT>::ReadObject(SnapshotSpace space) {
|
||||
const int size_in_tagged = source_.GetInt();
|
||||
const int size_in_bytes = size_in_tagged * kTaggedSize;
|
||||
|
||||
@ -555,8 +616,8 @@ Handle<HeapObject> Deserializer::ReadObject(SnapshotSpace space) {
|
||||
JSObject js_obj = JSObject::cast(raw_obj);
|
||||
for (int i = 0; i < js_obj.GetEmbedderFieldCount(); ++i) {
|
||||
void* pointer;
|
||||
CHECK(EmbedderDataSlot(js_obj, i).ToAlignedPointerSafe(isolate(),
|
||||
&pointer));
|
||||
CHECK(EmbedderDataSlot(js_obj, i).ToAlignedPointerSafe(
|
||||
main_thread_isolate(), &pointer));
|
||||
CHECK_NULL(pointer);
|
||||
}
|
||||
} else if (raw_obj.IsEmbedderDataArray()) {
|
||||
@ -565,7 +626,7 @@ Handle<HeapObject> Deserializer::ReadObject(SnapshotSpace space) {
|
||||
EmbedderDataSlot end(array, array.length());
|
||||
for (EmbedderDataSlot slot = start; slot < end; ++slot) {
|
||||
void* pointer;
|
||||
CHECK(slot.ToAlignedPointerSafe(isolate(), &pointer));
|
||||
CHECK(slot.ToAlignedPointerSafe(main_thread_isolate(), &pointer));
|
||||
CHECK_NULL(pointer);
|
||||
}
|
||||
}
|
||||
@ -577,8 +638,6 @@ Handle<HeapObject> Deserializer::ReadObject(SnapshotSpace space) {
|
||||
ReadData(obj, 1, size_in_tagged);
|
||||
PostProcessNewObject(map, obj, space);
|
||||
|
||||
DCHECK(!obj->IsThinString(isolate()));
|
||||
|
||||
#ifdef DEBUG
|
||||
if (obj->IsCode()) {
|
||||
DCHECK(space == SnapshotSpace::kCode ||
|
||||
@ -591,7 +650,8 @@ Handle<HeapObject> Deserializer::ReadObject(SnapshotSpace space) {
|
||||
return obj;
|
||||
}
|
||||
|
||||
Handle<HeapObject> Deserializer::ReadMetaMap() {
|
||||
template <typename IsolateT>
|
||||
Handle<HeapObject> Deserializer<IsolateT>::ReadMetaMap() {
|
||||
const SnapshotSpace space = SnapshotSpace::kReadOnlyHeap;
|
||||
const int size_in_bytes = Map::kSize;
|
||||
const int size_in_tagged = size_in_bytes / kTaggedSize;
|
||||
@ -613,12 +673,20 @@ Handle<HeapObject> Deserializer::ReadMetaMap() {
|
||||
return obj;
|
||||
}
|
||||
|
||||
class Deserializer::RelocInfoVisitor {
|
||||
class DeserializerRelocInfoVisitor {
|
||||
public:
|
||||
RelocInfoVisitor(Deserializer* deserializer,
|
||||
const std::vector<Handle<HeapObject>>* objects)
|
||||
DeserializerRelocInfoVisitor(Deserializer<Isolate>* deserializer,
|
||||
const std::vector<Handle<HeapObject>>* objects)
|
||||
: deserializer_(deserializer), objects_(objects), current_object_(0) {}
|
||||
~RelocInfoVisitor() { DCHECK_EQ(current_object_, objects_->size()); }
|
||||
|
||||
DeserializerRelocInfoVisitor(Deserializer<LocalIsolate>* deserializer,
|
||||
const std::vector<Handle<HeapObject>>* objects) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
~DeserializerRelocInfoVisitor() {
|
||||
DCHECK_EQ(current_object_, objects_->size());
|
||||
}
|
||||
|
||||
void VisitCodeTarget(Code host, RelocInfo* rinfo);
|
||||
void VisitEmbeddedPointer(Code host, RelocInfo* rinfo);
|
||||
@ -631,34 +699,34 @@ class Deserializer::RelocInfoVisitor {
|
||||
Isolate* isolate() { return deserializer_->isolate(); }
|
||||
SnapshotByteSource& source() { return deserializer_->source_; }
|
||||
|
||||
Deserializer* deserializer_;
|
||||
Deserializer<Isolate>* deserializer_;
|
||||
const std::vector<Handle<HeapObject>>* objects_;
|
||||
int current_object_;
|
||||
};
|
||||
|
||||
void Deserializer::RelocInfoVisitor::VisitCodeTarget(Code host,
|
||||
RelocInfo* rinfo) {
|
||||
void DeserializerRelocInfoVisitor::VisitCodeTarget(Code host,
|
||||
RelocInfo* rinfo) {
|
||||
HeapObject object = *objects_->at(current_object_++);
|
||||
rinfo->set_target_address(Code::cast(object).raw_instruction_start());
|
||||
}
|
||||
|
||||
void Deserializer::RelocInfoVisitor::VisitEmbeddedPointer(Code host,
|
||||
RelocInfo* rinfo) {
|
||||
void DeserializerRelocInfoVisitor::VisitEmbeddedPointer(Code host,
|
||||
RelocInfo* rinfo) {
|
||||
HeapObject object = *objects_->at(current_object_++);
|
||||
// Embedded object reference must be a strong one.
|
||||
rinfo->set_target_object(isolate()->heap(), object);
|
||||
}
|
||||
|
||||
void Deserializer::RelocInfoVisitor::VisitRuntimeEntry(Code host,
|
||||
RelocInfo* rinfo) {
|
||||
void DeserializerRelocInfoVisitor::VisitRuntimeEntry(Code host,
|
||||
RelocInfo* rinfo) {
|
||||
// We no longer serialize code that contains runtime entries.
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
void Deserializer::RelocInfoVisitor::VisitExternalReference(Code host,
|
||||
RelocInfo* rinfo) {
|
||||
void DeserializerRelocInfoVisitor::VisitExternalReference(Code host,
|
||||
RelocInfo* rinfo) {
|
||||
byte data = source().Get();
|
||||
CHECK_EQ(data, kExternalReference);
|
||||
CHECK_EQ(data, Deserializer<Isolate>::kExternalReference);
|
||||
|
||||
Address address = deserializer_->ReadExternalReferenceCase();
|
||||
|
||||
@ -671,10 +739,10 @@ void Deserializer::RelocInfoVisitor::VisitExternalReference(Code host,
|
||||
}
|
||||
}
|
||||
|
||||
void Deserializer::RelocInfoVisitor::VisitInternalReference(Code host,
|
||||
RelocInfo* rinfo) {
|
||||
void DeserializerRelocInfoVisitor::VisitInternalReference(Code host,
|
||||
RelocInfo* rinfo) {
|
||||
byte data = source().Get();
|
||||
CHECK_EQ(data, kInternalReference);
|
||||
CHECK_EQ(data, Deserializer<Isolate>::kInternalReference);
|
||||
|
||||
// Internal reference target is encoded as an offset from code entry.
|
||||
int target_offset = source().GetInt();
|
||||
@ -689,10 +757,10 @@ void Deserializer::RelocInfoVisitor::VisitInternalReference(Code host,
|
||||
rinfo->pc(), target, rinfo->rmode());
|
||||
}
|
||||
|
||||
void Deserializer::RelocInfoVisitor::VisitOffHeapTarget(Code host,
|
||||
RelocInfo* rinfo) {
|
||||
void DeserializerRelocInfoVisitor::VisitOffHeapTarget(Code host,
|
||||
RelocInfo* rinfo) {
|
||||
byte data = source().Get();
|
||||
CHECK_EQ(data, kOffHeapTarget);
|
||||
CHECK_EQ(data, Deserializer<Isolate>::kOffHeapTarget);
|
||||
|
||||
Builtin builtin = Builtins::FromInt(source().GetInt());
|
||||
|
||||
@ -711,9 +779,10 @@ void Deserializer::RelocInfoVisitor::VisitOffHeapTarget(Code host,
|
||||
}
|
||||
}
|
||||
|
||||
template <typename IsolateT>
|
||||
template <typename SlotAccessor>
|
||||
int Deserializer::ReadRepeatedObject(SlotAccessor slot_accessor,
|
||||
int repeat_count) {
|
||||
int Deserializer<IsolateT>::ReadRepeatedObject(SlotAccessor slot_accessor,
|
||||
int repeat_count) {
|
||||
CHECK_LE(2, repeat_count);
|
||||
|
||||
Handle<HeapObject> heap_object = ReadObject();
|
||||
@ -765,8 +834,10 @@ constexpr byte VerifyBytecodeCount(byte bytecode) {
|
||||
: case SpaceEncoder<bytecode>::Encode(SnapshotSpace::kMap) \
|
||||
: case SpaceEncoder<bytecode>::Encode(SnapshotSpace::kReadOnlyHeap)
|
||||
|
||||
void Deserializer::ReadData(Handle<HeapObject> object, int start_slot_index,
|
||||
int end_slot_index) {
|
||||
template <typename IsolateT>
|
||||
void Deserializer<IsolateT>::ReadData(Handle<HeapObject> object,
|
||||
int start_slot_index,
|
||||
int end_slot_index) {
|
||||
int current = start_slot_index;
|
||||
while (current < end_slot_index) {
|
||||
byte data = source_.Get();
|
||||
@ -776,8 +847,9 @@ void Deserializer::ReadData(Handle<HeapObject> object, int start_slot_index,
|
||||
CHECK_EQ(current, end_slot_index);
|
||||
}
|
||||
|
||||
void Deserializer::ReadData(FullMaybeObjectSlot start,
|
||||
FullMaybeObjectSlot end) {
|
||||
template <typename IsolateT>
|
||||
void Deserializer<IsolateT>::ReadData(FullMaybeObjectSlot start,
|
||||
FullMaybeObjectSlot end) {
|
||||
FullMaybeObjectSlot current = start;
|
||||
while (current < end) {
|
||||
byte data = source_.Get();
|
||||
@ -786,9 +858,10 @@ void Deserializer::ReadData(FullMaybeObjectSlot start,
|
||||
CHECK_EQ(current, end);
|
||||
}
|
||||
|
||||
template <typename IsolateT>
|
||||
template <typename SlotAccessor>
|
||||
int Deserializer::ReadSingleBytecodeData(byte data,
|
||||
SlotAccessor slot_accessor) {
|
||||
int Deserializer<IsolateT>::ReadSingleBytecodeData(byte data,
|
||||
SlotAccessor slot_accessor) {
|
||||
using TSlot = decltype(slot_accessor.slot());
|
||||
|
||||
switch (data) {
|
||||
@ -841,8 +914,8 @@ int Deserializer::ReadSingleBytecodeData(byte data,
|
||||
int cache_index = source_.GetInt();
|
||||
// TODO(leszeks): Could we use the address of the startup_object_cache
|
||||
// entry as a Handle backing?
|
||||
HeapObject heap_object =
|
||||
HeapObject::cast(isolate()->startup_object_cache()->at(cache_index));
|
||||
HeapObject heap_object = HeapObject::cast(
|
||||
main_thread_isolate()->startup_object_cache()->at(cache_index));
|
||||
return slot_accessor.Write(heap_object, GetAndResetNextReferenceType());
|
||||
}
|
||||
|
||||
@ -989,7 +1062,7 @@ int Deserializer::ReadSingleBytecodeData(byte data,
|
||||
DisallowGarbageCollection no_gc;
|
||||
|
||||
Code code = Code::cast(*slot_accessor.object());
|
||||
RelocInfoVisitor visitor(this, &preserialized_objects);
|
||||
DeserializerRelocInfoVisitor visitor(this, &preserialized_objects);
|
||||
for (RelocIterator it(code, Code::BodyDescriptor::kRelocModeMask);
|
||||
!it.done(); it.next()) {
|
||||
it.rinfo()->Visit(&visitor);
|
||||
@ -1007,11 +1080,10 @@ int Deserializer::ReadSingleBytecodeData(byte data,
|
||||
}
|
||||
|
||||
case kOffHeapBackingStore: {
|
||||
AlwaysAllocateScope scope(isolate()->heap());
|
||||
int byte_length = source_.GetInt();
|
||||
std::unique_ptr<BackingStore> backing_store =
|
||||
BackingStore::Allocate(isolate(), byte_length, SharedFlag::kNotShared,
|
||||
InitializedFlag::kUninitialized);
|
||||
std::unique_ptr<BackingStore> backing_store = BackingStore::Allocate(
|
||||
main_thread_isolate(), byte_length, SharedFlag::kNotShared,
|
||||
InitializedFlag::kUninitialized);
|
||||
CHECK_NOT_NULL(backing_store);
|
||||
source_.CopyRaw(backing_store->buffer_start(), byte_length);
|
||||
backing_stores_.push_back(std::move(backing_store));
|
||||
@ -1022,11 +1094,11 @@ int Deserializer::ReadSingleBytecodeData(byte data,
|
||||
case kApiReference: {
|
||||
uint32_t reference_id = static_cast<uint32_t>(source_.GetInt());
|
||||
Address address;
|
||||
if (isolate()->api_external_references()) {
|
||||
if (main_thread_isolate()->api_external_references()) {
|
||||
DCHECK_WITH_MSG(reference_id < num_api_references_,
|
||||
"too few external references provided through the API");
|
||||
address = static_cast<Address>(
|
||||
isolate()->api_external_references()[reference_id]);
|
||||
main_thread_isolate()->api_external_references()[reference_id]);
|
||||
} else {
|
||||
address = reinterpret_cast<Address>(NoExternalReferencesCallback);
|
||||
}
|
||||
@ -1117,9 +1189,11 @@ int Deserializer::ReadSingleBytecodeData(byte data,
|
||||
#undef CASE_R2
|
||||
#undef CASE_R1
|
||||
|
||||
Address Deserializer::ReadExternalReferenceCase() {
|
||||
template <typename IsolateT>
|
||||
Address Deserializer<IsolateT>::ReadExternalReferenceCase() {
|
||||
uint32_t reference_id = static_cast<uint32_t>(source_.GetInt());
|
||||
return isolate()->external_reference_table()->address(reference_id);
|
||||
return main_thread_isolate()->external_reference_table()->address(
|
||||
reference_id);
|
||||
}
|
||||
|
||||
namespace {
|
||||
@ -1137,8 +1211,9 @@ AllocationType SpaceToType(SnapshotSpace space) {
|
||||
}
|
||||
} // namespace
|
||||
|
||||
HeapObject Deserializer::Allocate(SnapshotSpace space, int size,
|
||||
AllocationAlignment alignment) {
|
||||
template <typename IsolateT>
|
||||
HeapObject Deserializer<IsolateT>::Allocate(SnapshotSpace space, int size,
|
||||
AllocationAlignment alignment) {
|
||||
#ifdef DEBUG
|
||||
if (!previous_allocation_obj_.is_null()) {
|
||||
// Make sure that the previous object is initialized sufficiently to
|
||||
@ -1148,8 +1223,8 @@ HeapObject Deserializer::Allocate(SnapshotSpace space, int size,
|
||||
}
|
||||
#endif
|
||||
|
||||
HeapObject obj = isolate()->heap()->AllocateRawWith<Heap::kRetryOrFail>(
|
||||
size, SpaceToType(space), AllocationOrigin::kRuntime, alignment);
|
||||
HeapObject obj = HeapObject::FromAddress(isolate()->heap()->AllocateRawOrFail(
|
||||
size, SpaceToType(space), AllocationOrigin::kRuntime, alignment));
|
||||
|
||||
#ifdef DEBUG
|
||||
previous_allocation_obj_ = handle(obj, isolate());
|
||||
@ -1159,5 +1234,9 @@ HeapObject Deserializer::Allocate(SnapshotSpace space, int size,
|
||||
return obj;
|
||||
}
|
||||
|
||||
template class EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE) Deserializer<Isolate>;
|
||||
template class EXPORT_TEMPLATE_DEFINE(V8_EXPORT_PRIVATE)
|
||||
Deserializer<LocalIsolate>;
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
@ -8,7 +8,10 @@
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "src/base/macros.h"
|
||||
#include "src/base/optional.h"
|
||||
#include "src/common/globals.h"
|
||||
#include "src/execution/local-isolate.h"
|
||||
#include "src/objects/allocation-site.h"
|
||||
#include "src/objects/api-callbacks.h"
|
||||
#include "src/objects/backing-store.h"
|
||||
@ -39,7 +42,8 @@ class Object;
|
||||
#endif
|
||||
|
||||
// A Deserializer reads a snapshot and reconstructs the Object graph it defines.
|
||||
class V8_EXPORT_PRIVATE Deserializer : public SerializerDeserializer {
|
||||
template <typename IsolateT>
|
||||
class Deserializer : public SerializerDeserializer {
|
||||
public:
|
||||
~Deserializer() override;
|
||||
Deserializer(const Deserializer&) = delete;
|
||||
@ -49,7 +53,7 @@ class V8_EXPORT_PRIVATE Deserializer : public SerializerDeserializer {
|
||||
|
||||
protected:
|
||||
// Create a deserializer from a snapshot byte source.
|
||||
Deserializer(Isolate* isolate, base::Vector<const byte> payload,
|
||||
Deserializer(IsolateT* isolate, base::Vector<const byte> payload,
|
||||
uint32_t magic_number, bool deserializing_user_code,
|
||||
bool can_rehash);
|
||||
|
||||
@ -79,7 +83,9 @@ class V8_EXPORT_PRIVATE Deserializer : public SerializerDeserializer {
|
||||
CHECK_EQ(new_off_heap_array_buffers().size(), 0);
|
||||
}
|
||||
|
||||
Isolate* isolate() const { return isolate_; }
|
||||
IsolateT* isolate() const { return isolate_; }
|
||||
|
||||
Isolate* main_thread_isolate() const { return isolate_->AsIsolate(); }
|
||||
|
||||
SnapshotByteSource* source() { return &source_; }
|
||||
const std::vector<Handle<AllocationSite>>& new_allocation_sites() const {
|
||||
@ -120,7 +126,7 @@ class V8_EXPORT_PRIVATE Deserializer : public SerializerDeserializer {
|
||||
Handle<HeapObject> ReadObject();
|
||||
|
||||
private:
|
||||
class RelocInfoVisitor;
|
||||
friend class DeserializerRelocInfoVisitor;
|
||||
// A circular queue of hot objects. This is added to in the same order as in
|
||||
// Serializer::HotObjectsList, but this stores the objects as a vector of
|
||||
// existing handles. This allows us to add Handles to the queue without having
|
||||
@ -196,7 +202,7 @@ class V8_EXPORT_PRIVATE Deserializer : public SerializerDeserializer {
|
||||
AllocationAlignment alignment);
|
||||
|
||||
// Cached current isolate.
|
||||
Isolate* isolate_;
|
||||
IsolateT* isolate_;
|
||||
|
||||
// Objects from the attached object descriptions in the serialized user code.
|
||||
std::vector<Handle<HeapObject>> attached_objects_;
|
||||
@ -253,19 +259,27 @@ class V8_EXPORT_PRIVATE Deserializer : public SerializerDeserializer {
|
||||
#endif // DEBUG
|
||||
};
|
||||
|
||||
extern template class EXPORT_TEMPLATE_DECLARE(V8_EXPORT_PRIVATE)
|
||||
Deserializer<Isolate>;
|
||||
extern template class EXPORT_TEMPLATE_DECLARE(V8_EXPORT_PRIVATE)
|
||||
Deserializer<LocalIsolate>;
|
||||
|
||||
// Used to insert a deserialized internalized string into the string table.
|
||||
class StringTableInsertionKey final : public StringTableKey {
|
||||
public:
|
||||
explicit StringTableInsertionKey(Handle<String> string);
|
||||
explicit StringTableInsertionKey(Isolate* isolate, Handle<String> string);
|
||||
explicit StringTableInsertionKey(LocalIsolate* isolate,
|
||||
Handle<String> string);
|
||||
|
||||
bool IsMatch(Isolate* isolate, String string);
|
||||
template <typename IsolateT>
|
||||
bool IsMatch(IsolateT* isolate, String string);
|
||||
|
||||
V8_WARN_UNUSED_RESULT Handle<String> AsHandle(Isolate* isolate);
|
||||
V8_WARN_UNUSED_RESULT Handle<String> AsHandle(LocalIsolate* isolate);
|
||||
template <typename IsolateT>
|
||||
V8_WARN_UNUSED_RESULT Handle<String> AsHandle(IsolateT* isolate) {
|
||||
return string_;
|
||||
}
|
||||
|
||||
private:
|
||||
uint32_t ComputeRawHashField(String string);
|
||||
|
||||
Handle<String> string_;
|
||||
DISALLOW_GARBAGE_COLLECTION(no_gc)
|
||||
};
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "src/codegen/assembler-inl.h"
|
||||
#include "src/execution/isolate.h"
|
||||
#include "src/heap/heap-inl.h"
|
||||
#include "src/heap/local-factory-inl.h"
|
||||
#include "src/objects/allocation-site-inl.h"
|
||||
#include "src/objects/js-array-buffer-inl.h"
|
||||
#include "src/objects/objects.h"
|
||||
@ -34,14 +35,6 @@ ObjectDeserializer::DeserializeSharedFunctionInfo(
|
||||
: MaybeHandle<SharedFunctionInfo>();
|
||||
}
|
||||
|
||||
MaybeHandle<SharedFunctionInfo>
|
||||
ObjectDeserializer::DeserializeSharedFunctionInfoOffThread(
|
||||
LocalIsolate* isolate, const SerializedCodeData* data,
|
||||
Handle<String> source) {
|
||||
// TODO(leszeks): Add LocalHeap support to deserializer
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
MaybeHandle<HeapObject> ObjectDeserializer::Deserialize() {
|
||||
DCHECK(deserializing_user_code());
|
||||
HandleScope scope(isolate());
|
||||
@ -102,5 +95,56 @@ void ObjectDeserializer::LinkAllocationSites() {
|
||||
}
|
||||
}
|
||||
|
||||
OffThreadObjectDeserializer::OffThreadObjectDeserializer(
|
||||
LocalIsolate* isolate, const SerializedCodeData* data)
|
||||
: Deserializer(isolate, data->Payload(), data->GetMagicNumber(), true,
|
||||
false) {}
|
||||
|
||||
MaybeHandle<SharedFunctionInfo>
|
||||
OffThreadObjectDeserializer::DeserializeSharedFunctionInfo(
|
||||
LocalIsolate* isolate, const SerializedCodeData* data,
|
||||
std::vector<Handle<Script>>* deserialized_scripts) {
|
||||
OffThreadObjectDeserializer d(isolate, data);
|
||||
|
||||
// Attach the empty string as the source.
|
||||
d.AddAttachedObject(isolate->factory()->empty_string());
|
||||
|
||||
Handle<HeapObject> result;
|
||||
if (!d.Deserialize(deserialized_scripts).ToHandle(&result)) {
|
||||
return MaybeHandle<SharedFunctionInfo>();
|
||||
}
|
||||
return Handle<SharedFunctionInfo>::cast(result);
|
||||
}
|
||||
|
||||
MaybeHandle<HeapObject> OffThreadObjectDeserializer::Deserialize(
|
||||
std::vector<Handle<Script>>* deserialized_scripts) {
|
||||
DCHECK(deserializing_user_code());
|
||||
LocalHandleScope scope(isolate());
|
||||
Handle<HeapObject> result;
|
||||
{
|
||||
result = ReadObject();
|
||||
DeserializeDeferredObjects();
|
||||
CHECK(new_code_objects().empty());
|
||||
CHECK(new_allocation_sites().empty());
|
||||
CHECK(new_maps().empty());
|
||||
WeakenDescriptorArrays();
|
||||
}
|
||||
|
||||
Rehash();
|
||||
CHECK(new_off_heap_array_buffers().empty());
|
||||
|
||||
// TODO(leszeks): Figure out a better way of dealing with scripts.
|
||||
CHECK_EQ(new_scripts().size(), 1);
|
||||
for (Handle<Script> script : new_scripts()) {
|
||||
// Assign a new script id to avoid collision.
|
||||
script->set_id(isolate()->GetNextScriptId());
|
||||
LogScriptEvents(*script);
|
||||
deserialized_scripts->push_back(
|
||||
isolate()->heap()->NewPersistentHandle(script));
|
||||
}
|
||||
|
||||
return scope.CloseAndEscape(result);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
@ -14,13 +14,10 @@ class SerializedCodeData;
|
||||
class SharedFunctionInfo;
|
||||
|
||||
// Deserializes the object graph rooted at a given object.
|
||||
class ObjectDeserializer final : public Deserializer {
|
||||
class ObjectDeserializer final : public Deserializer<Isolate> {
|
||||
public:
|
||||
static MaybeHandle<SharedFunctionInfo> DeserializeSharedFunctionInfo(
|
||||
Isolate* isolate, const SerializedCodeData* data, Handle<String> source);
|
||||
static MaybeHandle<SharedFunctionInfo> DeserializeSharedFunctionInfoOffThread(
|
||||
LocalIsolate* isolate, const SerializedCodeData* data,
|
||||
Handle<String> source);
|
||||
|
||||
private:
|
||||
explicit ObjectDeserializer(Isolate* isolate, const SerializedCodeData* data);
|
||||
@ -32,6 +29,22 @@ class ObjectDeserializer final : public Deserializer {
|
||||
void CommitPostProcessedObjects();
|
||||
};
|
||||
|
||||
// Deserializes the object graph rooted at a given object.
|
||||
class OffThreadObjectDeserializer final : public Deserializer<LocalIsolate> {
|
||||
public:
|
||||
static MaybeHandle<SharedFunctionInfo> DeserializeSharedFunctionInfo(
|
||||
LocalIsolate* isolate, const SerializedCodeData* data,
|
||||
std::vector<Handle<Script>>* deserialized_scripts);
|
||||
|
||||
private:
|
||||
explicit OffThreadObjectDeserializer(LocalIsolate* isolate,
|
||||
const SerializedCodeData* data);
|
||||
|
||||
// Deserialize an object graph. Fail gracefully.
|
||||
MaybeHandle<HeapObject> Deserialize(
|
||||
std::vector<Handle<Script>>* deserialized_scripts);
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
||||
|
@ -14,7 +14,7 @@ namespace internal {
|
||||
|
||||
// Deserializes the read-only blob, creating the read-only roots and the
|
||||
// Read-only object cache used by the other deserializers.
|
||||
class ReadOnlyDeserializer final : public Deserializer {
|
||||
class ReadOnlyDeserializer final : public Deserializer<Isolate> {
|
||||
public:
|
||||
explicit ReadOnlyDeserializer(Isolate* isolate, const SnapshotData* data,
|
||||
bool can_rehash)
|
||||
|
@ -85,7 +85,7 @@ void StartupDeserializer::DeserializeStringTable() {
|
||||
// TODO(leszeks): Consider pre-sizing the string table.
|
||||
for (int i = 0; i < string_table_size; ++i) {
|
||||
Handle<String> string = Handle<String>::cast(ReadObject());
|
||||
StringTableInsertionKey key(string);
|
||||
StringTableInsertionKey key(isolate(), string);
|
||||
Handle<String> result =
|
||||
isolate()->string_table()->LookupKey(isolate(), &key);
|
||||
USE(result);
|
||||
|
@ -13,7 +13,7 @@ namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
// Initializes an isolate with context-independent data from a given snapshot.
|
||||
class StartupDeserializer final : public Deserializer {
|
||||
class StartupDeserializer final : public Deserializer<Isolate> {
|
||||
public:
|
||||
explicit StartupDeserializer(Isolate* isolate,
|
||||
const SnapshotData* startup_data,
|
||||
|
Loading…
Reference in New Issue
Block a user