1// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4
5// Generate a snapshot file after loading all the scripts specified on the
6// command line.
7
8#include <stdio.h>
9#include <stdlib.h>
10#include <string.h>
11
12#include <cstdarg>
13#include <memory>
14
15#include "bin/builtin.h"
16#include "bin/console.h"
17#include "bin/dartutils.h"
18#include "bin/error_exit.h"
19#include "bin/eventhandler.h"
20#include "bin/file.h"
21#include "bin/loader.h"
22#include "bin/options.h"
23#include "bin/platform.h"
24#include "bin/snapshot_utils.h"
25#include "bin/thread.h"
26#include "bin/utils.h"
27#include "bin/vmservice_impl.h"
28
29#include "include/dart_api.h"
30#include "include/dart_tools_api.h"
31
32#include "platform/globals.h"
33#include "platform/growable_array.h"
34#include "platform/hashmap.h"
35#include "platform/syslog.h"
36#include "platform/text_buffer.h"
37
38namespace dart {
39namespace bin {
40
41#define CHECK_RESULT(result) \
42 if (Dart_IsError(result)) { \
43 intptr_t exit_code = 0; \
44 Syslog::PrintErr("Error: %s\n", Dart_GetError(result)); \
45 if (Dart_IsCompilationError(result)) { \
46 exit_code = kCompilationErrorExitCode; \
47 } else if (Dart_IsApiError(result)) { \
48 exit_code = kApiErrorExitCode; \
49 } else { \
50 exit_code = kErrorExitCode; \
51 } \
52 Dart_ExitScope(); \
53 Dart_ShutdownIsolate(); \
54 exit(exit_code); \
55 }
56
57// The environment provided through the command line using -D options.
58static dart::SimpleHashMap* environment = nullptr;
59
60static bool ProcessEnvironmentOption(const char* arg,
61 CommandLineOptions* vm_options) {
62 return OptionProcessor::ProcessEnvironmentOption(arg, vm_options,
63 environment: &environment);
64}
65
66// The core snapshot to use when creating isolates. Normally nullptr, but loaded
67// from a file when creating AppJIT snapshots.
68const uint8_t* isolate_snapshot_data = nullptr;
69const uint8_t* isolate_snapshot_instructions = nullptr;
70
71// Global state that indicates whether a snapshot is to be created and
72// if so which file to write the snapshot into. The ordering of this list must
73// match kSnapshotKindNames below.
74enum SnapshotKind {
75 kCore,
76 kCoreJIT,
77 kApp,
78 kAppJIT,
79 kAppAOTAssembly,
80 kAppAOTElf,
81 kVMAOTAssembly,
82};
83static SnapshotKind snapshot_kind = kCore;
84
85// The ordering of this list must match the SnapshotKind enum above.
86static const char* const kSnapshotKindNames[] = {
87 // clang-format off
88 "core",
89 "core-jit",
90 "app",
91 "app-jit",
92 "app-aot-assembly",
93 "app-aot-elf",
94 "vm-aot-assembly",
95 nullptr,
96 // clang-format on
97};
98
99#define STRING_OPTIONS_LIST(V) \
100 V(load_vm_snapshot_data, load_vm_snapshot_data_filename) \
101 V(load_vm_snapshot_instructions, load_vm_snapshot_instructions_filename) \
102 V(load_isolate_snapshot_data, load_isolate_snapshot_data_filename) \
103 V(load_isolate_snapshot_instructions, \
104 load_isolate_snapshot_instructions_filename) \
105 V(vm_snapshot_data, vm_snapshot_data_filename) \
106 V(vm_snapshot_instructions, vm_snapshot_instructions_filename) \
107 V(isolate_snapshot_data, isolate_snapshot_data_filename) \
108 V(isolate_snapshot_instructions, isolate_snapshot_instructions_filename) \
109 V(blobs_container_filename, blobs_container_filename) \
110 V(assembly, assembly_filename) \
111 V(elf, elf_filename) \
112 V(loading_unit_manifest, loading_unit_manifest_filename) \
113 V(save_debugging_info, debugging_info_filename) \
114 V(save_obfuscation_map, obfuscation_map_filename)
115
116#define BOOL_OPTIONS_LIST(V) \
117 V(compile_all, compile_all) \
118 V(help, help) \
119 V(obfuscate, obfuscate) \
120 V(strip, strip) \
121 V(verbose, verbose) \
122 V(version, version)
123
124#define STRING_OPTION_DEFINITION(flag, variable) \
125 static const char* variable = nullptr; \
126 DEFINE_STRING_OPTION(flag, variable)
127STRING_OPTIONS_LIST(STRING_OPTION_DEFINITION)
128#undef STRING_OPTION_DEFINITION
129
130#define BOOL_OPTION_DEFINITION(flag, variable) \
131 static bool variable = false; \
132 DEFINE_BOOL_OPTION(flag, variable)
133BOOL_OPTIONS_LIST(BOOL_OPTION_DEFINITION)
134#undef BOOL_OPTION_DEFINITION
135
136DEFINE_ENUM_OPTION(snapshot_kind, SnapshotKind, snapshot_kind);
137DEFINE_CB_OPTION(ProcessEnvironmentOption);
138
139static bool IsSnapshottingForPrecompilation() {
140 return (snapshot_kind == kAppAOTAssembly) || (snapshot_kind == kAppAOTElf) ||
141 (snapshot_kind == kVMAOTAssembly);
142}
143
144// clang-format off
145static void PrintUsage() {
146 Syslog::PrintErr(
147format: "Usage: gen_snapshot [<vm-flags>] [<options>] <dart-kernel-file> \n"
148" \n"
149"Common options: \n"
150"--help \n"
151" Display this message (add --verbose for information about all VM options).\n"
152"--version \n"
153" Print the SDK version. \n"
154" \n"
155"To create a core snapshot: \n"
156"--snapshot_kind=core \n"
157"--vm_snapshot_data=<output-file> \n"
158"--isolate_snapshot_data=<output-file> \n"
159"<dart-kernel-file> \n"
160" \n"
161"To create an AOT application snapshot as assembly suitable for compilation \n"
162"as a static or dynamic library: \n"
163"--snapshot_kind=app-aot-assembly \n"
164"--assembly=<output-file> \n"
165"[--strip] \n"
166"[--obfuscate] \n"
167"[--save-debugging-info=<debug-filename>] \n"
168"[--save-obfuscation-map=<map-filename>] \n"
169"<dart-kernel-file> \n"
170" \n"
171"To create an AOT application snapshot as an ELF shared library: \n"
172"--snapshot_kind=app-aot-elf \n"
173"--elf=<output-file> \n"
174"[--strip] \n"
175"[--obfuscate] \n"
176"[--save-debugging-info=<debug-filename>] \n"
177"[--save-obfuscation-map=<map-filename>] \n"
178"<dart-kernel-file> \n"
179" \n"
180"AOT snapshots can be obfuscated: that is all identifiers will be renamed \n"
181"during compilation. This mode is enabled with --obfuscate flag. Mapping \n"
182"between original and obfuscated names can be serialized as a JSON array \n"
183"using --save-obfuscation-map=<filename> option. See dartbug.com/30524 \n"
184"for implementation details and limitations of the obfuscation pass. \n"
185" \n"
186"\n");
187 if (verbose) {
188 Syslog::PrintErr(
189format: "The following options are only used for VM development and may\n"
190"be changed in any future version:\n");
191 const char* print_flags = "--print_flags";
192 char* error = Dart_SetVMFlags(argc: 1, argv: &print_flags);
193 ASSERT(error == nullptr);
194 }
195}
196// clang-format on
197
198// Parse out the command line arguments. Returns -1 if the arguments
199// are incorrect, 0 otherwise.
200static int ParseArguments(int argc,
201 char** argv,
202 CommandLineOptions* vm_options,
203 CommandLineOptions* inputs) {
204 // Skip the binary name.
205 int i = 1;
206
207 // Parse out the vm options.
208 while ((i < argc) && OptionProcessor::IsValidShortFlag(name: argv[i])) {
209 if (OptionProcessor::TryProcess(option: argv[i], options: vm_options)) {
210 i += 1;
211 continue;
212 }
213 vm_options->AddArgument(argument: argv[i]);
214 i += 1;
215 }
216
217 // Parse out the kernel inputs.
218 while (i < argc) {
219 inputs->AddArgument(argument: argv[i]);
220 i++;
221 }
222
223 if (help) {
224 PrintUsage();
225 Platform::Exit(exit_code: 0);
226 } else if (version) {
227 Syslog::PrintErr(format: "Dart SDK version: %s\n", Dart_VersionString());
228 Platform::Exit(exit_code: 0);
229 }
230
231 // Verify consistency of arguments.
232 if (inputs->count() < 1) {
233 Syslog::PrintErr(format: "At least one input is required\n");
234 return -1;
235 }
236
237 switch (snapshot_kind) {
238 case kCore: {
239 if ((vm_snapshot_data_filename == nullptr) ||
240 (isolate_snapshot_data_filename == nullptr)) {
241 Syslog::PrintErr(
242 format: "Building a core snapshot requires specifying output files for "
243 "--vm_snapshot_data and --isolate_snapshot_data.\n\n");
244 return -1;
245 }
246 break;
247 }
248 case kCoreJIT: {
249 if ((vm_snapshot_data_filename == nullptr) ||
250 (vm_snapshot_instructions_filename == nullptr) ||
251 (isolate_snapshot_data_filename == nullptr) ||
252 (isolate_snapshot_instructions_filename == nullptr)) {
253 Syslog::PrintErr(
254 format: "Building a core JIT snapshot requires specifying output "
255 "files for --vm_snapshot_data, --vm_snapshot_instructions, "
256 "--isolate_snapshot_data and --isolate_snapshot_instructions.\n\n");
257 return -1;
258 }
259 break;
260 }
261 case kApp:
262 case kAppJIT: {
263 if ((load_vm_snapshot_data_filename == nullptr) ||
264 (isolate_snapshot_data_filename == nullptr) ||
265 (isolate_snapshot_instructions_filename == nullptr)) {
266 Syslog::PrintErr(
267 format: "Building an app JIT snapshot requires specifying input files for "
268 "--load_vm_snapshot_data and --load_vm_snapshot_instructions, an "
269 " output file for --isolate_snapshot_data, and an output "
270 "file for --isolate_snapshot_instructions.\n\n");
271 return -1;
272 }
273 break;
274 }
275 case kAppAOTElf: {
276 if (elf_filename == nullptr) {
277 Syslog::PrintErr(
278 format: "Building an AOT snapshot as ELF requires specifying "
279 "an output file for --elf.\n\n");
280 return -1;
281 }
282 break;
283 }
284 case kAppAOTAssembly:
285 case kVMAOTAssembly: {
286 if (assembly_filename == nullptr) {
287 Syslog::PrintErr(
288 format: "Building an AOT snapshot as assembly requires specifying "
289 "an output file for --assembly.\n\n");
290 return -1;
291 }
292 break;
293 }
294 }
295
296 if (!obfuscate && obfuscation_map_filename != nullptr) {
297 Syslog::PrintErr(
298 format: "--save-obfuscation_map=<...> should only be specified when "
299 "obfuscation is enabled by the --obfuscate flag.\n\n");
300 return -1;
301 }
302
303 if (!IsSnapshottingForPrecompilation()) {
304 if (obfuscate) {
305 Syslog::PrintErr(
306 format: "Obfuscation can only be enabled when building an AOT snapshot.\n\n");
307 return -1;
308 }
309
310 if (debugging_info_filename != nullptr) {
311 Syslog::PrintErr(
312 format: "--save-debugging-info=<...> can only be enabled when building an "
313 "AOT snapshot.\n\n");
314 return -1;
315 }
316
317 if (strip) {
318 Syslog::PrintErr(
319 format: "Stripping can only be enabled when building an AOT snapshot.\n\n");
320 return -1;
321 }
322 }
323
324 return 0;
325}
326
327PRINTF_ATTRIBUTE(1, 2) static void PrintErrAndExit(const char* format, ...) {
328 va_list args;
329 va_start(args, format);
330 Syslog::VPrintErr(format, args);
331 va_end(args);
332
333 Dart_ExitScope();
334 Dart_ShutdownIsolate();
335 exit(kErrorExitCode);
336}
337
338static File* OpenFile(const char* filename) {
339 File* file = File::Open(namespc: nullptr, path: filename, mode: File::kWriteTruncate);
340 if (file == nullptr) {
341 PrintErrAndExit(format: "Error: Unable to write file: %s\n\n", filename);
342 }
343 return file;
344}
345
346static void WriteFile(const char* filename,
347 const uint8_t* buffer,
348 const intptr_t size) {
349 File* file = OpenFile(filename);
350 RefCntReleaseScope<File> rs(file);
351 if (!file->WriteFully(buffer, num_bytes: size)) {
352 PrintErrAndExit(format: "Error: Unable to write file: %s\n\n", filename);
353 }
354}
355
356static void ReadFile(const char* filename, uint8_t** buffer, intptr_t* size) {
357 File* file = File::Open(namespc: nullptr, path: filename, mode: File::kRead);
358 if (file == nullptr) {
359 PrintErrAndExit(format: "Error: Unable to read file: %s\n", filename);
360 }
361 RefCntReleaseScope<File> rs(file);
362 *size = file->Length();
363 *buffer = reinterpret_cast<uint8_t*>(malloc(size: *size));
364 if (!file->ReadFully(buffer: *buffer, num_bytes: *size)) {
365 PrintErrAndExit(format: "Error: Unable to read file: %s\n", filename);
366 }
367}
368
369static void MallocFinalizer(void* isolate_callback_data, void* peer) {
370 free(peer);
371}
372
373static void MaybeLoadExtraInputs(const CommandLineOptions& inputs) {
374 for (intptr_t i = 1; i < inputs.count(); i++) {
375 uint8_t* buffer = nullptr;
376 intptr_t size = 0;
377 ReadFile(filename: inputs.GetArgument(index: i), buffer: &buffer, size: &size);
378 Dart_Handle td = Dart_NewExternalTypedDataWithFinalizer(
379 Dart_TypedData_kUint8, buffer, size, buffer, size, MallocFinalizer);
380 CHECK_RESULT(td);
381 Dart_Handle result = Dart_LoadLibrary(kernel_buffer: td);
382 CHECK_RESULT(result);
383 }
384}
385
386static void MaybeLoadCode() {
387 if (compile_all &&
388 ((snapshot_kind == kCoreJIT) || (snapshot_kind == kAppJIT))) {
389 Dart_Handle result = Dart_CompileAll();
390 CHECK_RESULT(result);
391 }
392}
393
394static void CreateAndWriteCoreSnapshot() {
395 ASSERT(snapshot_kind == kCore);
396 ASSERT(vm_snapshot_data_filename != nullptr);
397 ASSERT(isolate_snapshot_data_filename != nullptr);
398
399 Dart_Handle result;
400 uint8_t* vm_snapshot_data_buffer = nullptr;
401 intptr_t vm_snapshot_data_size = 0;
402 uint8_t* isolate_snapshot_data_buffer = nullptr;
403 intptr_t isolate_snapshot_data_size = 0;
404
405 // First create a snapshot.
406 result = Dart_CreateSnapshot(&vm_snapshot_data_buffer, &vm_snapshot_data_size,
407 &isolate_snapshot_data_buffer,
408 &isolate_snapshot_data_size,
409 /*is_core=*/true);
410 CHECK_RESULT(result);
411
412 // Now write the vm isolate and isolate snapshots out to the
413 // specified file and exit.
414 WriteFile(filename: vm_snapshot_data_filename, buffer: vm_snapshot_data_buffer,
415 size: vm_snapshot_data_size);
416 if (vm_snapshot_instructions_filename != nullptr) {
417 // Create empty file for the convenience of build systems. Makes things
418 // polymorphic with generating core-jit snapshots.
419 WriteFile(filename: vm_snapshot_instructions_filename, buffer: nullptr, size: 0);
420 }
421 WriteFile(filename: isolate_snapshot_data_filename, buffer: isolate_snapshot_data_buffer,
422 size: isolate_snapshot_data_size);
423 if (isolate_snapshot_instructions_filename != nullptr) {
424 // Create empty file for the convenience of build systems. Makes things
425 // polymorphic with generating core-jit snapshots.
426 WriteFile(filename: isolate_snapshot_instructions_filename, buffer: nullptr, size: 0);
427 }
428}
429
430static std::unique_ptr<MappedMemory> MapFile(const char* filename,
431 File::MapType type,
432 const uint8_t** buffer) {
433 File* file = File::Open(namespc: nullptr, path: filename, mode: File::kRead);
434 if (file == nullptr) {
435 Syslog::PrintErr(format: "Failed to open: %s\n", filename);
436 exit(kErrorExitCode);
437 }
438 RefCntReleaseScope<File> rs(file);
439 intptr_t length = file->Length();
440 if (length == 0) {
441 // Can't map an empty file.
442 *buffer = nullptr;
443 return nullptr;
444 }
445 MappedMemory* mapping = file->Map(type, position: 0, length);
446 if (mapping == nullptr) {
447 Syslog::PrintErr(format: "Failed to read: %s\n", filename);
448 exit(kErrorExitCode);
449 }
450 *buffer = reinterpret_cast<const uint8_t*>(mapping->address());
451 return std::unique_ptr<MappedMemory>(mapping);
452}
453
454static void CreateAndWriteCoreJITSnapshot() {
455 ASSERT(snapshot_kind == kCoreJIT);
456 ASSERT(vm_snapshot_data_filename != nullptr);
457 ASSERT(vm_snapshot_instructions_filename != nullptr);
458 ASSERT(isolate_snapshot_data_filename != nullptr);
459 ASSERT(isolate_snapshot_instructions_filename != nullptr);
460
461 Dart_Handle result;
462 uint8_t* vm_snapshot_data_buffer = nullptr;
463 intptr_t vm_snapshot_data_size = 0;
464 uint8_t* vm_snapshot_instructions_buffer = nullptr;
465 intptr_t vm_snapshot_instructions_size = 0;
466 uint8_t* isolate_snapshot_data_buffer = nullptr;
467 intptr_t isolate_snapshot_data_size = 0;
468 uint8_t* isolate_snapshot_instructions_buffer = nullptr;
469 intptr_t isolate_snapshot_instructions_size = 0;
470
471 // First create a snapshot.
472 result = Dart_CreateCoreJITSnapshotAsBlobs(
473 &vm_snapshot_data_buffer, &vm_snapshot_data_size,
474 &vm_snapshot_instructions_buffer, &vm_snapshot_instructions_size,
475 &isolate_snapshot_data_buffer, &isolate_snapshot_data_size,
476 &isolate_snapshot_instructions_buffer,
477 &isolate_snapshot_instructions_size);
478 CHECK_RESULT(result);
479
480 // Now write the vm isolate and isolate snapshots out to the
481 // specified file and exit.
482 WriteFile(filename: vm_snapshot_data_filename, buffer: vm_snapshot_data_buffer,
483 size: vm_snapshot_data_size);
484 WriteFile(filename: vm_snapshot_instructions_filename, buffer: vm_snapshot_instructions_buffer,
485 size: vm_snapshot_instructions_size);
486 WriteFile(filename: isolate_snapshot_data_filename, buffer: isolate_snapshot_data_buffer,
487 size: isolate_snapshot_data_size);
488 WriteFile(filename: isolate_snapshot_instructions_filename,
489 buffer: isolate_snapshot_instructions_buffer,
490 size: isolate_snapshot_instructions_size);
491}
492
493static void CreateAndWriteAppSnapshot() {
494 ASSERT(snapshot_kind == kApp);
495 ASSERT(isolate_snapshot_data_filename != nullptr);
496
497 Dart_Handle result;
498 uint8_t* isolate_snapshot_data_buffer = nullptr;
499 intptr_t isolate_snapshot_data_size = 0;
500
501 result = Dart_CreateSnapshot(nullptr, nullptr, &isolate_snapshot_data_buffer,
502 &isolate_snapshot_data_size, /*is_core=*/false);
503 CHECK_RESULT(result);
504
505 WriteFile(filename: isolate_snapshot_data_filename, buffer: isolate_snapshot_data_buffer,
506 size: isolate_snapshot_data_size);
507 if (isolate_snapshot_instructions_filename != nullptr) {
508 // Create empty file for the convenience of build systems. Makes things
509 // polymorphic with generating core-jit snapshots.
510 WriteFile(filename: isolate_snapshot_instructions_filename, buffer: nullptr, size: 0);
511 }
512}
513
514static void CreateAndWriteAppJITSnapshot() {
515 ASSERT(snapshot_kind == kAppJIT);
516 ASSERT(isolate_snapshot_data_filename != nullptr);
517 ASSERT(isolate_snapshot_instructions_filename != nullptr);
518
519 Dart_Handle result;
520 uint8_t* isolate_snapshot_data_buffer = nullptr;
521 intptr_t isolate_snapshot_data_size = 0;
522 uint8_t* isolate_snapshot_instructions_buffer = nullptr;
523 intptr_t isolate_snapshot_instructions_size = 0;
524
525 result = Dart_CreateAppJITSnapshotAsBlobs(
526 &isolate_snapshot_data_buffer, &isolate_snapshot_data_size,
527 &isolate_snapshot_instructions_buffer,
528 &isolate_snapshot_instructions_size);
529 CHECK_RESULT(result);
530
531 WriteFile(filename: isolate_snapshot_data_filename, buffer: isolate_snapshot_data_buffer,
532 size: isolate_snapshot_data_size);
533 WriteFile(filename: isolate_snapshot_instructions_filename,
534 buffer: isolate_snapshot_instructions_buffer,
535 size: isolate_snapshot_instructions_size);
536}
537
538static void StreamingWriteCallback(void* callback_data,
539 const uint8_t* buffer,
540 intptr_t size) {
541 File* file = reinterpret_cast<File*>(callback_data);
542 if ((file != nullptr) && !file->WriteFully(buffer, num_bytes: size)) {
543 PrintErrAndExit(format: "Error: Unable to write snapshot file\n\n");
544 }
545}
546
547static void StreamingCloseCallback(void* callback_data) {
548 File* file = reinterpret_cast<File*>(callback_data);
549 file->Release();
550}
551
552static File* OpenLoadingUnitManifest() {
553 File* manifest_file = OpenFile(filename: loading_unit_manifest_filename);
554 if (!manifest_file->Print(format: "{ \"loadingUnits\": [\n")) {
555 PrintErrAndExit(format: "Error: Unable to write file: %s\n\n",
556 loading_unit_manifest_filename);
557 }
558 return manifest_file;
559}
560
561static void WriteLoadingUnitManifest(File* manifest_file,
562 intptr_t id,
563 const char* path) {
564 TextBuffer line(128);
565 if (id != 1) {
566 line.AddString(s: ",\n");
567 }
568 line.Printf("{ \"id\": %" Pd ", \"path\": \"", id);
569 line.AddEscapedString(s: path);
570 line.AddString(s: "\", \"libraries\": [\n");
571 Dart_Handle uris = Dart_LoadingUnitLibraryUris(id);
572 CHECK_RESULT(uris);
573 intptr_t length;
574 CHECK_RESULT(Dart_ListLength(uris, &length));
575 for (intptr_t i = 0; i < length; i++) {
576 const char* uri;
577 CHECK_RESULT(Dart_StringToCString(Dart_ListGetAt(uris, i), &uri));
578 if (i != 0) {
579 line.AddString(s: ",\n");
580 }
581 line.AddString(s: "\"");
582 line.AddEscapedString(s: uri);
583 line.AddString(s: "\"");
584 }
585 line.AddString(s: "]}");
586 if (!manifest_file->Print(format: "%s\n", line.buffer())) {
587 PrintErrAndExit(format: "Error: Unable to write file: %s\n\n",
588 loading_unit_manifest_filename);
589 }
590}
591
592static void CloseLoadingUnitManifest(File* manifest_file) {
593 if (!manifest_file->Print(format: "] }\n")) {
594 PrintErrAndExit(format: "Error: Unable to write file: %s\n\n",
595 loading_unit_manifest_filename);
596 }
597 manifest_file->Release();
598}
599
600static void NextLoadingUnit(void* callback_data,
601 intptr_t loading_unit_id,
602 void** write_callback_data,
603 void** write_debug_callback_data,
604 const char* main_filename,
605 const char* suffix) {
606 char* filename = loading_unit_id == 1
607 ? Utils::StrDup(main_filename)
608 : Utils::SCreate("%s-%" Pd ".part.%s", main_filename,
609 loading_unit_id, suffix);
610 File* file = OpenFile(filename);
611 *write_callback_data = file;
612
613 if (debugging_info_filename != nullptr) {
614 char* debug_filename =
615 loading_unit_id == 1
616 ? Utils::StrDup(debugging_info_filename)
617 : Utils::SCreate("%s-%" Pd ".part.so", debugging_info_filename,
618 loading_unit_id);
619 File* debug_file = OpenFile(filename: debug_filename);
620 *write_debug_callback_data = debug_file;
621 free(debug_filename);
622 }
623
624 WriteLoadingUnitManifest(manifest_file: reinterpret_cast<File*>(callback_data),
625 id: loading_unit_id, path: filename);
626
627 free(filename);
628}
629
630static void NextAsmCallback(void* callback_data,
631 intptr_t loading_unit_id,
632 void** write_callback_data,
633 void** write_debug_callback_data) {
634 NextLoadingUnit(callback_data, loading_unit_id, write_callback_data,
635 write_debug_callback_data, main_filename: assembly_filename, suffix: "S");
636}
637
638static void NextElfCallback(void* callback_data,
639 intptr_t loading_unit_id,
640 void** write_callback_data,
641 void** write_debug_callback_data) {
642 NextLoadingUnit(callback_data, loading_unit_id, write_callback_data,
643 write_debug_callback_data, main_filename: elf_filename, suffix: "so");
644}
645
646static void CreateAndWritePrecompiledSnapshot() {
647 ASSERT(IsSnapshottingForPrecompilation());
648 Dart_Handle result;
649
650 // Precompile with specified embedder entry points
651 result = Dart_Precompile();
652 CHECK_RESULT(result);
653
654 // Create a precompiled snapshot.
655 if (snapshot_kind == kAppAOTAssembly) {
656 if (strip && (debugging_info_filename == nullptr)) {
657 Syslog::PrintErr(
658 format: "Warning: Generating assembly code without DWARF debugging"
659 " information.\n");
660 }
661 if (loading_unit_manifest_filename == nullptr) {
662 File* file = OpenFile(filename: assembly_filename);
663 RefCntReleaseScope<File> rs(file);
664 File* debug_file = nullptr;
665 if (debugging_info_filename != nullptr) {
666 debug_file = OpenFile(filename: debugging_info_filename);
667 }
668 result = Dart_CreateAppAOTSnapshotAsAssembly(StreamingWriteCallback, file,
669 strip, debug_file);
670 if (debug_file != nullptr) debug_file->Release();
671 CHECK_RESULT(result);
672 } else {
673 File* manifest_file = OpenLoadingUnitManifest();
674 result = Dart_CreateAppAOTSnapshotAsAssemblies(
675 NextAsmCallback, manifest_file, strip, StreamingWriteCallback,
676 StreamingCloseCallback);
677 CHECK_RESULT(result);
678 CloseLoadingUnitManifest(manifest_file);
679 }
680 if (obfuscate && !strip) {
681 Syslog::PrintErr(
682 format: "Warning: The generated assembly code contains unobfuscated DWARF "
683 "debugging information.\n"
684 " To avoid this, use --strip to remove it.\n");
685 }
686 } else if (snapshot_kind == kAppAOTElf) {
687 if (strip && (debugging_info_filename == nullptr)) {
688 Syslog::PrintErr(
689 format: "Warning: Generating ELF library without DWARF debugging"
690 " information.\n");
691 }
692 if (loading_unit_manifest_filename == nullptr) {
693 File* file = OpenFile(filename: elf_filename);
694 RefCntReleaseScope<File> rs(file);
695 File* debug_file = nullptr;
696 if (debugging_info_filename != nullptr) {
697 debug_file = OpenFile(filename: debugging_info_filename);
698 }
699 result = Dart_CreateAppAOTSnapshotAsElf(StreamingWriteCallback, file,
700 strip, debug_file);
701 if (debug_file != nullptr) debug_file->Release();
702 CHECK_RESULT(result);
703 } else {
704 File* manifest_file = OpenLoadingUnitManifest();
705 result = Dart_CreateAppAOTSnapshotAsElfs(NextElfCallback, manifest_file,
706 strip, StreamingWriteCallback,
707 StreamingCloseCallback);
708 CHECK_RESULT(result);
709 CloseLoadingUnitManifest(manifest_file);
710 }
711 if (obfuscate && !strip) {
712 Syslog::PrintErr(
713 format: "Warning: The generated ELF library contains unobfuscated DWARF "
714 "debugging information.\n"
715 " To avoid this, use --strip to remove it and "
716 "--save-debugging-info=<...> to save it to a separate file.\n");
717 }
718 } else {
719 UNREACHABLE();
720 }
721
722 // Serialize obfuscation map if requested.
723 if (obfuscation_map_filename != nullptr) {
724 ASSERT(obfuscate);
725 uint8_t* buffer = nullptr;
726 intptr_t size = 0;
727 result = Dart_GetObfuscationMap(&buffer, &size);
728 CHECK_RESULT(result);
729 WriteFile(filename: obfuscation_map_filename, buffer, size);
730 }
731}
732
733static int CreateIsolateAndSnapshot(const CommandLineOptions& inputs) {
734 uint8_t* kernel_buffer = nullptr;
735 intptr_t kernel_buffer_size = 0;
736 ReadFile(filename: inputs.GetArgument(index: 0), buffer: &kernel_buffer, size: &kernel_buffer_size);
737
738 Dart_IsolateFlags isolate_flags;
739 Dart_IsolateFlagsInitialize(flags: &isolate_flags);
740 isolate_flags.null_safety =
741 Dart_DetectNullSafety(nullptr, nullptr, nullptr, nullptr, nullptr,
742 kernel_buffer, kernel_buffer_size);
743 if (IsSnapshottingForPrecompilation()) {
744 isolate_flags.obfuscate = obfuscate;
745 }
746
747 auto isolate_group_data = std::unique_ptr<IsolateGroupData>(
748 new IsolateGroupData(nullptr, nullptr, nullptr, false));
749 Dart_Isolate isolate;
750 char* error = nullptr;
751
752 bool loading_kernel_failed = false;
753 if (isolate_snapshot_data == nullptr) {
754 // We need to capture the vmservice library in the core snapshot, so load it
755 // in the main isolate as well.
756 isolate_flags.load_vmservice_library = true;
757 isolate = Dart_CreateIsolateGroupFromKernel(
758 nullptr, nullptr, kernel_buffer, kernel_buffer_size, &isolate_flags,
759 isolate_group_data.get(), /*isolate_data=*/nullptr, &error);
760 loading_kernel_failed = (isolate == nullptr);
761 } else {
762 isolate = Dart_CreateIsolateGroup(nullptr, nullptr, isolate_snapshot_data,
763 isolate_snapshot_instructions,
764 &isolate_flags, isolate_group_data.get(),
765 /*isolate_data=*/nullptr, &error);
766 }
767 if (isolate == nullptr) {
768 Syslog::PrintErr(format: "%s\n", error);
769 free(error);
770 free(kernel_buffer);
771 // The only real reason when `gen_snapshot` fails to create an isolate from
772 // a valid kernel file is if loading the kernel results in a "compile-time"
773 // error.
774 //
775 // There are other possible reasons, like memory allocation failures, but
776 // those are very uncommon.
777 //
778 // The Dart API doesn't allow us to distinguish the different error cases,
779 // so we'll use [kCompilationErrorExitCode] for failed kernel loading, since
780 // a compile-time error is the most probable cause.
781 return loading_kernel_failed ? kCompilationErrorExitCode : kErrorExitCode;
782 }
783
784 Dart_EnterScope();
785 Dart_Handle result =
786 Dart_SetEnvironmentCallback(callback: DartUtils::EnvironmentCallback);
787 CHECK_RESULT(result);
788
789 // The root library has to be set to generate AOT snapshots, and sometimes we
790 // set one for the core snapshot too.
791 // If the input dill file has a root library, then Dart_LoadScript will
792 // ignore this dummy uri and set the root library to the one reported in
793 // the dill file. Since dill files are not dart script files,
794 // trying to resolve the root library URI based on the dill file name
795 // would not help.
796 //
797 // If the input dill file does not have a root library, then
798 // Dart_LoadScript will error.
799 //
800 // TODO(kernel): Dart_CreateIsolateGroupFromKernel should respect the root
801 // library in the kernel file, though this requires auditing the other
802 // loading paths in the embedders that had to work around this.
803 result = Dart_SetRootLibrary(
804 Dart_LoadLibraryFromKernel(kernel_buffer, kernel_buffer_size));
805 CHECK_RESULT(result);
806
807 MaybeLoadExtraInputs(inputs);
808
809 MaybeLoadCode();
810
811 switch (snapshot_kind) {
812 case kCore:
813 CreateAndWriteCoreSnapshot();
814 break;
815 case kCoreJIT:
816 CreateAndWriteCoreJITSnapshot();
817 break;
818 case kApp:
819 CreateAndWriteAppSnapshot();
820 break;
821 case kAppJIT:
822 CreateAndWriteAppJITSnapshot();
823 break;
824 case kAppAOTAssembly:
825 case kAppAOTElf:
826 CreateAndWritePrecompiledSnapshot();
827 break;
828 case kVMAOTAssembly: {
829 File* file = OpenFile(filename: assembly_filename);
830 RefCntReleaseScope<File> rs(file);
831 result = Dart_CreateVMAOTSnapshotAsAssembly(StreamingWriteCallback, file);
832 CHECK_RESULT(result);
833 break;
834 }
835 default:
836 UNREACHABLE();
837 }
838
839 Dart_ExitScope();
840 Dart_ShutdownIsolate();
841
842 free(kernel_buffer);
843 return 0;
844}
845
846int main(int argc, char** argv) {
847 const int EXTRA_VM_ARGUMENTS = 7;
848 CommandLineOptions vm_options(argc + EXTRA_VM_ARGUMENTS);
849 CommandLineOptions inputs(argc);
850
851 // When running from the command line we assume that we are optimizing for
852 // throughput, and therefore use a larger new gen semi space size and a faster
853 // new gen growth factor unless others have been specified.
854 if (kWordSize <= 4) {
855 vm_options.AddArgument(argument: "--new_gen_semi_max_size=16");
856 } else {
857 vm_options.AddArgument(argument: "--new_gen_semi_max_size=32");
858 }
859 vm_options.AddArgument(argument: "--new_gen_growth_factor=4");
860 vm_options.AddArgument(argument: "--deterministic");
861
862 // Parse command line arguments.
863 if (ParseArguments(argc, argv, vm_options: &vm_options, inputs: &inputs) < 0) {
864 PrintUsage();
865 return kErrorExitCode;
866 }
867 DartUtils::SetEnvironment(environment);
868
869 if (!Platform::Initialize()) {
870 Syslog::PrintErr(format: "Initialization failed\n");
871 return kErrorExitCode;
872 }
873 Console::SaveConfig();
874 Loader::InitOnce();
875 DartUtils::SetOriginalWorkingDirectory();
876 // Start event handler.
877 TimerUtils::InitOnce();
878 EventHandler::Start();
879
880 if (IsSnapshottingForPrecompilation()) {
881 vm_options.AddArgument(argument: "--precompilation");
882 } else if ((snapshot_kind == kCoreJIT) || (snapshot_kind == kAppJIT)) {
883 // Core-jit and app-jit snapshot can be deployed to another machine,
884 // so generated code should not depend on the CPU features
885 // of the system where snapshot was generated.
886 vm_options.AddArgument(argument: "--target-unknown-cpu");
887#if !defined(TARGET_ARCH_IA32)
888 vm_options.AddArgument(argument: "--link_natives_lazily");
889#endif
890 }
891
892 char* error = Dart_SetVMFlags(argc: vm_options.count(), argv: vm_options.arguments());
893 if (error != nullptr) {
894 Syslog::PrintErr(format: "Setting VM flags failed: %s\n", error);
895 free(error);
896 return kErrorExitCode;
897 }
898
899 Dart_InitializeParams init_params;
900 memset(&init_params, 0, sizeof(init_params));
901 init_params.version = DART_INITIALIZE_PARAMS_CURRENT_VERSION;
902 init_params.file_open = DartUtils::OpenFile;
903 init_params.file_read = DartUtils::ReadFile;
904 init_params.file_write = DartUtils::WriteFile;
905 init_params.file_close = DartUtils::CloseFile;
906 init_params.entropy_source = DartUtils::EntropySource;
907 init_params.start_kernel_isolate = false;
908#if defined(DART_HOST_OS_FUCHSIA)
909 init_params.vmex_resource = Platform::GetVMEXResource();
910#endif
911
912 std::unique_ptr<MappedMemory> mapped_vm_snapshot_data;
913 std::unique_ptr<MappedMemory> mapped_vm_snapshot_instructions;
914 std::unique_ptr<MappedMemory> mapped_isolate_snapshot_data;
915 std::unique_ptr<MappedMemory> mapped_isolate_snapshot_instructions;
916 if (load_vm_snapshot_data_filename != nullptr) {
917 mapped_vm_snapshot_data =
918 MapFile(load_vm_snapshot_data_filename, File::kReadOnly,
919 &init_params.vm_snapshot_data);
920 }
921 if (load_vm_snapshot_instructions_filename != nullptr) {
922 mapped_vm_snapshot_instructions =
923 MapFile(load_vm_snapshot_instructions_filename, File::kReadExecute,
924 &init_params.vm_snapshot_instructions);
925 }
926 if (load_isolate_snapshot_data_filename != nullptr) {
927 mapped_isolate_snapshot_data =
928 MapFile(load_isolate_snapshot_data_filename, File::kReadOnly,
929 &isolate_snapshot_data);
930 }
931 if (load_isolate_snapshot_instructions_filename != nullptr) {
932 mapped_isolate_snapshot_instructions =
933 MapFile(load_isolate_snapshot_instructions_filename, File::kReadExecute,
934 &isolate_snapshot_instructions);
935 }
936
937 error = Dart_Initialize(params: &init_params);
938 if (error != nullptr) {
939 Syslog::PrintErr(format: "VM initialization failed: %s\n", error);
940 free(error);
941 return kErrorExitCode;
942 }
943
944 int result = CreateIsolateAndSnapshot(inputs);
945 if (result != 0) {
946 return result;
947 }
948
949 error = Dart_Cleanup();
950 if (error != nullptr) {
951 Syslog::PrintErr(format: "VM cleanup failed: %s\n", error);
952 free(error);
953 }
954 EventHandler::Stop();
955 return 0;
956}
957
958} // namespace bin
959} // namespace dart
960
961int main(int argc, char** argv) {
962 return dart::bin::main(argc, argv);
963}
964

source code of dart_sdk/runtime/bin/gen_snapshot.cc