Bug Summary

File:out/../deps/v8/src/web-snapshot/web-snapshot.cc
Warning:line 1225, column 3
Undefined or garbage value returned to caller

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name web-snapshot.cc -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -ffunction-sections -fdata-sections -fcoverage-compilation-dir=/home/maurizio/node-v18.6.0/out -resource-dir /usr/local/lib/clang/16.0.0 -D _GLIBCXX_USE_CXX11_ABI=1 -D NODE_OPENSSL_CONF_NAME=nodejs_conf -D NODE_OPENSSL_HAS_QUIC -D V8_GYP_BUILD -D V8_TYPED_ARRAY_MAX_SIZE_IN_HEAP=64 -D __STDC_FORMAT_MACROS -D OPENSSL_NO_PINSHARED -D OPENSSL_THREADS -D V8_TARGET_ARCH_X64 -D V8_HAVE_TARGET_OS -D V8_TARGET_OS_LINUX -D V8_EMBEDDER_STRING="-node.8" -D ENABLE_DISASSEMBLER -D V8_PROMISE_INTERNAL_FIELD_COUNT=1 -D V8_SHORT_BUILTIN_CALLS -D OBJECT_PRINT -D V8_INTL_SUPPORT -D V8_ATOMIC_OBJECT_FIELD_WRITES -D V8_ENABLE_LAZY_SOURCE_POSITIONS -D V8_USE_SIPHASH -D V8_SHARED_RO_HEAP -D V8_WIN64_UNWINDING_INFO -D V8_ENABLE_REGEXP_INTERPRETER_THREADED_DISPATCH -D V8_SNAPSHOT_COMPRESSION -D V8_ENABLE_WEBASSEMBLY -D V8_ENABLE_JAVASCRIPT_PROMISE_HOOKS -D V8_ALLOCATION_FOLDING -D V8_ALLOCATION_SITE_TRACKING -D V8_SCRIPTORMODULE_LEGACY_LIFETIME -D V8_ADVANCED_BIGINT_ALGORITHMS -D ICU_UTIL_DATA_IMPL=ICU_UTIL_DATA_STATIC -D UCONFIG_NO_SERVICE=1 -D U_ENABLE_DYLOAD=0 -D U_STATIC_IMPLEMENTATION=1 -D U_HAVE_STD_STRING=1 -D UCONFIG_NO_BREAK_ITERATION=0 -I ../deps/v8 -I ../deps/v8/include -I /home/maurizio/node-v18.6.0/out/Release/obj/gen/inspector-generated-output-root -I ../deps/v8/third_party/inspector_protocol -I /home/maurizio/node-v18.6.0/out/Release/obj/gen -I /home/maurizio/node-v18.6.0/out/Release/obj/gen/generate-bytecode-output-root -I ../deps/icu-small/source/i18n -I ../deps/icu-small/source/common -I ../deps/v8/third_party/zlib -I ../deps/v8/third_party/zlib/google -internal-isystem /usr/lib/gcc/x86_64-redhat-linux/8/../../../../include/c++/8 -internal-isystem /usr/lib/gcc/x86_64-redhat-linux/8/../../../../include/c++/8/x86_64-redhat-linux -internal-isystem /usr/lib/gcc/x86_64-redhat-linux/8/../../../../include/c++/8/backward -internal-isystem /usr/local/lib/clang/16.0.0/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-redhat-linux/8/../../../../x86_64-redhat-linux/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O3 -Wno-unused-parameter -Wno-return-type -std=gnu++17 -fdeprecated-macro -fdebug-compilation-dir=/home/maurizio/node-v18.6.0/out -ferror-limit 19 -fno-rtti -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2022-08-22-142216-507842-1 -x c++ ../deps/v8/src/web-snapshot/web-snapshot.cc

../deps/v8/src/web-snapshot/web-snapshot.cc

