Commit e24fa913 authored by Leszek Swirski's avatar Leszek Swirski Committed by V8 LUCI CQ

[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/+/2562254Reviewed-by: 's avatarJakob Gruber <jgruber@chromium.org>
Reviewed-by: 's avatarDominik Inführ <dinfuehr@chromium.org>
Commit-Queue: Leszek Swirski <leszeks@chromium.org>
Cr-Commit-Position: refs/heads/master@{#75834}
parent 7179c71e
......@@ -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,
......
This diff is collapsed.
......@@ -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,
......
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