1// Copyright (c) 2012, 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#include "bin/main_impl.h"
6
7#include <stdio.h>
8#include <stdlib.h>
9#include <string.h>
10
11#include <memory>
12#include <utility>
13
14#include "bin/builtin.h"
15#include "bin/console.h"
16#include "bin/crashpad.h"
17#include "bin/dartdev_isolate.h"
18#include "bin/dartutils.h"
19#include "bin/dfe.h"
20#include "bin/error_exit.h"
21#include "bin/eventhandler.h"
22#include "bin/file.h"
23#include "bin/gzip.h"
24#include "bin/isolate_data.h"
25#include "bin/loader.h"
26#include "bin/main_options.h"
27#include "bin/platform.h"
28#include "bin/process.h"
29#include "bin/snapshot_utils.h"
30#include "bin/thread.h"
31#include "bin/utils.h"
32#include "bin/vmservice_impl.h"
33#include "include/bin/dart_io_api.h"
34#include "include/dart_api.h"
35#include "include/dart_embedder_api.h"
36#include "include/dart_tools_api.h"
37#include "platform/globals.h"
38#include "platform/growable_array.h"
39#include "platform/hashmap.h"
40#include "platform/syslog.h"
41#include "platform/text_buffer.h"
42#include "platform/utils.h"
43
44extern "C" {
45extern const uint8_t kDartVmSnapshotData[];
46extern const uint8_t kDartVmSnapshotInstructions[];
47extern const uint8_t kDartCoreIsolateSnapshotData[];
48extern const uint8_t kDartCoreIsolateSnapshotInstructions[];
49}
50
51namespace dart {
52namespace bin {
53
54// Snapshot pieces we link in a snapshot.
55const uint8_t* vm_snapshot_data = kDartVmSnapshotData;
56const uint8_t* vm_snapshot_instructions = kDartVmSnapshotInstructions;
57const uint8_t* core_isolate_snapshot_data = kDartCoreIsolateSnapshotData;
58const uint8_t* core_isolate_snapshot_instructions =
59 kDartCoreIsolateSnapshotInstructions;
60
61/**
62 * Global state used to control and store generation of application snapshots.
63 * An application snapshot can be generated and run using the following
64 * command
65 * dart --snapshot-kind=app-jit --snapshot=<app_snapshot_filename>
66 * <script_uri> [<script_options>]
67 * To Run the application snapshot generated above, use :
68 * dart <app_snapshot_filename> [<script_options>]
69 */
70static bool vm_run_app_snapshot = false;
71static char* app_script_uri = nullptr;
72static const uint8_t* app_isolate_snapshot_data = nullptr;
73static const uint8_t* app_isolate_snapshot_instructions = nullptr;
74static bool kernel_isolate_is_running = false;
75
76static Dart_Isolate main_isolate = nullptr;
77
78#define SAVE_ERROR_AND_EXIT(result) \
79 *error = Utils::StrDup(Dart_GetError(result)); \
80 if (Dart_IsCompilationError(result)) { \
81 *exit_code = kCompilationErrorExitCode; \
82 } else if (Dart_IsApiError(result)) { \
83 *exit_code = kApiErrorExitCode; \
84 } else { \
85 *exit_code = kErrorExitCode; \
86 } \
87 Dart_ExitScope(); \
88 Dart_ShutdownIsolate(); \
89 return nullptr;
90
91#define CHECK_RESULT(result) \
92 if (Dart_IsError(result)) { \
93 SAVE_ERROR_AND_EXIT(result); \
94 }
95
96#define CHECK_RESULT_CLEANUP(result, cleanup) \
97 if (Dart_IsError(result)) { \
98 delete (cleanup); \
99 SAVE_ERROR_AND_EXIT(result); \
100 }
101
102static void WriteDepsFile() {
103 if (Options::depfile() == nullptr) {
104 return;
105 }
106 File* file = File::Open(namespc: nullptr, path: Options::depfile(), mode: File::kWriteTruncate);
107 if (file == nullptr) {
108 ErrorExit(exit_code: kErrorExitCode, format: "Error: Unable to open snapshot depfile: %s\n\n",
109 Options::depfile());
110 }
111 bool success = true;
112 if (Options::depfile_output_filename() != nullptr) {
113 success &= file->Print(format: "%s: ", Options::depfile_output_filename());
114 } else {
115 success &= file->Print(format: "%s: ", Options::snapshot_filename());
116 }
117 if (kernel_isolate_is_running) {
118 Dart_KernelCompilationResult result = Dart_KernelListDependencies();
119 if (result.status != Dart_KernelCompilationStatus_Ok) {
120 ErrorExit(
121 exit_code: kErrorExitCode,
122 format: "Error: Failed to fetch dependencies from kernel service: %s\n\n",
123 result.error);
124 }
125 success &= file->WriteFully(buffer: result.kernel, num_bytes: result.kernel_size);
126 free(result.kernel);
127 }
128 success &= file->Print(format: "\n");
129 if (!success) {
130 ErrorExit(exit_code: kErrorExitCode, format: "Error: Unable to write snapshot depfile: %s\n\n",
131 Options::depfile());
132 }
133 file->Release();
134}
135
136static void OnExitHook(int64_t exit_code) {
137 if (Dart_CurrentIsolate() != main_isolate) {
138 Syslog::PrintErr(
139 "A snapshot was requested, but a secondary isolate "
140 "performed a hard exit (%" Pd64 ").\n",
141 exit_code);
142 Platform::Exit(exit_code: kErrorExitCode);
143 }
144 if (exit_code == 0) {
145 if (Options::gen_snapshot_kind() == kAppJIT) {
146 Snapshot::GenerateAppJIT(snapshot_filename: Options::snapshot_filename());
147 }
148 WriteDepsFile();
149 }
150}
151
152static Dart_Handle SetupCoreLibraries(Dart_Isolate isolate,
153 IsolateData* isolate_data,
154 bool is_isolate_group_start,
155 const char** resolved_packages_config) {
156 auto isolate_group_data = isolate_data->isolate_group_data();
157 const auto packages_file = isolate_data->packages_file();
158 const auto script_uri = isolate_group_data->script_url;
159
160 Dart_Handle result;
161
162 // Prepare builtin and other core libraries for use to resolve URIs.
163 // Set up various closures, e.g: printing, timers etc.
164 // Set up package configuration for URI resolution.
165 result = DartUtils::PrepareForScriptLoading(is_service_isolate: false, trace_loading: Options::trace_loading());
166 if (Dart_IsError(handle: result)) return result;
167
168 // Setup packages config if specified.
169 result = DartUtils::SetupPackageConfig(packages_file);
170 if (Dart_IsError(handle: result)) return result;
171 if (!Dart_IsNull(object: result) && resolved_packages_config != nullptr) {
172 result = Dart_StringToCString(str: result, cstr: resolved_packages_config);
173 if (Dart_IsError(handle: result)) return result;
174 ASSERT(*resolved_packages_config != nullptr);
175#if !defined(DART_PRECOMPILED_RUNTIME)
176 if (is_isolate_group_start) {
177 isolate_group_data->set_resolved_packages_config(
178 *resolved_packages_config);
179 } else {
180 ASSERT(strcmp(isolate_group_data->resolved_packages_config(),
181 *resolved_packages_config) == 0);
182 }
183#endif
184 }
185
186 result = Dart_SetEnvironmentCallback(callback: DartUtils::EnvironmentCallback);
187 if (Dart_IsError(handle: result)) return result;
188
189 // Setup the native resolver as the snapshot does not carry it.
190 Builtin::SetNativeResolver(Builtin::kBuiltinLibrary);
191 Builtin::SetNativeResolver(Builtin::kIOLibrary);
192 Builtin::SetNativeResolver(Builtin::kCLILibrary);
193 VmService::SetNativeResolver();
194
195 const char* namespc =
196 Dart_IsKernelIsolate(isolate) ? nullptr : Options::namespc();
197 result =
198 DartUtils::SetupIOLibrary(namespc_path: namespc, script_uri, disable_exit: Options::exit_disabled());
199 if (Dart_IsError(handle: result)) return result;
200
201 return Dart_Null();
202}
203
204static bool OnIsolateInitialize(void** child_callback_data, char** error) {
205 Dart_Isolate isolate = Dart_CurrentIsolate();
206 ASSERT(isolate != nullptr);
207
208 auto isolate_group_data =
209 reinterpret_cast<IsolateGroupData*>(Dart_CurrentIsolateGroupData());
210
211 auto isolate_data = new IsolateData(isolate_group_data);
212 *child_callback_data = isolate_data;
213
214 Dart_EnterScope();
215 const auto script_uri = isolate_group_data->script_url;
216 const bool isolate_run_app_snapshot =
217 isolate_group_data->RunFromAppSnapshot();
218 Dart_Handle result = SetupCoreLibraries(isolate, isolate_data,
219 /*group_start=*/is_isolate_group_start: false,
220 /*resolved_packages_config=*/nullptr);
221 if (Dart_IsError(handle: result)) goto failed;
222
223 if (isolate_run_app_snapshot) {
224 result = Loader::InitForSnapshot(snapshot_uri: script_uri, isolate_data);
225 if (Dart_IsError(handle: result)) goto failed;
226 } else {
227 result = DartUtils::ResolveScript(url: Dart_NewStringFromCString(str: script_uri));
228 if (Dart_IsError(handle: result)) goto failed;
229
230 if (isolate_group_data->kernel_buffer() != nullptr) {
231 // Various core-library parts will send requests to the Loader to resolve
232 // relative URIs and perform other related tasks. We need Loader to be
233 // initialized for this to work because loading from Kernel binary
234 // bypasses normal source code loading paths that initialize it.
235 const char* resolved_script_uri = nullptr;
236 result = Dart_StringToCString(str: result, cstr: &resolved_script_uri);
237 if (Dart_IsError(handle: result)) goto failed;
238 result = Loader::InitForSnapshot(snapshot_uri: resolved_script_uri, isolate_data);
239 if (Dart_IsError(handle: result)) goto failed;
240 }
241 }
242
243 Dart_ExitScope();
244 return true;
245
246failed:
247 *error = Utils::StrDup(s: Dart_GetError(handle: result));
248 Dart_ExitScope();
249 return false;
250}
251
252static Dart_Isolate IsolateSetupHelper(Dart_Isolate isolate,
253 bool is_main_isolate,
254 const char* script_uri,
255 const char* packages_config,
256 bool isolate_run_app_snapshot,
257 Dart_IsolateFlags* flags,
258 char** error,
259 int* exit_code) {
260 Dart_EnterScope();
261
262 // Set up the library tag handler for the isolate group shared by all
263 // isolates in the group.
264 Dart_Handle result = Dart_SetLibraryTagHandler(handler: Loader::LibraryTagHandler);
265 CHECK_RESULT(result);
266 result = Dart_SetDeferredLoadHandler(Loader::DeferredLoadHandler);
267 CHECK_RESULT(result);
268
269 auto isolate_data = reinterpret_cast<IsolateData*>(Dart_IsolateData(isolate));
270
271 const char* resolved_packages_config = nullptr;
272 result = SetupCoreLibraries(isolate, isolate_data,
273 /*is_isolate_group_start=*/true,
274 resolved_packages_config: &resolved_packages_config);
275 CHECK_RESULT(result);
276
277#if !defined(DART_PRECOMPILED_RUNTIME)
278 auto isolate_group_data = isolate_data->isolate_group_data();
279 const uint8_t* kernel_buffer = isolate_group_data->kernel_buffer().get();
280 intptr_t kernel_buffer_size = isolate_group_data->kernel_buffer_size();
281 if (!isolate_run_app_snapshot && kernel_buffer == nullptr &&
282 !Dart_IsKernelIsolate(isolate)) {
283 if (!dfe.CanUseDartFrontend()) {
284 const char* format = "Dart frontend unavailable to compile script %s.";
285 intptr_t len = snprintf(nullptr, 0, format, script_uri) + 1;
286 *error = reinterpret_cast<char*>(malloc(size: len));
287 ASSERT(error != nullptr);
288 snprintf(*error, len, format, script_uri);
289 *exit_code = kErrorExitCode;
290 Dart_ExitScope();
291 Dart_ShutdownIsolate();
292 return nullptr;
293 }
294 uint8_t* application_kernel_buffer = nullptr;
295 intptr_t application_kernel_buffer_size = 0;
296 // Only pass snapshot = true when generating an AppJIT snapshot to avoid
297 // duplicate null-safety info messages from the frontend when generating
298 // a kernel snapshot (this flag is instead set in
299 // Snapshot::GenerateKernel()).
300 const bool for_snapshot = Options::gen_snapshot_kind() == kAppJIT;
301 // If we compile for AppJIT the sources will not be included across app-jit
302 // snapshotting, so there's no reason CFE should embed them in the kernel.
303 const bool embed_sources = Options::gen_snapshot_kind() != kAppJIT;
304 dfe.CompileAndReadScript(script_uri, kernel_buffer: &application_kernel_buffer,
305 kernel_buffer_size: &application_kernel_buffer_size, error, exit_code,
306 package_config: resolved_packages_config, for_snapshot,
307 embed_sources);
308 if (application_kernel_buffer == nullptr) {
309 Dart_ExitScope();
310 Dart_ShutdownIsolate();
311 return nullptr;
312 }
313 isolate_group_data->SetKernelBufferNewlyOwned(
314 buffer: application_kernel_buffer, size: application_kernel_buffer_size);
315 kernel_buffer = application_kernel_buffer;
316 kernel_buffer_size = application_kernel_buffer_size;
317 }
318 if (kernel_buffer != nullptr) {
319 Dart_Handle uri = Dart_NewStringFromCString(str: script_uri);
320 CHECK_RESULT(uri);
321 Dart_Handle resolved_script_uri = DartUtils::ResolveScript(url: uri);
322 CHECK_RESULT(resolved_script_uri);
323 result = Dart_LoadScriptFromKernel(kernel_buffer, kernel_buffer_size);
324 CHECK_RESULT(result);
325 }
326#endif // !defined(DART_PRECOMPILED_RUNTIME)
327
328 if (isolate_run_app_snapshot) {
329 Dart_Handle result = Loader::InitForSnapshot(snapshot_uri: script_uri, isolate_data);
330 CHECK_RESULT(result);
331#if !defined(DART_PRECOMPILED_RUNTIME)
332 if (is_main_isolate) {
333 // Find the canonical uri of the app snapshot. We'll use this to decide if
334 // other isolates should use the app snapshot or the core snapshot.
335 const char* resolved_script_uri = nullptr;
336 result = Dart_StringToCString(
337 str: DartUtils::ResolveScript(url: Dart_NewStringFromCString(str: script_uri)),
338 cstr: &resolved_script_uri);
339 CHECK_RESULT(result);
340 ASSERT(app_script_uri == nullptr);
341 app_script_uri = Utils::StrDup(s: resolved_script_uri);
342 }
343#endif // !defined(DART_PRECOMPILED_RUNTIME)
344 } else {
345#if !defined(DART_PRECOMPILED_RUNTIME)
346 // Load the specified application script into the newly created isolate.
347 Dart_Handle uri =
348 DartUtils::ResolveScript(url: Dart_NewStringFromCString(str: script_uri));
349 CHECK_RESULT(uri);
350 if (kernel_buffer != nullptr) {
351 // relative URIs and perform other related tasks. We need Loader to be
352 // initialized for this to work because loading from Kernel binary
353 // bypasses normal source code loading paths that initialize it.
354 const char* resolved_script_uri = nullptr;
355 result = Dart_StringToCString(str: uri, cstr: &resolved_script_uri);
356 CHECK_RESULT(result);
357 result = Loader::InitForSnapshot(snapshot_uri: resolved_script_uri, isolate_data);
358 CHECK_RESULT(result);
359 }
360 Dart_RecordTimelineEvent(label: "LoadScript", timestamp0: Dart_TimelineGetMicros(),
361 timestamp1_or_id: Dart_GetMainPortId(), /*flow_id_count=*/0, flow_ids: nullptr,
362 type: Dart_Timeline_Event_Async_End,
363 /*argument_count=*/0, argument_names: nullptr, argument_values: nullptr);
364#else
365 UNREACHABLE();
366#endif // !defined(DART_PRECOMPILED_RUNTIME)
367 }
368
369 if ((Options::gen_snapshot_kind() == kAppJIT) && is_main_isolate) {
370 result = Dart_SortClasses();
371 CHECK_RESULT(result);
372 }
373
374 // Disable pausing the DartDev isolate on start and exit.
375 const char* isolate_name = nullptr;
376 result = Dart_StringToCString(str: Dart_DebugName(), cstr: &isolate_name);
377 CHECK_RESULT(result);
378#if !defined(DART_PRECOMPILED_RUNTIME)
379 if (strstr(isolate_name, DART_DEV_ISOLATE_NAME) != nullptr) {
380 Dart_SetShouldPauseOnStart(should_pause: false);
381 Dart_SetShouldPauseOnExit(should_pause: false);
382 }
383#endif // !defined(DART_PRECOMPILED_RUNTIME)
384
385 // Make the isolate runnable so that it is ready to handle messages.
386 Dart_ExitScope();
387 Dart_ExitIsolate();
388 *error = Dart_IsolateMakeRunnable(isolate);
389 if (*error != nullptr) {
390 Dart_EnterIsolate(isolate);
391 Dart_ShutdownIsolate();
392 return nullptr;
393 }
394
395 return isolate;
396}
397
398#if !defined(EXCLUDE_CFE_AND_KERNEL_PLATFORM)
399// Returns newly created Kernel Isolate on success, nullptr on failure.
400// For now we only support the kernel isolate coming up from an
401// application snapshot or from a .dill file.
402static Dart_Isolate CreateAndSetupKernelIsolate(const char* script_uri,
403 const char* packages_config,
404 Dart_IsolateFlags* flags,
405 char** error,
406 int* exit_code) {
407 // Do not start a kernel isolate if we are doing a training run
408 // to create an app JIT snapshot and a kernel file is specified
409 // as the application to run.
410 if (Options::gen_snapshot_kind() == kAppJIT) {
411 const uint8_t* kernel_buffer = nullptr;
412 intptr_t kernel_buffer_size = 0;
413 dfe.application_kernel_buffer(buffer: &kernel_buffer, size: &kernel_buffer_size);
414 if (kernel_buffer_size != 0) {
415 return nullptr;
416 }
417 }
418 // Create and Start the kernel isolate.
419 const char* kernel_snapshot_uri = dfe.frontend_filename();
420 const char* uri =
421 kernel_snapshot_uri != nullptr ? kernel_snapshot_uri : script_uri;
422
423 if (packages_config == nullptr) {
424 packages_config = Options::packages_file();
425 }
426
427 Dart_Isolate isolate = nullptr;
428 IsolateGroupData* isolate_group_data = nullptr;
429 IsolateData* isolate_data = nullptr;
430 bool isolate_run_app_snapshot = false;
431 AppSnapshot* app_snapshot = nullptr;
432 // Kernel isolate uses an app snapshot or uses the dill file.
433 if ((kernel_snapshot_uri != nullptr) &&
434 (app_snapshot = Snapshot::TryReadAppSnapshot(
435 script_uri: kernel_snapshot_uri, /*force_load_elf_from_memory=*/false,
436 /*decode_uri=*/false)) != nullptr) {
437 const uint8_t* isolate_snapshot_data = nullptr;
438 const uint8_t* isolate_snapshot_instructions = nullptr;
439 const uint8_t* ignore_vm_snapshot_data;
440 const uint8_t* ignore_vm_snapshot_instructions;
441 isolate_run_app_snapshot = true;
442 app_snapshot->SetBuffers(
443 vm_data_buffer: &ignore_vm_snapshot_data, vm_instructions_buffer: &ignore_vm_snapshot_instructions,
444 isolate_data_buffer: &isolate_snapshot_data, isolate_instructions_buffer: &isolate_snapshot_instructions);
445 isolate_group_data = new IsolateGroupData(
446 uri, packages_config, app_snapshot, isolate_run_app_snapshot);
447 isolate_data = new IsolateData(isolate_group_data);
448 isolate = Dart_CreateIsolateGroup(
449 DART_KERNEL_ISOLATE_NAME, DART_KERNEL_ISOLATE_NAME,
450 isolate_snapshot_data, isolate_snapshot_instructions, flags,
451 isolate_group_data, isolate_data, error);
452 }
453 if (isolate == nullptr) {
454 // Clear error from app snapshot and re-trying from kernel file.
455 free(*error);
456 *error = nullptr;
457 delete isolate_data;
458 delete isolate_group_data;
459
460 const uint8_t* kernel_service_buffer = nullptr;
461 intptr_t kernel_service_buffer_size = 0;
462 dfe.LoadKernelService(kernel_service_buffer: &kernel_service_buffer, kernel_service_buffer_size: &kernel_service_buffer_size);
463 ASSERT(kernel_service_buffer != nullptr);
464 isolate_group_data = new IsolateGroupData(uri, packages_config, nullptr,
465 isolate_run_app_snapshot);
466 isolate_group_data->SetKernelBufferUnowned(
467 buffer: const_cast<uint8_t*>(kernel_service_buffer),
468 size: kernel_service_buffer_size);
469 isolate_data = new IsolateData(isolate_group_data);
470 isolate = Dart_CreateIsolateGroupFromKernel(
471 DART_KERNEL_ISOLATE_NAME, DART_KERNEL_ISOLATE_NAME,
472 kernel_service_buffer, kernel_service_buffer_size, flags,
473 isolate_group_data, isolate_data, error);
474 }
475
476 if (isolate == nullptr) {
477 Syslog::PrintErr(format: "%s\n", *error);
478 delete isolate_data;
479 delete isolate_group_data;
480 return nullptr;
481 }
482 kernel_isolate_is_running = true;
483
484 return IsolateSetupHelper(isolate, is_main_isolate: false, script_uri: uri, packages_config,
485 isolate_run_app_snapshot, flags, error, exit_code);
486}
487#endif // !defined(EXCLUDE_CFE_AND_KERNEL_PLATFORM)
488
489// Returns newly created Service Isolate on success, nullptr on failure.
490// For now we only support the service isolate coming up from sources
491// which are compiled by the VM parser.
492static Dart_Isolate CreateAndSetupServiceIsolate(const char* script_uri,
493 const char* packages_config,
494 Dart_IsolateFlags* flags,
495 char** error,
496 int* exit_code) {
497#if !defined(PRODUCT)
498 ASSERT(script_uri != nullptr);
499 Dart_Isolate isolate = nullptr;
500 auto isolate_group_data =
501 new IsolateGroupData(script_uri, packages_config, nullptr, false);
502 ASSERT(flags != nullptr);
503
504#if defined(DART_PRECOMPILED_RUNTIME)
505 // AOT: The service isolate is included in any AOT snapshot in non-PRODUCT
506 // mode - so we launch the vm-service from the main app AOT snapshot.
507 const uint8_t* isolate_snapshot_data = app_isolate_snapshot_data;
508 const uint8_t* isolate_snapshot_instructions =
509 app_isolate_snapshot_instructions;
510 flags->null_safety =
511 Dart_DetectNullSafety(nullptr, nullptr, nullptr, isolate_snapshot_data,
512 isolate_snapshot_instructions, nullptr, -1);
513 isolate = Dart_CreateIsolateGroup(
514 script_uri, DART_VM_SERVICE_ISOLATE_NAME, isolate_snapshot_data,
515 isolate_snapshot_instructions, flags, isolate_group_data,
516 /*isolate_data=*/nullptr, error);
517#else
518 // JIT: Service isolate uses the core libraries snapshot.
519
520 // Set flag to load and retain the vmservice library.
521 flags->load_vmservice_library = true;
522 const uint8_t* isolate_snapshot_data = core_isolate_snapshot_data;
523 const uint8_t* isolate_snapshot_instructions =
524 core_isolate_snapshot_instructions;
525 isolate = Dart_CreateIsolateGroup(
526 script_uri, DART_VM_SERVICE_ISOLATE_NAME, isolate_snapshot_data,
527 isolate_snapshot_instructions, flags, isolate_group_data,
528 /*isolate_data=*/nullptr, error);
529#endif // !defined(DART_PRECOMPILED_RUNTIME)
530 if (isolate == nullptr) {
531 delete isolate_group_data;
532 return nullptr;
533 }
534
535 Dart_EnterScope();
536
537 Dart_Handle result = Dart_SetLibraryTagHandler(handler: Loader::LibraryTagHandler);
538 CHECK_RESULT(result);
539 result = Dart_SetDeferredLoadHandler(Loader::DeferredLoadHandler);
540 CHECK_RESULT(result);
541
542 int vm_service_server_port = INVALID_VM_SERVICE_SERVER_PORT;
543 if (Options::disable_dart_dev() || Options::disable_dds()) {
544 vm_service_server_port = Options::vm_service_server_port();
545 } else if (Options::vm_service_server_port() !=
546 INVALID_VM_SERVICE_SERVER_PORT) {
547 vm_service_server_port = 0;
548 }
549
550 // We do not want to wait for DDS to advertise availability of VM service in
551 // the following scenarios:
552 // - The DartDev CLI is disabled (CLI isolate starts DDS) and VM service is
553 // enabled.
554 // - DDS is disabled.
555 // TODO(bkonyi): do we want to tie DevTools / DDS to the CLI in the long run?
556 bool wait_for_dds_to_advertise_service =
557 !(Options::disable_dart_dev() || Options::disable_dds());
558 // Load embedder specific bits and return.
559 if (!VmService::Setup(
560 server_ip: !wait_for_dds_to_advertise_service ? Options::vm_service_server_ip()
561 : DEFAULT_VM_SERVICE_SERVER_IP,
562 server_port: vm_service_server_port, dev_mode_server: Options::vm_service_dev_mode(),
563 auth_codes_disabled: Options::vm_service_auth_disabled(),
564 write_service_info_filename: Options::vm_write_service_info_filename(), trace_loading: Options::trace_loading(),
565 deterministic: Options::deterministic(), enable_service_port_fallback: Options::enable_service_port_fallback(),
566 wait_for_dds_to_advertise_service, serve_observatory: Options::enable_observatory())) {
567 *error = Utils::StrDup(s: VmService::GetErrorMessage());
568 return nullptr;
569 }
570 if (Options::compile_all()) {
571 result = Dart_CompileAll();
572 CHECK_RESULT(result);
573 }
574 result = Dart_SetEnvironmentCallback(callback: DartUtils::EnvironmentCallback);
575 CHECK_RESULT(result);
576 Dart_ExitScope();
577 Dart_ExitIsolate();
578 return isolate;
579#else // !defined(PRODUCT)
580 return nullptr;
581#endif // !defined(PRODUCT)
582}
583
584#if !defined(DART_PRECOMPILED_RUNTIME)
585
586static Dart_Isolate CreateAndSetupDartDevIsolate(const char* script_uri,
587 const char* packages_config,
588 Dart_IsolateFlags* flags,
589 char** error,
590 int* exit_code) {
591 int64_t start = Dart_TimelineGetMicros();
592
593 auto dartdev_path = DartDevIsolate::TryResolveDartDevSnapshotPath();
594 if (dartdev_path.get() == nullptr) {
595 Syslog::PrintErr(
596 format: "Failed to start the Dart CLI isolate. Could not resolve DartDev "
597 "snapshot or kernel.\n");
598 if (error != nullptr && *error != nullptr) {
599 free(*error);
600 *error = nullptr;
601 }
602 return nullptr;
603 }
604
605 Dart_Isolate isolate = nullptr;
606 const uint8_t* isolate_snapshot_data = core_isolate_snapshot_data;
607 const uint8_t* isolate_snapshot_instructions =
608 core_isolate_snapshot_instructions;
609 IsolateGroupData* isolate_group_data = nullptr;
610 IsolateData* isolate_data = nullptr;
611 AppSnapshot* app_snapshot = nullptr;
612 bool isolate_run_app_snapshot = true;
613 if ((app_snapshot = Snapshot::TryReadAppSnapshot(
614 script_uri: dartdev_path.get(), /*force_load_elf_from_memory=*/false,
615 /*decode_uri=*/false)) != nullptr) {
616 const uint8_t* isolate_snapshot_data = nullptr;
617 const uint8_t* isolate_snapshot_instructions = nullptr;
618 const uint8_t* ignore_vm_snapshot_data;
619 const uint8_t* ignore_vm_snapshot_instructions;
620 app_snapshot->SetBuffers(
621 vm_data_buffer: &ignore_vm_snapshot_data, vm_instructions_buffer: &ignore_vm_snapshot_instructions,
622 isolate_data_buffer: &isolate_snapshot_data, isolate_instructions_buffer: &isolate_snapshot_instructions);
623 isolate_group_data =
624 new IsolateGroupData(DART_DEV_ISOLATE_NAME, packages_config,
625 app_snapshot, isolate_run_app_snapshot);
626 isolate_data = new IsolateData(isolate_group_data);
627 isolate = Dart_CreateIsolateGroup(
628 DART_DEV_ISOLATE_NAME, DART_DEV_ISOLATE_NAME, isolate_snapshot_data,
629 isolate_snapshot_instructions, flags, isolate_group_data, isolate_data,
630 error);
631 }
632
633 if (isolate == nullptr) {
634 // dartdev_path was not an application snapshot, try it as a kernel file.
635 // Clear error from app snapshot and retry from kernel.
636 if (error != nullptr && *error != nullptr) {
637 free(*error);
638 *error = nullptr;
639 }
640 isolate_run_app_snapshot = false;
641 if (app_snapshot != nullptr) {
642 delete app_snapshot;
643 }
644 isolate_group_data =
645 new IsolateGroupData(DART_DEV_ISOLATE_NAME, packages_config, nullptr,
646 isolate_run_app_snapshot);
647 uint8_t* application_kernel_buffer = nullptr;
648 intptr_t application_kernel_buffer_size = 0;
649 dfe.ReadScript(dartdev_path.get(), &application_kernel_buffer,
650 &application_kernel_buffer_size, /*decode_uri=*/false);
651 isolate_group_data->SetKernelBufferNewlyOwned(
652 buffer: application_kernel_buffer, size: application_kernel_buffer_size);
653
654 isolate_data = new IsolateData(isolate_group_data);
655 isolate = Dart_CreateIsolateGroup(
656 DART_DEV_ISOLATE_NAME, DART_DEV_ISOLATE_NAME, isolate_snapshot_data,
657 isolate_snapshot_instructions, flags, isolate_group_data, isolate_data,
658 error);
659 }
660
661 Dart_Isolate created_isolate =
662 IsolateSetupHelper(isolate, is_main_isolate: false, DART_DEV_ISOLATE_NAME, packages_config,
663 isolate_run_app_snapshot, flags, error, exit_code);
664
665 int64_t end = Dart_TimelineGetMicros();
666 Dart_RecordTimelineEvent(label: "CreateAndSetupDartDevIsolate", timestamp0: start, timestamp1_or_id: end,
667 /*flow_id_count=*/0, flow_ids: nullptr,
668 type: Dart_Timeline_Event_Duration,
669 /*argument_count=*/0, argument_names: nullptr, argument_values: nullptr);
670 return created_isolate;
671}
672
673#endif // !defined(DART_PRECOMPILED_RUNTIME)
674
675// Returns newly created Isolate on success, nullptr on failure.
676static Dart_Isolate CreateIsolateGroupAndSetupHelper(
677 bool is_main_isolate,
678 const char* script_uri,
679 const char* name,
680 const char* packages_config,
681 Dart_IsolateFlags* flags,
682 void* callback_data,
683 char** error,
684 int* exit_code,
685 bool force_no_sound_null_safety = false) {
686 int64_t start = Dart_TimelineGetMicros();
687 ASSERT(script_uri != nullptr);
688 uint8_t* kernel_buffer = nullptr;
689 std::shared_ptr<uint8_t> kernel_buffer_ptr;
690 intptr_t kernel_buffer_size = 0;
691 AppSnapshot* app_snapshot = nullptr;
692
693#if defined(DART_PRECOMPILED_RUNTIME)
694 const uint8_t* isolate_snapshot_data = nullptr;
695 const uint8_t* isolate_snapshot_instructions = nullptr;
696 if (is_main_isolate) {
697 isolate_snapshot_data = app_isolate_snapshot_data;
698 isolate_snapshot_instructions = app_isolate_snapshot_instructions;
699 } else {
700 // AOT: All isolates need to be run from AOT compiled snapshots.
701 const bool kForceLoadElfFromMemory = false;
702 app_snapshot =
703 Snapshot::TryReadAppSnapshot(script_uri, kForceLoadElfFromMemory);
704 if (app_snapshot == nullptr) {
705 *error = Utils::StrDup(
706 "The uri provided to `Isolate.spawnUri()` does not "
707 "contain a valid AOT snapshot.");
708 return nullptr;
709 }
710
711 const uint8_t* ignore_vm_snapshot_data;
712 const uint8_t* ignore_vm_snapshot_instructions;
713 app_snapshot->SetBuffers(
714 &ignore_vm_snapshot_data, &ignore_vm_snapshot_instructions,
715 &isolate_snapshot_data, &isolate_snapshot_instructions);
716 }
717
718 bool isolate_run_app_snapshot = true;
719 flags->null_safety =
720 Dart_DetectNullSafety(nullptr, nullptr, nullptr, isolate_snapshot_data,
721 isolate_snapshot_instructions, nullptr, -1);
722#else
723 // JIT: Main isolate starts from the app snapshot, if any. Other isolates
724 // use the core libraries snapshot.
725 bool isolate_run_app_snapshot = false;
726 const uint8_t* isolate_snapshot_data = core_isolate_snapshot_data;
727 const uint8_t* isolate_snapshot_instructions =
728 core_isolate_snapshot_instructions;
729 if ((app_isolate_snapshot_data != nullptr) &&
730 (is_main_isolate || ((app_script_uri != nullptr) &&
731 (strcmp(script_uri, app_script_uri) == 0)))) {
732 isolate_run_app_snapshot = true;
733 isolate_snapshot_data = app_isolate_snapshot_data;
734 isolate_snapshot_instructions = app_isolate_snapshot_instructions;
735 } else if (!is_main_isolate) {
736 app_snapshot = Snapshot::TryReadAppSnapshot(script_uri);
737 if (app_snapshot != nullptr) {
738 isolate_run_app_snapshot = true;
739 const uint8_t* ignore_vm_snapshot_data;
740 const uint8_t* ignore_vm_snapshot_instructions;
741 app_snapshot->SetBuffers(
742 vm_data_buffer: &ignore_vm_snapshot_data, vm_instructions_buffer: &ignore_vm_snapshot_instructions,
743 isolate_data_buffer: &isolate_snapshot_data, isolate_instructions_buffer: &isolate_snapshot_instructions);
744 }
745 }
746
747 if (flags->copy_parent_code && callback_data != nullptr) {
748 auto parent_isolate_group_data =
749 reinterpret_cast<IsolateData*>(callback_data)->isolate_group_data();
750 kernel_buffer_ptr = parent_isolate_group_data->kernel_buffer();
751 kernel_buffer = kernel_buffer_ptr.get();
752 kernel_buffer_size = parent_isolate_group_data->kernel_buffer_size();
753 }
754
755 if (kernel_buffer == nullptr && !isolate_run_app_snapshot) {
756 dfe.ReadScript(script_uri, &kernel_buffer, &kernel_buffer_size,
757 /*decode_uri=*/true, &kernel_buffer_ptr);
758 }
759 PathSanitizer script_uri_sanitizer(script_uri);
760 PathSanitizer packages_config_sanitizer(packages_config);
761 if (force_no_sound_null_safety) {
762 flags->null_safety = false;
763 } else {
764 flags->null_safety = Dart_DetectNullSafety(
765 script_uri_sanitizer.sanitized_uri(),
766 packages_config_sanitizer.sanitized_uri(),
767 DartUtils::original_working_directory, isolate_snapshot_data,
768 isolate_snapshot_instructions, kernel_buffer, kernel_buffer_size);
769 }
770#endif // !defined(DART_PRECOMPILED_RUNTIME)
771
772 auto isolate_group_data = new IsolateGroupData(
773 script_uri, packages_config, app_snapshot, isolate_run_app_snapshot);
774 if (kernel_buffer != nullptr) {
775 if (kernel_buffer_ptr) {
776 isolate_group_data->SetKernelBufferAlreadyOwned(
777 std::move(kernel_buffer_ptr), kernel_buffer_size);
778 } else {
779 isolate_group_data->SetKernelBufferNewlyOwned(buffer: kernel_buffer,
780 size: kernel_buffer_size);
781 }
782 }
783
784 Dart_Isolate isolate = nullptr;
785
786 IsolateData* isolate_data = nullptr;
787#if !defined(DART_PRECOMPILED_RUNTIME)
788 if (!isolate_run_app_snapshot && (isolate_snapshot_data == nullptr)) {
789 const uint8_t* platform_kernel_buffer = nullptr;
790 intptr_t platform_kernel_buffer_size = 0;
791 dfe.LoadPlatform(kernel_buffer: &platform_kernel_buffer, kernel_buffer_size: &platform_kernel_buffer_size);
792 if (platform_kernel_buffer == nullptr) {
793 platform_kernel_buffer = kernel_buffer;
794 platform_kernel_buffer_size = kernel_buffer_size;
795 }
796 if (platform_kernel_buffer == nullptr) {
797#if defined(EXCLUDE_CFE_AND_KERNEL_PLATFORM)
798 FATAL(
799 "Binary built with --exclude-kernel-service. Cannot run"
800 " from source.");
801#else
802 FATAL("platform_program cannot be nullptr.");
803#endif // defined(EXCLUDE_CFE_AND_KERNEL_PLATFORM)
804 }
805 // TODO(sivachandra): When the platform program is unavailable, check if
806 // application kernel binary is self contained or an incremental binary.
807 // Isolate should be created only if it is a self contained kernel binary.
808 isolate_data = new IsolateData(isolate_group_data);
809 isolate = Dart_CreateIsolateGroupFromKernel(
810 script_uri, name, platform_kernel_buffer, platform_kernel_buffer_size,
811 flags, isolate_group_data, isolate_data, error);
812 } else {
813 isolate_data = new IsolateData(isolate_group_data);
814 isolate = Dart_CreateIsolateGroup(script_uri, name, isolate_snapshot_data,
815 isolate_snapshot_instructions, flags,
816 isolate_group_data, isolate_data, error);
817 }
818#else
819 isolate_data = new IsolateData(isolate_group_data);
820 isolate = Dart_CreateIsolateGroup(script_uri, name, isolate_snapshot_data,
821 isolate_snapshot_instructions, flags,
822 isolate_group_data, isolate_data, error);
823#endif // !defined(DART_PRECOMPILED_RUNTIME)
824
825 Dart_Isolate created_isolate = nullptr;
826 if (isolate == nullptr) {
827 delete isolate_data;
828 delete isolate_group_data;
829 } else {
830 created_isolate = IsolateSetupHelper(
831 isolate, is_main_isolate, script_uri, packages_config,
832 isolate_run_app_snapshot, flags, error, exit_code);
833 }
834 int64_t end = Dart_TimelineGetMicros();
835 Dart_RecordTimelineEvent(label: "CreateIsolateGroupAndSetupHelper", timestamp0: start, timestamp1_or_id: end,
836 /*flow_id_count=*/0, flow_ids: nullptr,
837 type: Dart_Timeline_Event_Duration,
838 /*argument_count=*/0, argument_names: nullptr, argument_values: nullptr);
839 return created_isolate;
840}
841
842#undef CHECK_RESULT
843
844static Dart_Isolate CreateIsolateGroupAndSetup(const char* script_uri,
845 const char* main,
846 const char* package_root,
847 const char* package_config,
848 Dart_IsolateFlags* flags,
849 void* callback_data,
850 char** error) {
851 // The VM should never call the isolate helper with a nullptr flags.
852 ASSERT(flags != nullptr);
853 ASSERT(flags->version == DART_FLAGS_CURRENT_VERSION);
854 ASSERT(package_root == nullptr);
855
856 if (error != nullptr) {
857 *error = nullptr;
858 }
859
860 bool dontneed_safe = true;
861#if defined(DART_HOST_OS_LINUX)
862 // This would also be true in Linux, except that Google3 overrides the default
863 // ELF interpreter to one that apparently doesn't create proper mappings.
864 dontneed_safe = false;
865#elif defined(DEBUG)
866 // If the snapshot isn't file-backed, madvise(DONT_NEED) is destructive.
867 if (Options::force_load_elf_from_memory()) {
868 dontneed_safe = false;
869 }
870#endif
871 flags->snapshot_is_dontneed_safe = dontneed_safe;
872
873 int exit_code = 0;
874#if !defined(EXCLUDE_CFE_AND_KERNEL_PLATFORM)
875 if (strcmp(script_uri, DART_KERNEL_ISOLATE_NAME) == 0) {
876 return CreateAndSetupKernelIsolate(script_uri, packages_config: package_config, flags, error,
877 exit_code: &exit_code);
878 }
879#endif // !defined(EXCLUDE_CFE_AND_KERNEL_PLATFORM)
880
881#if !defined(DART_PRECOMPILED_RUNTIME)
882 if (strcmp(script_uri, DART_DEV_ISOLATE_NAME) == 0) {
883 return CreateAndSetupDartDevIsolate(script_uri, packages_config: package_config, flags,
884 error, exit_code: &exit_code);
885 }
886#endif // !defined(DART_PRECOMPILED_RUNTIME)
887
888 if (strcmp(script_uri, DART_VM_SERVICE_ISOLATE_NAME) == 0) {
889 return CreateAndSetupServiceIsolate(script_uri, packages_config: package_config, flags,
890 error, exit_code: &exit_code);
891 }
892
893 bool is_main_isolate = false;
894 return CreateIsolateGroupAndSetupHelper(is_main_isolate, script_uri, name: main,
895 packages_config: package_config, flags, callback_data,
896 error, exit_code: &exit_code);
897}
898
899#if !defined(DART_PRECOMPILED_RUNTIME)
900static const char* RegisterKernelBlob(const uint8_t* kernel_buffer,
901 intptr_t kernel_buffer_size) {
902 return dfe.RegisterKernelBlob(kernel_buffer, kernel_buffer_size);
903}
904static void UnregisterKernelBlob(const char* kernel_blob_uri) {
905 dfe.UnregisterKernelBlob(uri: kernel_blob_uri);
906}
907#endif // !defined(DART_PRECOMPILED_RUNTIME)
908
909static void OnIsolateShutdown(void* isolate_group_data, void* isolate_data) {
910 Dart_EnterScope();
911 Dart_Handle sticky_error = Dart_GetStickyError();
912 if (!Dart_IsNull(object: sticky_error) && !Dart_IsFatalError(handle: sticky_error)) {
913 Syslog::PrintErr(format: "%s\n", Dart_GetError(handle: sticky_error));
914 }
915 Dart_ExitScope();
916}
917
918static void DeleteIsolateData(void* isolate_group_data, void* callback_data) {
919 auto isolate_data = reinterpret_cast<IsolateData*>(callback_data);
920 delete isolate_data;
921}
922
923static void DeleteIsolateGroupData(void* callback_data) {
924 auto isolate_group_data = reinterpret_cast<IsolateGroupData*>(callback_data);
925 delete isolate_group_data;
926}
927
928static constexpr const char* kStdoutStreamId = "Stdout";
929static constexpr const char* kStderrStreamId = "Stderr";
930
931static bool ServiceStreamListenCallback(const char* stream_id) {
932 if (strcmp(stream_id, kStdoutStreamId) == 0) {
933 SetCaptureStdout(true);
934 return true;
935 } else if (strcmp(stream_id, kStderrStreamId) == 0) {
936 SetCaptureStderr(true);
937 return true;
938 }
939 return false;
940}
941
942static void ServiceStreamCancelCallback(const char* stream_id) {
943 if (strcmp(stream_id, kStdoutStreamId) == 0) {
944 SetCaptureStdout(false);
945 } else if (strcmp(stream_id, kStderrStreamId) == 0) {
946 SetCaptureStderr(false);
947 }
948}
949
950static bool FileModifiedCallback(const char* url, int64_t since) {
951 auto path = File::UriToPath(uri: url);
952 if (path == nullptr) {
953 // If it isn't a file on local disk, we don't know if it has been
954 // modified.
955 return true;
956 }
957 int64_t data[File::kStatSize];
958 File::Stat(namespc: nullptr, path: path.get(), data);
959 if (data[File::kType] == File::kDoesNotExist) {
960 return true;
961 }
962 return data[File::kModifiedTime] > since;
963}
964
965static void EmbedderInformationCallback(Dart_EmbedderInformation* info) {
966 info->version = DART_EMBEDDER_INFORMATION_CURRENT_VERSION;
967 info->name = "Dart VM";
968 Process::GetRSSInformation(max_rss: &(info->max_rss), current_rss: &(info->current_rss));
969}
970
971#define CHECK_RESULT(result) \
972 if (Dart_IsError(result)) { \
973 const int exit_code = Dart_IsCompilationError(result) \
974 ? kCompilationErrorExitCode \
975 : kErrorExitCode; \
976 ErrorExit(exit_code, "%s\n", Dart_GetError(result)); \
977 }
978
979static void CompileAndSaveKernel(const char* script_name,
980 const char* package_config_override,
981 CommandLineOptions* dart_options) {
982 if (vm_run_app_snapshot) {
983 Syslog::PrintErr(format: "Cannot create a script snapshot from an app snapshot.\n");
984 // The snapshot would contain references to the app snapshot instead of
985 // the core snapshot.
986 Platform::Exit(exit_code: kErrorExitCode);
987 }
988 Snapshot::GenerateKernel(snapshot_filename: Options::snapshot_filename(), script_name,
989 package_config: package_config_override);
990 WriteDepsFile();
991}
992
993void RunMainIsolate(const char* script_name,
994 const char* package_config_override,
995 bool force_no_sound_null_safety,
996 CommandLineOptions* dart_options) {
997 if (script_name != nullptr) {
998 const char* base_name = strrchr(script_name, '/');
999 if (base_name == nullptr) {
1000 base_name = script_name;
1001 } else {
1002 base_name++; // Skip '/'.
1003 }
1004 const intptr_t kMaxNameLength = 64;
1005 char name[kMaxNameLength];
1006 Utils::SNPrint(str: name, size: kMaxNameLength, format: "dart:%s", base_name);
1007 Platform::SetProcessName(name);
1008 }
1009
1010 // Call CreateIsolateGroupAndSetup which creates an isolate and loads up
1011 // the specified application script.
1012 char* error = nullptr;
1013 int exit_code = 0;
1014 Dart_IsolateFlags flags;
1015 Dart_IsolateFlagsInitialize(flags: &flags);
1016 flags.is_system_isolate = Options::mark_main_isolate_as_system_isolate();
1017 bool dontneed_safe = true;
1018#if defined(DART_HOST_OS_LINUX)
1019 // This would also be true in Linux, except that Google3 overrides the default
1020 // ELF interpreter to one that apparently doesn't create proper mappings.
1021 dontneed_safe = false;
1022#elif defined(DEBUG)
1023 // If the snapshot isn't file-backed, madvise(DONT_NEED) is destructive.
1024 if (Options::force_load_elf_from_memory()) {
1025 dontneed_safe = false;
1026 }
1027#endif
1028 flags.snapshot_is_dontneed_safe = dontneed_safe;
1029
1030 Dart_Isolate isolate = CreateIsolateGroupAndSetupHelper(
1031 /* is_main_isolate */ true, script_uri: script_name, name: "main",
1032 packages_config: Options::packages_file() == nullptr ? package_config_override
1033 : Options::packages_file(),
1034 flags: &flags, callback_data: nullptr /* callback_data */, error: &error, exit_code: &exit_code,
1035 force_no_sound_null_safety);
1036
1037 if (isolate == nullptr) {
1038 Syslog::PrintErr(format: "%s\n", error);
1039 free(error);
1040 error = nullptr;
1041 Process::TerminateExitCodeHandler();
1042 error = Dart_Cleanup();
1043 if (error != nullptr) {
1044 Syslog::PrintErr(format: "VM cleanup failed: %s\n", error);
1045 free(error);
1046 }
1047 dart::embedder::Cleanup();
1048 Platform::Exit(exit_code: (exit_code != 0) ? exit_code : kErrorExitCode);
1049 }
1050 main_isolate = isolate;
1051
1052 Dart_EnterIsolate(isolate);
1053 ASSERT(isolate == Dart_CurrentIsolate());
1054 ASSERT(isolate != nullptr);
1055 Dart_Handle result;
1056
1057 Dart_EnterScope();
1058
1059 // Kernel snapshots should have been handled before reaching this point.
1060 ASSERT(Options::gen_snapshot_kind() != kKernel);
1061 // Lookup the library of the root script.
1062 Dart_Handle root_lib = Dart_RootLibrary();
1063
1064#if !defined(DART_PRECOMPILED_RUNTIME)
1065 if (Options::compile_all()) {
1066 result = Dart_CompileAll();
1067 CHECK_RESULT(result);
1068 }
1069#endif // !defined(DART_PRECOMPILED_RUNTIME)
1070
1071 if (Dart_IsNull(object: root_lib)) {
1072 ErrorExit(exit_code: kErrorExitCode, format: "Unable to find root library for '%s'\n",
1073 script_name);
1074 }
1075
1076 // Create a closure for the main entry point which is in the exported
1077 // namespace of the root library or invoke a getter of the same name
1078 // in the exported namespace and return the resulting closure.
1079 Dart_Handle main_closure =
1080 Dart_GetField(container: root_lib, name: Dart_NewStringFromCString(str: "main"));
1081 CHECK_RESULT(main_closure);
1082 if (!Dart_IsClosure(object: main_closure)) {
1083 ErrorExit(exit_code: kErrorExitCode, format: "Unable to find 'main' in root library '%s'\n",
1084 script_name);
1085 }
1086
1087 // Call _startIsolate in the isolate library to enable dispatching the
1088 // initial startup message.
1089 const intptr_t kNumIsolateArgs = 2;
1090 Dart_Handle isolate_args[kNumIsolateArgs];
1091 isolate_args[0] = main_closure; // entryPoint
1092 isolate_args[1] = dart_options->CreateRuntimeOptions(); // args
1093
1094 Dart_Handle isolate_lib =
1095 Dart_LookupLibrary(url: Dart_NewStringFromCString(str: "dart:isolate"));
1096 result =
1097 Dart_Invoke(target: isolate_lib, name: Dart_NewStringFromCString(str: "_startMainIsolate"),
1098 number_of_arguments: kNumIsolateArgs, arguments: isolate_args);
1099 CHECK_RESULT(result);
1100
1101 // Keep handling messages until the last active receive port is closed.
1102 result = Dart_RunLoop();
1103 // Generate an app snapshot after execution if specified.
1104 if (Options::gen_snapshot_kind() == kAppJIT) {
1105 if (!Dart_IsCompilationError(handle: result)) {
1106 Snapshot::GenerateAppJIT(snapshot_filename: Options::snapshot_filename());
1107 }
1108 }
1109 CHECK_RESULT(result);
1110
1111 WriteDepsFile();
1112
1113 Dart_ExitScope();
1114
1115 // Shutdown the isolate.
1116 Dart_ShutdownIsolate();
1117}
1118
1119#undef CHECK_RESULT
1120
1121static bool CheckForInvalidPath(const char* path) {
1122 // TODO(zichangguo): "\\?\" is a prefix for paths on Windows.
1123 // Arguments passed are parsed as an URI. "\\?\" causes problems as a part
1124 // of URIs. This is a temporary workaround to prevent VM from crashing.
1125 // Issue: https://github.com/dart-lang/sdk/issues/42779
1126 if (strncmp(path, "\\\\?\\", 4) == 0) {
1127 Syslog::PrintErr(format: "\\\\?\\ prefix is not supported");
1128 return false;
1129 }
1130 return true;
1131}
1132
1133// Observatory assets are not included in a product build.
1134#if !defined(PRODUCT)
1135extern unsigned int observatory_assets_archive_len;
1136extern const uint8_t* observatory_assets_archive;
1137
1138Dart_Handle GetVMServiceAssetsArchiveCallback() {
1139 uint8_t* decompressed = nullptr;
1140 intptr_t decompressed_len = 0;
1141 Decompress(input: observatory_assets_archive, input_len: observatory_assets_archive_len,
1142 output: &decompressed, output_length: &decompressed_len);
1143 Dart_Handle tar_file =
1144 DartUtils::MakeUint8Array(buffer: decompressed, length: decompressed_len);
1145 // Free decompressed memory as it has been copied into a Dart array.
1146 free(decompressed);
1147 return tar_file;
1148}
1149#else // !defined(PRODUCT)
1150static Dart_GetVMServiceAssetsArchive GetVMServiceAssetsArchiveCallback =
1151 nullptr;
1152#endif // !defined(PRODUCT)
1153
1154void main(int argc, char** argv) {
1155 char* script_name = nullptr;
1156 // Allows the dartdev process to point to the desired package_config.
1157 char* package_config_override = nullptr;
1158 const int EXTRA_VM_ARGUMENTS = 10;
1159 CommandLineOptions vm_options(argc + EXTRA_VM_ARGUMENTS);
1160 CommandLineOptions dart_options(argc + EXTRA_VM_ARGUMENTS);
1161 bool print_flags_seen = false;
1162 bool verbose_debug_seen = false;
1163
1164 // Perform platform specific initialization.
1165 if (!Platform::Initialize()) {
1166 Syslog::PrintErr(format: "Initialization failed\n");
1167 Platform::Exit(exit_code: kErrorExitCode);
1168 }
1169
1170 // Save the console state so we can restore it at shutdown.
1171 Console::SaveConfig();
1172
1173 // On Windows, the argv strings are code page encoded and not
1174 // utf8. We need to convert them to utf8.
1175 bool argv_converted = ShellUtils::GetUtf8Argv(argc, argv);
1176
1177#if !defined(DART_PRECOMPILED_RUNTIME)
1178 // Processing of some command line flags directly manipulates dfe.
1179 Options::set_dfe(&dfe);
1180#endif // !defined(DART_PRECOMPILED_RUNTIME)
1181
1182 // When running from the command line we assume that we are optimizing for
1183 // throughput, and therefore use a larger new gen semi space size and a faster
1184 // new gen growth factor unless others have been specified.
1185 if (kWordSize <= 4) {
1186 vm_options.AddArgument(argument: "--new_gen_semi_max_size=16");
1187 } else {
1188 vm_options.AddArgument(argument: "--new_gen_semi_max_size=32");
1189 }
1190 vm_options.AddArgument(argument: "--new_gen_growth_factor=4");
1191
1192 AppSnapshot* app_snapshot = nullptr;
1193#if defined(DART_PRECOMPILED_RUNTIME)
1194 // If the executable binary contains the runtime together with an appended
1195 // snapshot, load and run that.
1196 // Any arguments passed to such an executable are meant for the actual
1197 // application so skip all Dart VM flag parsing.
1198
1199 const size_t kPathBufSize = PATH_MAX + 1;
1200 char executable_path[kPathBufSize];
1201 if (Platform::ResolveExecutablePathInto(executable_path, kPathBufSize) > 0) {
1202 app_snapshot = Snapshot::TryReadAppendedAppSnapshotElf(executable_path);
1203 if (app_snapshot != nullptr) {
1204 script_name = argv[0];
1205
1206 // Store the executable name.
1207 Platform::SetExecutableName(argv[0]);
1208
1209 // Parse out options to be passed to dart main.
1210 for (int i = 1; i < argc; i++) {
1211 dart_options.AddArgument(argv[i]);
1212 }
1213 }
1214 }
1215#endif
1216
1217 // Parse command line arguments.
1218 if (app_snapshot == nullptr) {
1219 bool success = Options::ParseArguments(
1220 argc, argv, vm_run_app_snapshot, vm_options: &vm_options, script_name: &script_name,
1221 dart_options: &dart_options, print_flags_seen: &print_flags_seen, verbose_debug_seen: &verbose_debug_seen);
1222 if (!success) {
1223 if (Options::help_option()) {
1224 Options::PrintUsage();
1225 Platform::Exit(exit_code: 0);
1226 } else if (Options::version_option()) {
1227 Options::PrintVersion();
1228 Platform::Exit(exit_code: 0);
1229 } else if (print_flags_seen) {
1230 // Will set the VM flags, print them out and then we exit as no
1231 // script was specified on the command line.
1232 char* error =
1233 Dart_SetVMFlags(argc: vm_options.count(), argv: vm_options.arguments());
1234 if (error != nullptr) {
1235 Syslog::PrintErr(format: "Setting VM flags failed: %s\n", error);
1236 free(error);
1237 Platform::Exit(exit_code: kErrorExitCode);
1238 }
1239 Platform::Exit(exit_code: 0);
1240 } else {
1241 // This usage error case will only be invoked when
1242 // Options::disable_dart_dev() is false.
1243 Options::PrintUsage();
1244 Platform::Exit(exit_code: kErrorExitCode);
1245 }
1246 }
1247 }
1248
1249 DartUtils::SetEnvironment(Options::environment());
1250
1251 if (Options::suppress_core_dump()) {
1252 Platform::SetCoreDumpResourceLimit(0);
1253 } else {
1254 InitializeCrashpadClient();
1255 }
1256
1257 Loader::InitOnce();
1258
1259 auto try_load_snapshots_lambda = [&](void) -> void {
1260 if (app_snapshot == nullptr) {
1261 // For testing purposes we add a flag to debug-mode to use the
1262 // in-memory ELF loader.
1263 const bool force_load_elf_from_memory =
1264 false DEBUG_ONLY(|| Options::force_load_elf_from_memory());
1265 app_snapshot =
1266 Snapshot::TryReadAppSnapshot(script_uri: script_name, force_load_elf_from_memory);
1267 }
1268 if (app_snapshot != nullptr) {
1269 vm_run_app_snapshot = true;
1270 app_snapshot->SetBuffers(vm_data_buffer: &vm_snapshot_data, vm_instructions_buffer: &vm_snapshot_instructions,
1271 isolate_data_buffer: &app_isolate_snapshot_data,
1272 isolate_instructions_buffer: &app_isolate_snapshot_instructions);
1273 }
1274 };
1275
1276 // At this point, script_name now points to a script if DartDev is disabled
1277 // or a valid file path was provided as the first non-flag argument.
1278 // Otherwise, script_name can be nullptr if DartDev should be run.
1279 if (script_name != nullptr) {
1280 if (!CheckForInvalidPath(path: script_name)) {
1281 Platform::Exit(exit_code: 0);
1282 }
1283 try_load_snapshots_lambda();
1284 }
1285
1286#if defined(DART_PRECOMPILED_RUNTIME)
1287 vm_options.AddArgument("--precompilation");
1288#endif
1289 if (Options::gen_snapshot_kind() == kAppJIT) {
1290 // App-jit snapshot can be deployed to another machine,
1291 // so generated code should not depend on the CPU features
1292 // of the system where snapshot was generated.
1293 vm_options.AddArgument(argument: "--target-unknown-cpu");
1294 }
1295 // If we need to write an app-jit snapshot or a depfile, then add an exit
1296 // hook that writes the snapshot and/or depfile as appropriate.
1297 if ((Options::gen_snapshot_kind() == kAppJIT) ||
1298 (Options::depfile() != nullptr)) {
1299 Process::SetExitHook(OnExitHook);
1300 }
1301
1302 char* error = nullptr;
1303 if (!dart::embedder::InitOnce(error: &error)) {
1304 Syslog::PrintErr(format: "Standalone embedder initialization failed: %s\n", error);
1305 free(error);
1306 Platform::Exit(exit_code: kErrorExitCode);
1307 }
1308
1309 error = Dart_SetVMFlags(argc: vm_options.count(), argv: vm_options.arguments());
1310 if (error != nullptr) {
1311 Syslog::PrintErr(format: "Setting VM flags failed: %s\n", error);
1312 free(error);
1313 Platform::Exit(exit_code: kErrorExitCode);
1314 }
1315
1316// Note: must read platform only *after* VM flags are parsed because
1317// they might affect how the platform is loaded.
1318#if !defined(DART_PRECOMPILED_RUNTIME)
1319 // Load vm_platform_strong.dill for dart:* source support.
1320 dfe.Init();
1321 dfe.set_verbosity(Options::verbosity_level());
1322 if (script_name != nullptr) {
1323 uint8_t* application_kernel_buffer = nullptr;
1324 intptr_t application_kernel_buffer_size = 0;
1325 dfe.ReadScript(script_name, &application_kernel_buffer,
1326 &application_kernel_buffer_size);
1327 if (application_kernel_buffer != nullptr) {
1328 // Since we loaded the script anyway, save it.
1329 dfe.set_application_kernel_buffer(buffer: application_kernel_buffer,
1330 size: application_kernel_buffer_size);
1331 Options::dfe()->set_use_dfe();
1332 }
1333 }
1334#endif
1335
1336 // Initialize the Dart VM.
1337 Dart_InitializeParams init_params;
1338 memset(&init_params, 0, sizeof(init_params));
1339 init_params.version = DART_INITIALIZE_PARAMS_CURRENT_VERSION;
1340 init_params.vm_snapshot_data = vm_snapshot_data;
1341 init_params.vm_snapshot_instructions = vm_snapshot_instructions;
1342 init_params.create_group = CreateIsolateGroupAndSetup;
1343 init_params.initialize_isolate = OnIsolateInitialize;
1344 init_params.shutdown_isolate = OnIsolateShutdown;
1345 init_params.cleanup_isolate = DeleteIsolateData;
1346 init_params.cleanup_group = DeleteIsolateGroupData;
1347 init_params.file_open = DartUtils::OpenFile;
1348 init_params.file_read = DartUtils::ReadFile;
1349 init_params.file_write = DartUtils::WriteFile;
1350 init_params.file_close = DartUtils::CloseFile;
1351 init_params.entropy_source = DartUtils::EntropySource;
1352 init_params.get_service_assets = GetVMServiceAssetsArchiveCallback;
1353#if !defined(DART_PRECOMPILED_RUNTIME)
1354 init_params.start_kernel_isolate =
1355 dfe.UseDartFrontend() && dfe.CanUseDartFrontend();
1356 if (init_params.start_kernel_isolate) {
1357 init_params.register_kernel_blob = RegisterKernelBlob;
1358 init_params.unregister_kernel_blob = UnregisterKernelBlob;
1359 }
1360#else
1361 init_params.start_kernel_isolate = false;
1362#endif
1363#if defined(DART_HOST_OS_FUCHSIA)
1364#if defined(DART_PRECOMPILED_RUNTIME)
1365 init_params.vmex_resource = ZX_HANDLE_INVALID;
1366#else
1367 init_params.vmex_resource = Platform::GetVMEXResource();
1368#endif
1369#endif
1370
1371 error = Dart_Initialize(params: &init_params);
1372 if (error != nullptr) {
1373 dart::embedder::Cleanup();
1374 Syslog::PrintErr(format: "VM initialization failed: %s\n", error);
1375 free(error);
1376 Platform::Exit(exit_code: kErrorExitCode);
1377 }
1378
1379 Dart_SetServiceStreamCallbacks(listen_callback: &ServiceStreamListenCallback,
1380 cancel_callback: &ServiceStreamCancelCallback);
1381 Dart_SetFileModifiedCallback(file_modified_callback: &FileModifiedCallback);
1382 Dart_SetEmbedderInformationCallback(callback: &EmbedderInformationCallback);
1383 bool ran_dart_dev = false;
1384 bool should_run_user_program = true;
1385 bool force_no_sound_null_safety = false;
1386#if !defined(DART_PRECOMPILED_RUNTIME)
1387 if (DartDevIsolate::should_run_dart_dev() && !Options::disable_dart_dev() &&
1388 Options::gen_snapshot_kind() == SnapshotKind::kNone) {
1389 DartDevIsolate::DartDev_Result dartdev_result = DartDevIsolate::RunDartDev(
1390 create_isolate: CreateIsolateGroupAndSetup, packages_file: &package_config_override, script: &script_name,
1391 sound_null_safety: &force_no_sound_null_safety, dart_options: &dart_options);
1392 ASSERT(dartdev_result != DartDevIsolate::DartDev_Result_Unknown);
1393 ran_dart_dev = true;
1394 should_run_user_program =
1395 (dartdev_result == DartDevIsolate::DartDev_Result_Run);
1396 if (should_run_user_program) {
1397 try_load_snapshots_lambda();
1398 }
1399 } else if (script_name == nullptr &&
1400 Options::gen_snapshot_kind() != SnapshotKind::kNone) {
1401 Syslog::PrintErr(
1402 format: "Snapshot generation should be done using the 'dart compile' "
1403 "command.\n");
1404 Platform::Exit(exit_code: kErrorExitCode);
1405 }
1406#endif // !defined(DART_PRECOMPILED_RUNTIME)
1407
1408 if (should_run_user_program) {
1409 if (!Dart_IsPrecompiledRuntime() && Snapshot::IsAOTSnapshot(snapshot_filename: script_name)) {
1410 Syslog::PrintErr(
1411 format: "%s is an AOT snapshot and should be run with 'dartaotruntime'\n",
1412 script_name);
1413 Platform::Exit(exit_code: kErrorExitCode);
1414 } else {
1415 if (Options::gen_snapshot_kind() == kKernel) {
1416 CompileAndSaveKernel(script_name, package_config_override,
1417 dart_options: &dart_options);
1418
1419 } else {
1420 // Run the main isolate until we aren't told to restart.
1421 RunMainIsolate(script_name, package_config_override,
1422 force_no_sound_null_safety, dart_options: &dart_options);
1423 }
1424 }
1425 }
1426
1427 // Terminate process exit-code handler.
1428 Process::TerminateExitCodeHandler();
1429
1430 error = Dart_Cleanup();
1431 if (error != nullptr) {
1432 Syslog::PrintErr(format: "VM cleanup failed: %s\n", error);
1433 free(error);
1434 }
1435 const intptr_t global_exit_code = Process::GlobalExitCode();
1436 dart::embedder::Cleanup();
1437
1438 delete app_snapshot;
1439 free(app_script_uri);
1440 if (ran_dart_dev && script_name != nullptr) {
1441 free(script_name);
1442 }
1443
1444 // Free copied argument strings if converted.
1445 if (argv_converted) {
1446 for (int i = 0; i < argc; i++) {
1447 free(argv[i]);
1448 }
1449 }
1450
1451 // Free environment if any.
1452 Options::DestroyEnvironment();
1453
1454 Platform::Exit(exit_code: global_exit_code);
1455}
1456
1457} // namespace bin
1458} // namespace dart
1459

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