// Copyright 2018 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_EMBEDDED_EMBEDDED_FILE_WRITER_H_
#define V8_SNAPSHOT_EMBEDDED_EMBEDDED_FILE_WRITER_H_

#include <cinttypes>
#include <cstdio>
#include <cstring>

#include "src/common/globals.h"
#include "src/snapshot/embedded/embedded-data.h"
#include "src/snapshot/embedded/platform-embedded-file-writer-base.h"

#if defined(V8_OS_WIN_X64)
#include "src/diagnostics/unwinding-info-win64.h"
#endif

namespace v8 {
namespace internal {

static constexpr char kDefaultEmbeddedVariant[] = "Default";

// Detailed source-code information about builtins can only be obtained by
// registration on the isolate during compilation.
class EmbeddedFileWriterInterface {
 public:
  // We maintain a database of filenames to synthetic IDs.
  virtual int LookupOrAddExternallyCompiledFilename(const char* filename) = 0;
  virtual const char* GetExternallyCompiledFilename(int index) const = 0;
  virtual int GetExternallyCompiledFilenameCount() const = 0;

  // The isolate will call the method below just prior to replacing the
  // compiled builtin Code objects with trampolines.
  virtual void PrepareBuiltinSourcePositionMap(Builtins* builtins) = 0;

#if defined(V8_OS_WIN_X64)
  virtual void SetBuiltinUnwindData(
      int builtin_index,
      const win64_unwindinfo::BuiltinUnwindInfo& unwinding_info) = 0;
#endif
};

// Generates the embedded.S file which is later compiled into the final v8
// binary. Its contents are exported through two symbols:
//
// v8_<variant>_embedded_blob_ (intptr_t):
//     a pointer to the start of the embedded blob.
// v8_<variant>_embedded_blob_size_ (uint32_t):
//     size of the embedded blob in bytes.
//
// The variant is usually "Default" but can be modified in multisnapshot builds.
class EmbeddedFileWriter : public EmbeddedFileWriterInterface {
 public:
  int LookupOrAddExternallyCompiledFilename(const char* filename) override;
  const char* GetExternallyCompiledFilename(int fileid) const override;
  int GetExternallyCompiledFilenameCount() const override;

  void PrepareBuiltinSourcePositionMap(Builtins* builtins) override;

#if defined(V8_OS_WIN_X64)
  void SetBuiltinUnwindData(
      int builtin_index,
      const win64_unwindinfo::BuiltinUnwindInfo& unwinding_info) override {
    DCHECK_LT(builtin_index, Builtins::builtin_count);
    unwind_infos_[builtin_index] = unwinding_info;
  }
#endif

  void SetEmbeddedFile(const char* embedded_src_path) {
    embedded_src_path_ = embedded_src_path;
  }

  void SetEmbeddedVariant(const char* embedded_variant) {
    if (embedded_variant == nullptr) return;
    embedded_variant_ = embedded_variant;
  }

  void SetTargetArch(const char* target_arch) { target_arch_ = target_arch; }

  void SetTargetOs(const char* target_os) { target_os_ = target_os; }

  void WriteEmbedded(const i::EmbeddedData* blob) const {
    MaybeWriteEmbeddedFile(blob);
  }

 private:
  void MaybeWriteEmbeddedFile(const i::EmbeddedData* blob) const {
    if (embedded_src_path_ == nullptr) return;

    FILE* fp = GetFileDescriptorOrDie(embedded_src_path_);

    std::unique_ptr<PlatformEmbeddedFileWriterBase> writer =
        NewPlatformEmbeddedFileWriter(target_arch_, target_os_);
    writer->SetFile(fp);

    WriteFilePrologue(writer.get());
    WriteExternalFilenames(writer.get());
    WriteMetadataSection(writer.get(), blob);
    WriteInstructionStreams(writer.get(), blob);
    WriteFileEpilogue(writer.get(), blob);

    fclose(fp);
  }

  static FILE* GetFileDescriptorOrDie(const char* filename) {
    FILE* fp = v8::base::OS::FOpen(filename, "wb");
    if (fp == nullptr) {
      i::PrintF("Unable to open file \"%s\" for writing.\n", filename);
      exit(1);
    }
    return fp;
  }

