v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
mksnapshot.cc
Go to the documentation of this file.
1// Copyright 2006-2008 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <errno.h>
6#include <signal.h>
7#include <stdio.h>
8
9#include <iomanip>
10
16#include "src/base/vector.h"
18#include "src/common/globals.h"
19#include "src/flags/flags.h"
23
24namespace {
25
26class SnapshotFileWriter {
27 public:
28 void SetSnapshotFile(const char* snapshot_cpp_file) {
29 snapshot_cpp_path_ = snapshot_cpp_file;
30 }
31
32 void SetStartupBlobFile(const char* snapshot_blob_file) {
33 snapshot_blob_path_ = snapshot_blob_file;
34 }
35
36 void WriteSnapshot(v8::StartupData blob) const {
37 // TODO(crbug/633159): if we crash before the files have been fully created,
38 // we end up with a corrupted snapshot file. The build step would succeed,
39 // but the build target is unusable. Ideally we would write out temporary
40 // files and only move them to the final destination as last step.
42 reinterpret_cast<const uint8_t*>(blob.data), blob.raw_size);
43 MaybeWriteSnapshotFile(blob_vector);
44 MaybeWriteStartupBlob(blob_vector);
45 }
46
47 private:
48 void MaybeWriteStartupBlob(v8::base::Vector<const uint8_t> blob) const {
49 if (!snapshot_blob_path_) return;
50
51 FILE* fp = GetFileDescriptorOrDie(snapshot_blob_path_);
52 size_t written = fwrite(blob.begin(), 1, blob.length(), fp);
54 if (written != static_cast<size_t>(blob.length())) {
55 i::PrintF("Writing snapshot file failed.. Aborting.\n");
56 remove(snapshot_blob_path_);
57 exit(1);
58 }
59 }
60
61 void MaybeWriteSnapshotFile(v8::base::Vector<const uint8_t> blob) const {
62 if (!snapshot_cpp_path_) return;
63
64 FILE* fp = GetFileDescriptorOrDie(snapshot_cpp_path_);
65
66 WriteSnapshotFilePrefix(fp);
67 WriteSnapshotFileData(fp, blob);
68 WriteSnapshotFileSuffix(fp);
69
71 }
72
73 static void WriteSnapshotFilePrefix(FILE* fp) {
74 fprintf(fp, "// Autogenerated snapshot file. Do not edit.\n\n");
75 fprintf(fp, "#include \"src/init/v8.h\"\n");
76 fprintf(fp, "#include \"src/base/platform/platform.h\"\n\n");
77 fprintf(fp, "#include \"src/flags/flags.h\"\n");
78 fprintf(fp, "#include \"src/snapshot/snapshot.h\"\n\n");
79 fprintf(fp, "namespace v8 {\n");
80 fprintf(fp, "namespace internal {\n\n");
81 }
82
83 static void WriteSnapshotFileSuffix(FILE* fp) {
84 fprintf(fp, "const v8::StartupData* Snapshot::DefaultSnapshotBlob() {\n");
85 fprintf(fp, " return &blob;\n");
86 fprintf(fp, "}\n");
87 fprintf(fp, "\n");
88 fprintf(
89 fp,
90 "bool Snapshot::ShouldVerifyChecksum(const v8::StartupData* data) {\n");
91 fprintf(fp, " return v8_flags.verify_snapshot_checksum;\n");
92 fprintf(fp, "}\n");
93 fprintf(fp, "} // namespace internal\n");
94 fprintf(fp, "} // namespace v8\n");
95 }
96
97 static void WriteSnapshotFileData(FILE* fp,
99 fprintf(
100 fp,
101 "alignas(kPointerAlignment) static const uint8_t blob_data[] = {\n");
102 WriteBinaryContentsAsCArray(fp, blob);
103 fprintf(fp, "};\n");
104 fprintf(fp, "static const int blob_size = %d;\n", blob.length());
105 fprintf(fp, "static const v8::StartupData blob =\n");
106 fprintf(fp, "{ (const char*) blob_data, blob_size };\n");
107 }
108
109 static void WriteBinaryContentsAsCArray(
110 FILE* fp, v8::base::Vector<const uint8_t> blob) {
111 for (int i = 0; i < blob.length(); i++) {
112 if ((i & 0x1F) == 0x1F) fprintf(fp, "\n");
113 if (i > 0) fprintf(fp, ",");
114 fprintf(fp, "%u", static_cast<unsigned char>(blob.at(i)));
115 }
116 fprintf(fp, "\n");
117 }
118
119 static FILE* GetFileDescriptorOrDie(const char* filename) {
120 FILE* fp = v8::base::OS::FOpen(filename, "wb");
121 if (fp == nullptr) {
122 i::PrintF("Unable to open file \"%s\" for writing.\n", filename);
123 exit(1);
124 }
125 return fp;
126 }
127
128 const char* snapshot_cpp_path_ = nullptr;
129 const char* snapshot_blob_path_ = nullptr;
130};
131
132std::unique_ptr<char[]> GetExtraCode(char* filename, const char* description) {
133 if (filename == nullptr || strlen(filename) == 0) return nullptr;
134 ::printf("Loading script for %s: %s\n", description, filename);
135 FILE* file = v8::base::OS::FOpen(filename, "rb");
136 if (file == nullptr) {
137 fprintf(stderr, "Failed to open '%s': errno %d\n", filename, errno);
138 exit(1);
139 }
140 fseek(file, 0, SEEK_END);
141 size_t size = ftell(file);
142 rewind(file);
143 char* chars = new char[size + 1];
144 chars[size] = '\0';
145 for (size_t i = 0; i < size;) {
146 size_t read = fread(&chars[i], 1, size - i, file);
147 if (ferror(file)) {
148 fprintf(stderr, "Failed to read '%s': errno %d\n", filename, errno);
149 exit(1);
150 }
151 i += read;
152 }
153 v8::base::Fclose(file);
154 return std::unique_ptr<char[]>(chars);
155}
156
157v8::StartupData CreateSnapshotDataBlob(v8::SnapshotCreator& snapshot_creator,
158 const char* embedded_source) {
160 timer.Start();
161
164 snapshot_creator);
165
166 if (i::v8_flags.profile_deserialization) {
167 i::PrintF("[Creating snapshot took %0.3f ms]\n",
168 timer.Elapsed().InMillisecondsF());
169 }
170
171 timer.Stop();
172 return result;
173}
174
175v8::StartupData WarmUpSnapshotDataBlob(v8::StartupData cold_snapshot_blob,
176 const char* warmup_source) {
178 timer.Start();
179
181 i::WarmUpSnapshotDataBlobInternal(cold_snapshot_blob, warmup_source);
182
183 if (i::v8_flags.profile_deserialization) {
184 i::PrintF("Warming up snapshot took %0.3f ms\n",
185 timer.Elapsed().InMillisecondsF());
186 }
187
188 timer.Stop();
189 return result;
190}
191
192void WriteEmbeddedFile(i::EmbeddedFileWriter* writer) {
193 i::EmbeddedData embedded_blob = i::EmbeddedData::FromBlob();
194 writer->WriteEmbedded(&embedded_blob);
195}
196
197using CounterMap = std::map<std::string, int>;
198CounterMap* counter_map_ = nullptr;
199
200void MaybeSetCounterFunction(v8::Isolate* isolate) {
201 // If --native-code-counters is on then we enable all counters to make
202 // sure we generate code to increment them from the snapshot.
203 //
204 // Note: For the sake of the mksnapshot, the counter function must only
205 // return distinct addresses for each counter s.t. the serializer can properly
206 // distinguish between them. In theory it should be okay to just return an
207 // incremented int value each time this function is called, but we play it
208 // safe and return a real distinct memory location tied to every counter name.
209 if (i::v8_flags.native_code_counters) {
210 counter_map_ = new CounterMap();
211 isolate->SetCounterFunction([](const char* name) -> int* {
212 auto map_entry = counter_map_->find(name);
213 if (map_entry == counter_map_->end()) {
214 counter_map_->emplace(name, 0);
215 }
216 return &counter_map_->at(name);
217 });
218 }
219}
220
221} // namespace
222
223int main(int argc, char** argv) {
225
226 // Make mksnapshot runs predictable to create reproducible snapshots.
227 i::v8_flags.predictable = true;
228
229 // Disable ICs globally in mksnapshot to avoid problems with Code handlers.
230 // See https://crbug.com/345280736.
231 // TODO(jgruber): Re-enable once a better fix is available.
232 i::v8_flags.use_ic = false;
233
234 // Print the usage if an error occurs when parsing the command line
235 // flags or if the help flag is set.
236 using HelpOptions = i::FlagList::HelpOptions;
237 std::string usage = "Usage: " + std::string(argv[0]) +
238 " [--startup-src=file]" + " [--startup-blob=file]" +
239 " [--embedded-src=file]" + " [--embedded-variant=label]" +
240 " [--static-roots-src=file]" + " [--target-arch=arch]" +
241 " [--target-os=os] [extras]\n\n";
242 int result = i::FlagList::SetFlagsFromCommandLine(
243 &argc, argv, true, HelpOptions(HelpOptions::kExit, usage.c_str()));
244 if (result > 0 || (argc > 3)) {
245 i::PrintF(stdout, "%s", usage.c_str());
246 return result;
247 }
248
249 i::CpuFeatures::Probe(true);
251 std::unique_ptr<v8::Platform> platform = v8::platform::NewDefaultPlatform();
252 v8::V8::InitializePlatform(platform.get());
254
255 {
256 SnapshotFileWriter snapshot_writer;
257 snapshot_writer.SetSnapshotFile(i::v8_flags.startup_src);
258 snapshot_writer.SetStartupBlobFile(i::v8_flags.startup_blob);
259
260 i::EmbeddedFileWriter embedded_writer;
261 embedded_writer.SetEmbeddedFile(i::v8_flags.embedded_src);
262 embedded_writer.SetEmbeddedVariant(i::v8_flags.embedded_variant);
263 embedded_writer.SetTargetArch(i::v8_flags.target_arch);
264 embedded_writer.SetTargetOs(i::v8_flags.target_os);
265
266 std::unique_ptr<char[]> embed_script =
267 GetExtraCode(argc >= 2 ? argv[1] : nullptr, "embedding");
268 std::unique_ptr<char[]> warmup_script =
269 GetExtraCode(argc >= 3 ? argv[2] : nullptr, "warm up");
270
271 v8::StartupData blob;
272 {
274
275 MaybeSetCounterFunction(isolate);
276
277 // The isolate contains data from builtin compilation that needs
278 // to be written out if builtins are embedded.
279 i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
280 i_isolate->RegisterEmbeddedFileWriter(&embedded_writer);
281
282 std::unique_ptr<v8::ArrayBuffer::Allocator> array_buffer_allocator(
284 v8::Isolate::CreateParams create_params;
285 create_params.array_buffer_allocator = array_buffer_allocator.get();
286
287 // Set code range such that relative jumps for builtins to
288 // builtin calls in the snapshot are possible.
289 size_t code_range_size_mb =
292 : std::min(i::kMaximalCodeRangeSize / i::MB,
295 code_range_size_mb * i::MB);
296
297 {
298 v8::SnapshotCreator creator(isolate, create_params);
299
300 blob = CreateSnapshotDataBlob(creator, embed_script.get());
301
302 WriteEmbeddedFile(&embedded_writer);
303
304#if V8_STATIC_ROOTS_GENERATION_BOOL
305 if (i::v8_flags.static_roots_src) {
306 i::StaticRootsTableGen::write(i_isolate,
307 i::v8_flags.static_roots_src);
308 }
309#endif
310 }
311 isolate->Dispose();
312 }
313
314 if (warmup_script) {
315 v8::StartupData cold = blob;
316 blob = WarmUpSnapshotDataBlob(cold, warmup_script.get());
317 delete[] cold.data;
318 }
319
320 delete counter_map_;
321
322 CHECK(blob.data);
323 snapshot_writer.WriteSnapshot(blob);
324 delete[] blob.data;
325 }
326
329 return 0;
330}
static Allocator * NewDefaultAllocator()
Definition api.cc:8923
static Isolate * Allocate()
Definition api.cc:9964
void set_code_range_size_in_bytes(size_t limit)
Definition v8-isolate.h:115
const char * data
Definition v8-snapshot.h:35
static void DisposePlatform()
Definition api.cc:6389
static void InitializePlatform(Platform *platform)
Definition api.cc:6385
static bool InitializeICUDefaultLocation(const char *exec_path, const char *icu_data_file=nullptr)
Definition api.cc:6560
static V8_INLINE bool Initialize()
static bool Dispose()
Definition api.cc:6513
static FILE * FOpen(const char *path, const char *mode)
void WriteEmbedded(const i::EmbeddedData *blob) const
void SetTargetArch(const char *target_arch)
void SetTargetOs(const char *target_os)
void SetEmbeddedVariant(const char *embedded_variant)
void SetEmbeddedFile(const char *embedded_src_path)
void RegisterEmbeddedFileWriter(EmbeddedFileWriterInterface *writer)
Definition isolate.h:2009
std::string filename
Isolate * isolate
ZoneVector< RpoNumber > & result
int main(int argc, char **argv)
int Fclose(FILE *stream)
Definition wrappers.h:22
void EnsureConsoleOutput()
Definition platform.h:435
void PrintF(const char *format,...)
Definition utils.cc:39
constexpr size_t kMaxPCRelativeCodeRangeInMB
V8_EXPORT_PRIVATE FlagValues v8_flags
v8::StartupData WarmUpSnapshotDataBlobInternal(v8::StartupData cold_snapshot_blob, const char *warmup_source)
Definition snapshot.cc:823
constexpr size_t kMaximalCodeRangeSize
Definition globals.h:508
v8::StartupData CreateSnapshotDataBlobInternal(v8::SnapshotCreator::FunctionCodeHandling function_code_handling, const char *embedded_source, SnapshotCreator &snapshot_creator, Snapshot::SerializerFlags serializer_flags)
Definition snapshot.cc:784
std::unique_ptr< v8::Platform > NewDefaultPlatform(int thread_pool_size, IdleTaskSupport idle_task_support, InProcessStackDumping in_process_stack_dumping, std::unique_ptr< v8::TracingController > tracing_controller, PriorityMode priority_mode)
std::unordered_map< std::string, Counter * > CounterMap
Definition d8.h:86
#define CHECK(condition)
Definition logging.h:124
ResourceConstraints constraints
Definition v8-isolate.h:294
ArrayBuffer::Allocator * array_buffer_allocator
Definition v8-isolate.h:326