// Copyright 2016 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "src/snapshot/startup-serializer.h" #include "src/api.h" #include "src/code-tracer.h" #include "src/global-handles.h" #include "src/objects-inl.h" #include "src/objects/slots.h" #include "src/snapshot/read-only-serializer.h" #include "src/v8threads.h" namespace v8 { namespace internal { StartupSerializer::StartupSerializer(Isolate* isolate, ReadOnlySerializer* read_only_serializer) : RootsSerializer(isolate, RootIndex::kFirstStrongRoot), read_only_serializer_(read_only_serializer) { InitializeCodeAddressMap(); } StartupSerializer::~StartupSerializer() { RestoreExternalReferenceRedirectors(accessor_infos_); RestoreExternalReferenceRedirectors(call_handler_infos_); OutputStatistics("StartupSerializer"); } namespace { // Due to how we currently create the embedded blob, we may encounter both // off-heap trampolines and old, outdated full Code objects during // serialization. This ensures that we only serialize the canonical version of // each builtin. // See also CreateOffHeapTrampolines(). HeapObject* MaybeCanonicalizeBuiltin(Isolate* isolate, HeapObject* obj) { if (!obj->IsCode()) return obj; const int builtin_index = Code::cast(obj)->builtin_index(); if (!Builtins::IsBuiltinId(builtin_index)) return obj; return isolate->builtins()->builtin(builtin_index); } } // namespace void StartupSerializer::SerializeObject(HeapObject* obj, HowToCode how_to_code, WhereToPoint where_to_point, int skip) { DCHECK(!obj->IsJSFunction()); // TODO(jgruber): Remove canonicalization once off-heap trampoline creation // moves to Isolate::Init(). obj = MaybeCanonicalizeBuiltin(isolate(), obj); if (SerializeHotObject(obj, how_to_code, where_to_point, skip)) return; if (IsRootAndHasBeenSerialized(obj) && SerializeRoot(obj, how_to_code, where_to_point, skip)) return; if (SerializeUsingReadOnlyObjectCache(&sink_, obj, how_to_code, where_to_point, skip)) return; if (SerializeBackReference(obj, how_to_code, where_to_point, skip)) return; FlushSkip(skip); bool use_simulator = false; #ifdef USE_SIMULATOR use_simulator = true; #endif if (use_simulator && obj->IsAccessorInfo()) { // Wipe external reference redirects in the accessor info. AccessorInfo* info = AccessorInfo::cast(obj); Address original_address = Foreign::cast(info->getter())->foreign_address(); Foreign::cast(info->js_getter())->set_foreign_address(original_address); accessor_infos_.push_back(info); } else if (use_simulator && obj->IsCallHandlerInfo()) { CallHandlerInfo* info = CallHandlerInfo::cast(obj); Address original_address = Foreign::cast(info->callback())->foreign_address(); Foreign::cast(info->js_callback())->set_foreign_address(original_address); call_handler_infos_.push_back(info); } else if (obj->IsScript() && Script::cast(obj)->IsUserJavaScript()) { Script::cast(obj)->set_context_data( ReadOnlyRoots(isolate()).uninitialized_symbol()); } else if (obj->IsSharedFunctionInfo()) { // Clear inferred name for native functions. SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj); if (!shared->IsSubjectToDebugging() && shared->HasUncompiledData()) { shared->uncompiled_data()->set_inferred_name( ReadOnlyRoots(isolate()).empty_string()); } } CheckRehashability(obj); // Object has not yet been serialized. Serialize it here. DCHECK(!isolate()->heap()->read_only_space()->Contains(obj)); ObjectSerializer object_serializer(this, obj, &sink_, how_to_code, where_to_point); object_serializer.Serialize(); } void StartupSerializer::SerializeWeakReferencesAndDeferred() { // This comes right after serialization of the partial snapshot, where we // add entries to the partial snapshot cache of the startup snapshot. Add // one entry with 'undefined' to terminate the partial snapshot cache. Object* undefined = ReadOnlyRoots(isolate()).undefined_value(); VisitRootPointer(Root::kPartialSnapshotCache, nullptr, ObjectSlot(&undefined)); isolate()->heap()->IterateWeakRoots(this, VISIT_FOR_SERIALIZATION); SerializeDeferredObjects(); Pad(); } void StartupSerializer::SerializeStrongReferences() { Isolate* isolate = this->isolate(); // No active threads. CHECK_NULL(isolate->thread_manager()->FirstThreadStateInUse()); // No active or weak handles. CHECK(isolate->handle_scope_implementer()->blocks()->empty()); // Visit smi roots. // Clear the stack limits to make the snapshot reproducible. // Reset it again afterwards. isolate->heap()->ClearStackLimits(); isolate->heap()->IterateSmiRoots(this); isolate->heap()->SetStackLimits(); // First visit immortal immovables to make sure they end up in the first page. isolate->heap()->IterateStrongRoots(this, VISIT_FOR_SERIALIZATION); } SerializedHandleChecker::SerializedHandleChecker( Isolate* isolate, std::vector<Context*>* contexts) : isolate_(isolate) { AddToSet(isolate->heap()->serialized_objects()); for (auto const& context : *contexts) { AddToSet(context->serialized_objects()); } } bool StartupSerializer::SerializeUsingReadOnlyObjectCache( SnapshotByteSink* sink, HeapObject* obj, HowToCode how_to_code, WhereToPoint where_to_point, int skip) { return read_only_serializer_->SerializeUsingReadOnlyObjectCache( sink, obj, how_to_code, where_to_point, skip); } void StartupSerializer::SerializeUsingPartialSnapshotCache( SnapshotByteSink* sink, HeapObject* obj, HowToCode how_to_code, WhereToPoint where_to_point, int skip) { FlushSkip(sink, skip); int cache_index = SerializeInObjectCache(obj); sink->Put(kPartialSnapshotCache + how_to_code + where_to_point, "PartialSnapshotCache"); sink->PutInt(cache_index, "partial_snapshot_cache_index"); } void SerializedHandleChecker::AddToSet(FixedArray* serialized) { int length = serialized->length(); for (int i = 0; i < length; i++) serialized_.insert(serialized->get(i)); } void SerializedHandleChecker::VisitRootPointers(Root root, const char* description, ObjectSlot start, ObjectSlot end) { for (ObjectSlot p = start; p < end; ++p) { if (serialized_.find(*p) != serialized_.end()) continue; PrintF("%s handle not serialized: ", root == Root::kGlobalHandles ? "global" : "eternal"); (*p)->Print(); ok_ = false; } } bool SerializedHandleChecker::CheckGlobalAndEternalHandles() { isolate_->global_handles()->IterateAllRoots(this); isolate_->eternal_handles()->IterateAllRoots(this); return ok_; } } // namespace internal } // namespace v8