_;
  arrays_ = *arrays_handle_;
  array_buffers_ = *array_buffers_handle_;
  typed_arrays_ = *typed_arrays_handle_;
  objects_ = *objects_handle_;
  external_references_ = *external_references_handle_;
}

// static
std::tuple<const uint8_t*, uint32_t, bool>
WebSnapshotDeserializer::ExtractScriptBuffer(
    Isolate* isolate, Handle<Script> snapshot_as_script) {
  Handle<String> source =
      handle(String::cast(snapshot_as_script->source()), isolate);
  if (source->IsExternalOneByteString()) {
    const v8::String::ExternalOneByteStringResource* resource =
        ExternalOneByteString::cast(*source).resource();
    return std::make_tuple(reinterpret_cast<const uint8_t*>(resource->data()),
                           resource->length(), false);
  } else if (source->IsSeqOneByteString()) {
    SeqOneByteString source_as_seq = SeqOneByteString::cast(*source);
    size_t length = source_as_seq.length();
    std::unique_ptr<uint8_t[]> data_copy(new uint8_t[length]);
    {
      DisallowGarbageCollection no_gc;
      uint8_t* data = source_as_seq.GetChars(no_gc);
      memcpy(data_copy.get(), data, length);
    }
    return std::make_tuple(data_copy.release(), length, true);
  } else if (source->IsExternalTwoByteString()) {
    // TODO(v8:11525): Implement end-to-end snapshot processing which gets rid
    // of the need to copy the data here.
    const v8::String::ExternalStringResource* resource =
        ExternalTwoByteString::cast(*source).resource();
    size_t length = resource->length();
    std::unique_ptr<uint8_t[]> data_copy(new uint8_t[length]);
    {
      DisallowGarbageCollection no_gc;
      const uint16_t* data = resource->data();
      uint8_t* data_copy_ptr = data_copy.get();
      for (size_t i = 0; i < length; ++i) {
        data_copy_ptr[i] = static_cast<uint8_t>(data[i]);
      }
    }
    return std::make_tuple(data_copy.release(), length, true);
  } else if (source->IsSeqTwoByteString()) {
    SeqTwoByteString source_as_seq = SeqTwoByteString::cast(*source);
    size_t length = source_as_seq.length();
    std::unique_ptr<uint8_t[]> data_copy(new uint8_t[length]);
    {
      DisallowGarbageCollection no_gc;
      uint16_t* data = source_as_seq.GetChars(no_gc);
      uint8_t* data_copy_ptr = data_copy.get();
      for (size_t i = 0; i < length; ++i) {
        data_copy_ptr[i] = static_cast<uint8_t>(data[i]);
      }
    }
    return std::make_tuple(data_copy.release(), length, true);
  }
  UNREACHABLE();
}

void WebSnapshotDeserializer::Throw(const char* message) {
  string_count_ = 0;
  symbol_count_ = 0;
  map_count_ = 0;
  builtin_object_count_ = 0;
  context_count_ = 0;
  class_count_ = 0;
  function_count_ = 0;
  object_count_ = 0;
  deferred_references_->SetLength(0);

  // Make sure we don't read any more data
  deserializer_->position_ = deserializer_->end_;

  WebSnapshotSerializerDeserializer::Throw(message);
}

bool WebSnapshotDeserializer::Deserialize(
    MaybeHandle<FixedArray> external_references, bool skip_exports) {
  RCS_SCOPE(isolate_, RuntimeCallCounterId::kWebSnapshotDeserialize);
  if (external_references.ToHandle(&external_references_handle_)) {
    external_references_ = *external_references_handle_;
  } else {
    external_references_handle_ = roots_.empty_fixed_array_handle();
  }

  if (deserialized_) {
    Throw("Can't reuse WebSnapshotDeserializer");
    return false;
  }
  deserialized_ = true;
  auto buffer_size = deserializer_->end_ - deserializer_->position_;

  base::ElapsedTimer timer;
  if (FLAG_trace_web_snapshot) {
    timer.Start();
  }
  if (!DeserializeSnapshot(skip_exports)) {
    return false;
  }
  if (!DeserializeScript()) {
    return false;
  }

  if (FLAG_trace_web_snapshot) {
    double ms = timer.Elapsed().InMillisecondsF();
    PrintF("[Deserializing snapshot (%zu bytes) took %0.3f ms]\n", buffer_size,
           ms);
  }
  return true;
}

bool WebSnapshotDeserializer::DeserializeSnapshot(bool skip_exports) {
  CollectBuiltinObjects();

  deferred_references_ = ArrayList::New(isolate_, 30);

  const void* magic_bytes;
  if (!deserializer_->ReadRawBytes(sizeof(kMagicNumber), &magic_bytes) ||
      memcmp(magic_bytes, kMagicNumber, sizeof(kMagicNumber))!= 0) {
    Throw("Invalid magic number");
    return false;
  }

  DeserializeStrings();
  DeserializeSymbols();
  DeserializeBuiltinObjects();
  DeserializeMaps();
  DeserializeContexts();
  DeserializeFunctions();
  DeserializeArrays();
  DeserializeArrayBuffers();
  DeserializeTypedArrays();
  DeserializeObjects();
  DeserializeClasses();
  ProcessDeferredReferences();
  DeserializeExports(skip_exports);
  DCHECK_EQ(0, deferred_references_->Length());

  return!has_error();
}

void WebSnapshotDeserializer::CollectBuiltinObjects() {
  // TODO(v8:11525): Look up the builtin objects from the global object.
  builtin_object_name_to_object_ =
      ObjectHashTable::New(isolate_, kBuiltinObjectCount);
#if DEBUG
  int i = 0;
#endif
  IterateBuiltinObjects([&](Handle<String> name, Handle<HeapObject> object) {
    auto new_builtin_object_name_to_object =
        ObjectHashTable::Put(builtin_object_name_to_object_, name, object);
    USE(new_builtin_object_name_to_object);
    // We preallocated the correct size, so the hash table doesn't grow.
    DCHECK_EQ(*new_builtin_object_name_to_object,
              *builtin_object_name_to_object_);
#if DEBUG
    ++i;
#endif
  });
  DCHECK_EQ(i, kBuiltinObjectCount);
}

bool WebSnapshotDeserializer::DeserializeScript() {
  // If there is more data, treat it as normal JavaScript.
  DCHECK_LE(deserializer_->position_, deserializer_->end_);
  auto remaining_bytes = deserializer_->end_ - deserializer_->position_;
  if (remaining_bytes > 0 && remaining_bytes < v8::String::kMaxLength) {
    v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate_);
    v8::Local<v8::String> source =
        v8::String::NewFromUtf8(
            v8_isolate, reinterpret_cast<const char*>(deserializer_->position_),
            NewStringType::kNormal, static_cast<int>(remaining_bytes))
           .ToLocalChecked();

    ScriptOrigin origin(v8_isolate, Utils::ToLocal(script_name_));

    ScriptCompiler::Source script_source(source, origin);
    Local<UnboundScript> script;
    if (!ScriptCompiler::CompileUnboundScript(v8_isolate, &script_source)
            .ToLocal(&script)) {
      // The exception