summaryrefslogtreecommitdiff
path: root/chromium/v8/src/snapshot/embedded/embedded-file-writer.h
blob: e487b9be9bcc77e97d2da6109e1218f3fee69ce4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
// 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_WIN64)
#include "src/diagnostics/unwinding-info-win64.h"
#endif  // V8_OS_WIN64

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_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;

#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());
    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)
  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_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_