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());
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();
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);  // Iterated in order.
548    DCHECK_LE(interval.first, interval.second);
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);
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());
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());
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());
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());
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());
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());
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());
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());
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);
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());
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();
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);  // 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);
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);
1176  USE(return_value);
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);
1184  USE(return_value);
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);
1192  USE(return_value);
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);
1200  USE(return_value);
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);
1208  USE(return_value);
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);
1216  USE(return_value);
1217  return static_cast<uint32_t>(object_ids_.size() - 1 - id);
1218}
1219
1220uint32_t WebSnapshotSerializer::GetExternalId(HeapObject object) {
1221  int id;
1222  bool return_value = external_objects_ids_.Lookup(object, &id);
1223  DCHECK(return_value);
1224  USE(return_value);
1225  return static_cast<uint32_t>(id);
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();
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());
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_);
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());
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());
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);
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());
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);
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);
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);
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());
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_);
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);
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);
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);
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);
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);
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);
1963      CHECK_EQ(PropertyKind::kData, details.kind());
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();
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()));
2005      DCHECK(!IsDoubleElementsKind(object->map().elements_kind()));
2006      DCHECK(IsHoleyElementsKind(object->map().elements_kind()));
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);
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);
2062      USE(export_value);
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);
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() ||
2336         container->IsFixedArray() || container->IsJSFunction() ||
2337         container->IsMap());
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();
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);
2411      DCHECK(target.IsJSReceiver());
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);
2421      DCHECK(target.IsJSReceiver());
2422      Map::cast(container).set_prototype(HeapObject::cast(target),
2423                                         UPDATE_WRITE_BARRIER);
2424    } else {
2425      UNREACHABLE();
2426    }
2427  }
2428  deferred_references_->SetLength(0);
2429}
2430
2431}  // namespace internal
2432}  // namespace v8
2433