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 | |
37 | namespace dart { |
38 | namespace bin { |
39 | |
40 | // Exit code indicating an API error. |
41 | static const int kApiErrorExitCode = 253; |
42 | // Exit code indicating a compilation error. |
43 | static const int kCompilationErrorExitCode = 254; |
44 | // Exit code indicating an unhandled error that is not a compilation error. |
45 | static 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. |
64 | static dart::SimpleHashMap* environment = NULL; |
65 | |
66 | static 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. |
74 | const uint8_t* isolate_snapshot_data = NULL; |
75 | const 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. |
80 | enum SnapshotKind { |
81 | kCore, |
82 | kCoreJIT, |
83 | kApp, |
84 | kAppJIT, |
85 | kAppAOTAssembly, |
86 | kAppAOTElf, |
87 | kVMAOTAssembly, |
88 | }; |
89 | static SnapshotKind snapshot_kind = kCore; |
90 | |
91 | // The ordering of this list must match the SnapshotKind enum above. |
92 | static 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) |
136 | STRING_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) |
142 | BOOL_OPTIONS_LIST(BOOL_OPTION_DEFINITION) |
143 | #undef BOOL_OPTION_DEFINITION |
144 | |
145 | DEFINE_ENUM_OPTION(snapshot_kind, SnapshotKind, snapshot_kind); |
146 | DEFINE_CB_OPTION(ProcessEnvironmentOption); |
147 | |
148 | static bool IsSnapshottingForPrecompilation() { |
149 | return (snapshot_kind == kAppAOTAssembly) || (snapshot_kind == kAppAOTElf) || |
150 | (snapshot_kind == kVMAOTAssembly); |
151 | } |
152 | |
153 | // clang-format off |
154 | static 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. |
209 | static 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 | |
340 | PRINTF_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 | |
351 | static 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 | |
359 | static 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 | |
369 | static 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 | |
382 | static 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 | |
392 | static 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 | |
435 | static 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 | |
470 | static 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 | |
494 | static 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 | |
533 | static 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 | |
554 | static 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 | |
578 | static 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 | |
587 | static void StreamingCloseCallback(void* callback_data) { |
588 | File* file = reinterpret_cast<File*>(callback_data); |
589 | file->Release(); |
590 | } |
591 | |
592 | static 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 | |
601 | static 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 | |
617 | static 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 | |
625 | static 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 | |
655 | static 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 | |
663 | static 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 | |
671 | static 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 | |
758 | static Dart_QualifiedFunctionName no_entry_points[] = { |
759 | {NULL, NULL, NULL} // Must be terminated with NULL entries. |
760 | }; |
761 | |
762 | static 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 | |
876 | int main(int argc, char** argv) { |
877 | const int = 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 | |
985 | int main(int argc, char** argv) { |
986 | return dart::bin::main(argc, argv); |
987 | } |
988 | |