Commit c212d10d authored by Leszek Swirski's avatar Leszek Swirski Committed by Commit Bot

[serializer] Introduce HandleScopes for object contents

Create a HandleScope when serializing an object's contents, to reduce
the number of live handles during serialization. There's only a couple
of cases where these handles have to outlive the serialized contents,
and for these cases we introduce GlobalHandleVector or similar manual
strong root mechanisms.

In particular, backrefs don't actually need to exist as a handle vector
(the object addresses are already referred to by the reference map's
IdentityMap), except for DCHECKs, so this becomes a DEBUG-only global
handle vector.

To support this manual strong-rooting, the HotObjectList is split up
into a strong-rooted find-only class in Serializer, and a Handle
vector in Deserializer.

Bug: chromium:1075999
Change-Id: I586eeeb543e3f6c934c168961b068f2c34e72456
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2449980Reviewed-by: 's avatarUlan Degenbaev <ulan@chromium.org>
Reviewed-by: 's avatarJakob Gruber <jgruber@chromium.org>
Commit-Queue: Leszek Swirski <leszeks@chromium.org>
Cr-Commit-Position: refs/heads/master@{#70411}
parent 4ddb0347
......@@ -371,6 +371,18 @@ class Recorder;
} \
} while (false)
#define WHILE_WITH_HANDLE_SCOPE(isolate, limit_check, body) \
do { \
Isolate* for_with_handle_isolate = isolate; \
while (limit_check) { \
HandleScope loop_scope(for_with_handle_isolate); \
for (int for_with_handle_it = 0; \
limit_check && for_with_handle_it < 1024; ++for_with_handle_it) { \
body \
} \
} \
} while (false)
#define FIELD_ACCESSOR(type, name) \
inline void set_##name(type v) { name##_ = v; } \
inline type name() const { return name##_; }
......
......@@ -10,12 +10,12 @@
#include <utility>
#include <vector>
#include "include/v8.h"
#include "include/v8-profiler.h"
#include "src/utils/utils.h"
#include "include/v8.h"
#include "src/handles/handles.h"
#include "src/heap/heap.h"
#include "src/objects/objects.h"
#include "src/utils/utils.h"
namespace v8 {
namespace internal {
......@@ -323,6 +323,52 @@ class EternalHandles final {
DISALLOW_COPY_AND_ASSIGN(EternalHandles);
};
// A vector of global Handles which automatically manages the backing of those
// Handles as a vector of strong-rooted addresses. Handles returned by the
// vector are valid as long as they are present in the vector.
template <typename T>
class GlobalHandleVector {
public:
class Iterator {
public:
explicit Iterator(
std::vector<Address, StrongRootBlockAllocator>::iterator it)
: it_(it) {}
Iterator& operator++() {
++it_;
return *this;
}
Handle<T> operator*() { return Handle<T>(&*it_); }
bool operator!=(Iterator& that) { return it_ != that.it_; }
private:
std::vector<Address, StrongRootBlockAllocator>::iterator it_;
};
explicit GlobalHandleVector(Heap* heap)
: locations_(StrongRootBlockAllocator(heap)) {}
Handle<T> operator[](size_t i) { return Handle<T>(&locations_[i]); }
size_t size() const { return locations_.size(); }
bool empty() const { return locations_.empty(); }
void Push(T val) { locations_.push_back(val.ptr()); }
// Handles into the GlobalHandleVector become invalid when they are removed,
// so "pop" returns a raw object rather than a handle.
T Pop() {
T obj = T::cast(Object(locations_.back()));
locations_.pop_back();
return obj;
}
Iterator begin() { return Iterator(locations_.begin()); }
Iterator end() { return Iterator(locations_.end()); }
private:
std::vector<Address, StrongRootBlockAllocator> locations_;
};
} // namespace internal
} // namespace v8
......
......@@ -248,7 +248,7 @@ class HandleScope {
// Limit for number of handles with --check-handle-count. This is
// large enough to compile natives and pass unit tests with some
// slack for future changes to natives.
static const int kCheckHandleThreshold = 42 * 1024;
static const int kCheckHandleThreshold = 30 * 1024;
private:
Isolate* isolate_;
......
......@@ -6746,5 +6746,41 @@ void Heap::IncrementObjectCounters() {
}
#endif // DEBUG
// StrongRootBlocks are allocated as a block of addresses, prefixed with a
// StrongRootsEntry pointer:
//
// | StrongRootsEntry*
// | Address 1
// | ...
// | Address N
//
// The allocate method registers the range "Address 1" to "Address N" with the
// heap as a strong root array, saves that entry in StrongRootsEntry*, and
// returns a pointer to Address 1.
Address* StrongRootBlockAllocator::allocate(size_t n) {
void* block = malloc(sizeof(StrongRootsEntry*) + n * sizeof(Address));
StrongRootsEntry** header = reinterpret_cast<StrongRootsEntry**>(block);
Address* ret = reinterpret_cast<Address*>(reinterpret_cast<char*>(block) +
sizeof(StrongRootsEntry*));
memset(ret, kNullAddress, n * sizeof(Address));
*header =
heap_->RegisterStrongRoots(FullObjectSlot(ret), FullObjectSlot(ret + n));
return ret;
}
void StrongRootBlockAllocator::deallocate(Address* p, size_t n) noexcept {
// The allocate method returns a pointer to Address 1, so the deallocate
// method has to offset that pointer back by sizeof(StrongRootsEntry*).
void* block = reinterpret_cast<char*>(p) - sizeof(StrongRootsEntry*);
StrongRootsEntry** header = reinterpret_cast<StrongRootsEntry**>(block);
heap_->UnregisterStrongRoots(*header);
free(block);
}
} // namespace internal
} // namespace v8
......@@ -2653,6 +2653,32 @@ T ForwardingAddress(T heap_obj) {
}
}
// Address block allocator compatible with standard containers which registers
// its allocated range as strong roots.
class StrongRootBlockAllocator {
public:
using pointer = Address*;
using const_pointer = const Address*;
using reference = Address&;
using const_reference = const Address&;
using value_type = Address;
using size_type = size_t;
using difference_type = ptrdiff_t;
template <class U>
struct rebind {
STATIC_ASSERT((std::is_same<Address, U>::value));
using other = StrongRootBlockAllocator;
};
explicit StrongRootBlockAllocator(Heap* heap) : heap_(heap) {}
Address* allocate(size_t n);
void deallocate(Address* p, size_t n) noexcept;
private:
Heap* heap_;
};
} // namespace internal
} // namespace v8
......
......@@ -195,8 +195,7 @@ bool ContextSerializer::ShouldBeInTheStartupObjectCache(HeapObject o) {
return o.IsName() || o.IsSharedFunctionInfo() || o.IsHeapNumber() ||
o.IsCode() || o.IsScopeInfo() || o.IsAccessorInfo() ||
o.IsTemplateInfo() || o.IsClassPositions() ||
o.map() == ReadOnlyRoots(startup_serializer_->isolate())
.fixed_cow_array_map();
o.map() == ReadOnlyRoots(isolate()).fixed_cow_array_map();
}
namespace {
......
......@@ -1124,11 +1124,11 @@ HeapObject Deserializer::Allocate(SnapshotSpace space, int size,
}
#endif
HeapObject obj = isolate_->heap()->AllocateRawWith<Heap::kRetryOrFail>(
HeapObject obj = isolate()->heap()->AllocateRawWith<Heap::kRetryOrFail>(
size, SpaceToType(space), AllocationOrigin::kRuntime, alignment);
#ifdef DEBUG
previous_allocation_obj_ = handle(obj, isolate_);
previous_allocation_obj_ = handle(obj, isolate());
previous_allocation_size_ = size;
#endif
......
......@@ -130,6 +130,34 @@ class V8_EXPORT_PRIVATE Deserializer : public SerializerDeserializer {
private:
class RelocInfoVisitor;
// 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
// to create new handles. Note that this depends on those Handles staying
// valid as long as the HotObjectsList is alive.
class HotObjectsList {
public:
HotObjectsList() = default;
void Add(Handle<HeapObject> object) {
circular_queue_[index_] = object;
index_ = (index_ + 1) & kSizeMask;
}
Handle<HeapObject> Get(int index) {
DCHECK(!circular_queue_[index].is_null());
return circular_queue_[index];
}
private:
static const int kSize = kHotObjectCount;
static const int kSizeMask = kSize - 1;
STATIC_ASSERT(base::bits::IsPowerOfTwo(kSize));
Handle<HeapObject> circular_queue_[kSize];
int index_ = 0;
DISALLOW_COPY_AND_ASSIGN(HotObjectsList);
};
void VisitRootPointers(Root root, const char* description,
FullObjectSlot start, FullObjectSlot end) override;
......@@ -184,6 +212,7 @@ class V8_EXPORT_PRIVATE Deserializer : public SerializerDeserializer {
SnapshotByteSource source_;
uint32_t magic_number_;
HotObjectsList hot_objects_;
std::vector<Handle<Map>> new_maps_;
std::vector<Handle<AllocationSite>> new_allocation_sites_;
std::vector<Handle<Code>> new_code_objects_;
......
......@@ -39,22 +39,17 @@ bool SerializerDeserializer::CanBeDeferred(HeapObject o) {
return !o.IsMap() && !o.IsInternalizedString();
}
void SerializerDeserializer::RestoreExternalReferenceRedirectors(
Isolate* isolate, const std::vector<Handle<AccessorInfo>>& accessor_infos) {
void SerializerDeserializer::RestoreExternalReferenceRedirector(
Isolate* isolate, Handle<AccessorInfo> accessor_info) {
// Restore wiped accessor infos.
for (Handle<AccessorInfo> info : accessor_infos) {
Foreign::cast(info->js_getter())
.set_foreign_address(isolate, info->redirected_getter());
}
Foreign::cast(accessor_info->js_getter())
.set_foreign_address(isolate, accessor_info->redirected_getter());
}
void SerializerDeserializer::RestoreExternalReferenceRedirectors(
Isolate* isolate,
const std::vector<Handle<CallHandlerInfo>>& call_handler_infos) {
for (Handle<CallHandlerInfo> info : call_handler_infos) {
Foreign::cast(info->js_callback())
.set_foreign_address(isolate, info->redirected_callback());
}
void SerializerDeserializer::RestoreExternalReferenceRedirector(
Isolate* isolate, Handle<CallHandlerInfo> call_handler_info) {
Foreign::cast(call_handler_info->js_callback())
.set_foreign_address(isolate, call_handler_info->redirected_callback());
}
} // namespace internal
......
......@@ -23,51 +23,12 @@ class SerializerDeserializer : public RootVisitor {
static void Iterate(Isolate* isolate, RootVisitor* visitor);
protected:
class HotObjectsList {
public:
HotObjectsList() = default;
void Add(Handle<HeapObject> object) {
circular_queue_[index_] = object;
index_ = (index_ + 1) & kSizeMask;
}
Handle<HeapObject> Get(int index) {
DCHECK(!circular_queue_[index].is_null());
return circular_queue_[index];
}
static const int kNotFound = -1;
int Find(HeapObject object) {
DCHECK(!AllowGarbageCollection::IsAllowed());
for (int i = 0; i < kSize; i++) {
if (!circular_queue_[i].is_null() && *circular_queue_[i] == object) {
return i;
}
}
return kNotFound;
}
static const int kSize = 8;
private:
STATIC_ASSERT(base::bits::IsPowerOfTwo(kSize));
static const int kSizeMask = kSize - 1;
Handle<HeapObject> circular_queue_[kSize];
int index_ = 0;
DISALLOW_COPY_AND_ASSIGN(HotObjectsList);
};
static bool CanBeDeferred(HeapObject o);
void RestoreExternalReferenceRedirectors(
Isolate* isolate,
const std::vector<Handle<AccessorInfo>>& accessor_infos);
void RestoreExternalReferenceRedirectors(
Isolate* isolate,
const std::vector<Handle<CallHandlerInfo>>& call_handler_infos);
void RestoreExternalReferenceRedirector(Isolate* isolate,
Handle<AccessorInfo> accessor_info);
void RestoreExternalReferenceRedirector(
Isolate* isolate, Handle<CallHandlerInfo> call_handler_info);
// clang-format off
#define UNUSED_SERIALIZER_BYTE_CODES(V) \
......@@ -116,7 +77,6 @@ class SerializerDeserializer : public RootVisitor {
// 8 hot (recently seen or back-referenced) objects with optional skip.
static const int kHotObjectCount = 8;
STATIC_ASSERT(kHotObjectCount == HotObjectsList::kSize);
enum Bytecode : byte {
//
......@@ -298,9 +258,6 @@ class SerializerDeserializer : public RootVisitor {
// This backing store reference value represents nullptr values during
// serialization/deserialization.
static const uint32_t kNullRefSentinel = 0;
// ---------- member variable ----------
HotObjectsList hot_objects_;
};
} // namespace internal
......
......@@ -17,17 +17,26 @@
#include "src/objects/objects-body-descriptors-inl.h"
#include "src/objects/slots-inl.h"
#include "src/objects/smi.h"
#include "src/snapshot/serializer-deserializer.h"
namespace v8 {
namespace internal {
Serializer::Serializer(Isolate* isolate, Snapshot::SerializerFlags flags)
: isolate_(isolate),
hot_objects_(isolate->heap()),
reference_map_(isolate),
external_reference_encoder_(isolate),
root_index_map_(isolate),
deferred_objects_(isolate->heap()),
forward_refs_per_pending_object_(isolate->heap()),
flags_(flags) {
flags_(flags)
#ifdef DEBUG
,
back_refs_(isolate->heap()),
stack_(isolate->heap())
#endif
{
#ifdef OBJECT_PRINT
if (FLAG_serialization_statistics) {
for (int space = 0; space < kNumberOfSnapshotSpaces; ++space) {
......@@ -98,12 +107,12 @@ void Serializer::SerializeDeferredObjects() {
if (FLAG_trace_serializer) {
PrintF("Serializing deferred objects\n");
}
while (!deferred_objects_.empty()) {
Handle<HeapObject> obj = deferred_objects_.back();
deferred_objects_.pop_back();
WHILE_WITH_HANDLE_SCOPE(isolate(), !deferred_objects_.empty(), {
Handle<HeapObject> obj = handle(deferred_objects_.Pop(), isolate());
ObjectSerializer obj_serializer(this, obj, &sink_);
obj_serializer.SerializeDeferred();
}
});
sink_.Put(kSynchronize, "Finished with deferred objects");
}
......@@ -235,7 +244,7 @@ void Serializer::PutRoot(RootIndex root) {
} else {
sink_.Put(kRootArray, "RootSerialization");
sink_.PutInt(root_index, "root_index");
hot_objects_.Add(object);
hot_objects_.Add(*object);
}
}
......@@ -258,7 +267,7 @@ void Serializer::PutBackReference(Handle<HeapObject> object,
SerializerReference reference) {
DCHECK_EQ(*object, *back_refs_[reference.back_ref_index()]);
sink_.PutInt(reference.back_ref_index(), "BackRefIndex");
hot_objects_.Add(object);
hot_objects_.Add(*object);
}
void Serializer::PutAttachedReference(SerializerReference reference) {
......@@ -372,7 +381,7 @@ void Serializer::ObjectSerializer::SerializePrologue(SnapshotSpace space,
}
if (map == *object_) {
DCHECK_EQ(*object_, ReadOnlyRoots(serializer_->isolate()).meta_map());
DCHECK_EQ(*object_, ReadOnlyRoots(isolate()).meta_map());
DCHECK_EQ(space, SnapshotSpace::kReadOnlyHeap);
sink_->Put(kNewMetaMap, "NewMetaMap");
......@@ -391,12 +400,12 @@ void Serializer::ObjectSerializer::SerializePrologue(SnapshotSpace space,
// isn't a pending object.
DCHECK_NULL(serializer_->forward_refs_per_pending_object_.Find(map));
DCHECK(map.IsMap());
serializer_->SerializeObject(handle(map, serializer_->isolate()));
serializer_->SerializeObject(handle(map, isolate()));
// Make sure the map serialization didn't accidentally recursively serialize
// this object.
DCHECK_IMPLIES(
*object_ != ReadOnlyRoots(serializer_->isolate()).not_mapped_symbol(),
*object_ != ReadOnlyRoots(isolate()).not_mapped_symbol(),
serializer_->reference_map()->LookupReference(object_) == nullptr);
// Now that the object is allocated, we can resolve pending references to
......@@ -410,13 +419,17 @@ void Serializer::ObjectSerializer::SerializePrologue(SnapshotSpace space,
// Mark this object as already serialized, and add it to the reference map so
// that it can be accessed by backreference by future objects.
serializer_->back_refs_.push_back(object_);
if (*object_ != ReadOnlyRoots(serializer_->isolate()).not_mapped_symbol()) {
serializer_->num_back_refs_++;
#ifdef DEBUG
serializer_->back_refs_.Push(*object_);
DCHECK_EQ(serializer_->back_refs_.size(), serializer_->num_back_refs_);
#endif
if (*object_ != ReadOnlyRoots(isolate()).not_mapped_symbol()) {
// Only add the object to the map if it's not not_mapped_symbol, else
// the reference IdentityMap has issues. We don't expect to have back
// references to the not_mapped_symbol anyway, so it's fine.
SerializerReference back_reference = SerializerReference::BackReference(
static_cast<int>(serializer_->back_refs_.size()) - 1);
SerializerReference back_reference =
SerializerReference::BackReference(serializer_->num_back_refs_ - 1);
serializer_->reference_map()->Add(*object_, back_reference);
DCHECK_EQ(*object_,
*serializer_->back_refs_[back_reference.back_ref_index()]);
......@@ -452,8 +465,7 @@ uint32_t Serializer::ObjectSerializer::SerializeBackingStore(
void Serializer::ObjectSerializer::SerializeJSTypedArray() {
Handle<JSTypedArray> typed_array = Handle<JSTypedArray>::cast(object_);
if (typed_array->is_on_heap()) {
typed_array->RemoveExternalPointerCompensationForSerialization(
serializer_->isolate());
typed_array->RemoveExternalPointerCompensationForSerialization(isolate());
} else {
if (!typed_array->WasDetached()) {
// Explicitly serialize the backing store now.
......@@ -506,7 +518,7 @@ void Serializer::ObjectSerializer::SerializeJSArrayBuffer() {
#ifdef V8_HEAP_SANDBOX
buffer->SetBackingStoreRefForSerialization(external_pointer_entry);
#else
buffer->set_backing_store(serializer_->isolate(), backing_store);
buffer->set_backing_store(isolate(), backing_store);
#endif
buffer->set_extension(extension);
}
......@@ -529,7 +541,7 @@ void Serializer::ObjectSerializer::SerializeExternalString() {
#ifdef V8_HEAP_SANDBOX
string->SetResourceRefForSerialization(external_pointer_entry);
#else
string->set_address_as_resource(serializer_->isolate(), resource);
string->set_address_as_resource(isolate(), resource);
#endif
} else {
SerializeExternalStringAsSequentialString();
......@@ -539,7 +551,7 @@ void Serializer::ObjectSerializer::SerializeExternalString() {
void Serializer::ObjectSerializer::SerializeExternalStringAsSequentialString() {
// Instead of serializing this as an external string, we serialize
// an imaginary sequential string with the same content.
ReadOnlyRoots roots(serializer_->isolate());
ReadOnlyRoots roots(isolate());
DCHECK(object_->IsExternalString());
Handle<ExternalString> string = Handle<ExternalString>::cast(object_);
int length = string->length();
......@@ -675,7 +687,7 @@ void Serializer::ObjectSerializer::Serialize() {
if (object_->IsScript()) {
// Clear cached line ends.
Oddball undefined = ReadOnlyRoots(serializer_->isolate()).undefined_value();
Oddball undefined = ReadOnlyRoots(isolate()).undefined_value();
Handle<Script>::cast(object_)->set_line_ends(undefined);
}
......@@ -737,8 +749,8 @@ void Serializer::ObjectSerializer::SerializeObject() {
// deserialization completes.
//
// See also `Deserializer::WeakenDescriptorArrays`.
if (map == ReadOnlyRoots(serializer_->isolate()).descriptor_array_map()) {
map = ReadOnlyRoots(serializer_->isolate()).strong_descriptor_array_map();
if (map == ReadOnlyRoots(isolate()).descriptor_array_map()) {
map = ReadOnlyRoots(isolate()).strong_descriptor_array_map();
}
SnapshotSpace space = GetSnapshotSpace(object_);
SerializePrologue(space, size, map);
......@@ -770,7 +782,7 @@ void Serializer::ObjectSerializer::SerializeDeferred() {
}
void Serializer::ObjectSerializer::SerializeContent(Map map, int size) {
UnlinkWeakNextScope unlink_weak_next(serializer_->isolate()->heap(), object_);
UnlinkWeakNextScope unlink_weak_next(isolate()->heap(), object_);
if (object_->IsCode()) {
// For code objects, perform a custom serialization.
SerializeCode(map, size);
......@@ -791,6 +803,7 @@ void Serializer::ObjectSerializer::VisitPointers(HeapObject host,
void Serializer::ObjectSerializer::VisitPointers(HeapObject host,
MaybeObjectSlot start,
MaybeObjectSlot end) {
HandleScope scope(isolate());
DisallowGarbageCollection no_gc;
MaybeObjectSlot current = start;
......@@ -818,7 +831,7 @@ void Serializer::ObjectSerializer::VisitPointers(HeapObject host,
sink_->Put(kWeakPrefix, "WeakReference");
}
Handle<HeapObject> obj = handle(current_contents, serializer_->isolate());
Handle<HeapObject> obj = handle(current_contents, isolate());
if (serializer_->SerializePendingObject(obj)) {
bytes_processed_so_far_ += kTaggedSize;
++current;
......@@ -910,8 +923,7 @@ class Serializer::ObjectSerializer::RelocInfoObjectPreSerializer {
void VisitEmbeddedPointer(Code host, RelocInfo* target) {
Object object = target->target_object();
serializer_->SerializeObject(
handle(HeapObject::cast(object), serializer_->isolate()));
serializer_->SerializeObject(handle(HeapObject::cast(object), isolate()));
num_serialized_objects_++;
}
void VisitCodeTarget(Code host, RelocInfo* target) {
......@@ -919,7 +931,7 @@ class Serializer::ObjectSerializer::RelocInfoObjectPreSerializer {
DCHECK(!RelocInfo::IsRelativeCodeTarget(target->rmode()));
#endif
Code object = Code::GetCodeFromTargetAddress(target->target_address());
serializer_->SerializeObject(handle(object, serializer_->isolate()));
serializer_->SerializeObject(handle(object, isolate()));
num_serialized_objects_++;
}
......@@ -930,6 +942,8 @@ class Serializer::ObjectSerializer::RelocInfoObjectPreSerializer {
int num_serialized_objects() const { return num_serialized_objects_; }
Isolate* isolate() { return serializer_->isolate(); }
private:
Serializer* serializer_;
int num_serialized_objects_ = 0;
......@@ -978,7 +992,7 @@ void Serializer::ObjectSerializer::VisitOffHeapTarget(Code host,
Address addr = rinfo->target_off_heap_target();
CHECK_NE(kNullAddress, addr);
Code target = InstructionStream::TryLookupCode(serializer_->isolate(), addr);
Code target = InstructionStream::TryLookupCode(isolate(), addr);
CHECK(Builtins::IsIsolateIndependentBuiltin(target));
sink_->Put(kOffHeapTarget, "OffHeapTarget");
......@@ -1153,5 +1167,14 @@ void Serializer::ObjectSerializer::SerializeCode(Map map, int size) {
Code::kDataStart + kTaggedSize * pre_serializer.num_serialized_objects());
}
Serializer::HotObjectsList::HotObjectsList(Heap* heap) : heap_(heap) {
strong_roots_entry_ =
heap->RegisterStrongRoots(FullObjectSlot(&circular_queue_[0]),
FullObjectSlot(&circular_queue_[kSize]));
}
Serializer::HotObjectsList::~HotObjectsList() {
heap_->UnregisterStrongRoots(strong_roots_entry_);
}
} // namespace internal
} // namespace v8
......@@ -10,6 +10,7 @@
#include "src/codegen/external-reference-encoder.h"
#include "src/common/assert-scope.h"
#include "src/execution/isolate.h"
#include "src/handles/global-handles.h"
#include "src/logging/log.h"
#include "src/objects/objects.h"
#include "src/snapshot/embedded/embedded-data.h"
......@@ -250,7 +251,7 @@ class Serializer : public SerializerDeserializer {
void QueueDeferredObject(Handle<HeapObject> obj) {
DCHECK_NULL(reference_map_.LookupReference(obj));
deferred_objects_.push_back(obj);
deferred_objects_.Push(*obj);
}
// Register that the the given object shouldn't be immediately serialized, but
......@@ -266,8 +267,8 @@ class Serializer : public SerializerDeserializer {
void CountAllocation(Map map, int size, SnapshotSpace space);
#ifdef DEBUG
void PushStack(Handle<HeapObject> o) { stack_.push_back(o); }
void PopStack() { stack_.pop_back(); }
void PushStack(Handle<HeapObject> o) { stack_.Push(*o); }
void PopStack() { stack_.Pop(); }
void PrintStack();
void PrintStack(std::ostream&);
#endif // DEBUG
......@@ -284,21 +285,63 @@ class Serializer : public SerializerDeserializer {
return (flags_ & Snapshot::kAllowActiveIsolateForTesting) != 0;
}
std::vector<Handle<HeapObject>> back_refs_;
private:
// A circular queue of hot objects. This is added to in the same order as in
// Deserializer::HotObjectsList, but this stores the objects as an array of
// raw addresses that are considered strong roots. This allows objects to be
// added to the list without having to extend their handle's lifetime.
//
// We should never allow this class to return Handles to objects in the queue,
// as the object in the queue may change if kSize other objects are added to
// the queue during that Handle's lifetime.
class HotObjectsList {
public:
explicit HotObjectsList(Heap* heap);
~HotObjectsList();
void Add(HeapObject object) {
circular_queue_[index_] = object.ptr();
index_ = (index_ + 1) & kSizeMask;
}
static const int kNotFound = -1;
int Find(HeapObject object) {
DCHECK(!AllowGarbageCollection::IsAllowed());
for (int i = 0; i < kSize; i++) {
if (circular_queue_[i] == object.ptr()) {
return i;
}
}
return kNotFound;
}
private:
static const int kSize = kHotObjectCount;
static const int kSizeMask = kSize - 1;
STATIC_ASSERT(base::bits::IsPowerOfTwo(kSize));
Heap* heap_;
StrongRootsEntry* strong_roots_entry_;
Address circular_queue_[kSize] = {kNullAddress};
int index_ = 0;
DISALLOW_COPY_AND_ASSIGN(HotObjectsList);
};
// Disallow GC during serialization.
// TODO(leszeks, v8:10815): Remove this constraint.
DISALLOW_HEAP_ALLOCATION(no_gc)
Isolate* isolate_;
HotObjectsList hot_objects_;
SerializerReferenceMap reference_map_;
ExternalReferenceEncoder external_reference_encoder_;
RootIndexMap root_index_map_;
std::unique_ptr<CodeAddressMap> code_address_map_;
std::vector<byte> code_buffer_;
std::vector<Handle<HeapObject>>
GlobalHandleVector<HeapObject>
deferred_objects_; // To handle stack overflow.
int num_back_refs_ = 0;
// Objects which have started being serialized, but haven't yet been allocated
// with the allocator, are considered "pending". References to them don't have
......@@ -334,7 +377,8 @@ class Serializer : public SerializerDeserializer {
#endif // OBJECT_PRINT
#ifdef DEBUG
std::vector<Handle<HeapObject>> stack_;
GlobalHandleVector<HeapObject> back_refs_;
GlobalHandleVector<HeapObject> stack_;
#endif // DEBUG
DISALLOW_COPY_AND_ASSIGN(Serializer);
......@@ -346,7 +390,8 @@ class Serializer::ObjectSerializer : public ObjectVisitor {
public:
ObjectSerializer(Serializer* serializer, Handle<HeapObject> obj,
SnapshotByteSink* sink)
: serializer_(serializer),
: isolate_(serializer->isolate()),
serializer_(serializer),
object_(obj),
sink_(sink),
bytes_processed_so_far_(0) {
......@@ -375,6 +420,8 @@ class Serializer::ObjectSerializer : public ObjectVisitor {
void VisitRuntimeEntry(Code host, RelocInfo* reloc) override;
void VisitOffHeapTarget(Code host, RelocInfo* target) override;
Isolate* isolate() { return isolate_; }
private:
class RelocInfoObjectPreSerializer;
......@@ -393,6 +440,7 @@ class Serializer::ObjectSerializer : public ObjectVisitor {
void SerializeExternalString();
void SerializeExternalStringAsSequentialString();
Isolate* isolate_;
Serializer* serializer_;
Handle<HeapObject> object_;
SnapshotByteSink* sink_;
......
......@@ -37,8 +37,12 @@ void StartupDeserializer::DeserializeIntoIsolate() {
isolate()->heap()->IterateWeakRoots(
this, base::EnumSet<SkipRoot>{SkipRoot::kUnserializable});
DeserializeDeferredObjects();
RestoreExternalReferenceRedirectors(isolate(), accessor_infos());
RestoreExternalReferenceRedirectors(isolate(), call_handler_infos());
for (Handle<AccessorInfo> info : accessor_infos()) {
RestoreExternalReferenceRedirector(isolate(), info);
}
for (Handle<CallHandlerInfo> info : call_handler_infos()) {
RestoreExternalReferenceRedirector(isolate(), info);
}
// Flush the instruction cache for the entire code-space. Must happen after
// builtins deserialization.
......
......@@ -66,13 +66,19 @@ StartupSerializer::StartupSerializer(Isolate* isolate,
Snapshot::SerializerFlags flags,
ReadOnlySerializer* read_only_serializer)
: RootsSerializer(isolate, flags, RootIndex::kFirstStrongRoot),
read_only_serializer_(read_only_serializer) {
read_only_serializer_(read_only_serializer),
accessor_infos_(isolate->heap()),
call_handler_infos_(isolate->heap()) {
InitializeCodeAddressMap();
}
StartupSerializer::~StartupSerializer() {
RestoreExternalReferenceRedirectors(isolate(), accessor_infos_);
RestoreExternalReferenceRedirectors(isolate(), call_handler_infos_);
for (Handle<AccessorInfo> info : accessor_infos_) {
RestoreExternalReferenceRedirector(isolate(), info);
}
for (Handle<CallHandlerInfo> info : call_handler_infos_) {
RestoreExternalReferenceRedirector(isolate(), info);
}
OutputStatistics("StartupSerializer");
}
......@@ -144,14 +150,14 @@ void StartupSerializer::SerializeObjectImpl(Handle<HeapObject> obj) {
Foreign::cast(info->getter()).foreign_address(isolate());
Foreign::cast(info->js_getter())
.set_foreign_address(isolate(), original_address);
accessor_infos_.push_back(info);
accessor_infos_.Push(*info);
} else if (use_simulator && obj->IsCallHandlerInfo()) {
Handle<CallHandlerInfo> info = Handle<CallHandlerInfo>::cast(obj);
Address original_address =
Foreign::cast(info->callback()).foreign_address(isolate());
Foreign::cast(info->js_callback())
.set_foreign_address(isolate(), original_address);
call_handler_infos_.push_back(info);
call_handler_infos_.Push(*info);
} else if (obj->IsScript() && Handle<Script>::cast(obj)->IsUserJavaScript()) {
Handle<Script>::cast(obj)->set_context_data(
ReadOnlyRoots(isolate()).uninitialized_symbol());
......
......@@ -7,6 +7,7 @@
#include <unordered_set>
#include "src/handles/global-handles.h"
#include "src/snapshot/roots-serializer.h"
namespace v8 {
......@@ -51,8 +52,8 @@ class V8_EXPORT_PRIVATE StartupSerializer : public RootsSerializer {
void SerializeStringTable(StringTable* string_table);
ReadOnlySerializer* read_only_serializer_;
std::vector<Handle<AccessorInfo>> accessor_infos_;
std::vector<Handle<CallHandlerInfo>> call_handler_infos_;
GlobalHandleVector<AccessorInfo> accessor_infos_;
GlobalHandleVector<CallHandlerInfo> call_handler_infos_;
DISALLOW_COPY_AND_ASSIGN(StartupSerializer);
};
......
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