blob: c3f9b3eb61d50e7e8bc6acf9846c1aa46ffe4338 [file] [log] [blame]
Ben Murdochda12d292016-06-02 14:46:10 +01001// Copyright 2016 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "src/snapshot/startup-serializer.h"
6
7#include "src/objects-inl.h"
8#include "src/v8threads.h"
9
10namespace v8 {
11namespace internal {
12
13StartupSerializer::StartupSerializer(
14 Isolate* isolate, SnapshotByteSink* sink,
15 FunctionCodeHandling function_code_handling)
16 : Serializer(isolate, sink),
17 function_code_handling_(function_code_handling),
18 serializing_builtins_(false) {
19 InitializeCodeAddressMap();
20}
21
22StartupSerializer::~StartupSerializer() {
23 OutputStatistics("StartupSerializer");
24}
25
26void StartupSerializer::SerializeObject(HeapObject* obj, HowToCode how_to_code,
27 WhereToPoint where_to_point, int skip) {
28 DCHECK(!obj->IsJSFunction());
29
30 if (function_code_handling_ == CLEAR_FUNCTION_CODE) {
31 if (obj->IsCode()) {
32 Code* code = Code::cast(obj);
33 // If the function code is compiled (either as native code or bytecode),
34 // replace it with lazy-compile builtin. Only exception is when we are
35 // serializing the canonical interpreter-entry-trampoline builtin.
36 if (code->kind() == Code::FUNCTION ||
37 (!serializing_builtins_ && code->is_interpreter_entry_trampoline())) {
38 obj = isolate()->builtins()->builtin(Builtins::kCompileLazy);
39 }
40 } else if (obj->IsBytecodeArray()) {
41 obj = isolate()->heap()->undefined_value();
42 }
43 } else if (obj->IsCode()) {
44 DCHECK_EQ(KEEP_FUNCTION_CODE, function_code_handling_);
45 Code* code = Code::cast(obj);
46 if (code->kind() == Code::FUNCTION) {
47 code->ClearInlineCaches();
48 code->set_profiler_ticks(0);
49 }
50 }
51
52 int root_index = root_index_map_.Lookup(obj);
53 // We can only encode roots as such if it has already been serialized.
54 // That applies to root indices below the wave front.
55 if (root_index != RootIndexMap::kInvalidRootIndex) {
56 if (root_has_been_serialized_.test(root_index)) {
57 PutRoot(root_index, obj, how_to_code, where_to_point, skip);
58 return;
59 }
60 }
61
62 if (SerializeKnownObject(obj, how_to_code, where_to_point, skip)) return;
63
64 FlushSkip(skip);
65
66 // Object has not yet been serialized. Serialize it here.
67 ObjectSerializer object_serializer(this, obj, sink_, how_to_code,
68 where_to_point);
69 object_serializer.Serialize();
70
71 if (serializing_immortal_immovables_roots_ &&
72 root_index != RootIndexMap::kInvalidRootIndex) {
73 // Make sure that the immortal immovable root has been included in the first
74 // chunk of its reserved space , so that it is deserialized onto the first
75 // page of its space and stays immortal immovable.
Ben Murdochc5610432016-08-08 18:44:38 +010076 SerializerReference ref = reference_map_.Lookup(obj);
77 CHECK(ref.is_back_reference() && ref.chunk_index() == 0);
Ben Murdochda12d292016-06-02 14:46:10 +010078 }
79}
80
81void StartupSerializer::SerializeWeakReferencesAndDeferred() {
82 // This comes right after serialization of the partial snapshot, where we
83 // add entries to the partial snapshot cache of the startup snapshot. Add
84 // one entry with 'undefined' to terminate the partial snapshot cache.
85 Object* undefined = isolate()->heap()->undefined_value();
86 VisitPointer(&undefined);
87 isolate()->heap()->IterateWeakRoots(this, VISIT_ALL);
88 SerializeDeferredObjects();
89 Pad();
90}
91
92void StartupSerializer::Synchronize(VisitorSynchronization::SyncTag tag) {
93 // We expect the builtins tag after builtins have been serialized.
94 DCHECK(!serializing_builtins_ || tag == VisitorSynchronization::kBuiltins);
95 serializing_builtins_ = (tag == VisitorSynchronization::kHandleScope);
96 sink_->Put(kSynchronize, "Synchronize");
97}
98
99void StartupSerializer::SerializeStrongReferences() {
100 Isolate* isolate = this->isolate();
101 // No active threads.
102 CHECK_NULL(isolate->thread_manager()->FirstThreadStateInUse());
103 // No active or weak handles.
104 CHECK(isolate->handle_scope_implementer()->blocks()->is_empty());
105 CHECK_EQ(0, isolate->global_handles()->NumberOfWeakHandles());
106 CHECK_EQ(0, isolate->eternal_handles()->NumberOfHandles());
107 // We don't support serializing installed extensions.
108 CHECK(!isolate->has_installed_extensions());
109 // First visit immortal immovables to make sure they end up in the first page.
110 serializing_immortal_immovables_roots_ = true;
111 isolate->heap()->IterateStrongRoots(this, VISIT_ONLY_STRONG_ROOT_LIST);
112 // Check that immortal immovable roots are allocated on the first page.
113 CHECK(HasNotExceededFirstPageOfEachSpace());
114 serializing_immortal_immovables_roots_ = false;
115 // Visit the rest of the strong roots.
116 // Clear the stack limits to make the snapshot reproducible.
117 // Reset it again afterwards.
118 isolate->heap()->ClearStackLimits();
119 isolate->heap()->IterateSmiRoots(this);
120 isolate->heap()->SetStackLimits();
121
122 isolate->heap()->IterateStrongRoots(this,
123 VISIT_ONLY_STRONG_FOR_SERIALIZATION);
124}
125
126void StartupSerializer::VisitPointers(Object** start, Object** end) {
127 if (start == isolate()->heap()->roots_array_start()) {
128 // Serializing the root list needs special handling:
129 // - The first pass over the root list only serializes immortal immovables.
130 // - The second pass over the root list serializes the rest.
131 // - Only root list elements that have been fully serialized can be
132 // referenced via as root by using kRootArray bytecodes.
133 int skip = 0;
134 for (Object** current = start; current < end; current++) {
135 int root_index = static_cast<int>(current - start);
136 if (RootShouldBeSkipped(root_index)) {
137 skip += kPointerSize;
138 continue;
139 } else {
140 if ((*current)->IsSmi()) {
141 FlushSkip(skip);
142 PutSmi(Smi::cast(*current));
143 } else {
144 SerializeObject(HeapObject::cast(*current), kPlain, kStartOfObject,
145 skip);
146 }
147 root_has_been_serialized_.set(root_index);
148 skip = 0;
149 }
150 }
151 FlushSkip(skip);
152 } else {
153 Serializer::VisitPointers(start, end);
154 }
155}
156
157bool StartupSerializer::RootShouldBeSkipped(int root_index) {
158 if (root_index == Heap::kStackLimitRootIndex ||
159 root_index == Heap::kRealStackLimitRootIndex) {
160 return true;
161 }
162 return Heap::RootIsImmortalImmovable(root_index) !=
163 serializing_immortal_immovables_roots_;
164}
165
166} // namespace internal
167} // namespace v8