  void WriteFilePrologue(PlatformEmbeddedFileWriterBase* w) const {
    w->Comment("Autogenerated file. Do not edit.");
    w->Newline();
    w->FilePrologue();
  }

  void WriteExternalFilenames(PlatformEmbeddedFileWriterBase* w) const {
    w->Comment(
        "Source positions in the embedded blob refer to filenames by id.");
    w->Comment("Assembly directives here map the id to a filename.");
    w->Newline();

    // Write external filenames.
    int size = static_cast<int>(external_filenames_by_index_.size());
    for (int i = 0; i < size; i++) {
      w->DeclareExternalFilename(ExternalFilenameIndexToId(i),
                                 external_filenames_by_index_[i]);
    }
  }

  // Fairly arbitrary but should fit all symbol names.
  static constexpr int kTemporaryStringLength = 256;

  std::string EmbeddedBlobDataSymbol() const {
    i::EmbeddedVector<char, kTemporaryStringLength> embedded_blob_data_symbol;
    i::SNPrintF(embedded_blob_data_symbol, "v8_%s_embedded_blob_data_",
                embedded_variant_);
    return std::string{embedded_blob_data_symbol.begin()};
  }

  void WriteMetadataSection(PlatformEmbeddedFileWriterBase* w,
                            const i::EmbeddedData* blob) const {
    w->Comment("The embedded blob starts here. Metadata comes first, followed");
    w->Comment("by builtin instruction streams.");
    w->SectionText();
    w->AlignToCodeAlignment();
    w->DeclareLabel(EmbeddedBlobDataSymbol().c_str());

    WriteBinaryContentsAsInlineAssembly(w, blob->data(),
                                        i::EmbeddedData::RawDataOffset());
  }

  void WriteBuiltin(PlatformEmbeddedFileWriterBase* w,
                    const i::EmbeddedData* blob, const int builtin_id) const;

  void WriteInstructionStreams(PlatformEmbeddedFileWriterBase* w,
                               const i::EmbeddedData* blob) const {
    for (int i = 0; i < i::Builtins::builtin_count; i++) {
      if (!blob->ContainsBuiltin(i)) continue;

      WriteBuiltin(w, blob, i);
    }
    w->Newline();
  }

  void WriteFileEpilogue(PlatformEmbeddedFileWriterBase* w,
                         const i::EmbeddedData* blob) const;

#if defined(V8_OS_WIN_X64)
  std::string BuiltinsUnwindInfoLabel() const;
  void WriteUnwindInfo(PlatformEmbeddedFileWriterBase* w,
                       const i::EmbeddedData* blob) const;
  void WriteUnwindInfoEntry(PlatformEmbeddedFileWriterBase* w,
                            uint64_t rva_start, uint64_t rva_end) const;
#endif

  static void WriteBinaryContentsAsInlineAssembly(
      PlatformEmbeddedFileWriterBase* w, const uint8_t* data, uint32_t size);

  // In assembly directives, filename ids need to begin with 1.
  static constexpr int kFirstExternalFilenameId = 1;
  static int ExternalFilenameIndexToId(int index) {
    return kFirstExternalFilenameId + index;
  }
  static int ExternalFilenameIdToIndex(int id) {
    return id - kFirstExternalFilenameId;
  }

 private:
  std::vector<byte> source_positions_[Builtins::builtin_count];

#if defined(V8_OS_WIN_X64)
  win64_unwindinfo::BuiltinUnwindInfo unwind_infos_[Builtins::builtin_count];
#endif

  std::map<const char*, int> external_filenames_;
  std::vector<const char*> external_filenames_by_index_;

  // The file to generate or nullptr.
  const char* embedded_src_path_ = nullptr;

  // The variant is only used in multi-snapshot builds and otherwise set to
  // "Default".
  const char* embedded_variant_ = kDefaultEmbeddedVariant;

  // {target_arch} and {target_os} control the generated assembly format. Note
  // these may differ from both host- and target-platforms specified through
  // e.g. V8_OS_* and V8_TARGET_ARCH_* defines.
  const char* target_arch_ = nullptr;
  const char* target_os_ = nullptr;
};

}  // namespace internal
}  // namespace v8

#endif  // V8_SNAPSHOT_EMBEDDED_EMBEDDED_FILE_WRITER_H_
