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