1// Copyright 2021 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/web-snapshot/web-snapshot.h"
6
7#include <limits>
8
9#include "include/v8-isolate.h"
10#include "include/v8-local-handle.h"
11#include "include/v8-object.h"
12#include "include/v8-primitive.h"
13#include "include/v8-script.h"
14#include "src/api/api-inl.h"
15#include "src/base/platform/wrappers.h"
16#include "src/handles/handles.h"
17#include "src/logging/runtime-call-stats-scope.h"
18#include "src/objects/contexts.h"
19#include "src/objects/js-regexp-inl.h"
20#include "src/objects/script.h"
21
22namespace v8 {
23namespace internal {
24
25constexpr uint8_t WebSnapshotSerializerDeserializer::kMagicNumber[4];
26
27// When encountering an error during deserializing, we note down the error but
28// don't bail out from processing the snapshot further. This is to speed up
29// deserialization; the error case is now slower since we don't bail out, but
30// the non-error case is faster, since we don't repeatedly check for errors.
31// (Invariant: we might fill our internal data structures with arbitrary data,
32// but it shouldn't have an observable effect.)
33
34// This doesn't increase the complexity of processing the data in a robust and
35// secure way. We cannot trust the data anyway, so every upcoming byte can have
36// an arbitrary value, not depending on whether or not we've encountered an
37// error before.
38void WebSnapshotSerializerDeserializer::Throw(const char* message) {
39 if (error_message_ != nullptr) {
40 return;
41 }
42 error_message_ = message;
43 if (!isolate_->has_pending_exception()) {
44 isolate_->Throw(*factory()->NewError(
45 MessageTemplate::kWebSnapshotError,
46 factory()->NewStringFromAsciiChecked(error_message_)));
47 }
48}
49
50uint32_t WebSnapshotSerializerDeserializer::FunctionKindToFunctionFlags(
51 FunctionKind kind) {
52 // TODO(v8:11525): Support more function kinds.
53 switch (kind) {
54 case FunctionKind::kNormalFunction:
55 case FunctionKind::kArrowFunction:
56 case FunctionKind::kGeneratorFunction:
57 case FunctionKind::kAsyncFunction:
58 case FunctionKind::kAsyncArrowFunction:
59 case FunctionKind::kAsyncGeneratorFunction:
60 case FunctionKind::kBaseConstructor:
61 case FunctionKind::kDefaultBaseConstructor:
62 case FunctionKind::kConciseMethod:
63 case FunctionKind::kAsyncConciseMethod:
64 break;
65 default:
66 Throw("Unsupported function kind");
67 }
68 auto flags = AsyncFunctionBitField::encode(IsAsyncFunction(kind)) |
69 GeneratorFunctionBitField::encode(IsGeneratorFunction(kind)) |
70 ArrowFunctionBitField::encode(IsArrowFunction(kind)) |
71 MethodBitField::encode(IsConciseMethod(kind)) |
72 StaticBitField::encode(IsStatic(kind)) |
73 ClassConstructorBitField::encode(IsClassConstructor(kind)) |
74 DefaultConstructorBitField::encode(IsDefaultConstructor(kind)) |
75 DerivedConstructorBitField::encode(IsDerivedConstructor(kind));
76 return flags;
77}
78
79// TODO(v8:11525): Optionally, use an enum instead.
80FunctionKind WebSnapshotSerializerDeserializer::FunctionFlagsToFunctionKind(
81 uint32_t flags) {
82 FunctionKind kind;
83 if (IsFunctionOrMethod(flags)) {
84 if (ArrowFunctionBitField::decode(flags) && MethodBitField::decode(flags)) {
85 kind = FunctionKind::kInvalid;
86 } else {
87 uint32_t index = AsyncFunctionBitField::decode(flags) << 0 |
88 GeneratorFunctionBitField::decode(flags) << 1 |
89 (ArrowFunctionBitField::decode(flags) ||
90 StaticBitField::decode(flags))
91 << 2 |
92 MethodBitField::decode(flags) << 3;
93 static const FunctionKind kFunctionKinds[] = {
94 // kNormalFunction
95 // is_generator = false
96 FunctionKind::kNormalFunction, // is_async = false
97 FunctionKind::kAsyncFunction, // is_async = true
98 // is_generator = true
99 FunctionKind::kGeneratorFunction, // is_async = false
100 FunctionKind::kAsyncGeneratorFunction, // is_async = true
101
102 // kArrowFunction
103 // is_generator = false
104 FunctionKind::kArrowFunction, // is_async = false
105 FunctionKind::kAsyncArrowFunction, // is_async = true
106 // is_generator = true
107 FunctionKind::kInvalid, // is_async = false
108 FunctionKind::kInvalid, // is_async = true
109
110 // kNonStaticMethod
111 // is_generator = false
112 FunctionKind::kConciseMethod, // is_async = false
113 FunctionKind::kAsyncConciseMethod, // is_async = true
114 // is_generator = true
115 // TODO(v8::11525) Support FunctionKind::kConciseGeneratorMethod.
116 FunctionKind::kInvalid, // is_async = false
117 // TODO(v8::11525) Support FunctionKind::kAsyncConciseGeneratorMethod.
118 FunctionKind::kInvalid, // is_async = true
119
120 // kStaticMethod
121 // is_generator = false
122 // TODO(v8::11525) Support FunctionKind::kStaticConciseMethod.
123 FunctionKind::kInvalid, // is_async = false
124 // TODO(v8::11525) Support FunctionKind::kStaticAsyncConciseMethod.
125 FunctionKind::kInvalid, // is_async = true
126 // is_generator = true
127 // TODO(v8::11525) Support
128 // FunctionKind::kStaticConciseGeneratorMethod.
129 FunctionKind::kInvalid, // is_async = false
130 // TODO(v8::11525) Support
131 // FunctionKind::kStaticAsyncConciseGeneratorMethod.
132 FunctionKind::kInvalid // is_async = true
133 };
134 kind = kFunctionKinds[index];
135 }
136 } else if (IsConstructor(flags)) {
137 static const FunctionKind kFunctionKinds[] = {
138 // is_derived = false
139 FunctionKind::kBaseConstructor, // is_default = false
140 FunctionKind::kDefaultBaseConstructor, // is_default = true
141 // is_derived = true
142 FunctionKind::kDerivedConstructor, // is_default = false
143 FunctionKind::kDefaultDerivedConstructor // is_default = true
144 };
145 kind = kFunctionKinds[flags >> DefaultConstructorBitField::kShift];
146 } else {
147 kind = FunctionKind::kInvalid;
148 }
149 if (kind == FunctionKind::kInvalid) {
150 Throw("Invalid function flags\n");
151 }
152 return kind;
153}
154
155bool WebSnapshotSerializerDeserializer::IsFunctionOrMethod(uint32_t flags) {
156 uint32_t mask = AsyncFunctionBitField::kMask |
157 GeneratorFunctionBitField::kMask |
158 ArrowFunctionBitField::kMask | MethodBitField::kMask |
159 StaticBitField::kMask;
160 return (flags & mask) == flags;
161}
162
163bool WebSnapshotSerializerDeserializer::IsConstructor(uint32_t flags) {
164 uint32_t mask = ClassConstructorBitField::kMask |
165 DefaultConstructorBitField::kMask |
166 DerivedConstructorBitField::kMask;
167 return ClassConstructorBitField::decode(flags) && (flags & mask) == flags;
168}
169
170uint32_t WebSnapshotSerializerDeserializer::GetDefaultAttributeFlags() {
171 auto flags = ReadOnlyBitField::encode(false) |
172 ConfigurableBitField::encode(true) |
173 EnumerableBitField::encode(true);
174 return flags;
175}
176
177uint32_t WebSnapshotSerializerDeserializer::AttributesToFlags(
178 PropertyDetails details) {
179 auto flags = ReadOnlyBitField::encode(details.IsReadOnly()) |
180 ConfigurableBitField::encode(details.IsConfigurable()) |
181 EnumerableBitField::encode(details.IsEnumerable());
182 return flags;
183}
184
185PropertyAttributes WebSnapshotSerializerDeserializer::FlagsToAttributes(
186 uint32_t flags) {
187 int attributes = ReadOnlyBitField::decode(flags) * READ_ONLY +
188 !ConfigurableBitField::decode(flags) * DONT_DELETE +
189 !EnumerableBitField::decode(flags) * DONT_ENUM;
190 return PropertyAttributesFromInt(attributes);
191}
192
193WebSnapshotSerializer::WebSnapshotSerializer(v8::Isolate* isolate)
194 : WebSnapshotSerializer(reinterpret_cast<v8::internal::Isolate*>(isolate)) {
195}
196
197WebSnapshotSerializer::WebSnapshotSerializer(Isolate* isolate)
198 : WebSnapshotSerializerDeserializer(isolate),
199 string_serializer_(isolate_, nullptr),
200 map_serializer_(isolate_, nullptr),
201 context_serializer_(isolate_, nullptr),
202 function_serializer_(isolate_, nullptr),
203 class_serializer_(isolate_, nullptr),
204 array_serializer_(isolate_, nullptr),
205 object_serializer_(isolate_, nullptr),
206 export_serializer_(isolate_, nullptr),
207 external_objects_ids_(isolate_->heap()),
208 string_ids_(isolate_->heap()),
209 map_ids_(isolate_->heap()),
210 context_ids_(isolate_->heap()),
211 function_ids_(isolate_->heap()),
212 class_ids_(isolate_->heap()),
213 array_ids_(isolate_->heap()),
214 object_ids_(isolate_->heap()),
215 all_strings_(isolate_->heap()) {
216 auto empty_array_list = factory()->empty_array_list();
217 contexts_ = empty_array_list;
218 functions_ = empty_array_list;
219 classes_ = empty_array_list;
220 arrays_ = empty_array_list;
221 objects_ = empty_array_list;
222 strings_ = empty_array_list;
223 maps_ = empty_array_list;
224}
225
226WebSnapshotSerializer::~WebSnapshotSerializer() {}
227
228bool WebSnapshotSerializer::TakeSnapshot(
229 Handle<Object> object, MaybeHandle<FixedArray> maybe_externals,
230 WebSnapshotData& data_out) {
231 if (string_ids_.size() > 0) {
232 Throw("Can't reuse WebSnapshotSerializer");
233 return false;
234 }
235 if (!maybe_externals.is_null()) {
236 ShallowDiscoverExternals(*maybe_externals.ToHandleChecked());
237 }
238
239 if (object->IsHeapObject()) Discover(Handle<HeapObject>::cast(object));
240
241 ConstructSource();
242 // The export is serialized with the empty string as name; we need to
243 // "discover" the name here.
244 DiscoverString(factory()->empty_string());
245 SerializeExport(object, factory()->empty_string());
246
247 WriteSnapshot(data_out.buffer, data_out.buffer_size);
248
249 if (has_error()) {
250 isolate_->ReportPendingMessages();
251 return false;
252 }
253 return true;
254}
255
256bool WebSnapshotSerializer::TakeSnapshot(v8::Local<v8::Context> context,
257 v8::Local<v8::PrimitiveArray> exports,
258 WebSnapshotData& data_out) {
259 if (string_ids_.size() > 0) {
260 Throw("Can't reuse WebSnapshotSerializer");
261 return false;
262 }
263 v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate_);
264
265 std::unique_ptr<Handle<JSObject>[]> export_objects(
266 new Handle<JSObject>[exports->Length()]);
267 for (int i = 0, length = exports->Length(); i < length; ++i) {
268 v8::Local<v8::String> str =
269 exports->Get(v8_isolate, i)->ToString(context).ToLocalChecked();
270 if (str->Length() == 0) {
271 continue;
272 }
273 // Discover the export name.
274 DiscoverString(Handle<String>::cast(Utils::OpenHandle(*str)));
275 v8::ScriptCompiler::Source source(str);
276 auto script = ScriptCompiler::Compile(context, &source).ToLocalChecked();
277 v8::MaybeLocal<v8::Value> script_result = script->Run(context);
278 v8::Local<v8::Object> v8_object;
279 if (script_result.IsEmpty() ||
280 !script_result.ToLocalChecked()->ToObject(context).ToLocal(
281 &v8_object)) {
282 Throw("Exported object not found");
283 return false;
284 }
285 export_objects[i] = Handle<JSObject>::cast(Utils::OpenHandle(*v8_object));
286 Discover(export_objects[i]);
287 }
288
289 ConstructSource();
290
291 for (int i = 0, length = exports->Length(); i < length; ++i) {
292 v8::Local<v8::String> str =
293 exports->Get(v8_isolate, i)->ToString(context).ToLocalChecked();
294 if (str->Length() == 0) {
295 continue;
296 }
297 SerializeExport(export_objects[i],
298 Handle<String>::cast(Utils::OpenHandle(*str)));
299 }
300
301 WriteSnapshot(data_out.buffer, data_out.buffer_size);
302
303 if (has_error()) {
304 isolate_->ReportPendingMessages();
305 return false;
306 }
307 return true;
308}
309
310void WebSnapshotSerializer::SerializePendingItems() {
311 // The information about string reference counts is now complete. The strings
312 // in strings_ are not in place and can be serialized now. The in-place
313 // strings will be serialized as part of their respective objects.
314 for (int i = 0; i < strings_->Length(); ++i) {
315 Handle<String> string = handle(String::cast(strings_->Get(i)), isolate_);
316 SerializeString(string, string_serializer_);
317 }
318
319 for (int i = 0; i < maps_->Length(); ++i) {
320 Handle<Map> map = handle(Map::cast(maps_->Get(i)), isolate_);
321 SerializeMap(map);
322 }
323
324 // Serialize the items in the reverse order. The items at the end of the
325 // contexts_ etc get lower IDs and vice versa. IDs which items use for
326 // referring to each other are reversed by Get<item>Id functions().
327 for (int i = contexts_->Length() - 1; i >= 0; --i) {
328 Handle<Context> context =
329 handle(Context::cast(contexts_->Get(i)), isolate_);
330 SerializeContext(context);
331 }
332 for (int i = functions_->Length() - 1; i >= 0; --i) {
333 Handle<JSFunction> function =
334 handle(JSFunction::cast(functions_->Get(i)), isolate_);
335 SerializeFunction(function);
336 }
337 for (int i = classes_->Length() - 1; i >= 0; --i) {
338 Handle<JSFunction> function =
339 handle(JSFunction::cast(classes_->Get(i)), isolate_);
340 SerializeClass(function);
341 }
342 for (int i = arrays_->Length() - 1; i >= 0; --i) {
343 Handle<JSArray> array = handle(JSArray::cast(arrays_->Get(i)), isolate_);
344 SerializeArray(array);
345 }
346 for (int i = objects_->Length() - 1; i >= 0; --i) {
347 Handle<JSObject> object =
348 handle(JSObject::cast(objects_->Get(i)), isolate_);
349 SerializeObject(object);
350 }
351}
352
353// Format (full snapshot):
354// - Magic number (4 bytes)
355// - String count
356// - For each string:
357// - Serialized string
358// - Shape count
359// - For each shape:
360// - Serialized shape
361// - Context count
362// - For each context:
363// - Serialized context
364// - Function count
365// - For each function:
366// - Serialized function
367// - Object count
368// - For each object:
369// - Serialized object
370// - Export count
371// - For each export:
372// - Serialized export
373void WebSnapshotSerializer::WriteSnapshot(uint8_t*& buffer,
374 size_t& buffer_size) {
375 if (has_error()) {
376 return;
377 }
378 SerializePendingItems();
379
380 ValueSerializer total_serializer(isolate_, nullptr);
381 size_t needed_size =
382 sizeof(kMagicNumber) + string_serializer_.buffer_size_ +
383 map_serializer_.buffer_size_ + context_serializer_.buffer_size_ +
384 function_serializer_.buffer_size_ + class_serializer_.buffer_size_ +
385 array_serializer_.buffer_size_ + object_serializer_.buffer_size_ +
386 export_serializer_.buffer_size_ + 8 * sizeof(uint32_t);
387 if (total_serializer.ExpandBuffer(needed_size).IsNothing()) {
388 Throw("Out of memory");
389 return;
390 }
391
392 total_serializer.WriteRawBytes(kMagicNumber, 4);
393 WriteObjects(total_serializer, string_count(), string_serializer_, "strings");
394 WriteObjects(total_serializer, map_count(), map_serializer_, "maps");
395 WriteObjects(total_serializer, context_count(), context_serializer_,
396 "contexts");
397 WriteObjects(total_serializer, function_count(), function_serializer_,
398 "functions");
399 WriteObjects(total_serializer, array_count(), array_serializer_, "arrays");
400 WriteObjects(total_serializer, object_count(), object_serializer_, "objects");
401 WriteObjects(total_serializer, class_count(), class_serializer_, "classes");
402 WriteObjects(total_serializer, export_count_, export_serializer_, "exports");
403
404 if (has_error()) {
405 return;
406 }
407
408 auto result = total_serializer.Release();
409 buffer = result.first;
410 buffer_size = result.second;
411}
412void WebSnapshotSerializer::WriteObjects(ValueSerializer& destination,
413 size_t count, ValueSerializer& source,
414 const char* name) {
415 if (count > std::numeric_limits<uint32_t>::max()) {
416 Throw("Too many objects");
417 return;
418 }
419 destination.WriteUint32(static_cast<uint32_t>(count));
420 destination.WriteRawBytes(source.buffer_, source.buffer_size_);
421}
422
423bool WebSnapshotSerializer::InsertIntoIndexMap(ObjectCacheIndexMap& map,
424 HeapObject heap_object,
425 uint32_t& id) {
426 DisallowGarbageCollection no_gc;
427 int index_out;
428 if (external_objects_ids_.Lookup(heap_object, &index_out)) {
429 return true;
430 }
431 bool found = map.LookupOrInsert(heap_object, &index_out);
432 id = static_cast<uint32_t>(index_out);
433 return found;
434}
435
436// Format:
437// - Length
438// - Raw bytes (data)
439void WebSnapshotSerializer::SerializeString(Handle<String> string,
440 ValueSerializer& serializer) {
441 DisallowGarbageCollection no_gc;
442 String::FlatContent flat = string->GetFlatContent(no_gc);
443 DCHECK(flat.IsFlat())((void) 0);
444 if (flat.IsOneByte()) {
445 base::Vector<const uint8_t> chars = flat.ToOneByteVector();
446 serializer.WriteUint32(chars.length());
447 serializer.WriteRawBytes(chars.begin(), chars.length() * sizeof(uint8_t));
448 } else if (flat.IsTwoByte()) {
449 v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate_);
450 v8::Local<v8::String> api_string = Utils::ToLocal(string);
451 int length = api_string->Utf8Length(v8_isolate);
452 std::unique_ptr<char[]> buffer(new char[length]);
453 api_string->WriteUtf8(v8_isolate, buffer.get(), length);
454 serializer.WriteUint32(length);
455 serializer.WriteRawBytes(buffer.get(), length * sizeof(uint8_t));
456 } else {
457 UNREACHABLE()V8_Fatal("unreachable code");
458 }
459}
460
461// Format (serialized shape):
462// - PropertyAttributesType
463// - 0 if the __proto__ is Object.prototype, 1 + object id for the __proto__
464// otherwise
465// - Property count
466// - For each property
467// - String id (name)
468// - If the PropertyAttributesType is CUSTOM: attributes
469void WebSnapshotSerializer::SerializeMap(Handle<Map> map) {
470 int first_custom_index = -1;
471 std::vector<Handle<String>> keys;
472 std::vector<uint32_t> attributes;
473 keys.reserve(map->NumberOfOwnDescriptors());
474 attributes.reserve(map->NumberOfOwnDescriptors());
475 for (InternalIndex i : map->IterateOwnDescriptors()) {
476 Handle<Name> key(map->instance_descriptors(kRelaxedLoad).GetKey(i),
477 isolate_);
478 keys.push_back(Handle<String>::cast(key));
479
480 PropertyDetails details =
481 map->instance_descriptors(kRelaxedLoad).GetDetails(i);
482
483 if (details.location() != PropertyLocation::kField) {
484 Throw("Properties which are not fields not supported");
485 return;
486 }
487 if (first_custom_index >= 0 || details.IsReadOnly() ||
488 !details.IsConfigurable() || details.IsDontEnum()) {
489 if (first_custom_index == -1) first_custom_index = i.as_int();
490 attributes.push_back(AttributesToFlags(details));
491 }
492 }
493
494 map_serializer_.WriteUint32(first_custom_index == -1
495 ? PropertyAttributesType::DEFAULT
496 : PropertyAttributesType::CUSTOM);
497
498 if (map->prototype() ==
499 isolate_->native_context()->initial_object_prototype()) {
500 map_serializer_.WriteUint32(0);
501 } else {
502 // TODO(v8:11525): Support non-JSObject prototypes, at least null. Recognize
503 // well-known objects to that we don't end up encoding them in the snapshot.
504 if (!map->prototype().IsJSObject()) {
505 Throw("Non-JSObject __proto__s not supported");
506 return;
507 }
508 uint32_t prototype_id = GetObjectId(JSObject::cast(map->prototype()));
509 map_serializer_.WriteUint32(prototype_id + 1);
510 }
511
512 map_serializer_.WriteUint32(static_cast<uint32_t>(keys.size()));
513
514 uint32_t default_flags = GetDefaultAttributeFlags();
515 for (size_t i = 0; i < keys.size(); ++i) {
516 if (first_custom_index >= 0) {
517 if (static_cast<int>(i) < first_custom_index) {
518 map_serializer_.WriteUint32(default_flags);
519 } else {
520 map_serializer_.WriteUint32(attributes[i - first_custom_index]);
521 }
522 }
523 WriteStringId(keys[i], map_serializer_);
524 }
525}
526
527// Construct the minimal source string to be included in the snapshot. Maintain
528// the "inner function is textually inside its outer function" relationship.
529// Example:
530// Input:
531// Full source: abcdefghijklmnopqrstuvwxyzåäö
532// Functions: 11111111 22222222 3
533// Inner functions: 44 55 666
534// Output:
535// Constructed source: defghijkstuvwxyzö
536// Functions: 11111111222222223
537// Inner functions 44 55 666
538void WebSnapshotSerializer::ConstructSource() {
539 if (source_intervals_.empty()) {
540 return;
541 }
542
543 Handle<String> source_string = factory()->empty_string();
544 int current_interval_start = 0;
545 int current_interval_end = 0;
546 for (const auto& interval : source_intervals_) {
547 DCHECK_LE(current_interval_start, interval.first)((void) 0); // Iterated in order.
548 DCHECK_LE(interval.first, interval.second)((void) 0);
549 if (interval.second <= current_interval_end) {
550 // This interval is fully within the current interval. We don't need to
551 // include any new source code, just record the position conversion.
552 auto offset_within_parent = interval.first - current_interval_start;
553 source_offset_to_compacted_source_offset_[interval.first] =
554 source_offset_to_compacted_source_offset_[current_interval_start] +
555 offset_within_parent;
556 continue;
557 }
558 // Start a new interval.
559 current_interval_start = interval.first;
560 current_interval_end = interval.second;
561 source_offset_to_compacted_source_offset_[current_interval_start] =
562 source_string->length();
563 MaybeHandle<String> new_source_string = factory()->NewConsString(
564 source_string,
565 factory()->NewSubString(full_source_, current_interval_start,
566 current_interval_end));
567 if (!new_source_string.ToHandle(&source_string)) {
568 Throw("Cannot construct source string");
569 return;
570 }
571 }
572 DiscoverString(source_string);
573 bool in_place = false;
574 source_id_ = GetStringId(source_string, in_place);
575 DCHECK(!in_place)((void) 0);
576}
577
578void WebSnapshotSerializer::SerializeFunctionInfo(ValueSerializer* serializer,
579 Handle<JSFunction> function) {
580 if (!function->shared().HasSourceCode()) {
581 Throw("Function without source code");
582 return;
583 }
584
585 {
586 DisallowGarbageCollection no_gc;
587 Context context = function->context();
588 if (context.IsNativeContext() || context.IsScriptContext()) {
589 serializer->WriteUint32(0);
590 } else {
591 DCHECK(context.IsFunctionContext() || context.IsBlockContext())((void) 0);
592 uint32_t context_id = GetContextId(context);
593 serializer->WriteUint32(context_id + 1);
594 }
595 }
596
597 serializer->WriteUint32(source_id_);
598 int start = function->shared().StartPosition();
599 int end = function->shared().EndPosition();
600 serializer->WriteUint32(source_offset_to_compacted_source_offset_[start]);
601 serializer->WriteUint32(end - start);
602
603 serializer->WriteUint32(
604 function->shared().internal_formal_parameter_count_without_receiver());
605 serializer->WriteUint32(
606 FunctionKindToFunctionFlags(function->shared().kind()));
607
608 if (function->has_prototype_slot() && function->has_instance_prototype()) {
609 DisallowGarbageCollection no_gc;
610 JSObject prototype = JSObject::cast(function->instance_prototype());
611 uint32_t prototype_id = GetObjectId(prototype);
612 serializer->WriteUint32(prototype_id + 1);
613 } else {
614 serializer->WriteUint32(0);
615 }
616}
617
618void WebSnapshotSerializer::ShallowDiscoverExternals(FixedArray externals) {
619 DisallowGarbageCollection no_gc;
620 for (int i = 0; i < externals.length(); i++) {
621 Object object = externals.get(i);
622 if (!object.IsHeapObject()) continue;
623 uint32_t unused_id = 0;
624 InsertIntoIndexMap(external_objects_ids_, HeapObject::cast(object),
625 unused_id);
626 }
627}
628
629void WebSnapshotSerializer::Discover(Handle<HeapObject> start_object) {
630 // The object discovery phase assigns IDs for objects / functions / classes /
631 // arrays and discovers outgoing references from them. This is needed so that
632 // e.g., we know all functions upfront and can construct the source code that
633 // covers them before serializing the functions.
634
635 discovery_queue_.push(start_object);
636
637 while (!discovery_queue_.empty()) {
638 const Handle<HeapObject>& object = discovery_queue_.front();
639 switch (object->map().instance_type()) {
640 case JS_FUNCTION_TYPE:
641 DiscoverFunction(Handle<JSFunction>::cast(object));
642 break;
643 case JS_CLASS_CONSTRUCTOR_TYPE:
644 DiscoverClass(Handle<JSFunction>::cast(object));
645 break;
646 case JS_OBJECT_TYPE:
647 DiscoverObject(Handle<JSObject>::cast(object));
648 break;
649 case JS_ARRAY_TYPE:
650 DiscoverArray(Handle<JSArray>::cast(object));
651 break;
652 case ODDBALL_TYPE:
653 case HEAP_NUMBER_TYPE:
654 // Can't contain references to other objects.
655 break;
656 case JS_PRIMITIVE_WRAPPER_TYPE: {
657 Handle<JSPrimitiveWrapper> wrapper =
658 Handle<JSPrimitiveWrapper>::cast(object);
659 Handle<Object> value = handle(wrapper->value(), isolate_);
660 if (value->IsHeapObject()) {
661 discovery_queue_.push(Handle<HeapObject>::cast(value));
662 }
663 break;
664 }
665 case JS_REG_EXP_TYPE: {
666 Handle<JSRegExp> regexp = Handle<JSRegExp>::cast(object);
667 Handle<String> pattern = handle(regexp->source(), isolate_);
668 DiscoverString(pattern);
669 Handle<String> flags_string =
670 JSRegExp::StringFromFlags(isolate_, regexp->flags());
671 DiscoverString(flags_string);
672 break;
673 }
674 default:
675 if (object->IsString()) {
676 // These are array elements / object properties -> allow in place
677 // strings.
678 DiscoverString(Handle<String>::cast(object), AllowInPlace::Yes);
679 break;
680 } else if (external_objects_ids_.size() > 0) {
681 int unused_id;
682 external_objects_ids_.LookupOrInsert(*object, &unused_id);
683 } else {
684 Throw("Unsupported object");
685 }
686 }
687 discovery_queue_.pop();
688 }
689}
690
691void WebSnapshotSerializer::DiscoverMap(Handle<Map> map) {
692 uint32_t id;
693 if (InsertIntoIndexMap(map_ids_, *map, id)) {
694 return;
695 }
696 DCHECK_EQ(id, maps_->Length())((void) 0);
697 maps_ = ArrayList::Add(isolate_, maps_, map);
698 for (InternalIndex i : map->IterateOwnDescriptors()) {
699 Handle<Name> key(map->instance_descriptors(kRelaxedLoad).GetKey(i),
700 isolate_);
701 if (!key->IsString()) {
702 Throw("Key is not a string");
703 return;
704 }
705 DiscoverString(Handle<String>::cast(key));
706 }
707}
708
709void WebSnapshotSerializer::DiscoverString(Handle<String> string,
710 AllowInPlace can_be_in_place) {
711 // Can't contain references to other objects. We only log the existence of the
712 // string itself. Internalize the strings so that we can properly track which
713 // String objects are the same string.
714 string = factory()->InternalizeString(string);
715 auto result = all_strings_.FindOrInsert(string);
716 if (can_be_in_place == AllowInPlace::Yes && !result.already_exists) {
717 // This is the only reference to the string so far. Don't generate and
718 // ID for it yet; only generate it when another reference to the string is
719 // found.
720 return;
721 }
722 // The string is referred to more than two places, or in-placing not allowed
723 // -> not a candidate for writing it in-place. Generate an ID for it.
724
725 // TODO(v8:11525): Allow in-place strings in more places. Heuristics for
726 // when to make them in place?
727 uint32_t id;
728 if (InsertIntoIndexMap(string_ids_, *string, id)) {
729 return;
730 }
731 DCHECK_EQ(id, strings_->Length())((void) 0);
732 strings_ = ArrayList::Add(isolate_, strings_, string);
733}
734
735void WebSnapshotSerializer::DiscoverFunction(Handle<JSFunction> function) {
736 uint32_t id;
737 if (InsertIntoIndexMap(function_ids_, *function, id)) {
738 return;
739 }
740
741 DCHECK_EQ(id, functions_->Length())((void) 0);
742 functions_ = ArrayList::Add(isolate_, functions_, function);
743 DiscoverContextAndPrototype(function);
744 // TODO(v8:11525): Support properties in functions.
745 DiscoverSource(function);
746}
747
748void WebSnapshotSerializer::DiscoverClass(Handle<JSFunction> function) {
749 uint32_t id;
750 if (InsertIntoIndexMap(class_ids_, *function, id)) {
751 return;
752 }
753
754 DCHECK_EQ(id, classes_->Length())((void) 0);
755 classes_ = ArrayList::Add(isolate_, classes_, function);
756
757 DiscoverContextAndPrototype(function);
758 // TODO(v8:11525): Support properties in classes.
759 // TODO(v8:11525): Support class members.
760 DiscoverSource(function);
761}
762
763void WebSnapshotSerializer::DiscoverContextAndPrototype(
764 Handle<JSFunction> function) {
765 Handle<Context> context(function->context(), isolate_);
766 if (context->IsFunctionContext() || context->IsBlockContext()) {
767 DiscoverContext(context);
768 }
769
770 if (function->has_prototype_slot() &&
771 function->map().has_non_instance_prototype()) {
772 Throw("Functions with non-instance prototypes not supported");
773 return;
774 }
775
776 if (function->has_prototype_slot() && function->has_instance_prototype()) {
777 Handle<JSObject> prototype = Handle<JSObject>::cast(
778 handle(function->instance_prototype(), isolate_));
779 discovery_queue_.push(prototype);
780 }
781}
782
783void WebSnapshotSerializer::DiscoverContext(Handle<Context> context) {
784 uint32_t id;
785 if (InsertIntoIndexMap(context_ids_, *context, id)) return;
786
787 DCHECK_EQ(id, contexts_->Length())((void) 0);
788 contexts_ = ArrayList::Add(isolate_, contexts_, context);
789
790 Handle<ScopeInfo> scope_info = handle(context->scope_info(), isolate_);
791 int count = scope_info->ContextLocalCount();
792
793 for (int i = 0; i < count; ++i) {
794 // TODO(v8:11525): support parameters
795 // TODO(v8:11525): distinguish variable modes
796 Handle<String> name(scope_info->context_local_names(i), isolate_);
797 DiscoverString(name);
798 Object value = context->get(scope_info->ContextHeaderLength() + i);
799 if (!value.IsHeapObject()) continue;
800 discovery_queue_.push(handle(HeapObject::cast(value), isolate_));
801 }
802
803 if (!context->previous().IsNativeContext() &&
804 !context->previous().IsScriptContext()) {
805 DiscoverContext(handle(context->previous(), isolate_));
806 }
807}
808
809void WebSnapshotSerializer::DiscoverSource(Handle<JSFunction> function) {
810 source_intervals_.emplace(function->shared().StartPosition(),
811 function->shared().EndPosition());
812 Handle<String> function_script_source =
813 handle(String::cast(Script::cast(function->shared().script()).source()),
814 isolate_);
815 if (full_source_.is_null()) {
816 full_source_ = function_script_source;
817 } else if (!full_source_->Equals(*function_script_source)) {
818 Throw("Cannot include functions from multiple scripts");
819 }
820}
821
822void WebSnapshotSerializer::DiscoverArray(Handle<JSArray> array) {
823 uint32_t id;
824 if (InsertIntoIndexMap(array_ids_, *array, id)) {
825 return;
826 }
827 DCHECK_EQ(id, arrays_->Length())((void) 0);
828 arrays_ = ArrayList::Add(isolate_, arrays_, array);
829
830 auto elements_kind = array->GetElementsKind();
831 if (elements_kind != PACKED_SMI_ELEMENTS &&
832 elements_kind != PACKED_ELEMENTS) {
833 Throw("Unsupported array");
834 return;
835 }
836 // TODO(v8:11525): Support sparse arrays & arrays with holes.
837 DisallowGarbageCollection no_gc;
838 FixedArray elements = FixedArray::cast(array->elements());
839 for (int i = 0; i < elements.length(); ++i) {
840 Object object = elements.get(i);
841 if (!object.IsHeapObject()) continue;
842 discovery_queue_.push(handle(HeapObject::cast(object), isolate_));
843 }
844}
845
846void WebSnapshotSerializer::DiscoverObject(Handle<JSObject> object) {
847 uint32_t id;
848 if (InsertIntoIndexMap(object_ids_, *object, id)) return;
849
850 DCHECK_EQ(id, objects_->Length())((void) 0);
851 objects_ = ArrayList::Add(isolate_, objects_, object);
852
853 // TODO(v8:11525): Support objects with so many properties that they can't be
854 // in fast mode.
855 JSObject::MigrateSlowToFast(object, 0, "Web snapshot");
856 if (!object->HasFastProperties()) {
857 Throw("Dictionary mode objects not supported");
858 }
859
860 Handle<Map> map(object->map(), isolate_);
861 DiscoverMap(map);
862
863 // Discover __proto__.
864 if (map->prototype() !=
865 isolate_->native_context()->initial_object_prototype()) {
866 discovery_queue_.push(handle(map->prototype(), isolate_));
867 }
868
869 // Discover property values.
870 for (InternalIndex i : map->IterateOwnDescriptors()) {
871 PropertyDetails details =
872 map->instance_descriptors(kRelaxedLoad).GetDetails(i);
873 FieldIndex field_index = FieldIndex::ForDescriptor(*map, i);
874 Handle<Object> value = JSObject::FastPropertyAt(
875 isolate_, object, details.representation(), field_index);
876 if (!value->IsHeapObject()) continue;
877 discovery_queue_.push(Handle<HeapObject>::cast(value));
878 }
879
880 // Discover elements.
881 Handle<FixedArray> elements =
882 handle(FixedArray::cast(object->elements()), isolate_);
883 for (int i = 0; i < elements->length(); ++i) {
884 Object object = elements->get(i);
885 if (!object.IsHeapObject()) continue;
886 discovery_queue_.push(handle(HeapObject::cast(object), isolate_));
887 }
888}
889
890// Format (serialized function):
891// - 0 if there's no context, 1 + context id otherwise
892// - String id (source snippet)
893// - Start position in the source snippet
894// - Length in the source snippet
895// - Formal parameter count
896// - Flags (see FunctionFlags)
897// - 0 if there's no function prototype, 1 + object id for the function
898// prototype otherwise
899// TODO(v8:11525): Investigate whether the length is really needed.
900void WebSnapshotSerializer::SerializeFunction(Handle<JSFunction> function) {
901 SerializeFunctionInfo(&function_serializer_, function);
902 // TODO(v8:11525): Support properties in functions.
903}
904
905// Format (serialized class):
906// - 1 + context id
907// - String id (source snippet)
908// - Start position in the source snippet
909// - Length in the source snippet
910// - Formal parameter count
911// - Flags (see FunctionFlags)
912// - 1 + object id for the function prototype
913void WebSnapshotSerializer::SerializeClass(Handle<JSFunction> function) {
914 SerializeFunctionInfo(&class_serializer_, function);
915 // TODO(v8:11525): Support properties in classes.
916 // TODO(v8:11525): Support class members.
917}
918
919// Format (serialized context):
920// - 0 if there's no parent context, 1 + parent context id otherwise
921// - Variable count
922// - For each variable:
923// - String id (name)
924// - Serialized value
925void WebSnapshotSerializer::SerializeContext(Handle<Context> context) {
926 uint32_t parent_context_id = 0;
927 if (!context->previous().IsNativeContext() &&
928 !context->previous().IsScriptContext()) {
929 parent_context_id = GetContextId(context->previous()) + 1;
930 }
931
932 // TODO(v8:11525): Use less space for encoding the context type.
933 if (context->IsFunctionContext()) {
934 context_serializer_.WriteUint32(ContextType::FUNCTION);
935 } else if (context->IsBlockContext()) {
936 context_serializer_.WriteUint32(ContextType::BLOCK);
937 } else {
938 Throw("Unsupported context type");
939 return;
940 }
941
942 context_serializer_.WriteUint32(parent_context_id);
943
944 Handle<ScopeInfo> scope_info(context->scope_info(), isolate_);
945 int count = scope_info->ContextLocalCount();
946 context_serializer_.WriteUint32(count);
947
948 for (int i = 0; i < count; ++i) {
949 // TODO(v8:11525): support parameters
950 // TODO(v8:11525): distinguish variable modes
951 Handle<String> name(scope_info->context_local_names(i), isolate_);
952 WriteStringId(name, context_serializer_);
953 Handle<Object> value(context->get(scope_info->ContextHeaderLength() + i),
954 isolate_);
955 WriteValue(value, context_serializer_);
956 }
957}
958
959// Format (serialized object):
960// - Shape id
961// - For each property:
962// - Serialized value
963// - Max element index + 1 (or 0 if there are no elements)
964// - For each element:
965// - Index
966// - Serialized value
967// TODO(v8:11525): Support packed elements with a denser format.
968void WebSnapshotSerializer::SerializeObject(Handle<JSObject> object) {
969 Handle<Map> map(object->map(), isolate_);
970 uint32_t map_id = GetMapId(*map);
971 object_serializer_.WriteUint32(map_id);
972
973 // Properties.
974 for (InternalIndex i : map->IterateOwnDescriptors()) {
975 PropertyDetails details =
976 map->instance_descriptors(kRelaxedLoad).GetDetails(i);
977 FieldIndex field_index = FieldIndex::ForDescriptor(*map, i);
978 Handle<Object> value = JSObject::FastPropertyAt(
979 isolate_, object, details.representation(), field_index);
980 WriteValue(value, object_serializer_);
981 }
982
983 // Elements.
984 ReadOnlyRoots roots(isolate_);
985 Handle<FixedArray> elements =
986 handle(FixedArray::cast(object->elements()), isolate_);
987 uint32_t max_element_index = 0;
988 for (int i = 0; i < elements->length(); ++i) {
989 DisallowGarbageCollection no_gc;
990 Object value = elements->get(i);
991 if (value != roots.the_hole_value()) {
992 if (i > static_cast<int>(max_element_index)) {
993 max_element_index = i;
994 }
995 }
996 }
997 if (max_element_index == 0) {
998 object_serializer_.WriteUint32(0);
999 } else {
1000 object_serializer_.WriteUint32(max_element_index + 1);
1001 }
1002 for (int i = 0; i < elements->length(); ++i) {
1003 Handle<Object> value = handle(elements->get(i), isolate_);
1004 if (*value != roots.the_hole_value()) {
1005 DCHECK_LE(i, max_element_index)((void) 0);
1006 object_serializer_.WriteUint32(i);
1007 WriteValue(value, object_serializer_);
1008 }
1009 }
1010}
1011
1012// Format (serialized array):
1013// - Length
1014// - For each element:
1015// - Serialized value
1016void WebSnapshotSerializer::SerializeArray(Handle<JSArray> array) {
1017 auto elements_kind = array->GetElementsKind();
1018 if (elements_kind != PACKED_SMI_ELEMENTS &&
1019 elements_kind != PACKED_ELEMENTS) {
1020 Throw("Unsupported array");
1021 return;
1022 }
1023 // TODO(v8:11525): Support sparse arrays & arrays with holes.
1024 uint32_t length = static_cast<uint32_t>(array->length().ToSmi().value());
1025 array_serializer_.WriteUint32(length);
1026 Handle<FixedArray> elements =
1027 handle(FixedArray::cast(array->elements()), isolate_);
1028 for (uint32_t i = 0; i < length; ++i) {
1029 WriteValue(handle(elements->get(i), isolate_), array_serializer_);
1030 }
1031}
1032
1033// Format (serialized export):
1034// - String id (export name)
1035// - Serialized value (export value)
1036void WebSnapshotSerializer::SerializeExport(Handle<Object> object,
1037 Handle<String> export_name) {
1038 ++export_count_;
1039 WriteStringId(export_name, export_serializer_);
1040 if (object->IsJSPrimitiveWrapper()) {
1041 Handle<JSPrimitiveWrapper> wrapper =
1042 Handle<JSPrimitiveWrapper>::cast(object);
1043 Handle<Object> export_value = handle(wrapper->value(), isolate_);
1044 WriteValue(export_value, export_serializer_);
1045 } else {
1046 WriteValue(object, export_serializer_);
1047 }
1048}
1049
1050// Format (serialized value):
1051// - Type id (ValueType enum)
1052// - Value or id (interpretation depends on the type)
1053void WebSnapshotSerializer::WriteValue(Handle<Object> object,
1054 ValueSerializer& serializer) {
1055 if (object->IsSmi()) {
1056 serializer.WriteUint32(ValueType::INTEGER);
1057 serializer.WriteZigZag<int32_t>(Smi::cast(*object).value());
1058 return;
1059 }
1060
1061 int external_id;
1062 if (external_objects_ids_.Lookup(HeapObject::cast(*object), &external_id)) {
1063 serializer.WriteUint32(ValueType::EXTERNAL_ID);
1064 serializer.WriteUint32(static_cast<uint32_t>(external_id));
1065 return;
1066 }
1067
1068 DCHECK(object->IsHeapObject())((void) 0);
1069 Handle<HeapObject> heap_object = Handle<HeapObject>::cast(object);
1070 switch ((*heap_object).map().instance_type()) {
1071 case ODDBALL_TYPE:
1072 switch (Oddball::cast(*heap_object).kind()) {
1073 case Oddball::kFalse:
1074 serializer.WriteUint32(ValueType::FALSE_CONSTANT);
1075 return;
1076 case Oddball::kTrue:
1077 serializer.WriteUint32(ValueType::TRUE_CONSTANT);
1078 return;
1079 case Oddball::kNull:
1080 serializer.WriteUint32(ValueType::NULL_CONSTANT);
1081 return;
1082 case Oddball::kUndefined:
1083 serializer.WriteUint32(ValueType::UNDEFINED_CONSTANT);
1084 return;
1085 default:
1086 UNREACHABLE()V8_Fatal("unreachable code");
1087 }
1088 case HEAP_NUMBER_TYPE:
1089 // TODO(v8:11525): Handle possible endianness mismatch.
1090 serializer.WriteUint32(ValueType::DOUBLE);
1091 serializer.WriteDouble(HeapNumber::cast(*heap_object).value());
1092 break;
1093 case JS_FUNCTION_TYPE:
1094 serializer.WriteUint32(ValueType::FUNCTION_ID);
1095 serializer.WriteUint32(GetFunctionId(JSFunction::cast(*heap_object)));
1096 break;
1097 case JS_CLASS_CONSTRUCTOR_TYPE:
1098 serializer.WriteUint32(ValueType::CLASS_ID);
1099 serializer.WriteUint32(GetClassId(JSFunction::cast(*heap_object)));
1100 break;
1101 case JS_OBJECT_TYPE:
1102 serializer.WriteUint32(ValueType::OBJECT_ID);
1103 serializer.WriteUint32(GetObjectId(JSObject::cast(*heap_object)));
1104 break;
1105 case JS_ARRAY_TYPE:
1106 serializer.WriteUint32(ValueType::ARRAY_ID);
1107 serializer.WriteUint32(GetArrayId(JSArray::cast(*heap_object)));
1108 break;
1109 case JS_REG_EXP_TYPE: {
1110 Handle<JSRegExp> regexp = Handle<JSRegExp>::cast(heap_object);
1111 if (regexp->map() != isolate_->regexp_function()->initial_map()) {
1112 Throw("Unsupported RegExp map");
1113 return;
1114 }
1115 serializer.WriteUint32(ValueType::REGEXP);
1116 Handle<String> pattern = handle(regexp->source(), isolate_);
1117 WriteStringId(pattern, serializer);
1118 Handle<String> flags_string =
1119 JSRegExp::StringFromFlags(isolate_, regexp->flags());
1120 WriteStringId(flags_string, serializer);
1121 break;
1122 }
1123 default:
1124 if (heap_object->IsString()) {
1125 // Write strings which are referred to only once as in-place strings.
1126 WriteStringMaybeInPlace(Handle<String>::cast(heap_object), serializer);
1127 } else {
1128 Throw("Unsupported object");
1129 }
1130 }
1131 // TODO(v8:11525): Support more types.
1132}
1133
1134void WebSnapshotSerializer::WriteStringMaybeInPlace(
1135 Handle<String> string, ValueSerializer& serializer) {
1136 // If the string is only referred to by one location, write it in-place.
1137 bool in_place = false;
1138 uint32_t id = GetStringId(string, in_place);
1139 if (in_place) {
1140 serializer.WriteUint32(ValueType::IN_PLACE_STRING_ID);
1141 SerializeString(string, serializer);
1142 } else {
1143 serializer.WriteUint32(ValueType::STRING_ID);
1144 serializer.WriteUint32(id);
1145 }
1146}
1147
1148void WebSnapshotSerializer::WriteStringId(Handle<String> string,
1149 ValueSerializer& serializer) {
1150 bool in_place = false;
1151 uint32_t id = GetStringId(string, in_place);
1152 CHECK(!in_place)do { if ((__builtin_expect(!!(!(!in_place)), 0))) { V8_Fatal(
"Check failed: %s.", "!in_place"); } } while (false)
; // The string must have an ID.
1153 serializer.WriteUint32(id);
1154}
1155
1156uint32_t WebSnapshotSerializer::GetStringId(Handle<String> string,
1157 bool& in_place) {
1158 // Internalize strings so that they're unique.
1159 string = factory()->InternalizeString(string);
1160
1161 // Strings referred to more than one places are inserted in string_ids_.
1162 // Strings referred to by only one place aren't.
1163#ifdef DEBUG
1164 auto result = all_strings_.FindOrInsert(string);
1165 DCHECK(result.already_exists)((void) 0);
1166#endif
1167 int id = 0;
1168 in_place = !string_ids_.Lookup(*string, &id);
1169 return static_cast<uint32_t>(id);
1170}
1171
1172uint32_t WebSnapshotSerializer::GetMapId(Map map) {
1173 int id;
1174 bool return_value = map_ids_.Lookup(map, &id);
1175 DCHECK(return_value)((void) 0);
1176 USE(return_value)do { ::v8::base::Use unused_tmp_array_for_use_macro[]{return_value
}; (void)unused_tmp_array_for_use_macro; } while (false)
;
1177 return static_cast<uint32_t>(id);
1178}
1179
1180uint32_t WebSnapshotSerializer::GetFunctionId(JSFunction function) {
1181 int id;
1182 bool return_value = function_ids_.Lookup(function, &id);
1183 DCHECK(return_value)((void) 0);
1184 USE(return_value)do { ::v8::base::Use unused_tmp_array_for_use_macro[]{return_value
}; (void)unused_tmp_array_for_use_macro; } while (false)
;
1185 return static_cast<uint32_t>(function_ids_.size() - 1 - id);
1186}
1187
1188uint32_t WebSnapshotSerializer::GetClassId(JSFunction function) {
1189 int id;
1190 bool return_value = class_ids_.Lookup(function, &id);
1191 DCHECK(return_value)((void) 0);
1192 USE(return_value)do { ::v8::base::Use unused_tmp_array_for_use_macro[]{return_value
}; (void)unused_tmp_array_for_use_macro; } while (false)
;
1193 return static_cast<uint32_t>(class_ids_.size() - 1 - id);
1194}
1195
1196uint32_t WebSnapshotSerializer::GetContextId(Context context) {
1197 int id;
1198 bool return_value = context_ids_.Lookup(context, &id);
1199 DCHECK(return_value)((void) 0);
1200 USE(return_value)do { ::v8::base::Use unused_tmp_array_for_use_macro[]{return_value
}; (void)unused_tmp_array_for_use_macro; } while (false)
;
1201 return static_cast<uint32_t>(context_ids_.size() - 1 - id);
1202}
1203
1204uint32_t WebSnapshotSerializer::GetArrayId(JSArray array) {
1205 int id;
1206 bool return_value = array_ids_.Lookup(array, &id);
1207 DCHECK(return_value)((void) 0);
1208 USE(return_value)do { ::v8::base::Use unused_tmp_array_for_use_macro[]{return_value
}; (void)unused_tmp_array_for_use_macro; } while (false)
;
1209 return static_cast<uint32_t>(array_ids_.size() - 1 - id);
1210}
1211
1212uint32_t WebSnapshotSerializer::GetObjectId(JSObject object) {
1213 int id;
1214 bool return_value = object_ids_.Lookup(object, &id);
1215 DCHECK(return_value)((void) 0);
1216 USE(return_value)do { ::v8::base::Use unused_tmp_array_for_use_macro[]{return_value
}; (void)unused_tmp_array_for_use_macro; } while (false)
;
1217 return static_cast<uint32_t>(object_ids_.size() - 1 - id);
1218}
1219
1220uint32_t WebSnapshotSerializer::GetExternalId(HeapObject object) {
1221 int id;
1
'id' declared without an initial value
1222 bool return_value = external_objects_ids_.Lookup(object, &id);
2
Calling 'ObjectCacheIndexMap::Lookup'
6
Returning from 'ObjectCacheIndexMap::Lookup'
1223 DCHECK(return_value)((void) 0);
1224 USE(return_value)do { ::v8::base::Use unused_tmp_array_for_use_macro[]{return_value
}; (void)unused_tmp_array_for_use_macro; } while (false)
;
7
Loop condition is false. Exiting loop
1225 return static_cast<uint32_t>(id);
8
Undefined or garbage value returned to caller
1226}
1227
1228Handle<FixedArray> WebSnapshotSerializer::GetExternals() {
1229 return external_objects_ids_.Values(isolate_);
1230}
1231
1232WebSnapshotDeserializer::WebSnapshotDeserializer(v8::Isolate* isolate,
1233 const uint8_t* data,
1234 size_t buffer_size)
1235 : WebSnapshotDeserializer(reinterpret_cast<i::Isolate*>(isolate),
1236 Handle<Object>(), {data, buffer_size}) {}
1237
1238WebSnapshotDeserializer::WebSnapshotDeserializer(
1239 Isolate* isolate, Handle<Script> snapshot_as_script)
1240 : WebSnapshotDeserializer(
1241 isolate, handle(snapshot_as_script->name(), isolate),
1242 ExtractScriptBuffer(isolate, snapshot_as_script)) {}
1243
1244WebSnapshotDeserializer::WebSnapshotDeserializer(
1245 Isolate* isolate, Handle<Object> script_name,
1246 base::Vector<const uint8_t> buffer)
1247 : WebSnapshotSerializerDeserializer(isolate),
1248 script_name_(script_name),
1249 deserializer_(isolate_, buffer.data(), buffer.length()),
1250 roots_(isolate) {
1251 Handle<FixedArray> empty_array = factory()->empty_fixed_array();
1252 strings_handle_ = empty_array;
1253 maps_handle_ = empty_array;
1254 contexts_handle_ = empty_array;
1255 functions_handle_ = empty_array;
1256 classes_handle_ = empty_array;
1257 arrays_handle_ = empty_array;
1258 objects_handle_ = empty_array;
1259 external_references_handle_ = empty_array;
1260 isolate_->heap()->AddGCEpilogueCallback(UpdatePointersCallback,
1261 v8::kGCTypeAll, this);
1262}
1263
1264WebSnapshotDeserializer::~WebSnapshotDeserializer() {
1265 isolate_->heap()->RemoveGCEpilogueCallback(UpdatePointersCallback, this);
1266}
1267
1268void WebSnapshotDeserializer::UpdatePointers() {
1269 strings_ = *strings_handle_;
1270 maps_ = *maps_handle_;
1271 contexts_ = *contexts_handle_;
1272 functions_ = *functions_handle_;
1273 classes_ = *classes_handle_;
1274 arrays_ = *arrays_handle_;
1275 objects_ = *objects_handle_;
1276 external_references_ = *external_references_handle_;
1277}
1278
1279// static
1280base::Vector<const uint8_t> WebSnapshotDeserializer::ExtractScriptBuffer(
1281 Isolate* isolate, Handle<Script> snapshot_as_script) {
1282 Handle<String> source =
1283 handle(String::cast(snapshot_as_script->source()), isolate);
1284 if (source->IsExternalOneByteString()) {
1285 const v8::String::ExternalOneByteStringResource* resource =
1286 ExternalOneByteString::cast(*source).resource();
1287 return {reinterpret_cast<const uint8_t*>(resource->data()),
1288 resource->length()};
1289 } else if (source->IsSeqOneByteString()) {
1290 SeqOneByteString source_as_seq = SeqOneByteString::cast(*source);
1291 size_t length = source_as_seq.length();
1292 std::unique_ptr<uint8_t[]> data_copy(new uint8_t[length]);
1293 {
1294 DisallowGarbageCollection no_gc;
1295 uint8_t* data = source_as_seq.GetChars(no_gc);
1296 memcpy(data_copy.get(), data, length);
1297 }
1298 return {data_copy.get(), length};
1299 } else if (source->IsExternalTwoByteString()) {
1300 // TODO(v8:11525): Implement end-to-end snapshot processing which gets rid
1301 // of the need to copy the data here.
1302 const v8::String::ExternalStringResource* resource =
1303 ExternalTwoByteString::cast(*source).resource();
1304 size_t length = resource->length();
1305 std::unique_ptr<uint8_t[]> data_copy(new uint8_t[length]);
1306 {
1307 DisallowGarbageCollection no_gc;
1308 const uint16_t* data = resource->data();
1309 uint8_t* data_copy_ptr = data_copy.get();
1310 for (size_t i = 0; i < length; ++i) {
1311 data_copy_ptr[i] = static_cast<uint8_t>(data[i]);
1312 }
1313 }
1314 return {data_copy.get(), length};
1315 } else if (source->IsSeqTwoByteString()) {
1316 SeqTwoByteString source_as_seq = SeqTwoByteString::cast(*source);
1317 size_t length = source_as_seq.length();
1318 std::unique_ptr<uint8_t[]> data_copy(new uint8_t[length]);
1319 {
1320 DisallowGarbageCollection no_gc;
1321 uint16_t* data = source_as_seq.GetChars(no_gc);
1322 uint8_t* data_copy_ptr = data_copy.get();
1323 for (size_t i = 0; i < length; ++i) {
1324 data_copy_ptr[i] = static_cast<uint8_t>(data[i]);
1325 }
1326 }
1327 return {data_copy.get(), length};
1328 }
1329 UNREACHABLE()V8_Fatal("unreachable code");
1330}
1331
1332void WebSnapshotDeserializer::Throw(const char* message) {
1333 string_count_ = 0;
1334 map_count_ = 0;
1335 context_count_ = 0;
1336 class_count_ = 0;
1337 function_count_ = 0;
1338 object_count_ = 0;
1339 deferred_references_->SetLength(0);
1340
1341 // Make sure we don't read any more data
1342 deserializer_.position_ = deserializer_.end_;
1343
1344 WebSnapshotSerializerDeserializer::Throw(message);
1345}
1346
1347bool WebSnapshotDeserializer::Deserialize(
1348 MaybeHandle<FixedArray> external_references, bool skip_exports) {
1349 RCS_SCOPE(isolate_, RuntimeCallCounterId::kWebSnapshotDeserialize);
1350 if (external_references.ToHandle(&external_references_handle_)) {
1351 external_references_ = *external_references_handle_;
1352 } else {
1353 external_references_handle_ = roots_.empty_fixed_array_handle();
1354 }
1355
1356 if (deserialized_) {
1357 Throw("Can't reuse WebSnapshotDeserializer");
1358 return false;
1359 }
1360 deserialized_ = true;
1361 auto buffer_size = deserializer_.end_ - deserializer_.position_;
1362
1363 base::ElapsedTimer timer;
1364 if (FLAG_trace_web_snapshot) {
1365 timer.Start();
1366 }
1367 if (!DeserializeSnapshot(skip_exports)) {
1368 return false;
1369 }
1370 if (!DeserializeScript()) {
1371 return false;
1372 }
1373
1374 if (FLAG_trace_web_snapshot) {
1375 double ms = timer.Elapsed().InMillisecondsF();
1376 PrintF("[Deserializing snapshot (%zu bytes) took %0.3f ms]\n", buffer_size,
1377 ms);
1378 }
1379 return true;
1380}
1381
1382bool WebSnapshotDeserializer::DeserializeSnapshot(bool skip_exports) {
1383 deferred_references_ = ArrayList::New(isolate_, 30);
1384
1385 const void* magic_bytes;
1386 if (!deserializer_.ReadRawBytes(sizeof(kMagicNumber), &magic_bytes) ||
1387 memcmp(magic_bytes, kMagicNumber, sizeof(kMagicNumber)) != 0) {
1388 Throw("Invalid magic number");
1389 return false;
1390 }
1391
1392 DeserializeStrings();
1393 DeserializeMaps();
1394 DeserializeContexts();
1395 DeserializeFunctions();
1396 DeserializeArrays();
1397 DeserializeObjects();
1398 DeserializeClasses();
1399 ProcessDeferredReferences();
1400 DeserializeExports(skip_exports);
1401 DCHECK_EQ(0, deferred_references_->Length())((void) 0);
1402
1403 return !has_error();
1404}
1405
1406bool WebSnapshotDeserializer::DeserializeScript() {
1407 // If there is more data, treat it as normal JavaScript.
1408 DCHECK_LE(deserializer_.position_, deserializer_.end_)((void) 0);
1409 auto remaining_bytes = deserializer_.end_ - deserializer_.position_;
1410 if (remaining_bytes > 0 && remaining_bytes < v8::String::kMaxLength) {
1411 v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate_);
1412 v8::Local<v8::String> source =
1413 v8::String::NewFromUtf8(
1414 v8_isolate, reinterpret_cast<const char*>(deserializer_.position_),
1415 NewStringType::kNormal, static_cast<int>(remaining_bytes))
1416 .ToLocalChecked();
1417
1418 ScriptOrigin origin(v8_isolate, Utils::ToLocal(script_name_));
1419
1420 ScriptCompiler::Source script_source(source, origin);
1421 Local<UnboundScript> script;
1422 if (!ScriptCompiler::CompileUnboundScript(v8_isolate, &script_source)
1423 .ToLocal(&script)) {
1424 // The exception has already been reported.
1425 DCHECK(!isolate_->has_pending_exception())((void) 0);
1426 return false;
1427 }
1428 Local<Value> result;
1429 if (!script->BindToCurrentContext()
1430 ->Run(v8_isolate->GetCurrentContext())
1431 .ToLocal(&result)) {
1432 // The exception has already been reported.
1433 DCHECK(!isolate_->has_pending_exception())((void) 0);
1434 return false;
1435 }
1436 }
1437
1438 // TODO(v8:11525): Add verification mode; verify the objects we just produced.
1439 return !has_error();
1440}
1441
1442void WebSnapshotDeserializer::DeserializeStrings() {
1443 RCS_SCOPE(isolate_, RuntimeCallCounterId::kWebSnapshotDeserialize_Strings);
1444 if (!deserializer_.ReadUint32(&string_count_) ||
1445 string_count_ > kMaxItemCount) {
1446 Throw("Malformed string table");
1447 return;
1448 }
1449 STATIC_ASSERT(kMaxItemCount <= FixedArray::kMaxLength)static_assert(kMaxItemCount <= FixedArray::kMaxLength, "kMaxItemCount <= FixedArray::kMaxLength"
)
;
1450 strings_handle_ = factory()->NewFixedArray(string_count_);
1451 strings_ = *strings_handle_;
1452 for (uint32_t i = 0; i < string_count_; ++i) {
1453 MaybeHandle<String> maybe_string =
1454 deserializer_.ReadUtf8String(AllocationType::kOld);
1455 Handle<String> string;
1456 if (!maybe_string.ToHandle(&string)) {
1457 Throw("Malformed string");
1458 return;
1459 }
1460 strings_.set(i, *string);
1461 }
1462}
1463
1464String WebSnapshotDeserializer::ReadString(bool internalize) {
1465 DCHECK(!strings_handle_->is_null())((void) 0);
1466 uint32_t string_id;
1467 if (!deserializer_.ReadUint32(&string_id) || string_id >= string_count_) {
1468 Throw("malformed string id\n");
1469 return roots_.empty_string();
1470 }
1471 String string = String::cast(strings_.get(string_id));
1472 if (internalize && !string.IsInternalizedString(isolate_)) {
1473 string = *factory()->InternalizeString(handle(string, isolate_));
1474 strings_.set(string_id, string);
1475 }
1476 return string;
1477}
1478
1479String WebSnapshotDeserializer::ReadInPlaceString(bool internalize) {
1480 MaybeHandle<String> maybe_string =
1481 deserializer_.ReadUtf8String(AllocationType::kOld);
1482 Handle<String> string;
1483 if (!maybe_string.ToHandle(&string)) {
1484 Throw("Malformed string");
1485 return roots_.empty_string();
1486 }
1487 if (internalize) {
1488 string = factory()->InternalizeString(string);
1489 }
1490 return *string;
1491}
1492
1493void WebSnapshotDeserializer::DeserializeMaps() {
1494 RCS_SCOPE(isolate_, RuntimeCallCounterId::kWebSnapshotDeserialize_Maps);
1495 if (!deserializer_.ReadUint32(&map_count_) || map_count_ > kMaxItemCount) {
1496 Throw("Malformed shape table");
1497 return;
1498 }
1499 STATIC_ASSERT(kMaxItemCount <= FixedArray::kMaxLength)static_assert(kMaxItemCount <= FixedArray::kMaxLength, "kMaxItemCount <= FixedArray::kMaxLength"
)
;
1500 maps_handle_ = factory()->NewFixedArray(map_count_);
1501 maps_ = *maps_handle_;
1502 for (uint32_t i = 0; i < map_count_; ++i) {
1503 uint32_t map_type;
1504 if (!deserializer_.ReadUint32(&map_type)) {
1505 Throw("Malformed shape");
1506 return;
1507 }
1508 bool has_custom_property_attributes;
1509 switch (map_type) {
1510 case PropertyAttributesType::DEFAULT:
1511 has_custom_property_attributes = false;
1512 break;
1513 case PropertyAttributesType::CUSTOM:
1514 has_custom_property_attributes = true;
1515 break;
1516 default:
1517 Throw("Unsupported map type");
1518 return;
1519 }
1520
1521 uint32_t prototype_id;
1522 if (!deserializer_.ReadUint32(&prototype_id) ||
1523 prototype_id > kMaxItemCount) {
1524 Throw("Malformed shape");
1525 return;
1526 }
1527
1528 uint32_t property_count;
1529 if (!deserializer_.ReadUint32(&property_count)) {
1530 Throw("Malformed shape");
1531 return;
1532 }
1533 // TODO(v8:11525): Consider passing the upper bound as a param and
1534 // systematically enforcing it on the ValueSerializer side.
1535 if (property_count > kMaxNumberOfDescriptors) {
1536 Throw("Malformed shape: too many properties");
1537 return;
1538 }
1539
1540 if (property_count == 0) {
1541 DisallowGarbageCollection no_gc;
1542 Map empty_map =
1543 isolate_->native_context()->object_function().initial_map();
1544 maps_.set(i, empty_map);
1545 continue;
1546 }
1547
1548 Handle<DescriptorArray> descriptors =
1549 factory()->NewDescriptorArray(property_count, 0);
1550 for (InternalIndex i : InternalIndex::Range(property_count)) {
1551 PropertyAttributes attributes = PropertyAttributes::NONE;
1552 if (has_custom_property_attributes) {
1553 uint32_t flags;
1554 if (!deserializer_.ReadUint32(&flags)) {
1555 Throw("Malformed shape");
1556 return;
1557 }
1558 attributes = FlagsToAttributes(flags);
1559 }
1560
1561 Handle<String> key(ReadString(true), isolate_);
1562
1563 // Use the "none" representation until we see the first object having this
1564 // map. At that point, modify the representation.
1565 Descriptor desc = Descriptor::DataField(
1566 isolate_, key, i.as_int(), attributes, Representation::None());
1567 descriptors->Set(i, &desc);
1568 }
1569 DCHECK_EQ(descriptors->number_of_descriptors(), property_count)((void) 0);
1570 descriptors->Sort();
1571
1572 Handle<Map> map = factory()->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize,
1573 HOLEY_ELEMENTS, 0);
1574 map->InitializeDescriptors(isolate_, *descriptors);
1575 // TODO(v8:11525): Set 'constructor'.
1576
1577 if (prototype_id == 0) {
1578 // Use Object.prototype as the prototype.
1579 map->set_prototype(isolate_->native_context()->initial_object_prototype(),
1580 UPDATE_WRITE_BARRIER);
1581 } else {
1582 // TODO(v8::11525): Implement stricter checks, e.g., disallow cycles.
1583 --prototype_id;
1584 if (prototype_id < current_object_count_) {
1585 map->set_prototype(HeapObject::cast(objects_.get(prototype_id)),
1586 UPDATE_WRITE_BARRIER);
1587 } else {
1588 // The object hasn't been deserialized yet.
1589 AddDeferredReference(map, 0, OBJECT_ID, prototype_id);
1590 }
1591 }
1592 maps_.set(i, *map);
1593 }
1594}
1595
1596void WebSnapshotDeserializer::DeserializeContexts() {
1597 RCS_SCOPE(isolate_, RuntimeCallCounterId::kWebSnapshotDeserialize_Contexts);
1598 if (!deserializer_.ReadUint32(&context_count_) ||
1599 context_count_ > kMaxItemCount) {
1600 Throw("Malformed context table");
1601 return;
1602 }
1603 STATIC_ASSERT(kMaxItemCount <= FixedArray::kMaxLength)static_assert(kMaxItemCount <= FixedArray::kMaxLength, "kMaxItemCount <= FixedArray::kMaxLength"
)
;
1604 contexts_handle_ = factory()->NewFixedArray(context_count_);
1605 contexts_ = *contexts_handle_;
1606 for (uint32_t i = 0; i < context_count_; ++i) {
1607 uint32_t context_type;
1608 if (!deserializer_.ReadUint32(&context_type)) {
1609 Throw("Malformed context type");
1610 return;
1611 }
1612
1613 uint32_t parent_context_id;
1614 // Parent context is serialized before child context. Note: not >= on
1615 // purpose, we're going to subtract 1 later.
1616 if (!deserializer_.ReadUint32(&parent_context_id) ||
1617 parent_context_id > i) {
1618 Throw("Malformed context");
1619 return;
1620 }
1621
1622 uint32_t variable_count;
1623 if (!deserializer_.ReadUint32(&variable_count)) {
1624 Throw("Malformed context");
1625 return;
1626 }
1627 // TODO(v8:11525): Enforce upper limit for variable count.
1628 Handle<ScopeInfo> scope_info =
1629 CreateScopeInfo(variable_count, parent_context_id > 0,
1630 static_cast<ContextType>(context_type));
1631
1632 Handle<Context> parent_context;
1633 if (parent_context_id > 0) {
1634 parent_context =
1635 handle(Context::cast(contexts_.get(parent_context_id - 1)), isolate_);
1636 scope_info->set_outer_scope_info(parent_context->scope_info());
1637 } else {
1638 parent_context = handle(isolate_->context(), isolate_);
1639 }
1640
1641 const int context_local_base = ScopeInfo::kVariablePartIndex;
1642 const int context_local_info_base = context_local_base + variable_count;
1643 for (int variable_index = 0;
1644 variable_index < static_cast<int>(variable_count); ++variable_index) {
1645 {
1646 String name = ReadString(true);
1647 scope_info->set(context_local_base + variable_index, name);
1648 }
1649
1650 // TODO(v8:11525): Support variable modes etc.
1651 uint32_t info =
1652 ScopeInfo::VariableModeBits::encode(VariableMode::kLet) |
1653 ScopeInfo::InitFlagBit::encode(
1654 InitializationFlag::kNeedsInitialization) |
1655 ScopeInfo::MaybeAssignedFlagBit::encode(
1656 MaybeAssignedFlag::kMaybeAssigned) |
1657 ScopeInfo::ParameterNumberBits::encode(
1658 ScopeInfo::ParameterNumberBits::kMax) |
1659 ScopeInfo::IsStaticFlagBit::encode(IsStaticFlag::kNotStatic);
1660 scope_info->set(context_local_info_base + variable_index,
1661 Smi::FromInt(info));
1662 }
1663
1664 // Allocate the FunctionContext after setting up the ScopeInfo to avoid
1665 // pointing to a ScopeInfo which is not set up yet.
1666 Handle<Context> context;
1667 switch (context_type) {
1668 case ContextType::FUNCTION:
1669 context = factory()->NewFunctionContext(parent_context, scope_info);
1670 break;
1671 case ContextType::BLOCK:
1672 context = factory()->NewBlockContext(parent_context, scope_info);
1673 break;
1674 default:
1675 Throw("Unsupported context type");
1676 return;
1677 }
1678 int context_header_length = scope_info->ContextHeaderLength();
1679 for (int variable_index = 0;
1680 variable_index < static_cast<int>(variable_count); ++variable_index) {
1681 int context_index = context_header_length + variable_index;
1682 Object value = ReadValue(context, context_index);
1683 context->set(context_index, value);
1684 }
1685 contexts_.set(i, *context);
1686 }
1687}
1688
1689Handle<ScopeInfo> WebSnapshotDeserializer::CreateScopeInfo(
1690 uint32_t variable_count, bool has_parent, ContextType context_type) {
1691 // TODO(v8:11525): Decide how to handle language modes. (The code below sets
1692 // the language mode as strict.)
1693 // TODO(v8:11525): Support (context-allocating) receiver.
1694 // TODO(v8:11525): Support function variable & function name.
1695 // TODO(v8:11525): Support classes.
1696
1697 ScopeType scope_type;
1698 int flags =
1699 ScopeInfo::SloppyEvalCanExtendVarsBit::encode(false) |
1700 ScopeInfo::LanguageModeBit::encode(LanguageMode::kStrict) |
1701 ScopeInfo::DeclarationScopeBit::encode(false) |
1702 ScopeInfo::ReceiverVariableBits::encode(VariableAllocationInfo::NONE) |
1703 ScopeInfo::ClassScopeHasPrivateBrandBit::encode(false) |
1704 ScopeInfo::HasSavedClassVariableBit::encode(false) |
1705 ScopeInfo::HasNewTargetBit::encode(false) |
1706 ScopeInfo::FunctionVariableBits::encode(VariableAllocationInfo::NONE) |
1707 ScopeInfo::HasInferredFunctionNameBit::encode(false) |
1708 ScopeInfo::IsAsmModuleBit::encode(false) |
1709 ScopeInfo::HasSimpleParametersBit::encode(false) |
1710 ScopeInfo::FunctionKindBits::encode(FunctionKind::kNormalFunction) |
1711 ScopeInfo::HasOuterScopeInfoBit::encode(has_parent) |
1712 ScopeInfo::IsDebugEvaluateScopeBit::encode(false) |
1713 ScopeInfo::ForceContextAllocationBit::encode(false) |
1714 ScopeInfo::PrivateNameLookupSkipsOuterClassBit::encode(false) |
1715 ScopeInfo::HasContextExtensionSlotBit::encode(false) |
1716 ScopeInfo::IsReplModeScopeBit::encode(false) |
1717 ScopeInfo::HasLocalsBlockListBit::encode(false);
1718 switch (context_type) {
1719 case ContextType::FUNCTION:
1720 scope_type = ScopeType::FUNCTION_SCOPE;
1721 flags |= ScopeInfo::DeclarationScopeBit::encode(true) |
1722 ScopeInfo::HasSimpleParametersBit::encode(true);
1723 break;
1724 case ContextType::BLOCK:
1725 scope_type = ScopeType::CLASS_SCOPE;
1726 flags |= ScopeInfo::ForceContextAllocationBit::encode(true);
1727 break;
1728 default:
1729 // Default to a CLASS_SCOPE, so that the rest of the code can be executed
1730 // without failures.
1731 scope_type = ScopeType::CLASS_SCOPE;
1732 Throw("Unsupported context type");
1733 }
1734 flags |= ScopeInfo::ScopeTypeBits::encode(scope_type);
1735 const int length = ScopeInfo::kVariablePartIndex +
1736 (ScopeInfo::NeedsPositionInfo(scope_type)
1737 ? ScopeInfo::kPositionInfoEntries
1738 : 0) +
1739 (has_parent ? 1 : 0) + 2 * variable_count;
1740 Handle<ScopeInfo> scope_info = factory()->NewScopeInfo(length);
1741 {
1742 DisallowGarbageCollection no_gc;
1743 ScopeInfo raw = *scope_info;
1744
1745 raw.set_flags(flags);
1746 DCHECK(!raw.IsEmpty())((void) 0);
1747
1748 raw.set_context_local_count(variable_count);
1749 // TODO(v8:11525): Support parameters.
1750 raw.set_parameter_count(0);
1751 if (raw.HasPositionInfo()) {
1752 raw.SetPositionInfo(0, 0);
1753 }
1754 }
1755 return scope_info;
1756}
1757
1758Handle<JSFunction> WebSnapshotDeserializer::CreateJSFunction(
1759 int shared_function_info_index, uint32_t start_position, uint32_t length,
1760 uint32_t parameter_count, uint32_t flags, uint32_t context_id) {
1761 // TODO(v8:11525): Deduplicate the SFIs for class methods.
1762 FunctionKind kind = FunctionFlagsToFunctionKind(flags);
1763 Handle<SharedFunctionInfo> shared = factory()->NewSharedFunctionInfo(
1764 factory()->empty_string(), MaybeHandle<Code>(), Builtin::kCompileLazy,
1765 kind);
1766 Handle<UncompiledData> uncompiled_data =
1767 factory()->NewUncompiledDataWithoutPreparseData(
1768 roots_.empty_string_handle(), start_position,
1769 start_position + length);
1770 {
1771 DisallowGarbageCollection no_gc;
1772 SharedFunctionInfo raw = *shared;
1773 if (IsConciseMethod(kind)) {
1774 raw.set_syntax_kind(FunctionSyntaxKind::kAccessorOrMethod);
1775 }
1776 raw.set_script(*script_);
1777 raw.set_function_literal_id(shared_function_info_index);
1778 raw.set_internal_formal_parameter_count(JSParameterCount(parameter_count));
1779 // TODO(v8:11525): Decide how to handle language modes.
1780 raw.set_language_mode(LanguageMode::kStrict);
1781 raw.set_uncompiled_data(*uncompiled_data);
1782 raw.set_allows_lazy_compilation(true);
1783 shared_function_infos_.Set(shared_function_info_index,
1784 HeapObjectReference::Weak(raw));
1785 }
1786 shared_function_info_table_ = ObjectHashTable::Put(
1787 shared_function_info_table_,
1788 handle(Smi::FromInt(start_position), isolate_),
1789 handle(Smi::FromInt(shared_function_info_index), isolate_));
1790
1791 Handle<JSFunction> function =
1792 Factory::JSFunctionBuilder(isolate_, shared, isolate_->native_context())
1793 .Build();
1794 if (context_id > 0) {
1795 DCHECK_LT(context_id - 1, context_count_)((void) 0);
1796 // Guards raw pointer "context" below.
1797 DisallowHeapAllocation no_heap_access;
1798 Context context = Context::cast(contexts_.get(context_id - 1));
1799 function->set_context(context);
1800 shared->set_outer_scope_info(context.scope_info());
1801 }
1802 return function;
1803}
1804
1805void WebSnapshotDeserializer::DeserializeFunctions() {
1806 RCS_SCOPE(isolate_, RuntimeCallCounterId::kWebSnapshotDeserialize_Functions);
1807 if (!deserializer_.ReadUint32(&function_count_) ||
1808 function_count_ > kMaxItemCount) {
1809 Throw("Malformed function table");
1810 return;
1811 }
1812 STATIC_ASSERT(kMaxItemCount + 1 <= FixedArray::kMaxLength)static_assert(kMaxItemCount + 1 <= FixedArray::kMaxLength,
"kMaxItemCount + 1 <= FixedArray::kMaxLength")
;
1813 functions_handle_ = factory()->NewFixedArray(function_count_);
1814 functions_ = *functions_handle_;
1815
1816 // Overallocate the array for SharedFunctionInfos; functions which we
1817 // deserialize soon will create more SharedFunctionInfos when called.
1818 shared_function_infos_handle_ = factory()->NewWeakFixedArray(
1819 WeakArrayList::CapacityForLength(function_count_ + 1),
1820 AllocationType::kOld);
1821 shared_function_infos_ = *shared_function_infos_handle_;
1822 shared_function_info_table_ = ObjectHashTable::New(isolate_, function_count_);
1823 script_ = factory()->NewScript(factory()->empty_string());
1824 {
1825 DisallowGarbageCollection no_gc;
1826 Script raw = *script_;
1827 raw.set_type(Script::TYPE_WEB_SNAPSHOT);
1828 raw.set_shared_function_infos(shared_function_infos_);
1829 raw.set_shared_function_info_table(*shared_function_info_table_);
1830 }
1831
1832 for (; current_function_count_ < function_count_; ++current_function_count_) {
1833 uint32_t context_id;
1834 // Note: > (not >= on purpose, we will subtract 1).
1835 if (!deserializer_.ReadUint32(&context_id) || context_id > context_count_) {
1836 Throw("Malformed function");
1837 return;
1838 }
1839 {
1840 String source = ReadString(false);
1841 DisallowGarbageCollection no_gc;
1842 if (current_function_count_ == 0) {
1843 script_->set_source(source);
1844 } else {
1845 // TODO(v8:11525): Support multiple source snippets.
1846 DCHECK_EQ(script_->source(), source)((void) 0);
1847 }
1848 }
1849
1850 uint32_t start_position;
1851 uint32_t length;
1852 uint32_t parameter_count;
1853 uint32_t flags;
1854 if (!deserializer_.ReadUint32(&start_position) ||
1855 !deserializer_.ReadUint32(&length) ||
1856 !deserializer_.ReadUint32(&parameter_count) ||
1857 !deserializer_.ReadUint32(&flags)) {
1858 Throw("Malformed function");
1859 return;
1860 }
1861
1862 // Index 0 is reserved for top-level shared function info (which web
1863 // snapshot scripts don't have).
1864 Handle<JSFunction> function =
1865 CreateJSFunction(current_function_count_ + 1, start_position, length,
1866 parameter_count, flags, context_id);
1867 functions_.set(current_function_count_, *function);
1868
1869 ReadFunctionPrototype(function);
1870 }
1871}
1872
1873void WebSnapshotDeserializer::DeserializeClasses() {
1874 RCS_SCOPE(isolate_, RuntimeCallCounterId::kWebSnapshotDeserialize_Classes);
1875 if (!deserializer_.ReadUint32(&class_count_) ||
1876 class_count_ > kMaxItemCount) {
1877 Throw("Malformed class table");
1878 return;
1879 }
1880 STATIC_ASSERT(kMaxItemCount + 1 <= FixedArray::kMaxLength)static_assert(kMaxItemCount + 1 <= FixedArray::kMaxLength,
"kMaxItemCount + 1 <= FixedArray::kMaxLength")
;
1881 classes_handle_ = factory()->NewFixedArray(class_count_);
1882 classes_ = *classes_handle_;
1883
1884 // Grow the array for SharedFunctionInfos.
1885 shared_function_infos_handle_ = WeakFixedArray::EnsureSpace(
1886 isolate_, shared_function_infos_handle_,
1887 WeakArrayList::CapacityForLength(function_count_ + 1 + class_count_));
1888 shared_function_infos_ = *shared_function_infos_handle_;
1889 script_->set_shared_function_infos(shared_function_infos_);
1890
1891 for (; current_class_count_ < class_count_; ++current_class_count_) {
1892 uint32_t context_id;
1893 // Note: > (not >= on purpose, we will subtract 1).
1894 if (!deserializer_.ReadUint32(&context_id) || context_id > context_count_) {
1895 Throw("Malformed class");
1896 return;
1897 }
1898
1899 {
1900 String source = ReadString(false);
1901 if (current_function_count_ + current_class_count_ == 0) {
1902 script_->set_source(source);
1903 } else {
1904 // TODO(v8:11525): Support multiple source snippets.
1905 DCHECK_EQ(script_->source(), source)((void) 0);
1906 }
1907 }
1908
1909 uint32_t start_position;
1910 uint32_t length;
1911 uint32_t parameter_count;
1912 uint32_t flags;
1913 if (!deserializer_.ReadUint32(&start_position) ||
1914 !deserializer_.ReadUint32(&length) ||
1915 !deserializer_.ReadUint32(&parameter_count) ||
1916 !deserializer_.ReadUint32(&flags)) {
1917 Throw("Malformed class");
1918 return;
1919 }
1920
1921 // Index 0 is reserved for top-level shared function info (which web
1922 // snapshot scripts don't have).
1923 Handle<JSFunction> function = CreateJSFunction(
1924 function_count_ + current_class_count_ + 1, start_position, length,
1925 parameter_count, flags, context_id);
1926 classes_.set(current_class_count_, *function);
1927
1928 ReadFunctionPrototype(function);
1929 }
1930}
1931
1932void WebSnapshotDeserializer::DeserializeObjects() {
1933 RCS_SCOPE(isolate_, RuntimeCallCounterId::kWebSnapshotDeserialize_Objects);
1934 if (!deserializer_.ReadUint32(&object_count_) ||
1935 object_count_ > kMaxItemCount) {
1936 Throw("Malformed objects table");
1937 return;
1938 }
1939 STATIC_ASSERT(kMaxItemCount <= FixedArray::kMaxLength)static_assert(kMaxItemCount <= FixedArray::kMaxLength, "kMaxItemCount <= FixedArray::kMaxLength"
)
;
1940 objects_handle_ = factory()->NewFixedArray(object_count_);
1941 objects_ = *objects_handle_;
1942 for (; current_object_count_ < object_count_; ++current_object_count_) {
1943 uint32_t map_id;
1944 if (!deserializer_.ReadUint32(&map_id) || map_id >= map_count_) {
1945 Throw("Malformed object");
1946 return;
1947 }
1948 Map raw_map = Map::cast(maps_.get(map_id));
1949 Handle<DescriptorArray> descriptors =
1950 handle(raw_map.instance_descriptors(kRelaxedLoad), isolate_);
1951 int no_properties = raw_map.NumberOfOwnDescriptors();
1952 // TODO(v8:11525): In-object properties.
1953 Handle<Map> map(raw_map, isolate_);
1954 Handle<PropertyArray> property_array =
1955 factory()->NewPropertyArray(no_properties);
1956 for (int i = 0; i < no_properties; ++i) {
1957 Object value = ReadValue(property_array, i);
1958 DisallowGarbageCollection no_gc;
1959 // Read the representation from the map.
1960 DescriptorArray raw_descriptors = *descriptors;
1961 PropertyDetails details = raw_descriptors.GetDetails(InternalIndex(i));
1962 CHECK_EQ(details.location(), PropertyLocation::kField)do { bool _cmp = ::v8::base::CmpEQImpl< typename ::v8::base
::pass_value_or_ref<decltype(details.location())>::type
, typename ::v8::base::pass_value_or_ref<decltype(PropertyLocation
::kField)>::type>((details.location()), (PropertyLocation
::kField)); do { if ((__builtin_expect(!!(!(_cmp)), 0))) { V8_Fatal
("Check failed: %s.", "details.location()" " " "==" " " "PropertyLocation::kField"
); } } while (false); } while (false)
;
1963 CHECK_EQ(PropertyKind::kData, details.kind())do { bool _cmp = ::v8::base::CmpEQImpl< typename ::v8::base
::pass_value_or_ref<decltype(PropertyKind::kData)>::type
, typename ::v8::base::pass_value_or_ref<decltype(details.
kind())>::type>((PropertyKind::kData), (details.kind())
); do { if ((__builtin_expect(!!(!(_cmp)), 0))) { V8_Fatal("Check failed: %s."
, "PropertyKind::kData" " " "==" " " "details.kind()"); } } while
(false); } while (false)
;
1964 Representation r = details.representation();
1965 if (r.IsNone()) {
1966 // Switch over to wanted_representation.
1967 details = details.CopyWithRepresentation(Representation::Tagged());
1968 raw_descriptors.SetDetails(InternalIndex(i), details);
1969 } else if (!r.Equals(Representation::Tagged())) {
1970 // TODO(v8:11525): Support this case too.
1971 UNREACHABLE()V8_Fatal("unreachable code");
1972 }
1973 property_array->set(i, value);
1974 }
1975 Handle<JSObject> object = factory()->NewJSObjectFromMap(map);
1976 object->set_raw_properties_or_hash(*property_array, kRelaxedStore);
1977
1978 uint32_t max_element_index = 0;
1979 if (!deserializer_.ReadUint32(&max_element_index) ||
1980 max_element_index > kMaxItemCount + 1) {
1981 Throw("Malformed object");
1982 return;
1983 }
1984 if (max_element_index > 0) {
1985 --max_element_index; // Subtract 1 to get the real max_element_index.
1986 Handle<FixedArray> elements =
1987 factory()->NewFixedArray(max_element_index + 1);
1988 // Read (index, value) pairs until we encounter one where index ==
1989 // max_element_index.
1990 while (true) {
1991 uint32_t index;
1992 if (!deserializer_.ReadUint32(&index) || index > max_element_index) {
1993 Throw("Malformed object");
1994 return;
1995 }
1996 Object value = ReadValue(elements, index);
1997 elements->set(index, value);
1998 if (index == max_element_index) {
1999 break;
2000 }
2001 }
2002 object->set_elements(*elements);
2003 // Objects always get HOLEY_ELEMENTS.
2004 DCHECK(!IsSmiElementsKind(object->map().elements_kind()))((void) 0);
2005 DCHECK(!IsDoubleElementsKind(object->map().elements_kind()))((void) 0);
2006 DCHECK(IsHoleyElementsKind(object->map().elements_kind()))((void) 0);
2007 }
2008 objects_.set(static_cast<int>(current_object_count_), *object);
2009 }
2010}
2011
2012void WebSnapshotDeserializer::DeserializeArrays() {
2013 RCS_SCOPE(isolate_, RuntimeCallCounterId::kWebSnapshotDeserialize_Arrays);
2014 if (!deserializer_.ReadUint32(&array_count_) ||
2015 object_count_ > kMaxItemCount) {
2016 Throw("Malformed array table");
2017 return;
2018 }
2019 STATIC_ASSERT(kMaxItemCount <= FixedArray::kMaxLength)static_assert(kMaxItemCount <= FixedArray::kMaxLength, "kMaxItemCount <= FixedArray::kMaxLength"
)
;
2020 arrays_handle_ = factory()->NewFixedArray(array_count_);
2021 arrays_ = *arrays_handle_;
2022 for (; current_array_count_ < array_count_; ++current_array_count_) {
2023 uint32_t length;
2024 if (!deserializer_.ReadUint32(&length) || length > kMaxItemCount) {
2025 Throw("Malformed array");
2026 return;
2027 }
2028 Handle<FixedArray> elements = factory()->NewFixedArray(length);
2029 ElementsKind elements_kind = PACKED_SMI_ELEMENTS;
2030 for (uint32_t i = 0; i < length; ++i) {
2031 Object value = ReadValue(elements, i);
2032 DisallowGarbageCollection no_gc;
2033 if (!value.IsSmi()) {
2034 elements_kind = PACKED_ELEMENTS;
2035 }
2036 elements->set(static_cast<int>(i), value);
2037 }
2038 Handle<JSArray> array =
2039 factory()->NewJSArrayWithElements(elements, elements_kind, length);
2040 arrays_.set(static_cast<int>(current_array_count_), *array);
2041 }
2042}
2043
2044void WebSnapshotDeserializer::DeserializeExports(bool skip_exports) {
2045 RCS_SCOPE(isolate_, RuntimeCallCounterId::kWebSnapshotDeserialize_Exports);
2046 uint32_t count;
2047 if (!deserializer_.ReadUint32(&count) || count > kMaxItemCount) {
2048 Throw("Malformed export table");
2049 return;
2050 }
2051
2052 if (skip_exports) {
2053 // In the skip_exports mode, we read the exports but don't do anything about
2054 // them. This is useful for stress testing; otherwise the GlobalDictionary
2055 // handling below dominates.
2056 for (uint32_t i = 0; i < count; ++i) {
2057 Handle<String> export_name(ReadString(true), isolate_);
2058 // No deferred references should occur at this point, since all objects
2059 // have been deserialized.
2060 Object export_value = ReadValue();
2061 USE(export_name)do { ::v8::base::Use unused_tmp_array_for_use_macro[]{export_name
}; (void)unused_tmp_array_for_use_macro; } while (false)
;
2062 USE(export_value)do { ::v8::base::Use unused_tmp_array_for_use_macro[]{export_value
}; (void)unused_tmp_array_for_use_macro; } while (false)
;
2063 }
2064 return;
2065 }
2066
2067 // Pre-reserve the space for the properties we're going to add to the global
2068 // object.
2069 Handle<JSGlobalObject> global = isolate_->global_object();
2070 Handle<GlobalDictionary> dictionary(
2071 global->global_dictionary(isolate_, kAcquireLoad), isolate_);
2072
2073 dictionary = GlobalDictionary::EnsureCapacity(
2074 isolate_, dictionary, dictionary->NumberOfElements() + count,
2075 AllocationType::kYoung);
2076 bool has_exported_values = false;
2077
2078 // TODO(v8:11525): The code below skips checks, in particular
2079 // LookupIterator::UpdateProtectors and
2080 // LookupIterator::ExtendingNonExtensible.
2081 InternalIndex entry = InternalIndex::NotFound();
2082 for (uint32_t i = 0; i < count; ++i) {
2083 Handle<String> export_name(ReadString(true), isolate_);
2084 // No deferred references should occur at this point, since all objects have
2085 // been deserialized.
2086 Object export_value = ReadValue();
2087
2088 if (export_name->length() == 0 && i == 0) {
2089 // Hack: treat the first empty-string-named export value as a return value
2090 // from the deserializer.
2091 CHECK_EQ(i, 0)do { bool _cmp = ::v8::base::CmpEQImpl< typename ::v8::base
::pass_value_or_ref<decltype(i)>::type, typename ::v8::
base::pass_value_or_ref<decltype(0)>::type>((i), (0)
); do { if ((__builtin_expect(!!(!(_cmp)), 0))) { V8_Fatal("Check failed: %s."
, "i" " " "==" " " "0"); } } while (false); } while (false)
;
2092 return_value_ = handle(export_value, isolate_);
2093 continue;
2094 }
2095
2096 DisallowGarbageCollection no_gc;
2097 // Check for the correctness of the snapshot (thus far) before producing
2098 // something observable. TODO(v8:11525): Strictly speaking, we should
2099 // produce observable effects only when we know that the whole snapshot is
2100 // correct.
2101 if (has_error()) return;
2102
2103 PropertyDetails property_details =
2104 PropertyDetails(PropertyKind::kData, NONE,
2105 PropertyCell::InitialType(isolate_, export_value));
2106 Handle<Object> export_value_handle(export_value, isolate_);
2107 AllowGarbageCollection allow_gc;
2108 Handle<PropertyCell> transition_cell = factory()->NewPropertyCell(
2109 export_name, property_details, export_value_handle);
2110 dictionary =
2111 GlobalDictionary::Add(isolate_, dictionary, export_name,
2112 transition_cell, property_details, &entry);
2113 has_exported_values = true;
2114 }
2115
2116 if (!has_exported_values) return;
2117
2118 global->set_global_dictionary(*dictionary, kReleaseStore);
2119 JSObject::InvalidatePrototypeChains(global->map(isolate_));
2120}
2121
2122Object WebSnapshotDeserializer::ReadValue(Handle<HeapObject> container,
2123 uint32_t container_index) {
2124 uint32_t value_type;
2125 // TODO(v8:11525): Consider adding a ReadByte.
2126 if (!deserializer_.ReadUint32(&value_type)) {
2127 Throw("Malformed variable");
2128 // Set "value" here so that the "keep on trucking" error handling won't fail
2129 // when dereferencing the handle.
2130 return Smi::zero();
2131 }
2132 switch (value_type) {
2133 case ValueType::FALSE_CONSTANT:
2134 return roots_.false_value();
2135 case ValueType::TRUE_CONSTANT:
2136 return roots_.true_value();
2137 case ValueType::NULL_CONSTANT:
2138 return roots_.null_value();
2139 case ValueType::UNDEFINED_CONSTANT:
2140 return roots_.undefined_value();
2141 case ValueType::INTEGER:
2142 return ReadInteger();
2143 case ValueType::DOUBLE:
2144 return ReadNumber();
2145 case ValueType::STRING_ID:
2146 return ReadString(false);
2147 case ValueType::ARRAY_ID:
2148 return ReadArray(container, container_index);
2149 case ValueType::OBJECT_ID:
2150 return ReadObject(container, container_index);
2151 case ValueType::FUNCTION_ID:
2152 return ReadFunction(container, container_index);
2153 case ValueType::CLASS_ID:
2154 return ReadClass(container, container_index);
2155 case ValueType::REGEXP:
2156 return ReadRegexp();
2157 case ValueType::EXTERNAL_ID:
2158 return ReadExternalReference();
2159 case ValueType::IN_PLACE_STRING_ID:
2160 return ReadInPlaceString(false);
2161 default:
2162 // TODO(v8:11525): Handle other value types.
2163 Throw("Unsupported value type");
2164 return Smi::zero();
2165 }
2166}
2167
2168Object WebSnapshotDeserializer::ReadInteger() {
2169 Maybe<int32_t> number = deserializer_.ReadZigZag<int32_t>();
2170 if (number.IsNothing()) {
2171 Throw("Malformed integer");
2172 return Smi::zero();
2173 }
2174 return *factory()->NewNumberFromInt(number.FromJust());
2175}
2176
2177Object WebSnapshotDeserializer::ReadNumber() {
2178 double number;
2179 if (!deserializer_.ReadDouble(&number)) {
2180 Throw("Malformed double");
2181 return Smi::zero();
2182 }
2183 return *factory()->NewNumber(number);
2184}
2185
2186Object WebSnapshotDeserializer::ReadArray(Handle<HeapObject> container,
2187 uint32_t index) {
2188 uint32_t array_id;
2189 if (!deserializer_.ReadUint32(&array_id) || array_id >= kMaxItemCount) {
2190 Throw("Malformed variable");
2191 return Smi::zero();
2192 }
2193 if (array_id < current_array_count_) {
2194 return arrays_.get(array_id);
2195 }
2196 // The array hasn't been deserialized yet.
2197 return AddDeferredReference(container, index, ARRAY_ID, array_id);
2198}
2199
2200Object WebSnapshotDeserializer::ReadObject(Handle<HeapObject> container,
2201 uint32_t index) {
2202 uint32_t object_id;
2203 if (!deserializer_.ReadUint32(&object_id) || object_id > kMaxItemCount) {
2204 Throw("Malformed variable");
2205 return Smi::zero();
2206 }
2207 if (object_id < current_object_count_) {
2208 return objects_.get(object_id);
2209 }
2210 // The object hasn't been deserialized yet.
2211 return AddDeferredReference(container, index, OBJECT_ID, object_id);
2212}
2213
2214Object WebSnapshotDeserializer::ReadFunction(Handle<HeapObject> container,
2215 uint32_t index) {
2216 uint32_t function_id;
2217 if (!deserializer_.ReadUint32(&function_id) ||
2218 function_id >= function_count_) {
2219 Throw("Malformed object property");
2220 return Smi::zero();
2221 }
2222 if (function_id < current_function_count_) {
2223 return functions_.get(function_id);
2224 }
2225 // The function hasn't been deserialized yet.
2226 return AddDeferredReference(container, index, FUNCTION_ID, function_id);
2227}
2228
2229Object WebSnapshotDeserializer::ReadClass(Handle<HeapObject> container,
2230 uint32_t index) {
2231 uint32_t class_id;
2232 if (!deserializer_.ReadUint32(&class_id) || class_id >= kMaxItemCount) {
2233 Throw("Malformed object property");
2234 return Smi::zero();
2235 }
2236 if (class_id < current_class_count_) {
2237 return classes_.get(class_id);
2238 }
2239 // The class hasn't been deserialized yet.
2240 return AddDeferredReference(container, index, CLASS_ID, class_id);
2241}
2242
2243Object WebSnapshotDeserializer::ReadRegexp() {
2244 Handle<String> pattern(ReadString(false), isolate_);
2245 Handle<String> flags_string(ReadString(false), isolate_);
2246 base::Optional<JSRegExp::Flags> flags =
2247 JSRegExp::FlagsFromString(isolate_, flags_string);
2248 if (!flags.has_value()) {
2249 Throw("Malformed flags in regular expression");
2250 return Smi::zero();
2251 }
2252 MaybeHandle<JSRegExp> maybe_regexp =
2253 JSRegExp::New(isolate_, pattern, flags.value());
2254 Handle<JSRegExp> regexp;
2255 if (!maybe_regexp.ToHandle(&regexp)) {
2256 Throw("Malformed RegExp");
2257 return Smi::zero();
2258 }
2259 return *regexp;
2260}
2261
2262Object WebSnapshotDeserializer::ReadExternalReference() {
2263 uint32_t ref_id;
2264 if (!deserializer_.ReadUint32(&ref_id) ||
2265 ref_id >= static_cast<uint32_t>(external_references_.length())) {
2266 Throw("Invalid external reference");
2267 return Smi::zero();
2268 }
2269 return external_references_.get(ref_id);
2270}
2271
2272void WebSnapshotDeserializer::ReadFunctionPrototype(
2273 Handle<JSFunction> function) {
2274 uint32_t object_id;
2275
2276 if (!deserializer_.ReadUint32(&object_id) || object_id > kMaxItemCount + 1) {
2277 Throw("Malformed class / function");
2278 return;
2279 }
2280 if (object_id == 0) {
2281 // No prototype.
2282 return;
2283 }
2284 --object_id;
2285 if (object_id < current_object_count_) {
2286 if (!SetFunctionPrototype(*function,
2287 JSReceiver::cast(objects_.get(object_id)))) {
2288 Throw("Can't reuse function prototype");
2289 return;
2290 }
2291 } else {
2292 // The object hasn't been deserialized yet.
2293 AddDeferredReference(function, 0, OBJECT_ID, object_id);
2294 }
2295}
2296
2297bool WebSnapshotDeserializer::SetFunctionPrototype(JSFunction function,
2298 JSReceiver prototype) {
2299 DisallowGarbageCollection no_gc;
2300 // TODO(v8:11525): Enforce the invariant that no two prototypes share a map.
2301 Map map = prototype.map();
2302 map.set_is_prototype_map(true);
2303 if (!map.constructor_or_back_pointer().IsNullOrUndefined(isolate_)) {
2304 return false;
2305 }
2306 map.set_constructor_or_back_pointer(function);
2307 function.set_prototype_or_initial_map(prototype, kReleaseStore);
2308 return true;
2309}
2310
2311HeapObject WebSnapshotDeserializer::AddDeferredReference(
2312 Handle<HeapObject> container, uint32_t index, ValueType target_type,
2313 uint32_t target_index) {
2314 if (container.is_null()) {
2315 const char* message = "Invalid reference";
2316 switch (target_type) {
2317 case ARRAY_ID:
2318 message = "Invalid array reference";
2319 break;
2320 case OBJECT_ID:
2321 message = "Invalid object reference";
2322 break;
2323 case CLASS_ID:
2324 message = "Invalid class reference";
2325 break;
2326 case FUNCTION_ID:
2327 message = "Invalid function reference";
2328 break;
2329 default:
2330 break;
2331 }
2332 Throw(message);
2333 return roots_.undefined_value();
2334 }
2335 DCHECK(container->IsPropertyArray() || container->IsContext() ||((void) 0)
2336 container->IsFixedArray() || container->IsJSFunction() ||((void) 0)
2337 container->IsMap())((void) 0);
2338 deferred_references_ = ArrayList::Add(
2339 isolate_, deferred_references_, container, Smi::FromInt(index),
2340 Smi::FromInt(target_type), Smi::FromInt(target_index));
2341 // Use HeapObject as placeholder since this might break elements kinds.
2342 return roots_.undefined_value();
2343}
2344
2345void WebSnapshotDeserializer::ProcessDeferredReferences() {
2346 // Check for error now, since the FixedArrays below might not have been
2347 // created if there was an error.
2348 if (has_error()) return;
2349
2350 DisallowGarbageCollection no_gc;
2351 ArrayList raw_deferred_references = *deferred_references_;
2352
2353 // Deferred references is a list of (object, index, target type, target index)
2354 // tuples.
2355 for (int i = 0; i < raw_deferred_references.Length() - 3; i += 4) {
2356 HeapObject container = HeapObject::cast(raw_deferred_references.Get(i));
2357 int index = raw_deferred_references.Get(i + 1).ToSmi().value();
2358 ValueType target_type = static_cast<ValueType>(
2359 raw_deferred_references.Get(i + 2).ToSmi().value());
2360 int target_index = raw_deferred_references.Get(i + 3).ToSmi().value();
2361 Object target;
2362 switch (target_type) {
2363 case FUNCTION_ID:
2364 if (static_cast<uint32_t>(target_index) >= function_count_) {
2365 // Throw can allocate, but it's ok, since we're not using the raw
2366 // pointers after that.
2367 AllowGarbageCollection allow_gc;
2368 Throw("Invalid function reference");
2369 return;
2370 }
2371 target = functions_.get(target_index);
2372 break;
2373 case CLASS_ID:
2374 if (static_cast<uint32_t>(target_index) >= class_count_) {
2375 AllowGarbageCollection allow_gc;
2376 Throw("Invalid class reference");
2377 return;
2378 }
2379 target = classes_.get(target_index);
2380 break;
2381 case ARRAY_ID:
2382 if (static_cast<uint32_t>(target_index) >= array_count_) {
2383 AllowGarbageCollection allow_gc;
2384 Throw("Invalid array reference");
2385 return;
2386 }
2387 target = arrays_.get(target_index);
2388 break;
2389 case OBJECT_ID:
2390 if (static_cast<uint32_t>(target_index) >= object_count_) {
2391 AllowGarbageCollection allow_gc;
2392 Throw("Invalid object reference");
2393 return;
2394 }
2395 target = objects_.get(target_index);
2396 break;
2397 default:
2398 UNREACHABLE()V8_Fatal("unreachable code");
2399 }
2400 InstanceType instance_type = container.map().instance_type();
2401 if (InstanceTypeChecker::IsPropertyArray(instance_type)) {
2402 PropertyArray::cast(container).set(index, target);
2403 } else if (InstanceTypeChecker::IsContext(instance_type)) {
2404 Context::cast(container).set(index, target);
2405 } else if (InstanceTypeChecker::IsFixedArray(instance_type)) {
2406 FixedArray::cast(container).set(index, target);
2407 } else if (InstanceTypeChecker::IsJSFunction(instance_type)) {
2408 // The only deferred reference allowed for a JSFunction is the function
2409 // prototype.
2410 DCHECK_EQ(index, 0)((void) 0);
2411 DCHECK(target.IsJSReceiver())((void) 0);
2412 if (!SetFunctionPrototype(JSFunction::cast(container),
2413 JSReceiver::cast(target))) {
2414 AllowGarbageCollection allow_gc;
2415 Throw("Can't reuse function prototype");
2416 return;
2417 }
2418 } else if (InstanceTypeChecker::IsMap(instance_type)) {
2419 // The only deferred reference allowed for a Map is the __proto__.
2420 DCHECK_EQ(index, 0)((void) 0);
2421 DCHECK(target.IsJSReceiver())((void) 0);
2422 Map::cast(container).set_prototype(HeapObject::cast(target),
2423 UPDATE_WRITE_BARRIER);
2424 } else {
2425 UNREACHABLE()V8_Fatal("unreachable code");
2426 }
2427 }
2428 deferred_references_->SetLength(0);
2429}
2430
2431} // namespace internal
2432} // namespace v8

