// 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.

#ifndef V8_SNAPSHOT_BUILTIN_DESERIALIZER_H_
#define V8_SNAPSHOT_BUILTIN_DESERIALIZER_H_

#include "src/interpreter/interpreter.h"
#include "src/snapshot/builtin-deserializer-allocator.h"
#include "src/snapshot/builtin-snapshot-utils.h"
#include "src/snapshot/deserializer.h"

namespace v8 {
namespace internal {

class BuiltinSnapshotData;

// Deserializes the builtins blob.
class BuiltinDeserializer final
    : public Deserializer<BuiltinDeserializerAllocator> {
  using BSU = BuiltinSnapshotUtils;
  using Bytecode = interpreter::Bytecode;
  using OperandScale = interpreter::OperandScale;

 public:
  BuiltinDeserializer(Isolate* isolate, const BuiltinSnapshotData* data);

  // Builtins deserialization is tightly integrated with deserialization of the
  // startup blob. In particular, we need to ensure that no GC can occur
  // between startup- and builtins deserialization, as all builtins have been
  // pre-allocated and their pointers may not be invalidated.
  //
  // After this, the instruction cache must be flushed by the caller (we don't
  // do it ourselves since the startup serializer batch-flushes all code pages).
  void DeserializeEagerBuiltinsAndHandlers();

  // Deserializes the single given builtin. This is used whenever a builtin is
  // lazily deserialized at runtime.
  Code* DeserializeBuiltin(int builtin_id);

  // Deserializes the single given handler. This is used whenever a handler is
  // lazily deserialized at runtime.
  Code* DeserializeHandler(Bytecode bytecode, OperandScale operand_scale);

 private:
  // Deserializes the single given builtin. Assumes that reservations have
  // already been allocated.
  Code* DeserializeBuiltinRaw(int builtin_id);

  // Deserializes the single given bytecode handler. Assumes that reservations
  // have already been allocated.
  Code* DeserializeHandlerRaw(Bytecode bytecode, OperandScale operand_scale);

  // Extracts the size builtin Code objects (baked into the snapshot).
  uint32_t ExtractCodeObjectSize(int builtin_id);

  // BuiltinDeserializer implements its own builtin iteration logic. Make sure
  // the RootVisitor API is not used accidentally.
  void VisitRootPointers(Root root, const char* description, Object** start,
                         Object** end) override {
    UNREACHABLE();
  }

  int CurrentCodeObjectId() const { return current_code_object_id_; }

  // Convenience function to grab the handler off the heap's strong root list.
  Code* GetDeserializeLazyHandler(OperandScale operand_scale) const;

 private:
  // Stores the code object currently being deserialized. The
  // {current_code_object_id} stores the index of the currently-deserialized
  // code object within the snapshot (and within {code_offsets_}). We need this
  // to determine where to 'allocate' from during deserialization.
  static const int kNoCodeObjectId = -1;
  int current_code_object_id_ = kNoCodeObjectId;

  // The offsets of each builtin within the serialized data. Equivalent to
  // BuiltinSerializer::builtin_offsets_ but on the deserialization side.
  Vector<const uint32_t> code_offsets_;

  // For current_code_object_id_.
  friend class DeserializingCodeObjectScope;

  // For isolate(), IsLazyDeserializationEnabled(), CurrentCodeObjectId() and
  // ExtractBuiltinSize().
  friend class BuiltinDeserializerAllocator;
};

}  // namespace internal
}  // namespace v8

#endif  // V8_SNAPSHOT_BUILTIN_DESERIALIZER_H_
