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;
CHECK(!obj->IsCode(cage_base()));
ReadOnlyRoots roots(isolate());
if (ElideObject(*obj)) {
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);
// 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());
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;
instance_type = raw.map().instance_type();
CHECK(!InstanceTypeChecker::IsCode(instance_type));
if (ElideObject(raw)) {
AllowGarbageCollection allow_gc;
return SerializeObject(roots.undefined_value_handle());
}
// 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());
SerializeGeneric(obj);
script_obj->set_host_defined_options(host_options);
script_obj->set_context_data(context_data);
return;
}
if (obj->IsSharedFunctionInfo()) {
Handle<SharedFunctionInfo> sfi = Handle<SharedFunctionInfo>::cast(obj);
DCHECK(!sfi->IsApiFunction());
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 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);
{
DisallowGarbageCollection no_gc;
Script script_obj = Script::cast(*obj);
script_obj.set_host_defined_options(*host_options);
script_obj.set_context_data(*context_data);
}
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());
// TODO(7110): Enable serializing of Asm modules once the AsmWasmData
// is context independent.
DCHECK(!sfi.HasAsmWasmData());
#endif // V8_ENABLE_WEBASSEMBLY
DebugInfo debug_info;
BytecodeArray debug_bytecode_array;
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());
if (sfi.HasDebugInfo()) {
// Clear debug info.
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(raw_debug_info.script(), kReleaseStore);
debug_info = handle(raw_debug_info, isolate());
}
sfi->set_script_or_debug_info(debug_info.script(), kReleaseStore);
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());
// Clear literal boilerplates and feedback.
if (obj->IsFeedbackVector()) {
InstanceType instance_type = obj->map().instance_type();
if (InstanceTypeChecker::IsFeedbackVector(instance_type)) {
// Clear literal boilerplates and feedback.
Handle<FeedbackVector>::cast(obj)->ClearSlots(isolate());
}
// Clear InterruptBudget when serializing FeedbackCell.
if (obj->IsFeedbackCell()) {
} else if (InstanceTypeChecker::IsFeedbackCell(instance_type)) {
// Clear InterruptBudget when serializing FeedbackCell.
Handle<FeedbackCell>::cast(obj)->SetInitialInterruptBudget();
}
if (SerializeJSObjectWithEmbedderFields(obj)) {
return;
}
if (obj->IsJSFunction()) {
// 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();
} else if (InstanceTypeChecker::IsJSObject(instance_type)) {
if (SerializeJSObjectWithEmbedderFields(Handle<JSObject>::cast(obj))) {
return;
}
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.
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);
......
This diff is collapsed.
......@@ -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