../deps/v8/src/snapshot/serializer.h

1// 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#ifndef V8_SNAPSHOT_SERIALIZER_H_
6#define V8_SNAPSHOT_SERIALIZER_H_
7
8#include "src/codegen/external-reference-encoder.h"
9#include "src/common/assert-scope.h"
10#include "src/execution/isolate.h"
11#include "src/handles/global-handles.h"
12#include "src/logging/log.h"
13#include "src/objects/objects.h"
14#include "src/snapshot/embedded/embedded-data.h"
15#include "src/snapshot/serializer-deserializer.h"
16#include "src/snapshot/snapshot-source-sink.h"
17#include "src/snapshot/snapshot.h"
18#include "src/utils/identity-map.h"
19
20namespace v8 {
21namespace internal {
22
23class CodeAddressMap : public CodeEventLogger {
24 public:
25 explicit CodeAddressMap(Isolate* isolate) : CodeEventLogger(isolate) {
26 isolate->logger()->AddCodeEventListener(this);
27 }
28
29 ~CodeAddressMap() override {
30 isolate_->logger()->RemoveCodeEventListener(this);
31 }
32
33 void CodeMoveEvent(AbstractCode from, AbstractCode to) override {
34 address_to_name_map_.Move(from.address(), to.address());
35 }
36
37 void CodeDisableOptEvent(Handle<AbstractCode> code,
38 Handle<SharedFunctionInfo> shared) override {}
39
40 const char* Lookup(Address address) {
41 return address_to_name_map_.Lookup(address);
42 }
43
44 private:
45 class NameMap {
46 public:
47 NameMap() : impl_() {}
48 NameMap(const NameMap&) = delete;
49 NameMap& operator=(const NameMap&) = delete;
50
51 ~NameMap() {
52 for (base::HashMap::Entry* p = impl_.Start(); p != nullptr;
53 p = impl_.Next(p)) {
54 DeleteArray(static_cast<const char*>(p->value));
55 }
56 }
57
58 void Insert(Address code_address, const char* name, int name_size) {
59 base::HashMap::Entry* entry = FindOrCreateEntry(code_address);
60 if (entry->value == nullptr) {
61 entry->value = CopyName(name, name_size);
62 }
63 }
64
65 const char* Lookup(Address code_address) {
66 base::HashMap::Entry* entry = FindEntry(code_address);
67 return (entry != nullptr) ? static_cast<const char*>(entry->value)
68 : nullptr;
69 }
70
71 void Remove(Address code_address) {
72 base::HashMap::Entry* entry = FindEntry(code_address);
73 if (entry != nullptr) {
74 DeleteArray(static_cast<char*>(entry->value));
75 RemoveEntry(entry);
76 }
77 }
78
79 void Move(Address from, Address to) {
80 if (from == to) return;
81 base::HashMap::Entry* from_entry = FindEntry(from);
82 DCHECK_NOT_NULL(from_entry)((void) 0);
83 void* value = from_entry->value;
84 RemoveEntry(from_entry);
85 base::HashMap::Entry* to_entry = FindOrCreateEntry(to);
86 DCHECK_NULL(to_entry->value)((void) 0);
87 to_entry->value = value;
88 }
89
90 private:
91 static char* CopyName(const char* name, int name_size) {
92 char* result = NewArray<char>(name_size + 1);
93 for (int i = 0; i < name_size; ++i) {
94 char c = name[i];
95 if (c == '\0') c = ' ';
96 result[i] = c;
97 }
98 result[name_size] = '\0';
99 return result;
100 }
101
102 base::HashMap::Entry* FindOrCreateEntry(Address code_address) {
103 return impl_.LookupOrInsert(reinterpret_cast<void*>(code_address),
104 ComputeAddressHash(code_address));
105 }
106
107 base::HashMap::Entry* FindEntry(Address code_address) {
108 return impl_.Lookup(reinterpret_cast<void*>(code_address),
109 ComputeAddressHash(code_address));
110 }
111
112 void RemoveEntry(base::HashMap::Entry* entry) {
113 impl_.Remove(entry->key, entry->hash);
114 }
115
116 base::HashMap impl_;
117 };
118
119 void LogRecordedBuffer(Handle<AbstractCode> code,
120 MaybeHandle<SharedFunctionInfo>, const char* name,
121 int length) override {
122 address_to_name_map_.Insert(code->address(), name, length);
123 }
124
125#if V8_ENABLE_WEBASSEMBLY1
126 void LogRecordedBuffer(const wasm::WasmCode* code, const char* name,
127 int length) override {
128 UNREACHABLE()V8_Fatal("unreachable code");
129 }
130#endif // V8_ENABLE_WEBASSEMBLY
131
132 NameMap address_to_name_map_;
133};
134
135class ObjectCacheIndexMap {
136 public:
137 explicit ObjectCacheIndexMap(Heap* heap) : map_(heap), next_index_(0) {}
138 ObjectCacheIndexMap(const ObjectCacheIndexMap&) = delete;
139 ObjectCacheIndexMap& operator=(const ObjectCacheIndexMap&) = delete;
140
141 // If |obj| is in the map, immediately return true. Otherwise add it to the
142 // map and return false. In either case set |*index_out| to the index
143 // associated with the map.
144 bool LookupOrInsert(HeapObject obj, int* index_out) {
145 auto find_result = map_.FindOrInsert(obj);
146 if (!find_result.already_exists) {
147 *find_result.entry = next_index_++;
148 }
149 *index_out = *find_result.entry;
150 return find_result.already_exists;
151 }
152 bool LookupOrInsert(Handle<HeapObject> obj, int* index_out) {
153 return LookupOrInsert(*obj, index_out);
154 }
155
156 bool Lookup(HeapObject obj, int* index_out) const {
157 int* index = map_.Find(obj);
158 if (index == nullptr) {
3
Assuming the condition is true
4
Taking true branch
159 return false;
5
Returning without writing to '*index_out'
160 }
161 *index_out = *index;
162 return true;
163 }
164
165 Handle<FixedArray> Values(Isolate* isolate);
166
167 int size() const { return next_index_; }
168
169 private:
170 IdentityMap<int, base::DefaultAllocationPolicy> map_;
171 int next_index_;
172};
173
174class Serializer : public SerializerDeserializer {
175 public:
176 Serializer(Isolate* isolate, Snapshot::SerializerFlags flags);
177 ~Serializer() override { DCHECK_EQ(unresolved_forward_refs_, 0)((void) 0); }
178 Serializer(const Serializer&) = delete;
179 Serializer& operator=(const Serializer&) = delete;
180
181 const std::vector<byte>* Payload() const { return sink_.data(); }
182
183 bool ReferenceMapContains(Handle<HeapObject> o) {
184 return reference_map()->LookupReference(o) != nullptr;
185 }
186
187 Isolate* isolate() const { return isolate_; }
188
189 // The pointer compression cage base value used for decompression of all
190 // tagged values except references to Code objects.
191 PtrComprCageBase cage_base() const {
192#if V8_COMPRESS_POINTERS
193 return cage_base_;
194#else
195 return PtrComprCageBase{};
196#endif // V8_COMPRESS_POINTERS
197 }
198
199 int TotalAllocationSize() const;
200
201 protected:
202 using PendingObjectReferences = std::vector<int>*;
203
204 class ObjectSerializer;
205 class V8_NODISCARD[[nodiscard]] RecursionScope {
206 public:
207 explicit RecursionScope(Serializer* serializer) : serializer_(serializer) {
208 serializer_->recursion_depth_++;
209 }
210 ~RecursionScope() { serializer_->recursion_depth_--; }
211 bool ExceedsMaximum() {
212 return serializer_->recursion_depth_ >= kMaxRecursionDepth;
213 }
214
215 private:
216 static const int kMaxRecursionDepth = 32;
217 Serializer* serializer_;
218 };
219
220 // Compares obj with not_mapped_symbol root. When V8_EXTERNAL_CODE_SPACE is
221 // enabled it compares full pointers.
222 V8_INLINEinline __attribute__((always_inline)) bool IsNotMappedSymbol(HeapObject obj) const;
223
224 void SerializeDeferredObjects();
225 void SerializeObject(Handle<HeapObject> o);
226 virtual void SerializeObjectImpl(Handle<HeapObject> o) = 0;
227
228 virtual bool MustBeDeferred(HeapObject object);
229
230 void VisitRootPointers(Root root, const char* description,
231 FullObjectSlot start, FullObjectSlot end) override;
232 void SerializeRootObject(FullObjectSlot slot);
233
234 void PutRoot(RootIndex root_index);
235 void PutSmiRoot(FullObjectSlot slot);
236 void PutBackReference(HeapObject object, SerializerReference reference);
237 void PutAttachedReference(SerializerReference reference);
238 void PutNextChunk(SnapshotSpace space);
239 void PutRepeat(int repeat_count);
240
241 // Emit a marker noting that this slot is a forward reference to the an
242 // object which has not yet been serialized.
243 void PutPendingForwardReference(PendingObjectReferences& ref);
244 // Resolve the given previously registered forward reference to the current
245 // object.
246 void ResolvePendingForwardReference(int obj);
247
248 // Returns true if the object was successfully serialized as a root.
249 bool SerializeRoot(HeapObject obj);
250
251 // Returns true if the object was successfully serialized as hot object.
252 bool SerializeHotObject(HeapObject obj);
253
254 // Returns true if the object was successfully serialized as back reference.
255 bool SerializeBackReference(HeapObject obj);
256
257 // Returns true if the object was successfully serialized as pending object.
258 bool SerializePendingObject(HeapObject obj);
259
260 // Returns true if the given heap object is a bytecode handler code object.
261 bool ObjectIsBytecodeHandler(HeapObject obj) const;
262
263 ExternalReferenceEncoder::Value EncodeExternalReference(Address addr);
264
265 Maybe<ExternalReferenceEncoder::Value> TryEncodeExternalReference(
266 Address addr) {
267 return external_reference_encoder_.TryEncode(addr);
268 }
269
270 // GetInt reads 4 bytes at once, requiring padding at the end.
271 // Use padding_offset to specify the space you want to use after padding.
272 void Pad(int padding_offset = 0);
273
274 // We may not need the code address map for logging for every instance
275 // of the serializer. Initialize it on demand.
276 void InitializeCodeAddressMap();
277
278 Code CopyCode(Code code);
279
280 void QueueDeferredObject(HeapObject obj) {
281 DCHECK_NULL(reference_map_.LookupReference(obj))((void) 0);
282 deferred_objects_.Push(obj);
283 }
284
285 // Register that the the given object shouldn't be immediately serialized, but
286 // will be serialized later and any references to it should be pending forward
287 // references.
288 void RegisterObjectIsPending(HeapObject obj);
289
290 // Resolve the given pending object reference with the current object.
291 void ResolvePendingObject(HeapObject obj);
292
293 void OutputStatistics(const char* name);
294
295 void CountAllocation(Map map, int size, SnapshotSpace space);
296
297#ifdef DEBUG
298 void PushStack(Handle<HeapObject> o) { stack_.Push(*o); }
299 void PopStack();
300 void PrintStack();
301 void PrintStack(std::ostream&);
302#endif // DEBUG
303
304 SerializerReferenceMap* reference_map() { return &reference_map_; }
305 const RootIndexMap* root_index_map() const { return &root_index_map_; }
306
307 SnapshotByteSink sink_; // Used directly by subclasses.
308
309 bool allow_unknown_external_references_for_testing() const {
310 return (flags_ & Snapshot::kAllowUnknownExternalReferencesForTesting) != 0;
311 }
312 bool allow_active_isolate_for_testing() const {
313 return (flags_ & Snapshot::kAllowActiveIsolateForTesting) != 0;
314 }
315
316 bool reconstruct_read_only_and_shared_object_caches_for_testing() const {
317 return (flags_ &
318 Snapshot::kReconstructReadOnlyAndSharedObjectCachesForTesting) != 0;
319 }
320
321 private:
322 // A circular queue of hot objects. This is added to in the same order as in
323 // Deserializer::HotObjectsList, but this stores the objects as an array of
324 // raw addresses that are considered strong roots. This allows objects to be
325 // added to the list without having to extend their handle's lifetime.
326 //
327 // We should never allow this class to return Handles to objects in the queue,
328 // as the object in the queue may change if kSize other objects are added to
329 // the queue during that Handle's lifetime.
330 class HotObjectsList {
331 public:
332 explicit HotObjectsList(Heap* heap);
333 ~HotObjectsList();
334 HotObjectsList(const HotObjectsList&) = delete;
335 HotObjectsList& operator=(const HotObjectsList&) = delete;
336
337 void Add(HeapObject object) {
338 circular_queue_[index_] = object.ptr();
339 index_ = (index_ + 1) & kSizeMask;
340 }
341
342 static const int kNotFound = -1;
343
344 int Find(HeapObject object) {
345 DCHECK(!AllowGarbageCollection::IsAllowed())((void) 0);
346 for (int i = 0; i < kSize; i++) {
347 if (circular_queue_[i] == object.ptr()) {
348 return i;
349 }
350 }
351 return kNotFound;
352 }
353
354 private:
355 static const int kSize = kHotObjectCount;
356 static const int kSizeMask = kSize - 1;
357 STATIC_ASSERT(base::bits::IsPowerOfTwo(kSize))static_assert(base::bits::IsPowerOfTwo(kSize), "base::bits::IsPowerOfTwo(kSize)"
)
;
358 Heap* heap_;
359 StrongRootsEntry* strong_roots_entry_;
360 Address circular_queue_[kSize] = {kNullAddress};
361 int index_ = 0;
362 };
363
364 // Disallow GC during serialization.
365 // TODO(leszeks, v8:10815): Remove this constraint.
366 DISALLOW_GARBAGE_COLLECTION(no_gc_)
367
368 Isolate* isolate_;
369#if V8_COMPRESS_POINTERS
370 const PtrComprCageBase cage_base_;
371#endif // V8_COMPRESS_POINTERS
372 HotObjectsList hot_objects_;
373 SerializerReferenceMap reference_map_;
374 ExternalReferenceEncoder external_reference_encoder_;
375 RootIndexMap root_index_map_;
376 std::unique_ptr<CodeAddressMap> code_address_map_;
377 std::vector<byte> code_buffer_;
378 GlobalHandleVector<HeapObject>
379 deferred_objects_; // To handle stack overflow.
380 int num_back_refs_ = 0;
381
382 // Objects which have started being serialized, but haven't yet been allocated
383 // with the allocator, are considered "pending". References to them don't have
384 // an allocation to backref to, so instead they are registered as pending
385 // forward references, which are resolved once the object is allocated.
386 //
387 // Forward references are registered in a deterministic order, and can
388 // therefore be identified by an incrementing integer index, which is
389 // effectively an index into a vector of the currently registered forward
390 // refs. The references in this vector might not be resolved in order, so we
391 // can only clear it (and reset the indices) when there are no unresolved
392 // forward refs remaining.
393 int next_forward_ref_id_ = 0;
394 int unresolved_forward_refs_ = 0;
395 IdentityMap<PendingObjectReferences, base::DefaultAllocationPolicy>
396 forward_refs_per_pending_object_;
397
398 // Used to keep track of the off-heap backing stores used by TypedArrays/
399 // ArrayBuffers. Note that the index begins at 1 and not 0, because when a
400 // TypedArray has an on-heap backing store, the backing_store pointer in the
401 // corresponding ArrayBuffer will be null, which makes it indistinguishable
402 // from index 0.
403 uint32_t seen_backing_stores_index_ = 1;
404
405 int recursion_depth_ = 0;
406 const Snapshot::SerializerFlags flags_;
407
408 size_t allocation_size_[kNumberOfSnapshotSpaces] = {0};
409#ifdef OBJECT_PRINT1
410 static constexpr int kInstanceTypes = LAST_TYPE + 1;
411 std::unique_ptr<int[]> instance_type_count_[kNumberOfSnapshotSpaces];
412 std::unique_ptr<size_t[]> instance_type_size_[kNumberOfSnapshotSpaces];
413#endif // OBJECT_PRINT
414
415#ifdef DEBUG
416 GlobalHandleVector<HeapObject> back_refs_;
417 GlobalHandleVector<HeapObject> stack_;
418#endif // DEBUG
419};
420
421class RelocInfoIterator;
422
423class Serializer::ObjectSerializer : public ObjectVisitor {
424 public:
425 ObjectSerializer(Serializer* serializer, Handle<HeapObject> obj,
426 SnapshotByteSink* sink)
427 : isolate_(serializer->isolate()),
428 serializer_(serializer),
429 object_(obj),
430 sink_(sink),
431 bytes_processed_so_far_(0) {
432#ifdef DEBUG
433 serializer_->PushStack(obj);
434#endif // DEBUG
435 }
436 ~ObjectSerializer() override {
437#ifdef DEBUG
438 serializer_->PopStack();
439#endif // DEBUG
440 }
441 void Serialize();
442 void SerializeObject();
443 void SerializeDeferred();
444 void VisitPointers(HeapObject host, ObjectSlot start,
445 ObjectSlot end) override;
446 void VisitPointers(HeapObject host, MaybeObjectSlot start,
447 MaybeObjectSlot end) override;
448 void VisitCodePointer(HeapObject host, CodeObjectSlot slot) override;
449 void VisitEmbeddedPointer(Code host, RelocInfo* target) override;
450 void VisitExternalReference(Foreign host, Address* p) override;
451 void VisitExternalReference(Code host, RelocInfo* rinfo) override;
452 void VisitExternalPointer(HeapObject host, ExternalPointer_t ptr) override;
453 void VisitInternalReference(Code host, RelocInfo* rinfo) override;
454 void VisitCodeTarget(Code host, RelocInfo* target) override;
455 void VisitRuntimeEntry(Code host, RelocInfo* reloc) override;
456 void VisitOffHeapTarget(Code host, RelocInfo* target) override;
457
458 Isolate* isolate() { return isolate_; }
459
460 private:
461 class RelocInfoObjectPreSerializer;
462
463 void SerializePrologue(SnapshotSpace space, int size, Map map);
464
465 // This function outputs or skips the raw data between the last pointer and
466 // up to the current position.
467 void SerializeContent(Map map, int size);
468 void OutputExternalReference(Address target, int target_size, bool sandboxify,
469 ExternalPointerTag tag);
470 void OutputRawData(Address up_to);
471 void SerializeCode(Map map, int size);
472 uint32_t SerializeBackingStore(void* backing_store, int32_t byte_length,
473 Maybe<int32_t> max_byte_length);
474 void SerializeJSTypedArray();
475 void SerializeJSArrayBuffer();
476 void SerializeExternalString();
477 void SerializeExternalStringAsSequentialString();
478
479 Isolate* isolate_;
480 Serializer* serializer_;
481 Handle<HeapObject> object_;
482 SnapshotByteSink* sink_;
483 int bytes_processed_so_far_;
484};
485
486} // namespace internal
487} // namespace v8
488
489#endif // V8_SNAPSHOT_SERIALIZER_H_