Commit bd8ed720 authored by Jakob Gruber's avatar Jakob Gruber Committed by Commit Bot

Reland "[snapshot] Emit the embedded blob as assembly instead of inline assembly"

This is a reland of 0b13f0f5

Original change's description:
> [snapshot] Emit the embedded blob as assembly instead of inline assembly
>
> The motivation behind this is that MSVC doesn't support inline assembly
> on x64. Emitting the embedded blob as a plain assembly file will give us
> MSVC support (and possibly faster compilation times as a side-effect).
>
> Bug: v8:6666,v8:8349
> Change-Id: I2e6cf072faa9ef406fe721a05b63912c655546c2
> Reviewed-on: https://chromium-review.googlesource.com/c/1329205
> Commit-Queue: Jakob Gruber <jgruber@chromium.org>
> Reviewed-by: Michael Stanton <mvstanton@chromium.org>
> Reviewed-by: Yang Guo <yangguo@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#57524}

Tbr: yangguo@chromium.org,mvstanton@chromium.org
Bug: v8:6666, v8:8349
Change-Id: Ib35696b60a9cd01bc2edf459c8e8d84716e3438d
Reviewed-on: https://chromium-review.googlesource.com/c/1337733Reviewed-by: 's avatarJakob Gruber <jgruber@chromium.org>
Commit-Queue: Jakob Gruber <jgruber@chromium.org>
Cr-Commit-Position: refs/heads/master@{#57546}
parent 66e0c164
......@@ -24,8 +24,6 @@ import("snapshot_toolchain.gni")
is_target_simulator = (target_cpu != v8_target_cpu && !v8_multi_arch_build) ||
(current_cpu != v8_current_cpu && v8_multi_arch_build)
is_msvc = is_win && !is_clang
declare_args() {
# Print to stdout on Android.
v8_android_log_stdout = false
......@@ -85,8 +83,8 @@ declare_args() {
v8_enable_fast_mksnapshot = false
# Enable embedded builtins.
# TODO(v8:6666): Support aix and MSVC.
v8_enable_embedded_builtins = !is_aix && !is_msvc
# TODO(v8:8043): Support aix.
v8_enable_embedded_builtins = !is_aix
# Build-time flag for enabling nojit mode.
# TODO(v8:7777): Remove the build-time flag once the --jitless runtime flag
......@@ -1035,7 +1033,7 @@ action("generate_bytecode_builtins_list") {
# Template to generate different V8 snapshots based on different runtime flags.
# Can be invoked with run_mksnapshot(<name>). The target will resolve to
# run_mksnapshot_<name>. If <name> is "default", no file suffixes will be used.
# Otherwise files are suffixed, e.g. embedded_<name>.cc and
# Otherwise files are suffixed, e.g. embedded_<name>.S and
# snapshot_blob_<name>.bin.
#
# The template exposes the variables:
......@@ -1074,10 +1072,10 @@ template("run_mksnapshot") {
args += invoker.args
if (v8_enable_embedded_builtins) {
outputs += [ "$target_gen_dir/embedded${suffix}.cc" ]
outputs += [ "$target_gen_dir/embedded${suffix}.S" ]
args += [
"--embedded_src",
rebase_path("$target_gen_dir/embedded${suffix}.cc", root_build_dir),
rebase_path("$target_gen_dir/embedded${suffix}.S", root_build_dir),
]
if (invoker.embedded_variant != "") {
args += [
......@@ -1281,7 +1279,7 @@ if (v8_use_snapshot && !v8_use_external_startup_data) {
]
if (v8_enable_embedded_builtins) {
sources += [ "$target_gen_dir/embedded.cc" ]
sources += [ "$target_gen_dir/embedded.S" ]
} else {
sources += [ "src/snapshot/embedded-empty.cc" ]
}
......@@ -1328,15 +1326,15 @@ if (v8_use_snapshot && v8_use_external_startup_data) {
public = []
if (v8_enable_embedded_builtins) {
sources += [ "$target_gen_dir/embedded.cc" ]
sources += [ "$target_gen_dir/embedded.S" ]
if (v8_use_multi_snapshots) {
sources += [ "$target_gen_dir/embedded_trusted.cc" ]
sources += [ "$target_gen_dir/embedded_trusted.S" ]
if (use_jumbo_build == true) {
jumbo_excluded_sources = [
# Duplicated symbols with embedded.cc
"$target_gen_dir/embedded_trusted.cc",
# Duplicated symbols with embedded.S
"$target_gen_dir/embedded_trusted.S",
]
}
}
......@@ -2493,7 +2491,6 @@ v8_source_set("v8_base") {
"src/snapshot/deserializer-allocator.h",
"src/snapshot/deserializer.cc",
"src/snapshot/deserializer.h",
"src/snapshot/macros.h",
"src/snapshot/natives-common.cc",
"src/snapshot/natives.h",
"src/snapshot/object-deserializer.cc",
......@@ -3419,6 +3416,8 @@ if (v8_use_snapshot && current_toolchain == v8_snapshot_toolchain) {
visibility = [ ":*" ] # Only targets in this file can depend on this.
sources = [
"src/snapshot/embedded-file-writer.cc",
"src/snapshot/embedded-file-writer.h",
"src/snapshot/mksnapshot.cc",
]
......
......@@ -73,6 +73,9 @@
#include "unicode/uobject.h"
#endif // V8_INTL_SUPPORT
extern "C" const uint8_t* v8_Default_embedded_blob_;
extern "C" uint32_t v8_Default_embedded_blob_size_;
namespace v8 {
namespace internal {
......@@ -88,12 +91,15 @@ namespace internal {
#define TRACE_ISOLATE(tag)
#endif
extern const uint8_t* DefaultEmbeddedBlob();
extern uint32_t DefaultEmbeddedBlobSize();
const uint8_t* DefaultEmbeddedBlob() { return v8_Default_embedded_blob_; }
uint32_t DefaultEmbeddedBlobSize() { return v8_Default_embedded_blob_size_; }
#ifdef V8_MULTI_SNAPSHOTS
extern const uint8_t* TrustedEmbeddedBlob();
extern uint32_t TrustedEmbeddedBlobSize();
extern "C" const uint8_t* v8_Trusted_embedded_blob_;
extern "C" uint32_t v8_Trusted_embedded_blob_size_;
const uint8_t* TrustedEmbeddedBlob() { return v8_Trusted_embedded_blob_; }
uint32_t TrustedEmbeddedBlobSize() { return v8_Trusted_embedded_blob_size_; }
#endif
namespace {
......
......@@ -1160,7 +1160,7 @@ void CodeDataContainer::CodeDataContainerVerify(Isolate* isolate) {
void Code::CodeVerify(Isolate* isolate) {
CHECK_LE(constant_pool_offset(), InstructionSize());
CHECK(IsAligned(InstructionStart(), kCodeAlignment));
CHECK(IsAligned(raw_instruction_start(), kCodeAlignment));
relocation_info()->ObjectVerify(isolate);
Address last_gc_pc = kNullAddress;
......
......@@ -6,16 +6,18 @@
#include <cstdint>
namespace v8 {
namespace internal {
#include "src/base/macros.h"
const uint8_t* DefaultEmbeddedBlob() { return nullptr; }
uint32_t DefaultEmbeddedBlobSize() { return 0; }
extern "C" const uint8_t* v8_Default_embedded_blob_;
extern "C" uint32_t v8_Default_embedded_blob_size_;
const uint8_t* v8_Default_embedded_blob_ = nullptr;
uint32_t v8_Default_embedded_blob_size_ = 0;
#ifdef V8_MULTI_SNAPSHOTS
const uint8_t* TrustedEmbeddedBlob() { return nullptr; }
uint32_t TrustedEmbeddedBlobSize() { return 0; }
#endif
extern "C" const uint8_t* v8_Trusted_embedded_blob_;
extern "C" uint32_t v8_Trusted_embedded_blob_size_;
} // namespace internal
} // namespace v8
const uint8_t* v8_Trusted_embedded_blob_ = nullptr;
uint32_t v8_Trusted_embedded_blob_size_ = 0;
#endif
This diff is collapsed.
// 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_FILE_WRITER_H_
#define V8_SNAPSHOT_EMBEDDED_FILE_WRITER_H_
#include <cstdio>
#include <cstring>
#include "src/globals.h"
#include "src/snapshot/snapshot.h"
namespace v8 {
namespace internal {
enum DataDirective {
kByte,
kLong,
kQuad,
kOcta,
};
static constexpr char kDefaultEmbeddedVariant[] = "Default";
// The platform-dependent logic for emitting assembly code for the generated
// embedded.S file.
class PlatformDependentEmbeddedFileWriter final {
public:
void SetFile(FILE* fp) { fp_ = fp; }
void SectionText();
void SectionData();
void SectionRoData();
void AlignToCodeAlignment();
void DeclareUint32(const char* name, uint32_t value);
void DeclarePointerToSymbol(const char* name, const char* target);
void DeclareLabel(const char* name);
void DeclareFunctionBegin(const char* name);
void DeclareFunctionEnd(const char* name);
// Returns the number of printed characters.
int HexLiteral(int value);
void Comment(const char* string);
void Newline() { fprintf(fp_, "\n"); }
void FilePrologue();
void FileEpilogue();
int IndentedDataDirective(DataDirective directive);
FILE* fp() const { return fp_; }
private:
void DeclareSymbolGlobal(const char* name);
static const char* DirectiveAsString(DataDirective directive);
private:
FILE* fp_ = nullptr;
};
// 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:
void SetEmbeddedFile(const char* embedded_cpp_file) {
embedded_cpp_path_ = embedded_cpp_file;
}
void SetEmbeddedVariant(const char* embedded_variant) {
embedded_variant_ = embedded_variant;
}
void WriteEmbedded(const i::EmbeddedData* blob) const {
MaybeWriteEmbeddedFile(blob);
}
private:
void MaybeWriteEmbeddedFile(const i::EmbeddedData* blob) const {
if (embedded_cpp_path_ == nullptr) return;
FILE* fp = GetFileDescriptorOrDie(embedded_cpp_path_);
PlatformDependentEmbeddedFileWriter writer;
writer.SetFile(fp);
WriteFilePrologue(&writer);
WriteMetadataSection(&writer, blob);
WriteInstructionStreams(&writer, blob);
WriteFileEpilogue(&writer, 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;
}
static void WriteFilePrologue(PlatformDependentEmbeddedFileWriter* w) {
w->Comment("Autogenerated file. Do not edit.");
w->Newline();
w->FilePrologue();
}
// Fairly arbitrary but should fit all symbol names.
static constexpr int kTemporaryStringLength = 256;
void WriteMetadataSection(PlatformDependentEmbeddedFileWriter* w,
const i::EmbeddedData* blob) const {
char embedded_blob_data_symbol[kTemporaryStringLength];
i::SNPrintF(i::Vector<char>(embedded_blob_data_symbol),
"v8_%s_embedded_blob_data_", embedded_variant_);
w->Comment("The embedded blob starts here. Metadata comes first, followed");
w->Comment("by builtin instruction streams.");
w->SectionText();
w->AlignToCodeAlignment();
w->DeclareLabel(embedded_blob_data_symbol);
WriteBinaryContentsAsInlineAssembly(w, blob->data(),
i::EmbeddedData::RawDataOffset());
}
void WriteInstructionStreams(PlatformDependentEmbeddedFileWriter* w,
const i::EmbeddedData* blob) const {
const bool is_default_variant =
std::strcmp(embedded_variant_, kDefaultEmbeddedVariant) == 0;
for (int i = 0; i < i::Builtins::builtin_count; i++) {
if (!blob->ContainsBuiltin(i)) continue;
char builtin_symbol[kTemporaryStringLength];
if (is_default_variant) {
// Create nicer symbol names for the default mode.
i::SNPrintF(i::Vector<char>(builtin_symbol), "Builtins_%s",
i::Builtins::name(i));
} else {
i::SNPrintF(i::Vector<char>(builtin_symbol), "%s_Builtins_%s",
embedded_variant_, i::Builtins::name(i));
}
// Labels created here will show up in backtraces. We check in
// Isolate::SetEmbeddedBlob that the blob layout remains unchanged, i.e.
// that labels do not insert bytes into the middle of the blob byte
// stream.
w->DeclareFunctionBegin(builtin_symbol);
WriteBinaryContentsAsInlineAssembly(
w,
reinterpret_cast<const uint8_t*>(blob->InstructionStartOfBuiltin(i)),
blob->PaddedInstructionSizeOfBuiltin(i));
w->DeclareFunctionEnd(builtin_symbol);
}
w->Newline();
}
void WriteFileEpilogue(PlatformDependentEmbeddedFileWriter* w,
const i::EmbeddedData* blob) const {
{
char embedded_blob_data_symbol[kTemporaryStringLength];
i::SNPrintF(i::Vector<char>(embedded_blob_data_symbol),
"v8_%s_embedded_blob_data_", embedded_variant_);
char embedded_blob_symbol[kTemporaryStringLength];
i::SNPrintF(i::Vector<char>(embedded_blob_symbol), "v8_%s_embedded_blob_",
embedded_variant_);
w->Comment("Pointer to the beginning of the embedded blob.");
w->SectionData();
w->DeclarePointerToSymbol(embedded_blob_symbol,
embedded_blob_data_symbol);
w->Newline();
}
{
char embedded_blob_size_symbol[kTemporaryStringLength];
i::SNPrintF(i::Vector<char>(embedded_blob_size_symbol),
"v8_%s_embedded_blob_size_", embedded_variant_);
w->Comment("The size of the embedded blob in bytes.");
w->SectionRoData();
w->DeclareUint32(embedded_blob_size_symbol, blob->size());
w->Newline();
}
w->FileEpilogue();
}
static int WriteOcta(FILE* fp, int current_line_length, const uint8_t* data) {
const uint64_t* quad_ptr1 = reinterpret_cast<const uint64_t*>(data);
const uint64_t* quad_ptr2 = reinterpret_cast<const uint64_t*>(data + 8);
#ifdef V8_TARGET_BIG_ENDIAN
uint64_t part1 = *quad_ptr1;
uint64_t part2 = *quad_ptr2;
#else
uint64_t part1 = *quad_ptr2;
uint64_t part2 = *quad_ptr1;
#endif // V8_TARGET_BIG_ENDIAN
if (part1 != 0) {
current_line_length +=
fprintf(fp, "0x%" PRIx64 "%016" PRIx64, part1, part2);
} else {
current_line_length += fprintf(fp, "0x%" PRIx64, part2);
}
return current_line_length;
}
static int WriteDirectiveOrSeparator(PlatformDependentEmbeddedFileWriter* w,
int current_line_length,
DataDirective directive) {
int printed_chars;
if (current_line_length == 0) {
printed_chars = w->IndentedDataDirective(directive);
DCHECK_LT(0, printed_chars);
} else {
printed_chars = fprintf(w->fp(), ",");
DCHECK_EQ(1, printed_chars);
}
return current_line_length + printed_chars;
}
static int WriteLineEndIfNeeded(FILE* fp, int current_line_length,
int write_size) {
static const int kTextWidth = 80;
// Check if adding ',0xFF...FF\n"' would force a line wrap. This doesn't use
// the actual size of the string to be written to determine this so it's
// more conservative than strictly needed.
if (current_line_length + strlen(",0x") + write_size * 2 > kTextWidth) {
fprintf(fp, "\n");
return 0;
} else {
return current_line_length;
}
}
static void WriteBinaryContentsAsInlineAssembly(
PlatformDependentEmbeddedFileWriter* w, const uint8_t* data,
uint32_t size) {
int current_line_length = 0;
uint32_t i = 0;
#ifndef V8_OS_WIN
const uint32_t size_of_octa = 16;
for (; i <= size - size_of_octa; i += size_of_octa) {
current_line_length =
WriteDirectiveOrSeparator(w, current_line_length, kOcta);
current_line_length = WriteOcta(w->fp(), current_line_length, data + i);
current_line_length =
WriteLineEndIfNeeded(w->fp(), current_line_length, size_of_octa);
}
if (current_line_length != 0) w->Newline();
current_line_length = 0;
#endif
for (; i < size; i++) {
current_line_length =
WriteDirectiveOrSeparator(w, current_line_length, kByte);
current_line_length += w->HexLiteral(data[i]);
current_line_length =
WriteLineEndIfNeeded(w->fp(), current_line_length, 1);
}
if (current_line_length != 0) w->Newline();
}
const char* embedded_cpp_path_ = nullptr;
const char* embedded_variant_ = kDefaultEmbeddedVariant;
};
} // namespace internal
} // namespace v8
#endif // V8_SNAPSHOT_EMBEDDED_FILE_WRITER_H_
// 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_MACROS_H_
#define V8_SNAPSHOT_MACROS_H_
#include "include/v8config.h"
// .byte portability macros.
#if defined(V8_OS_MACOSX) // MACOSX
#define V8_ASM_MANGLE_LABEL "_"
#define V8_ASM_RODATA_SECTION ".const_data\n"
#define V8_ASM_TEXT_SECTION ".text\n"
#define V8_ASM_DECLARE(NAME) ".private_extern " V8_ASM_MANGLE_LABEL NAME "\n"
#elif defined(V8_OS_AIX) // AIX
#define V8_ASM_RODATA_SECTION ".csect[RO]\n"
#define V8_ASM_TEXT_SECTION ".csect .text[PR]\n"
#define V8_ASM_MANGLE_LABEL ""
#define V8_ASM_DECLARE(NAME) ".globl " V8_ASM_MANGLE_LABEL NAME "\n"
#elif defined(V8_OS_WIN) // WIN
#if defined(V8_TARGET_ARCH_X64) || defined(V8_TARGET_ARCH_ARM64)
#define V8_ASM_MANGLE_LABEL ""
#else
#define V8_ASM_MANGLE_LABEL "_"
#endif
#define V8_ASM_RODATA_SECTION ".section .rodata\n"
#define V8_ASM_TEXT_SECTION ".section .text\n"
#define V8_ASM_DECLARE(NAME)
#else // !MACOSX && !WIN && !AIX
#define V8_ASM_MANGLE_LABEL ""
#define V8_ASM_RODATA_SECTION ".section .rodata\n"
#if defined(OS_CHROMEOS) // ChromeOS
#define V8_ASM_TEXT_SECTION ".section .text.hot.embedded\n"
#else
#define V8_ASM_TEXT_SECTION ".section .text\n"
#endif
#if defined(V8_TARGET_ARCH_MIPS) || defined(V8_TARGET_ARCH_MIPS64)
#define V8_ASM_DECLARE(NAME) ".global " V8_ASM_MANGLE_LABEL NAME "\n"
#else
#define V8_ASM_DECLARE(NAME) ".local " V8_ASM_MANGLE_LABEL NAME "\n"
#endif
#endif
// Align to kCodeAlignment.
#define V8_ASM_BALIGN32 ".balign 32\n"
#define V8_ASM_LABEL(NAME) V8_ASM_MANGLE_LABEL NAME ":\n"
#if defined(V8_OS_WIN)
// The directives for inserting debugging information on Windows come
// from the PE (Portable Executable) and COFF (Common Object File Format)
// standards. Documented here:
// https://docs.microsoft.com/en-us/windows/desktop/debug/pe-format
#define V8_ASM_TYPE(NAME) \
/* .scl 2 means StorageClass external. */ \
/* .type 32 means Type Representation Function. */ \
".def " V8_ASM_MANGLE_LABEL NAME "; .scl 2; .type 32; .endef;\n"
#elif defined(V8_TARGET_ARCH_ARM) || defined(V8_TARGET_ARCH_ARM64)
// ELF format binaries on ARM use ".type <function name>, %function"
// to create a DWARF subprogram entry.
#define V8_ASM_TYPE(NAME) ".type " V8_ASM_MANGLE_LABEL NAME ", %function\n"
#else
// Other ELF Format binaries use ".type <function name>, @function"
// to create a DWARF subprogram entry.
#define V8_ASM_TYPE(NAME) ".type " V8_ASM_MANGLE_LABEL NAME ", @function\n"
#endif // !V8_OS_WIN
#define V8_ASM_DECLARE_FUNCTION(NAME) \
V8_ASM_LABEL(NAME) \
V8_ASM_TYPE(NAME)
// clang-format off
#if defined(V8_OS_AIX)
#define V8_EMBEDDED_TEXT_HEADER(LABEL) \
__asm__(V8_ASM_DECLARE(#LABEL) \
".csect " #LABEL "[DS]\n" \
#LABEL ":\n" \
".llong ." #LABEL ", TOC[tc0], 0\n" \
V8_ASM_TEXT_SECTION \
"." #LABEL ":\n");
#define V8_EMBEDDED_RODATA_HEADER(LABEL) \
__asm__(V8_ASM_RODATA_SECTION \
V8_ASM_DECLARE(#LABEL) \
".align 5\n" \
V8_ASM_LABEL(#LABEL));
#else
#define V8_EMBEDDED_TEXT_HEADER(LABEL) \
__asm__(V8_ASM_TEXT_SECTION \
V8_ASM_DECLARE(#LABEL) \
V8_ASM_BALIGN32 \
V8_ASM_LABEL(#LABEL));
#define V8_EMBEDDED_RODATA_HEADER(LABEL) \
__asm__(V8_ASM_RODATA_SECTION \
V8_ASM_DECLARE(#LABEL) \
V8_ASM_BALIGN32 \
V8_ASM_LABEL(#LABEL));
#endif // #if defined(V8_OS_AIX)
#endif // V8_SNAPSHOT_MACROS_H_
......@@ -11,25 +11,16 @@
#include "src/base/platform/platform.h"
#include "src/flags.h"
#include "src/msan.h"
#include "src/snapshot/embedded-file-writer.h"
#include "src/snapshot/natives.h"
#include "src/snapshot/partial-serializer.h"
#include "src/snapshot/snapshot.h"
#include "src/snapshot/startup-serializer.h"
namespace {
class SnapshotWriter {
public:
SnapshotWriter()
: snapshot_cpp_path_(nullptr), snapshot_blob_path_(nullptr) {}
void SetEmbeddedFile(const char* embedded_cpp_file) {
embedded_cpp_path_ = embedded_cpp_file;
}
void SetEmbeddedVariant(const char* embedded_variant) {
embedded_variant_ = embedded_variant;
}
class SnapshotFileWriter {
public:
void SetSnapshotFile(const char* snapshot_cpp_file) {
snapshot_cpp_path_ = snapshot_cpp_file;
}
......@@ -49,10 +40,6 @@ class SnapshotWriter {
MaybeWriteStartupBlob(blob_vector);
}
void WriteEmbedded(const i::EmbeddedData* blob) const {
MaybeWriteEmbeddedFile(blob);
}
private:
void MaybeWriteStartupBlob(const i::Vector<const i::byte>& blob) const {
if (!snapshot_blob_path_) return;
......@@ -116,170 +103,6 @@ class SnapshotWriter {
fprintf(fp, "\n");
}
void MaybeWriteEmbeddedFile(const i::EmbeddedData* blob) const {
if (embedded_cpp_path_ == nullptr) return;
FILE* fp = GetFileDescriptorOrDie(embedded_cpp_path_);
WriteEmbeddedFilePrefix(fp);
WriteEmbeddedFileData(fp, blob, embedded_variant_);
WriteEmbeddedFileSuffix(fp, embedded_variant_);
fclose(fp);
}
static void WriteEmbeddedFilePrefix(FILE* fp) {
fprintf(fp, "// Autogenerated file. Do not edit.\n\n");
fprintf(fp, "#include <cstdint>\n\n");
fprintf(fp, "#include \"src/snapshot/macros.h\"\n\n");
fprintf(fp, "namespace v8 {\n");
fprintf(fp, "namespace internal {\n\n");
fprintf(fp, "namespace {\n\n");
}
static void WriteEmbeddedFileSuffix(FILE* fp, const char* embedded_variant) {
fprintf(fp, "} // namespace\n\n");
fprintf(fp,
"const uint8_t* %sEmbeddedBlob() { return "
"v8_%s_embedded_blob_; }\n",
embedded_variant, embedded_variant);
fprintf(fp,
"uint32_t %sEmbeddedBlobSize() { return "
"v8_embedded_blob_size_; }\n\n",
embedded_variant);
fprintf(fp, "} // namespace internal\n");
fprintf(fp, "} // namespace v8\n");
}
static void WriteEmbeddedFileData(FILE* fp, const i::EmbeddedData* blob,
const char* embedded_variant) {
fprintf(fp, "V8_EMBEDDED_TEXT_HEADER(v8_%s_embedded_blob_)\n",
embedded_variant);
#ifdef V8_OS_MACOSX
// Note: On some platforms (observed on mac64), inserting labels into the
// .byte stream causes the compiler to reorder symbols, invalidating stored
// offsets.
// We either need to avoid doing so, or stop relying on our own offset table
// and directly reference symbols instead. But there is another complication
// there since the chrome build process on mac verifies the order of symbols
// present in the binary.
// For now, the straight-forward solution seems to be to just emit a pure
// .byte stream on OSX.
WriteBinaryContentsAsInlineAssembly(fp, blob->data(), blob->size());
#else
WriteBinaryContentsAsInlineAssembly(fp, blob->data(),
i::EmbeddedData::RawDataOffset());
WriteBuiltins(fp, blob, embedded_variant);
#endif
fprintf(fp, "extern \"C\" const uint8_t v8_%s_embedded_blob_[];\n",
embedded_variant);
fprintf(fp, "static const uint32_t v8_embedded_blob_size_ = %d;\n\n",
blob->size());
}
static void WriteBuiltins(FILE* fp, const i::EmbeddedData* blob,
const char* embedded_variant) {
const bool is_default_variant =
std::strcmp(embedded_variant, "Default") == 0;
for (int i = 0; i < i::Builtins::builtin_count; i++) {
if (!blob->ContainsBuiltin(i)) continue;
// Labels created here will show up in backtraces. We check in
// Isolate::SetEmbeddedBlob that the blob layout remains unchanged, i.e.
// that labels do not insert bytes into the middle of the blob byte
// stream.
if (is_default_variant) {
// Create nicer symbol names for the default mode.
fprintf(fp, "__asm__(V8_ASM_DECLARE_FUNCTION(\"Builtins_%s\"));\n",
i::Builtins::name(i));
} else {
fprintf(fp, "__asm__(V8_ASM_DECLARE_FUNCTION(\"%s_Builtins_%s\"));\n",
embedded_variant, i::Builtins::name(i));
}
WriteBinaryContentsAsInlineAssembly(
fp,
reinterpret_cast<const uint8_t*>(blob->InstructionStartOfBuiltin(i)),
blob->PaddedInstructionSizeOfBuiltin(i));
}
fprintf(fp, "\n");
}
static int WriteOcta(FILE* fp, int current_line_length, const uint8_t* data) {
const uint64_t* quad_ptr1 = reinterpret_cast<const uint64_t*>(data);
const uint64_t* quad_ptr2 = reinterpret_cast<const uint64_t*>(data + 8);
#ifdef V8_TARGET_BIG_ENDIAN
uint64_t part1 = *quad_ptr1;
uint64_t part2 = *quad_ptr2;
#else
uint64_t part1 = *quad_ptr2;
uint64_t part2 = *quad_ptr1;
#endif // V8_TARGET_BIG_ENDIAN
if (part1 != 0) {
current_line_length +=
fprintf(fp, "0x%" PRIx64 "%016" PRIx64, part1, part2);
} else {
current_line_length += fprintf(fp, "0x%" PRIx64, part2);
}
return current_line_length;
}
static int WriteDirectiveOrSeparator(FILE* fp, int current_line_length,
const char* directive) {
int printed_chars;
if (current_line_length == 0) {
printed_chars = fprintf(fp, " \"%s ", directive);
DCHECK_LT(0, printed_chars);
} else {
printed_chars = fprintf(fp, ",");
DCHECK_EQ(1, printed_chars);
}
return current_line_length + printed_chars;
}
static int WriteLineEndIfNeeded(FILE* fp, int current_line_length,
int write_size) {
static const int kTextWidth = 80;
// Check if adding ',0xFF...FF\n"' would force a line wrap. This doesn't use
// the actual size of the string to be written to determine this so it's
// more conservative than strictly needed.
if (current_line_length + strlen(",0x\\n\"") + write_size * 2 >
kTextWidth) {
fprintf(fp, "\\n\"\n");
return 0;
} else {
return current_line_length;
}
}
static void WriteBinaryContentsAsInlineAssembly(FILE* fp, const uint8_t* data,
uint32_t size) {
int current_line_length = 0;
fprintf(fp, "__asm__(\n");
uint32_t i = 0;
const uint32_t size_of_octa = 16;
for (; i <= size - size_of_octa; i += size_of_octa) {
current_line_length =
WriteDirectiveOrSeparator(fp, current_line_length, ".octa");
current_line_length = WriteOcta(fp, current_line_length, data + i);
current_line_length =
WriteLineEndIfNeeded(fp, current_line_length, size_of_octa);
}
if (current_line_length != 0) fprintf(fp, "\\n\"\n");
current_line_length = 0;
for (; i < size; i++) {
current_line_length =
WriteDirectiveOrSeparator(fp, current_line_length, ".byte");
current_line_length += fprintf(fp, "0x%x", data[i]);
current_line_length = WriteLineEndIfNeeded(fp, current_line_length, 1);
}
if (current_line_length != 0) fprintf(fp, "\\n\"\n");
fprintf(fp, ");\n");
}
static FILE* GetFileDescriptorOrDie(const char* filename) {
FILE* fp = v8::base::OS::FOpen(filename, "wb");
if (fp == nullptr) {
......@@ -289,10 +112,8 @@ class SnapshotWriter {
return fp;
}
const char* embedded_cpp_path_ = nullptr;
const char* embedded_variant_ = "Default";
const char* snapshot_cpp_path_;
const char* snapshot_blob_path_;
const char* snapshot_cpp_path_ = nullptr;
const char* snapshot_blob_path_ = nullptr;
};
char* GetExtraCode(char* filename, const char* description) {
......@@ -418,7 +239,7 @@ v8::StartupData WarmUpSnapshotDataBlob(v8::SnapshotCreator* snapshot_creator,
return result;
}
void WriteEmbeddedFile(SnapshotWriter* writer) {
void WriteEmbeddedFile(i::EmbeddedFileWriter* writer) {
i::EmbeddedData embedded_blob = i::EmbeddedData::FromBlob();
writer->WriteEmbedded(&embedded_blob);
}
......@@ -447,14 +268,13 @@ int main(int argc, char** argv) {
v8::V8::Initialize();
{
SnapshotWriter writer;
if (i::FLAG_startup_src) writer.SetSnapshotFile(i::FLAG_startup_src);
if (i::FLAG_startup_blob) writer.SetStartupBlobFile(i::FLAG_startup_blob);
if (i::FLAG_embedded_builtins) {
if (i::FLAG_embedded_src) writer.SetEmbeddedFile(i::FLAG_embedded_src);
if (i::FLAG_embedded_variant)
writer.SetEmbeddedVariant(i::FLAG_embedded_variant);
}
SnapshotFileWriter snapshot_writer;
snapshot_writer.SetSnapshotFile(i::FLAG_startup_src);
snapshot_writer.SetStartupBlobFile(i::FLAG_startup_blob);
i::EmbeddedFileWriter embedded_writer;
embedded_writer.SetEmbeddedFile(i::FLAG_embedded_src);
embedded_writer.SetEmbeddedVariant(i::FLAG_embedded_variant);
std::unique_ptr<char> embed_script(
GetExtraCode(argc >= 2 ? argv[1] : nullptr, "embedding"));
......@@ -477,7 +297,7 @@ int main(int argc, char** argv) {
i_isolate->heap()->ConfigureHeap(0, 0, code_range_size);
}
v8::SnapshotCreator snapshot_creator(isolate);
if (i::FLAG_embedded_builtins) WriteEmbeddedFile(&writer);
if (i::FLAG_embedded_builtins) WriteEmbeddedFile(&embedded_writer);
blob = CreateSnapshotDataBlob(&snapshot_creator, embed_script.get());
}
......@@ -490,7 +310,7 @@ int main(int argc, char** argv) {
}
CHECK(blob.data);
writer.WriteSnapshot(blob);
snapshot_writer.WriteSnapshot(blob);
delete[] blob.data;
}
i::FreeCurrentEmbeddedBlob();
......
......@@ -196,7 +196,6 @@ v8_source_set("cctest_sources") {
"test-inobject-slack-tracking.cc",
"test-inspector.cc",
"test-intl.cc",
"test-isolate-independent-builtins.cc",
"test-js-weak-refs.cc",
"test-liveedit.cc",
"test-lockers.cc",
......
// 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.
#include "test/cctest/cctest.h"
#include "src/assembler-inl.h"
#include "src/handles-inl.h"
#include "src/isolate.h"
#include "src/macro-assembler-inl.h"
#include "src/simulator.h"
#include "src/snapshot/macros.h"
#include "src/snapshot/snapshot.h"
#include "test/common/assembler-tester.h"
// To generate the binary files for the test function, enable this section and
// run GenerateTestFunctionData once on each arch.
#define GENERATE_TEST_FUNCTION_DATA false
namespace v8 {
namespace internal {
namespace test_isolate_independent_builtins {
// V8_CC_MSVC is true for both MSVC and clang on windows. clang can handle
// __asm__-style inline assembly but MSVC cannot, and thus we need a more
// precise compiler detection that can distinguish between the two. clang on
// windows sets both __clang__ and _MSC_VER, MSVC sets only _MSC_VER.
#if defined(_MSC_VER) && !defined(__clang__)
#define V8_COMPILER_IS_MSVC
#endif
#ifndef V8_COMPILER_IS_MSVC
#if GENERATE_TEST_FUNCTION_DATA
// Arch-specific defines.
#if V8_TARGET_ARCH_IA32
#define TEST_FUNCTION_FILE "f-ia32.bin"
#elif V8_TARGET_ARCH_X64 && _WIN64
#define TEST_FUNCTION_FILE "f-x64-win.bin"
#elif V8_TARGET_ARCH_X64
#define TEST_FUNCTION_FILE "f-x64.bin"
#elif V8_TARGET_ARCH_ARM64
#define TEST_FUNCTION_FILE "f-arm64.bin"
#elif V8_TARGET_ARCH_ARM
#define TEST_FUNCTION_FILE "f-arm.bin"
#elif V8_TARGET_ARCH_PPC
#define TEST_FUNCTION_FILE "f-ppc.bin"
#elif V8_TARGET_ARCH_MIPS
#define TEST_FUNCTION_FILE "f-mips.bin"
#elif V8_TARGET_ARCH_MIPS64
#define TEST_FUNCTION_FILE "f-mips64.bin"
#elif V8_TARGET_ARCH_S390
#define TEST_FUNCTION_FILE "f-s390.bin"
#else
#error "Unknown architecture."
#endif
#define __ masm.
TEST(GenerateTestFunctionData) {
CcTest::InitializeVM();
Isolate* isolate = CcTest::i_isolate();
HandleScope scope(isolate);
#if V8_TARGET_ARCH_IA32
v8::internal::byte buffer[256];
Assembler masm(isolate, buffer, sizeof(buffer));
__ mov(eax, Operand(esp, 4));
__ add(eax, Operand(esp, 8));
__ ret(0);
#elif V8_TARGET_ARCH_X64
size_t allocated;
byte* buffer = AllocateAssemblerBuffer(&allocated);
Assembler masm(isolate, buffer, static_cast<int>(allocated));
#ifdef _WIN64
static const Register arg1 = rcx;
static const Register arg2 = rdx;
#else
static const Register arg1 = rdi;
static const Register arg2 = rsi;
#endif
__ movq(rax, arg2);
__ addq(rax, arg1);
__ ret(0);
#elif V8_TARGET_ARCH_ARM64
MacroAssembler masm(isolate, nullptr, 0,
v8::internal::CodeObjectRequired::kYes);
__ Add(x0, x0, x1);
__ Ret();
#elif V8_TARGET_ARCH_ARM
Assembler masm(isolate, nullptr, 0);
__ add(r0, r0, Operand(r1));
__ mov(pc, Operand(lr));
#elif V8_TARGET_ARCH_PPC
Assembler masm(isolate, nullptr, 0);
__ function_descriptor();
__ add(r3, r3, r4);
__ blr();
#elif V8_TARGET_ARCH_MIPS
MacroAssembler masm(isolate, nullptr, 0,
v8::internal::CodeObjectRequired::kYes);
__ addu(v0, a0, a1);
__ jr(ra);
__ nop();
#elif V8_TARGET_ARCH_MIPS64
MacroAssembler masm(isolate, nullptr, 0,
v8::internal::CodeObjectRequired::kYes);
__ addu(v0, a0, a1);
__ jr(ra);
__ nop();
#elif V8_TARGET_ARCH_S390
Assembler masm(isolate, nullptr, 0);
__ agr(r2, r3);
__ b(r14);
#else // Unknown architecture.
#error "Unknown architecture."
#endif // Target architecture.
CodeDesc desc;
masm.GetCode(isolate, &desc);
std::ofstream of(TEST_FUNCTION_FILE, std::ios::out | std::ios::binary);
of.write(reinterpret_cast<char*>(desc.buffer), desc.instr_size);
}
#undef __
#endif // GENERATE_TEST_FUNCTION_DATA
#if V8_TARGET_ARCH_IA32
#define FUNCTION_BYTES \
".byte 0x8b, 0x44, 0x24, 0x04, 0x03, 0x44, 0x24, 0x08, 0xc3\n"
#elif V8_TARGET_ARCH_X64 && _WIN64
#define FUNCTION_BYTES ".byte 0x48, 0x8b, 0xc2, 0x48, 0x03, 0xc1, 0xc3\n"
#elif V8_TARGET_ARCH_X64
#define FUNCTION_BYTES ".byte 0x48, 0x8b, 0xc6, 0x48, 0x03, 0xc7, 0xc3\n"
#elif V8_TARGET_ARCH_ARM64
#define FUNCTION_BYTES ".byte 0x00, 0x00, 0x01, 0x8b, 0xc0, 0x03, 0x5f, 0xd6\n"
#elif V8_TARGET_ARCH_ARM
#define FUNCTION_BYTES ".byte 0x01, 0x00, 0x80, 0xe0, 0x0e, 0xf0, 0xa0, 0xe1\n"
#elif V8_TARGET_ARCH_PPC
#if defined(V8_OS_AIX)
#define FUNCTION_BYTES ".byte 0x7c, 0x64, 0x1a, 0x14, 0x4e, 0x80, 0x00, 0x20\n"
#else
#define FUNCTION_BYTES ".byte 0x14, 0x22, 0x63, 0x7c, 0x20, 0x00, 0x80, 0x4e\n"
#endif
#elif defined(V8_TARGET_ARCH_MIPS) || defined(V8_TARGET_ARCH_MIPS64)
#if defined(V8_TARGET_BIG_ENDIAN)
#define FUNCTION_BYTES \
".byte 0x00, 0x85, 0x10, 0x21, 0x03, 0xe0, 0x00, " \
"0x08, 0x00, 0x00, 0x00, 0x00\n"
#else
#define FUNCTION_BYTES \
".byte 0x21, 0x10, 0x85, 0x00, 0x08, 0x00, 0xe0, " \
"0x03, 0x00, 0x00, 0x00, 0x00\n"
#endif
#elif V8_TARGET_ARCH_S390
#define FUNCTION_BYTES \
".byte 0xb9, 0x08, 0x00, 0x23, 0x07, 0xfe\n"
#else
#error "Unknown architecture."
#endif
V8_EMBEDDED_RODATA_HEADER(test_string0_bytes)
__asm__(".byte 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37\n"
".byte 0x38, 0x39, 0x0a, 0x00\n");
extern "C" V8_ALIGNED(16) const char test_string0_bytes[];
V8_EMBEDDED_TEXT_HEADER(test_function0_bytes)
__asm__(FUNCTION_BYTES);
extern "C" V8_ALIGNED(16) const char test_function0_bytes[];
// clang-format on
// A historical note: We use .byte over .incbin since the latter leads to
// complications involving generation of build-time dependencies. Goma parses
// #include statements, and clang has -MD/-MMD. Neither recognize .incbin.
TEST(ByteInRodata) {
CHECK_EQ(0, std::strcmp("0123456789\n", test_string0_bytes));
}
TEST(ByteInText) {
CcTest::InitializeVM();
Isolate* isolate = CcTest::i_isolate();
auto f = GeneratedCode<int(int, int)>::FromAddress(
isolate, reinterpret_cast<Address>(&test_function0_bytes[0]));
CHECK_EQ(7, f.Call(3, 4));
CHECK_EQ(11, f.Call(5, 6));
}
#endif // #ifndef V8_COMPILER_IS_MSVC
#undef V8_COMPILER_IS_MSVC
#undef FUNCTION_BYTES
#undef GENERATE_TEST_FUNCTION_DATA
#undef TEST_FUNCTION_FILE
} // namespace test_isolate_independent_builtins
} // namespace internal
} // namespace v8
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment