blob: 3ed9208f41bd7dd9a59215fa1b48f71c66164b3d [file] [log] [blame]
// 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 <memory>
#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_WIN64)
#include "src/base/platform/wrappers.h"
#include "src/diagnostics/unwinding-info-win64.h"
#endif // V8_OS_WIN64
namespace v8 {
namespace internal {
static constexpr char kDefaultEmbeddedVariant[] = "Default";
struct LabelInfo {
int offset;
std::string name;
};
// 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;
virtual void PrepareBuiltinLabelInfoMap(int create_offset, int invoke_offset,
int arguments_adaptor_offset) = 0;
#if defined(V8_OS_WIN64)
virtual void SetBuiltinUnwindData(
int builtin_index,
const win64_unwindinfo::BuiltinUnwindInfo& unwinding_info) = 0;
#endif // V8_OS_WIN64
};
// 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;
void PrepareBuiltinLabelInfoMap(int create_offset, int invoke_create,
int arguments_adaptor_offset) override;
#if defined(V8_OS_WIN64)
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 // V8_OS_WIN64
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());
WriteDataSection(writer.get(), blob);
WriteCodeSection(writer.get(), blob);
WriteFileEpilogue(writer.get(), blob);
base::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 {
#ifndef DEBUG
// Release builds must not contain debug infos.
CHECK_EQ(external_filenames_by_index_.size(), 0);
#endif
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 EmbeddedBlobCodeDataSymbol() const {
i::EmbeddedVector<char, kTemporaryStringLength>
embedded_blob_code_data_symbol;
i::SNPrintF(embedded_blob_code_data_symbol,
"v8_%s_embedded_blob_code_data_", embedded_variant_);
return std::string{embedded_blob_code_data_symbol.begin()};
}
std::string EmbeddedBlobDataDataSymbol() const {
i::EmbeddedVector<char, kTemporaryStringLength>
embedded_blob_data_data_symbol;
i::SNPrintF(embedded_blob_data_data_symbol,
"v8_%s_embedded_blob_data_data_", embedded_variant_);
return std::string{embedded_blob_data_data_symbol.begin()};
}
void WriteDataSection(PlatformEmbeddedFileWriterBase* w,
const i::EmbeddedData* blob) const {
w->Comment("The embedded blob data section starts here.");
w->SectionRoData();
w->AlignToDataAlignment();
w->DeclareLabel(EmbeddedBlobDataDataSymbol().c_str());
WriteBinaryContentsAsInlineAssembly(w, blob->data(), blob->data_size());
}
void WriteBuiltin(PlatformEmbeddedFileWriterBase* w,
const i::EmbeddedData* blob, const int builtin_id) const;
void WriteBuiltinLabels(PlatformEmbeddedFileWriterBase* w,
std::string name) const;
void WriteCodeSection(PlatformEmbeddedFileWriterBase* w,
const i::EmbeddedData* blob) const;
void WriteFileEpilogue(PlatformEmbeddedFileWriterBase* w,
const i::EmbeddedData* blob) const;
#if defined(V8_OS_WIN_X64)
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];
std::vector<LabelInfo> label_info_[Builtins::builtin_count];
#if defined(V8_OS_WIN64)
win64_unwindinfo::BuiltinUnwindInfo unwind_infos_[Builtins::builtin_count];
#endif // V8_OS_WIN64
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_