// Copyright 2017 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "src/snapshot/object-deserializer.h"

#include "src/assembler-inl.h"
#include "src/code-stubs.h"
#include "src/isolate.h"
#include "src/objects.h"
#include "src/snapshot/code-serializer.h"
#include "src/wasm/wasm-objects.h"

namespace v8 {
namespace internal {

MaybeHandle<SharedFunctionInfo>
ObjectDeserializer::DeserializeSharedFunctionInfo(
    Isolate* isolate, const SerializedCodeData* data, Handle<String> source) {
  ObjectDeserializer d(data);

  d.AddAttachedObject(source);

  Vector<const uint32_t> code_stub_keys = data->CodeStubKeys();
  for (int i = 0; i < code_stub_keys.length(); i++) {
    d.AddAttachedObject(
        CodeStub::GetCode(isolate, code_stub_keys[i]).ToHandleChecked());
  }

  Handle<HeapObject> result;
  return d.Deserialize(isolate).ToHandle(&result)
             ? Handle<SharedFunctionInfo>::cast(result)
             : MaybeHandle<SharedFunctionInfo>();
}

MaybeHandle<WasmCompiledModule>
ObjectDeserializer::DeserializeWasmCompiledModule(
    Isolate* isolate, const SerializedCodeData* data,
    Vector<const byte> wire_bytes) {
  ObjectDeserializer d(data);

  d.AddAttachedObject(isolate->native_context());

  MaybeHandle<String> maybe_wire_bytes_as_string =
      isolate->factory()->NewStringFromOneByte(wire_bytes, TENURED);
  Handle<String> wire_bytes_as_string;
  if (!maybe_wire_bytes_as_string.ToHandle(&wire_bytes_as_string)) {
    return MaybeHandle<WasmCompiledModule>();
  }
  d.AddAttachedObject(wire_bytes_as_string);

  Vector<const uint32_t> code_stub_keys = data->CodeStubKeys();
  for (int i = 0; i < code_stub_keys.length(); i++) {
    d.AddAttachedObject(
        CodeStub::GetCode(isolate, code_stub_keys[i]).ToHandleChecked());
  }

  Handle<HeapObject> result;
  if (!d.Deserialize(isolate).ToHandle(&result))
    return MaybeHandle<WasmCompiledModule>();

  if (!result->IsFixedArray()) return MaybeHandle<WasmCompiledModule>();

  // Cast without type checks, as the module wrapper is not there yet.
  return handle(static_cast<WasmCompiledModule*>(*result), isolate);
}

MaybeHandle<HeapObject> ObjectDeserializer::Deserialize(Isolate* isolate) {
  Initialize(isolate);
  if (!ReserveSpace()) return MaybeHandle<HeapObject>();

  DCHECK(deserializing_user_code());
  HandleScope scope(isolate);
  Handle<HeapObject> result;
  {
    DisallowHeapAllocation no_gc;
    Object* root;
    VisitRootPointer(Root::kPartialSnapshotCache, &root);
    DeserializeDeferredObjects();
    FlushICacheForNewCodeObjectsAndRecordEmbeddedObjects();
    result = Handle<HeapObject>(HeapObject::cast(root));
    RegisterDeserializedObjectsForBlackAllocation();
  }
  CommitPostProcessedObjects();
  return scope.CloseAndEscape(result);
}

void ObjectDeserializer::
    FlushICacheForNewCodeObjectsAndRecordEmbeddedObjects() {
  DCHECK(deserializing_user_code());
  for (Code* code : new_code_objects()) {
    // Record all references to embedded objects in the new code object.
    isolate()->heap()->RecordWritesIntoCode(code);
    Assembler::FlushICache(isolate(), code->instruction_start(),
                           code->instruction_size());
  }
}

void ObjectDeserializer::CommitPostProcessedObjects() {
  CHECK(new_internalized_strings().size() <= kMaxInt);
  StringTable::EnsureCapacityForDeserialization(
      isolate(), static_cast<int>(new_internalized_strings().size()));
  for (Handle<String> string : new_internalized_strings()) {
    StringTableInsertionKey key(*string);
    DCHECK_NULL(StringTable::LookupKeyIfExists(isolate(), &key));
    StringTable::LookupKey(isolate(), &key);
  }

  Heap* heap = isolate()->heap();
  Factory* factory = isolate()->factory();
  for (Handle<Script> script : new_scripts()) {
    // Assign a new script id to avoid collision.
    script->set_id(isolate()->heap()->NextScriptId());
    // Add script to list.
    Handle<Object> list = WeakFixedArray::Add(factory->script_list(), script);
    heap->SetRootScriptList(*list);
  }
}

}  // namespace internal
}  // namespace v8
