Commit 899f0af7 authored by Camillo Bruni's avatar Camillo Bruni Committed by V8 LUCI CQ

[serializer] Dehandlify more De-/Serializer code

Bug: v8:11263
Change-Id: I6f9f43125e5a1b27d8f8595bbbebdff2665968da
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3471635Reviewed-by: 's avatarLeszek Swirski <leszeks@chromium.org>
Commit-Queue: Camillo Bruni <cbruni@chromium.org>
Cr-Commit-Position: refs/heads/main@{#79771}
parent cfa49d26
......@@ -109,13 +109,14 @@ AlignedCachedData* CodeSerializer::SerializeSharedFunctionInfo(
return data.GetScriptData();
}
bool CodeSerializer::SerializeReadOnlyObject(Handle<HeapObject> obj) {
if (!ReadOnlyHeap::Contains(*obj)) return false;
bool CodeSerializer::SerializeReadOnlyObject(
HeapObject obj, const DisallowGarbageCollection& no_gc) {
if (!ReadOnlyHeap::Contains(obj)) return false;
// For objects on the read-only heap, never serialize the object, but instead
// create a back reference that encodes the page number as the chunk_index and
// the offset within the page as the chunk_offset.
Address address = obj->address();
Address address = obj.address();
BasicMemoryChunk* chunk = BasicMemoryChunk::FromAddress(address);
uint32_t chunk_index = 0;
ReadOnlySpace* const read_only_space = isolate()->heap()->read_only_space();
......@@ -131,77 +132,93 @@ bool CodeSerializer::SerializeReadOnlyObject(Handle<HeapObject> obj) {
}
void CodeSerializer::SerializeObjectImpl(Handle<HeapObject> obj) {
if (SerializeHotObject(obj)) return;
if (SerializeRoot(obj)) return;
if (SerializeBackReference(obj)) return;
if (SerializeReadOnlyObject(obj)) return;
ReadOnlyRoots roots(isolate());
InstanceType instance_type;
{
DisallowGarbageCollection no_gc;
HeapObject raw = *obj;
if (SerializeHotObject(raw)) return;
if (SerializeRoot(raw)) return;
if (SerializeBackReference(raw)) return;
if (SerializeReadOnlyObject(raw, no_gc)) return;
CHECK(!obj->IsCode(cage_base()));
instance_type = raw.map().instance_type();
CHECK(!InstanceTypeChecker::IsCode(instance_type));
ReadOnlyRoots roots(isolate());
if (ElideObject(*obj)) {
if (ElideObject(raw)) {
AllowGarbageCollection allow_gc;
return SerializeObject(roots.undefined_value_handle());
}
}
if (obj->IsScript()) {
Handle<Script> script_obj = Handle<Script>::cast(obj);
DCHECK_NE(script_obj->compilation_type(), Script::COMPILATION_TYPE_EVAL);
if (InstanceTypeChecker::IsScript(instance_type)) {
Handle<FixedArray> host_options;
Handle<Object> context_data;
{
DisallowGarbageCollection no_gc;
Script script_obj = Script::cast(*obj);
DCHECK_NE(script_obj.compilation_type(), Script::COMPILATION_TYPE_EVAL);
// We want to differentiate between undefined and uninitialized_symbol for
// context_data for now. It is hack to allow debugging for scripts that are
// included as a part of custom snapshot. (see debug::Script::IsEmbedded())
Object context_data = script_obj->context_data();
if (context_data != roots.undefined_value() &&
context_data != roots.uninitialized_symbol()) {
script_obj->set_context_data(roots.undefined_value());
}
// We don't want to serialize host options to avoid serializing unnecessary
// object graph.
FixedArray host_options = script_obj->host_defined_options();
script_obj->set_host_defined_options(roots.empty_fixed_array());
// context_data for now. It is hack to allow debugging for scripts that
// are included as a part of custom snapshot. (see
// debug::Script::IsEmbedded())
Object raw_context_data = script_obj.context_data();
if (raw_context_data != roots.undefined_value() &&
raw_context_data != roots.uninitialized_symbol()) {
script_obj.set_context_data(roots.undefined_value());
}
context_data = handle(raw_context_data, isolate());
// We don't want to serialize host options to avoid serializing
// unnecessary object graph.
host_options = handle(script_obj.host_defined_options(), isolate());
script_obj.set_host_defined_options(roots.empty_fixed_array());
}
SerializeGeneric(obj);
script_obj->set_host_defined_options(host_options);
script_obj->set_context_data(context_data);
return;
{
DisallowGarbageCollection no_gc;
Script script_obj = Script::cast(*obj);
script_obj.set_host_defined_options(*host_options);
script_obj.set_context_data(*context_data);
}
if (obj->IsSharedFunctionInfo()) {
Handle<SharedFunctionInfo> sfi = Handle<SharedFunctionInfo>::cast(obj);
DCHECK(!sfi->IsApiFunction());
return;
} else if (InstanceTypeChecker::IsSharedFunctionInfo(instance_type)) {
Handle<DebugInfo> debug_info;
bool restore_bytecode = false;
{
DisallowGarbageCollection no_gc;
SharedFunctionInfo sfi = SharedFunctionInfo::cast(*obj);
DCHECK(!sfi.IsApiFunction());
#if V8_ENABLE_WEBASSEMBLY
// TODO(7110): Enable serializing of Asm modules once the AsmWasmData
// is context independent.
DCHECK(!sfi->HasAsmWasmData());
DCHECK(!sfi.HasAsmWasmData());
#endif // V8_ENABLE_WEBASSEMBLY
DebugInfo debug_info;
BytecodeArray debug_bytecode_array;
if (sfi->HasDebugInfo()) {
if (sfi.HasDebugInfo()) {
// Clear debug info.
debug_info = sfi->GetDebugInfo();
if (debug_info.HasInstrumentedBytecodeArray()) {
debug_bytecode_array = debug_info.DebugBytecodeArray();
sfi->SetActiveBytecodeArray(debug_info.OriginalBytecodeArray());
DebugInfo raw_debug_info = sfi.GetDebugInfo();
if (raw_debug_info.HasInstrumentedBytecodeArray()) {
restore_bytecode = true;
sfi.SetActiveBytecodeArray(raw_debug_info.OriginalBytecodeArray());
}
sfi->set_script_or_debug_info(debug_info.script(), kReleaseStore);
sfi.set_script_or_debug_info(raw_debug_info.script(), kReleaseStore);
debug_info = handle(raw_debug_info, isolate());
}
DCHECK(!sfi.HasDebugInfo());
}
DCHECK(!sfi->HasDebugInfo());
SerializeGeneric(obj);
// Restore debug info
if (!debug_info.is_null()) {
sfi->set_script_or_debug_info(debug_info, kReleaseStore);
if (!debug_bytecode_array.is_null()) {
sfi->SetActiveBytecodeArray(debug_bytecode_array);
DisallowGarbageCollection no_gc;
SharedFunctionInfo sfi = SharedFunctionInfo::cast(*obj);
sfi.set_script_or_debug_info(*debug_info, kReleaseStore);
if (restore_bytecode) {
sfi.SetActiveBytecodeArray(debug_info->DebugBytecodeArray());
}
}
return;
}
if (obj->IsUncompiledDataWithoutPreparseDataWithJob()) {
} else if (InstanceTypeChecker::IsUncompiledDataWithoutPreparseDataWithJob(
instance_type)) {
Handle<UncompiledDataWithoutPreparseDataWithJob> data =
Handle<UncompiledDataWithoutPreparseDataWithJob>::cast(obj);
Address job = data->job();
......@@ -209,8 +226,8 @@ void CodeSerializer::SerializeObjectImpl(Handle<HeapObject> obj) {
SerializeGeneric(data);
data->set_job(job);
return;
}
if (obj->IsUncompiledDataWithPreparseDataAndJob()) {
} else if (InstanceTypeChecker::IsUncompiledDataWithPreparseDataAndJob(
instance_type)) {
Handle<UncompiledDataWithPreparseDataAndJob> data =
Handle<UncompiledDataWithPreparseDataAndJob>::cast(obj);
Address job = data->job();
......@@ -233,14 +250,16 @@ void CodeSerializer::SerializeObjectImpl(Handle<HeapObject> obj) {
#endif // V8_TARGET_ARCH_ARM
// Past this point we should not see any (context-specific) maps anymore.
CHECK(!obj->IsMap());
CHECK(!InstanceTypeChecker::IsMap(instance_type));
// There should be no references to the global object embedded.
CHECK(!obj->IsJSGlobalProxy() && !obj->IsJSGlobalObject());
CHECK(!InstanceTypeChecker::IsJSGlobalProxy(instance_type) &&
!InstanceTypeChecker::IsJSGlobalObject(instance_type));
// Embedded FixedArrays that need rehashing must support rehashing.
CHECK_IMPLIES(obj->NeedsRehashing(cage_base()),
obj->CanBeRehashed(cage_base()));
// We expect no instantiated function objects or contexts.
CHECK(!obj->IsJSFunction() && !obj->IsContext());
CHECK(!InstanceTypeChecker::IsJSFunction(instance_type) &&
!InstanceTypeChecker::IsContext(instance_type));
SerializeGeneric(obj);
}
......
......@@ -104,7 +104,8 @@ class CodeSerializer : public Serializer {
private:
void SerializeObjectImpl(Handle<HeapObject> o) override;
bool SerializeReadOnlyObject(Handle<HeapObject> obj);
bool SerializeReadOnlyObject(HeapObject obj,
const DisallowGarbageCollection& no_gc);
DISALLOW_GARBAGE_COLLECTION(no_gc_)
uint32_t source_hash_;
......
......@@ -121,7 +121,7 @@ void ContextSerializer::Serialize(Context* o,
}
void ContextSerializer::SerializeObjectImpl(Handle<HeapObject> obj) {
DCHECK(!ObjectIsBytecodeHandler(obj)); // Only referenced in dispatch table.
DCHECK(!ObjectIsBytecodeHandler(*obj)); // Only referenced in dispatch table.
if (!allow_active_isolate_for_testing()) {
// When serializing a snapshot intended for real use, we should not end up
......@@ -132,11 +132,13 @@ void ContextSerializer::SerializeObjectImpl(Handle<HeapObject> obj) {
DCHECK_IMPLIES(obj->IsNativeContext(), *obj == context_);
}
if (SerializeHotObject(obj)) return;
if (SerializeRoot(obj)) return;
if (SerializeBackReference(obj)) return;
{
DisallowGarbageCollection no_gc;
HeapObject raw = *obj;
if (SerializeHotObject(raw)) return;
if (SerializeRoot(raw)) return;
if (SerializeBackReference(raw)) return;
}
if (startup_serializer_->SerializeUsingReadOnlyObjectCache(&sink_, obj)) {
return;
......@@ -161,30 +163,29 @@ void ContextSerializer::SerializeObjectImpl(Handle<HeapObject> obj) {
// Function and object templates are not context specific.
DCHECK(!obj->IsTemplateInfo());
InstanceType instance_type = obj->map().instance_type();
if (InstanceTypeChecker::IsFeedbackVector(instance_type)) {
// Clear literal boilerplates and feedback.
if (obj->IsFeedbackVector()) {
Handle<FeedbackVector>::cast(obj)->ClearSlots(isolate());
}
} else if (InstanceTypeChecker::IsFeedbackCell(instance_type)) {
// Clear InterruptBudget when serializing FeedbackCell.
if (obj->IsFeedbackCell()) {
Handle<FeedbackCell>::cast(obj)->SetInitialInterruptBudget();
}
if (SerializeJSObjectWithEmbedderFields(obj)) {
} else if (InstanceTypeChecker::IsJSObject(instance_type)) {
if (SerializeJSObjectWithEmbedderFields(Handle<JSObject>::cast(obj))) {
return;
}
if (obj->IsJSFunction()) {
if (InstanceTypeChecker::IsJSFunction(instance_type)) {
DisallowGarbageCollection no_gc;
// Unconditionally reset the JSFunction to its SFI's code, since we can't
// serialize optimized code anyway.
Handle<JSFunction> closure = Handle<JSFunction>::cast(obj);
closure->ResetIfCodeFlushed();
if (closure->is_compiled()) {
if (closure->shared().HasBaselineCode()) {
closure->shared().FlushBaselineCode();
JSFunction closure = JSFunction::cast(*obj);
closure.ResetIfCodeFlushed();
if (closure.is_compiled()) {
if (closure.shared().HasBaselineCode()) {
closure.shared().FlushBaselineCode();
}
closure.set_code(closure.shared().GetCode(), kReleaseStore);
}
closure->set_code(closure->shared().GetCode(), kReleaseStore);
}
}
......@@ -219,19 +220,18 @@ bool DataIsEmpty(const StartupData& data) { return data.raw_size == 0; }
} // anonymous namespace
bool ContextSerializer::SerializeJSObjectWithEmbedderFields(
Handle<HeapObject> obj) {
if (!obj->IsJSObject()) return false;
Handle<JSObject> js_obj = Handle<JSObject>::cast(obj);
int embedder_fields_count = js_obj->GetEmbedderFieldCount();
Handle<JSObject> obj) {
DisallowGarbageCollection no_gc;
JSObject js_obj = *obj;
int embedder_fields_count = js_obj.GetEmbedderFieldCount();
if (embedder_fields_count == 0) return false;
CHECK_GT(embedder_fields_count, 0);
DCHECK(!js_obj->NeedsRehashing(cage_base()));
DCHECK(!js_obj.NeedsRehashing(cage_base()));
DisallowGarbageCollection no_gc;
DisallowJavascriptExecution no_js(isolate());
DisallowCompilation no_compile(isolate());
v8::Local<v8::Object> api_obj = v8::Utils::ToLocal(js_obj);
v8::Local<v8::Object> api_obj = v8::Utils::ToLocal(obj);
std::vector<EmbedderDataSlot::RawData> original_embedder_values;
std::vector<StartupData> serialized_data;
......@@ -241,7 +241,7 @@ bool ContextSerializer::SerializeJSObjectWithEmbedderFields(
// serializer. For aligned pointers, call the serialize callback. Hold
// onto the result.
for (int i = 0; i < embedder_fields_count; i++) {
EmbedderDataSlot embedder_data_slot(*js_obj, i);
EmbedderDataSlot embedder_data_slot(js_obj, i);
original_embedder_values.emplace_back(
embedder_data_slot.load_raw(isolate(), no_gc));
Object object = embedder_data_slot.load_tagged();
......@@ -270,13 +270,18 @@ bool ContextSerializer::SerializeJSObjectWithEmbedderFields(
// with embedder callbacks.
for (int i = 0; i < embedder_fields_count; i++) {
if (!DataIsEmpty(serialized_data[i])) {
EmbedderDataSlot(*js_obj, i).store_raw(isolate(), kNullAddress, no_gc);
EmbedderDataSlot(js_obj, i).store_raw(isolate(), kNullAddress, no_gc);
}
}
// 3) Serialize the object. References from embedder fields to heap objects or
// smis are serialized regularly.
ObjectSerializer(this, js_obj, &sink_).Serialize();
{
AllowGarbageCollection allow_gc;
ObjectSerializer(this, obj, &sink_).Serialize();
// Reload raw pointer.
js_obj = *obj;
}
// 4) Obtain back reference for the serialized object.
const SerializerReference* reference =
......@@ -290,8 +295,8 @@ bool ContextSerializer::SerializeJSObjectWithEmbedderFields(
StartupData data = serialized_data[i];
if (DataIsEmpty(data)) continue;
// Restore original values from cleared fields.
EmbedderDataSlot(*js_obj, i)
.store_raw(isolate(), original_embedder_values[i], no_gc);
EmbedderDataSlot(js_obj, i).store_raw(isolate(),
original_embedder_values[i], no_gc);
embedder_fields_sink_.Put(kNewObject, "embedder field holder");
embedder_fields_sink_.PutInt(reference->back_ref_index(), "BackRefIndex");
embedder_fields_sink_.PutInt(i, "embedder field index");
......
......@@ -33,7 +33,7 @@ class V8_EXPORT_PRIVATE ContextSerializer : public Serializer {
void SerializeObjectImpl(Handle<HeapObject> o) override;
bool ShouldBeInTheStartupObjectCache(HeapObject o);
bool ShouldBeInTheSharedObjectCache(HeapObject o);
bool SerializeJSObjectWithEmbedderFields(Handle<HeapObject> obj);
bool SerializeJSObjectWithEmbedderFields(Handle<JSObject> obj);
void CheckRehashability(HeapObject obj);
StartupSerializer* startup_serializer_;
......
......@@ -41,13 +41,17 @@ void ReadOnlySerializer::SerializeObjectImpl(Handle<HeapObject> obj) {
// in the root table, so don't try to serialize a reference and rely on the
// below CHECK(!did_serialize_not_mapped_symbol_) to make sure it doesn't
// serialize twice.
if (!IsNotMappedSymbol(*obj)) {
if (SerializeHotObject(obj)) return;
if (IsRootAndHasBeenSerialized(*obj) && SerializeRoot(obj)) return;
if (SerializeBackReference(obj)) return;
{
DisallowGarbageCollection no_gc;
HeapObject raw = *obj;
if (!IsNotMappedSymbol(raw)) {
if (SerializeHotObject(raw)) return;
if (IsRootAndHasBeenSerialized(raw) && SerializeRoot(raw)) return;
if (SerializeBackReference(raw)) return;
}
CheckRehashability(*obj);
CheckRehashability(raw);
}
// Object has not yet been serialized. Serialize it here.
ObjectSerializer object_serializer(this, obj, &sink_);
......
......@@ -27,7 +27,7 @@ RootsSerializer::RootsSerializer(Isolate* isolate,
int RootsSerializer::SerializeInObjectCache(Handle<HeapObject> heap_object) {
int index;
if (!object_cache_index_map_.LookupOrInsert(heap_object, &index)) {
if (!object_cache_index_map_.LookupOrInsert(*heap_object, &index)) {
// This object is not part of the object cache yet. Add it to the cache so
// we can refer to it via cache index from the delegating snapshot.
SerializeObject(heap_object);
......
......@@ -171,32 +171,34 @@ void Serializer::PrintStack(std::ostream& out) {
}
#endif // DEBUG
bool Serializer::SerializeRoot(Handle<HeapObject> obj) {
bool Serializer::SerializeRoot(HeapObject obj) {
RootIndex root_index;
// Derived serializers are responsible for determining if the root has
// actually been serialized before calling this.
if (root_index_map()->Lookup(*obj, &root_index)) {
if (root_index_map()->Lookup(obj, &root_index)) {
PutRoot(root_index);
return true;
}
return false;
}
bool Serializer::SerializeHotObject(Handle<HeapObject> obj) {
bool Serializer::SerializeHotObject(HeapObject obj) {
DisallowGarbageCollection no_gc;
// Encode a reference to a hot object by its index in the working set.
int index = hot_objects_.Find(*obj);
int index = hot_objects_.Find(obj);
if (index == HotObjectsList::kNotFound) return false;
DCHECK(index >= 0 && index < kHotObjectCount);
if (FLAG_trace_serializer) {
PrintF(" Encoding hot object %d:", index);
obj->ShortPrint();
obj.ShortPrint();
PrintF("\n");
}
sink_.Put(HotObject::Encode(index), "HotObject");
return true;
}
bool Serializer::SerializeBackReference(Handle<HeapObject> obj) {
bool Serializer::SerializeBackReference(HeapObject obj) {
DisallowGarbageCollection no_gc;
const SerializerReference* reference = reference_map_.LookupReference(obj);
if (reference == nullptr) return false;
// Encode the location of an already deserialized object in order to write
......@@ -213,7 +215,7 @@ bool Serializer::SerializeBackReference(Handle<HeapObject> obj) {
DCHECK(reference->is_back_reference());
if (FLAG_trace_serializer) {
PrintF(" Encoding back reference to: ");
obj->ShortPrint();
obj.ShortPrint();
PrintF("\n");
}
......@@ -223,29 +225,28 @@ bool Serializer::SerializeBackReference(Handle<HeapObject> obj) {
return true;
}
bool Serializer::SerializePendingObject(Handle<HeapObject> obj) {
bool Serializer::SerializePendingObject(HeapObject obj) {
PendingObjectReferences* refs_to_object =
forward_refs_per_pending_object_.Find(obj);
if (refs_to_object == nullptr) {
return false;
}
PutPendingForwardReference(*refs_to_object);
return true;
}
bool Serializer::ObjectIsBytecodeHandler(Handle<HeapObject> obj) const {
if (!obj->IsCode()) return false;
return (Code::cast(*obj).kind() == CodeKind::BYTECODE_HANDLER);
bool Serializer::ObjectIsBytecodeHandler(HeapObject obj) const {
if (!obj.IsCode()) return false;
return (Code::cast(obj).kind() == CodeKind::BYTECODE_HANDLER);
}
void Serializer::PutRoot(RootIndex root) {
DisallowGarbageCollection no_gc;
int root_index = static_cast<int>(root);
Handle<HeapObject> object =
Handle<HeapObject>::cast(isolate()->root_handle(root));
HeapObject object = HeapObject::cast(isolate()->root(root));
if (FLAG_trace_serializer) {
PrintF(" Encoding root %d:", root_index);
object->ShortPrint();
object.ShortPrint();
PrintF("\n");
}
......@@ -256,12 +257,12 @@ void Serializer::PutRoot(RootIndex root) {
// TODO(ulan): Check that it works with young large objects.
if (root_index < kRootArrayConstantsCount &&
!Heap::InYoungGeneration(*object)) {
!Heap::InYoungGeneration(object)) {
sink_.Put(RootArrayConstant::Encode(root), "RootConstant");
} else {
sink_.Put(kRootArray, "RootSerialization");
sink_.PutInt(root_index, "root_index");
hot_objects_.Add(*object);
hot_objects_.Add(object);
}
}
......@@ -280,11 +281,11 @@ void Serializer::PutSmiRoot(FullObjectSlot slot) {
sink_.PutRaw(raw_value_as_bytes, bytes_to_output, "Bytes");
}
void Serializer::PutBackReference(Handle<HeapObject> object,
void Serializer::PutBackReference(HeapObject object,
SerializerReference reference) {
DCHECK_EQ(*object, *back_refs_[reference.back_ref_index()]);
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) {
......@@ -346,8 +347,9 @@ ExternalReferenceEncoder::Value Serializer::EncodeExternalReference(
return result.FromJust();
}
void Serializer::RegisterObjectIsPending(Handle<HeapObject> obj) {
if (IsNotMappedSymbol(*obj)) return;
void Serializer::RegisterObjectIsPending(HeapObject obj) {
DisallowGarbageCollection no_gc;
if (IsNotMappedSymbol(obj)) return;
// Add the given object to the pending objects -> forward refs map.
auto find_result = forward_refs_per_pending_object_.FindOrInsert(obj);
......@@ -358,11 +360,12 @@ void Serializer::RegisterObjectIsPending(Handle<HeapObject> obj) {
// deferred objects queue though, since it may be the very object we just
// popped off that queue, so just check that it can be deferred.
DCHECK_IMPLIES(find_result.already_exists, *find_result.entry != nullptr);
DCHECK_IMPLIES(find_result.already_exists, CanBeDeferred(*obj));
DCHECK_IMPLIES(find_result.already_exists, CanBeDeferred(obj));
}
void Serializer::ResolvePendingObject(Handle<HeapObject> obj) {
if (IsNotMappedSymbol(*obj)) return;
void Serializer::ResolvePendingObject(HeapObject obj) {
DisallowGarbageCollection no_gc;
if (IsNotMappedSymbol(obj)) return;
std::vector<int>* refs;
CHECK(forward_refs_per_pending_object_.Delete(obj, &refs));
......@@ -427,7 +430,7 @@ void Serializer::ObjectSerializer::SerializePrologue(SnapshotSpace space,
sink_->PutInt(size >> kObjectAlignmentBits, "ObjectSizeInWords");
// Until the space for the object is allocated, it is considered "pending".
serializer_->RegisterObjectIsPending(object_);
serializer_->RegisterObjectIsPending(*object_);
// Serialize map (first word of the object) before anything else, so that
// the deserializer can access it when allocating. Make sure that the map
......@@ -444,7 +447,7 @@ void Serializer::ObjectSerializer::SerializePrologue(SnapshotSpace space,
// Now that the object is allocated, we can resolve pending references to
// it.
serializer_->ResolvePendingObject(object_);
serializer_->ResolvePendingObject(*object_);
}
if (FLAG_serialization_statistics) {
......@@ -475,11 +478,14 @@ void Serializer::ObjectSerializer::SerializePrologue(SnapshotSpace space,
uint32_t Serializer::ObjectSerializer::SerializeBackingStore(
void* backing_store, int32_t byte_length, Maybe<int32_t> max_byte_length) {
DisallowGarbageCollection no_gc;
const SerializerReference* reference_ptr =
serializer_->reference_map()->LookupBackingStore(backing_store);
// Serialize the off-heap backing store.
if (!reference_ptr) {
if (reference_ptr) {
return reference_ptr->off_heap_backing_store_index();
}
if (max_byte_length.IsJust()) {
sink_->Put(kOffHeapResizableBackingStore,
"Off-heap resizable backing store");
......@@ -490,8 +496,7 @@ uint32_t Serializer::ObjectSerializer::SerializeBackingStore(
if (max_byte_length.IsJust()) {
sink_->PutInt(max_byte_length.FromJust(), "max length");
}
sink_->PutRaw(static_cast<byte*>(backing_store), byte_length,
"BackingStore");
sink_->PutRaw(static_cast<byte*>(backing_store), byte_length, "BackingStore");
DCHECK_NE(0, serializer_->seen_backing_stores_index_);
SerializerReference reference =
SerializerReference::OffHeapBackingStoreReference(
......@@ -499,76 +504,84 @@ uint32_t Serializer::ObjectSerializer::SerializeBackingStore(
// Mark this backing store as already serialized.
serializer_->reference_map()->AddBackingStore(backing_store, reference);
return reference.off_heap_backing_store_index();
} else {
return reference_ptr->off_heap_backing_store_index();
}
}
void Serializer::ObjectSerializer::SerializeJSTypedArray() {
Handle<JSTypedArray> typed_array = Handle<JSTypedArray>::cast(object_);
if (typed_array->is_on_heap()) {
typed_array->RemoveExternalPointerCompensationForSerialization(isolate());
{
DisallowGarbageCollection no_gc;
JSTypedArray typed_array = JSTypedArray::cast(*object_);
if (typed_array.is_on_heap()) {
typed_array.RemoveExternalPointerCompensationForSerialization(isolate());
} else {
if (!typed_array->WasDetached()) {
if (!typed_array.WasDetached()) {
// Explicitly serialize the backing store now.
JSArrayBuffer buffer = JSArrayBuffer::cast(typed_array->buffer());
// We cannot store byte_length or max_byte_length larger than int32 range
// in the snapshot.
JSArrayBuffer buffer = JSArrayBuffer::cast(typed_array.buffer());
// We cannot store byte_length or max_byte_length larger than int32
// range in the snapshot.
CHECK_LE(buffer.byte_length(), std::numeric_limits<int32_t>::max());
int32_t byte_length = static_cast<int32_t>(buffer.byte_length());
Maybe<int32_t> max_byte_length = Nothing<int32_t>();
if (buffer.is_resizable()) {
CHECK_LE(buffer.max_byte_length(), std::numeric_limits<int32_t>::max());
max_byte_length = Just(static_cast<int32_t>(buffer.max_byte_length()));
CHECK_LE(buffer.max_byte_length(),
std::numeric_limits<int32_t>::max());
max_byte_length =
Just(static_cast<int32_t>(buffer.max_byte_length()));
}
size_t byte_offset = typed_array->byte_offset();
size_t byte_offset = typed_array.byte_offset();
// We need to calculate the backing store from the data pointer
// because the ArrayBuffer may already have been serialized.
void* backing_store = reinterpret_cast<void*>(
reinterpret_cast<Address>(typed_array->DataPtr()) - byte_offset);
reinterpret_cast<Address>(typed_array.DataPtr()) - byte_offset);
uint32_t ref =
SerializeBackingStore(backing_store, byte_length, max_byte_length);
typed_array->SetExternalBackingStoreRefForSerialization(ref);
typed_array.SetExternalBackingStoreRefForSerialization(ref);
} else {
typed_array->SetExternalBackingStoreRefForSerialization(0);
typed_array.SetExternalBackingStoreRefForSerialization(0);
}
}
}
SerializeObject();
}
void Serializer::ObjectSerializer::SerializeJSArrayBuffer() {
Handle<JSArrayBuffer> buffer = Handle<JSArrayBuffer>::cast(object_);
void* backing_store = buffer->backing_store();
ArrayBufferExtension* extension;
void* backing_store;
{
DisallowGarbageCollection no_gc;
JSArrayBuffer buffer = JSArrayBuffer::cast(*object_);
backing_store = buffer.backing_store();
// We cannot store byte_length or max_byte_length larger than int32 range in
// the snapshot.
CHECK_LE(buffer->byte_length(), std::numeric_limits<int32_t>::max());
int32_t byte_length = static_cast<int32_t>(buffer->byte_length());
CHECK_LE(buffer.byte_length(), std::numeric_limits<int32_t>::max());
int32_t byte_length = static_cast<int32_t>(buffer.byte_length());
Maybe<int32_t> max_byte_length = Nothing<int32_t>();
if (buffer->is_resizable()) {
CHECK_LE(buffer->max_byte_length(), std::numeric_limits<int32_t>::max());
max_byte_length = Just(static_cast<int32_t>(buffer->max_byte_length()));
if (buffer.is_resizable()) {
CHECK_LE(buffer.max_byte_length(), std::numeric_limits<int32_t>::max());
max_byte_length = Just(static_cast<int32_t>(buffer.max_byte_length()));
}
ArrayBufferExtension* extension = buffer->extension();
extension = buffer.extension();
// Only serialize non-empty backing stores.
if (buffer->IsEmpty()) {
buffer->SetBackingStoreRefForSerialization(kEmptyBackingStoreRefSentinel);
if (buffer.IsEmpty()) {
buffer.SetBackingStoreRefForSerialization(kEmptyBackingStoreRefSentinel);
} else {
uint32_t ref =
SerializeBackingStore(backing_store, byte_length, max_byte_length);
buffer->SetBackingStoreRefForSerialization(ref);
buffer.SetBackingStoreRefForSerialization(ref);
// Ensure deterministic output by setting extension to null during
// serialization.
buffer->set_extension(nullptr);
buffer.set_extension(nullptr);
}
}
SerializeObject();
buffer->set_backing_store(isolate(), backing_store);
buffer->set_extension(extension);
{
JSArrayBuffer buffer = JSArrayBuffer::cast(*object_);
buffer.set_backing_store(isolate(), backing_store);
buffer.set_extension(extension);
}
}
void Serializer::ObjectSerializer::SerializeExternalString() {
......@@ -651,56 +664,59 @@ void Serializer::ObjectSerializer::SerializeExternalStringAsSequentialString() {
// maybe left-over bytes that need to be padded.
int padding_size = allocation_size - SeqString::kHeaderSize - content_size;
DCHECK(0 <= padding_size && padding_size < kObjectAlignment);
for (int i = 0; i < padding_size; i++)
for (int i = 0; i < padding_size; i++) {
sink_->Put(static_cast<byte>(0), "StringPadding");
}
}
// Clear and later restore the next link in the weak cell or allocation site.
// TODO(all): replace this with proper iteration of weak slots in serializer.
class V8_NODISCARD UnlinkWeakNextScope {
public:
explicit UnlinkWeakNextScope(Heap* heap, Handle<HeapObject> object) {
explicit UnlinkWeakNextScope(Heap* heap, HeapObject object) {
Isolate* isolate = heap->isolate();
if (object->IsAllocationSite(isolate) &&
Handle<AllocationSite>::cast(object)->HasWeakNext()) {
if (object.IsAllocationSite(isolate) &&
AllocationSite::cast(object).HasWeakNext()) {
object_ = object;
next_ = handle(AllocationSite::cast(*object).weak_next(), isolate);
Handle<AllocationSite>::cast(object)->set_weak_next(
next_ = AllocationSite::cast(object).weak_next();
AllocationSite::cast(object).set_weak_next(
ReadOnlyRoots(isolate).undefined_value());
}
}
~UnlinkWeakNextScope() {
if (!object_.is_null()) {
Handle<AllocationSite>::cast(object_)->set_weak_next(
*next_, UPDATE_WEAK_WRITE_BARRIER);
}
if (next_ == Smi::zero()) return;
AllocationSite::cast(object_).set_weak_next(next_,
UPDATE_WEAK_WRITE_BARRIER);
}
private:
Handle<HeapObject> object_;
Handle<Object> next_;
HeapObject object_;
Object next_ = Smi::zero();
DISALLOW_GARBAGE_COLLECTION(no_gc_)
};
void Serializer::ObjectSerializer::Serialize() {
RecursionScope recursion(serializer_);
{
DisallowGarbageCollection no_gc;
HeapObject raw = *object_;
// Defer objects as "pending" if they cannot be serialized now, or if we
// exceed a certain recursion depth. Some objects cannot be deferred.
if ((recursion.ExceedsMaximum() && CanBeDeferred(*object_)) ||
serializer_->MustBeDeferred(*object_)) {
DCHECK(CanBeDeferred(*object_));
if ((recursion.ExceedsMaximum() && CanBeDeferred(raw)) ||
serializer_->MustBeDeferred(raw)) {
DCHECK(CanBeDeferred(raw));
if (FLAG_trace_serializer) {
PrintF(" Deferring heap object: ");
object_->ShortPrint();
PrintF("\n");
}
// Deferred objects are considered "pending".
serializer_->RegisterObjectIsPending(object_);
serializer_->RegisterObjectIsPending(raw);
serializer_->PutPendingForwardReference(
*serializer_->forward_refs_per_pending_object_.Find(object_));
serializer_->QueueDeferredObject(object_);
*serializer_->forward_refs_per_pending_object_.Find(raw));
serializer_->QueueDeferredObject(raw);
return;
}
......@@ -709,9 +725,11 @@ void Serializer::ObjectSerializer::Serialize() {
object_->ShortPrint();
PrintF("\n");
}
}
PtrComprCageBase cage_base(isolate());
if (object_->IsExternalString(cage_base)) {
InstanceType instance_type = object_->map(cage_base).instance_type();
if (InstanceTypeChecker::IsExternalString(instance_type)) {
SerializeExternalString();
return;
} else if (!ReadOnlyHeap::Contains(*object_)) {
......@@ -725,43 +743,41 @@ void Serializer::ObjectSerializer::Serialize() {
Handle<SeqTwoByteString>::cast(object_)->clear_padding();
}
}
if (object_->IsJSTypedArray(cage_base)) {
if (InstanceTypeChecker::IsJSTypedArray(instance_type)) {
SerializeJSTypedArray();
return;
} else if (object_->IsJSArrayBuffer(cage_base)) {
} else if (InstanceTypeChecker::IsJSArrayBuffer(instance_type)) {
SerializeJSArrayBuffer();
return;
}
// We don't expect fillers.
DCHECK(!object_->IsFreeSpaceOrFiller(cage_base));
if (object_->IsScript(cage_base)) {
} else if (InstanceTypeChecker::IsScript(instance_type)) {
// Clear cached line ends.
Oddball undefined = ReadOnlyRoots(isolate()).undefined_value();
Handle<Script>::cast(object_)->set_line_ends(undefined);
}
// We don't expect fillers.
DCHECK(!object_->IsFreeSpaceOrFiller(cage_base));
SerializeObject();
}
namespace {
SnapshotSpace GetSnapshotSpace(Handle<HeapObject> object) {
SnapshotSpace GetSnapshotSpace(HeapObject object) {
if (V8_ENABLE_THIRD_PARTY_HEAP_BOOL) {
if (object->IsCode()) {
if (object.IsCode()) {
return SnapshotSpace::kCode;
} else if (ReadOnlyHeap::Contains(*object)) {
} else if (ReadOnlyHeap::Contains(object)) {
return SnapshotSpace::kReadOnlyHeap;
} else if (object->IsMap()) {
} else if (object.IsMap()) {
return SnapshotSpace::kMap;
} else {
return SnapshotSpace::kOld;
}
} else if (ReadOnlyHeap::Contains(*object)) {
} else if (ReadOnlyHeap::Contains(object)) {
return SnapshotSpace::kReadOnlyHeap;
} else {
AllocationSpace heap_space =
MemoryChunk::FromHeapObject(*object)->owner_identity();
MemoryChunk::FromHeapObject(object)->owner_identity();
// Large code objects are not supported and cannot be expressed by
// SnapshotSpace.
DCHECK_NE(heap_space, CODE_LO_SPACE);
......@@ -803,7 +819,7 @@ void Serializer::ObjectSerializer::SerializeObject() {
if (map == ReadOnlyRoots(isolate()).descriptor_array_map()) {
map = ReadOnlyRoots(isolate()).strong_descriptor_array_map();
}
SnapshotSpace space = GetSnapshotSpace(object_);
SnapshotSpace space = GetSnapshotSpace(*object_);
SerializePrologue(space, size, map);
// Serialize the rest of the object.
......@@ -833,15 +849,16 @@ void Serializer::ObjectSerializer::SerializeDeferred() {
}
void Serializer::ObjectSerializer::SerializeContent(Map map, int size) {
UnlinkWeakNextScope unlink_weak_next(isolate()->heap(), object_);
if (object_->IsCode()) {
HeapObject raw = *object_;
UnlinkWeakNextScope unlink_weak_next(isolate()->heap(), raw);
if (raw.IsCode()) {
// For code objects, perform a custom serialization.
SerializeCode(map, size);
} else {
// For other objects, iterate references first.
object_->IterateBody(map, size, this);
raw.IterateBody(map, size, this);
// Then output data payload, if any.
OutputRawData(object_->address() + size);
OutputRawData(raw.address() + size);
}
}
......@@ -884,7 +901,7 @@ void Serializer::ObjectSerializer::VisitPointers(HeapObject host,
}
Handle<HeapObject> obj = handle(current_contents, isolate());
if (serializer_->SerializePendingObject(obj)) {
if (serializer_->SerializePendingObject(*obj)) {
bytes_processed_so_far_ += kTaggedSize;
++current;
continue;
......@@ -935,7 +952,7 @@ void Serializer::ObjectSerializer::VisitCodePointer(HeapObject host,
DCHECK(contents.IsCode());
Handle<HeapObject> obj = handle(HeapObject::cast(contents), isolate());
if (!serializer_->SerializePendingObject(obj)) {
if (!serializer_->SerializePendingObject(*obj)) {
serializer_->SerializeObject(obj);
}
bytes_processed_so_far_ += kTaggedSize;
......
......@@ -233,8 +233,7 @@ class Serializer : public SerializerDeserializer {
void PutRoot(RootIndex root_index);
void PutSmiRoot(FullObjectSlot slot);
void PutBackReference(Handle<HeapObject> object,
SerializerReference reference);
void PutBackReference(HeapObject object, SerializerReference reference);
void PutAttachedReference(SerializerReference reference);
void PutNextChunk(SnapshotSpace space);
void PutRepeat(int repeat_count);
......@@ -247,19 +246,19 @@ class Serializer : public SerializerDeserializer {
void ResolvePendingForwardReference(int obj);
// Returns true if the object was successfully serialized as a root.
bool SerializeRoot(Handle<HeapObject> obj);
bool SerializeRoot(HeapObject obj);
// Returns true if the object was successfully serialized as hot object.
bool SerializeHotObject(Handle<HeapObject> obj);
bool SerializeHotObject(HeapObject obj);
// Returns true if the object was successfully serialized as back reference.
bool SerializeBackReference(Handle<HeapObject> obj);
bool SerializeBackReference(HeapObject obj);
// Returns true if the object was successfully serialized as pending object.
bool SerializePendingObject(Handle<HeapObject> obj);
bool SerializePendingObject(HeapObject obj);
// Returns true if the given heap object is a bytecode handler code object.
bool ObjectIsBytecodeHandler(Handle<HeapObject> obj) const;
bool ObjectIsBytecodeHandler(HeapObject obj) const;
ExternalReferenceEncoder::Value EncodeExternalReference(Address addr);
......@@ -278,18 +277,18 @@ class Serializer : public SerializerDeserializer {
Code CopyCode(Code code);
void QueueDeferredObject(Handle<HeapObject> obj) {
void QueueDeferredObject(HeapObject obj) {
DCHECK_NULL(reference_map_.LookupReference(obj));
deferred_objects_.Push(*obj);
deferred_objects_.Push(obj);
}
// Register that the the given object shouldn't be immediately serialized, but
// will be serialized later and any references to it should be pending forward
// references.
void RegisterObjectIsPending(Handle<HeapObject> obj);
void RegisterObjectIsPending(HeapObject obj);
// Resolve the given pending object reference with the current object.
void ResolvePendingObject(Handle<HeapObject> obj);
void ResolvePendingObject(HeapObject obj);
void OutputStatistics(const char* name);
......
......@@ -169,15 +169,22 @@ void SharedHeapSerializer::SerializeObjectImpl(Handle<HeapObject> obj) {
// Objects in the shared heap cannot depend on per-Isolate roots but can
// depend on RO roots since sharing objects requires sharing the RO space.
DCHECK(CanBeInSharedOldSpace(*obj) || ReadOnlyHeap::Contains(*obj));
if (SerializeHotObject(obj)) return;
if (IsRootAndHasBeenSerialized(*obj) && SerializeRoot(obj)) return;
{
DisallowGarbageCollection no_gc;
HeapObject raw = *obj;
if (SerializeHotObject(raw)) return;
if (IsRootAndHasBeenSerialized(raw) && SerializeRoot(raw)) return;
}
if (SerializeUsingReadOnlyObjectCache(&sink_, obj)) return;
if (SerializeBackReference(obj)) return;
{
DisallowGarbageCollection no_gc;
HeapObject raw = *obj;
if (SerializeBackReference(raw)) return;
CheckRehashability(raw);
CheckRehashability(*obj);
DCHECK(!ReadOnlyHeap::Contains(raw));
}
DCHECK(!ReadOnlyHeap::Contains(*obj));
ObjectSerializer object_serializer(this, obj, &sink_);
object_serializer.Serialize();
......
......@@ -144,13 +144,17 @@ void StartupSerializer::SerializeObjectImpl(Handle<HeapObject> obj) {
"the isolate snapshot");
}
#endif // DEBUG
DCHECK(!IsUnexpectedCodeObject(isolate(), *obj));
{
DisallowGarbageCollection no_gc;
HeapObject raw = *obj;
DCHECK(!IsUnexpectedCodeObject(isolate(), raw));
if (SerializeHotObject(raw)) return;
if (IsRootAndHasBeenSerialized(raw) && SerializeRoot(raw)) return;
}
if (SerializeHotObject(obj)) return;
if (IsRootAndHasBeenSerialized(*obj) && SerializeRoot(obj)) return;
if (SerializeUsingReadOnlyObjectCache(&sink_, obj)) return;
if (SerializeUsingSharedHeapObjectCache(&sink_, obj)) return;
if (SerializeBackReference(obj)) return;
if (SerializeBackReference(*obj)) return;
bool use_simulator = false;
#ifdef USE_SIMULATOR
......
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