d36adbacaf
The former contents of the VM isolate are now included into each isolate group. This makes each isolate group's heap independent, and in particular allows each heap to be allocated to a separate pointer cage (not done in this CL). The duplicated stubs that allowed PC relative calls are removed, since the originals can now be the target of PC relative calls. The bootstrapping needing to load an AppJIT or AppAOT snapshot is reduced to allocating the oddballs. The code is entirely dropped in the AOT runtime, but the JIT runtime still has it to allow for flags to affect the compilation of the stub code. Further refactoring might be able to remove this for the JIT runtime too, with only gen_snapshot knowing how to bootstrap. Class serialization no longer distinguishes predefined classes. The page containing null is marked as never-evacuate. null, false and true must not move because the compiler relies on their low bits having certain patterns for some optimizations. (Previously, the entire VM isolate heap never moved.) Compaction is disabled for IA32. Due to register pressure, some stub calls must not use a scratch register and embed the address of Code. The page containing the call-through-safepoint stub is frozen when running with --write-protect-code and the stub is created at runtime (instead of loaded from an AppJIT or AppAOT snapshot). This stub must remain executable even during a safepoint, as a foreign call might during return during a safepoint and only block after the stub directs it to the runtime. The snapshot symbols are renamed to kDartSnapshotData and kDartSnapshotText. There is no need to distinguish the VM isolate's snapshot, and snaphots are per isolate group not per isolate. Aliases with the old names are added to ease migration. Some global flags that were automatically set based on the VM isolate's snapshot are now isolate group flags and automatically set by the isolate group's snapshot. TEST=ci Change-Id: Iee82016057d609112e9b021d178fc3d4d18b5044 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/500621 Reviewed-by: Alexander Markov <alexmarkov@google.com> Reviewed-by: Tess Strickland <sstrickl@google.com> SLSA-Policy-Verified: SLSA Policy Verification Service <devtools-gerritcodereview-exitgate@google.com> Commit-Queue: Ryan Macnak <rmacnak@google.com>
1187 lines
42 KiB
C++
1187 lines
42 KiB
C++
// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file
|
|
// for details. All rights reserved. Use of this source code is governed by a
|
|
// BSD-style license that can be found in the LICENSE file.
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include <memory>
|
|
#include <utility>
|
|
|
|
#include "bin/builtin.h"
|
|
#include "bin/console.h"
|
|
#include "bin/crashpad.h"
|
|
#include "bin/dartdev_options.h"
|
|
#include "bin/dartutils.h"
|
|
#include "bin/error_exit.h"
|
|
#include "bin/eventhandler.h"
|
|
#include "bin/exe_utils.h"
|
|
#include "bin/file.h"
|
|
#include "bin/gzip.h"
|
|
#include "bin/isolate_data.h"
|
|
#include "bin/loader.h"
|
|
#include "bin/lockers.h"
|
|
#include "bin/platform.h"
|
|
#include "bin/process.h"
|
|
#include "bin/snapshot_utils.h"
|
|
#include "bin/thread.h"
|
|
#include "bin/utils.h"
|
|
#if defined(DART_HOST_OS_WINDOWS)
|
|
#include "bin/utils_win.h"
|
|
#endif
|
|
#include "bin/vmservice_impl.h"
|
|
#include "include/bin/dart_io_api.h"
|
|
#include "include/dart_api.h"
|
|
#include "include/dart_embedder_api.h"
|
|
#include "include/dart_native_api.h"
|
|
#include "include/dart_tools_api.h"
|
|
#include "platform/assert.h"
|
|
#include "platform/globals.h"
|
|
#include "platform/growable_array.h"
|
|
#include "platform/hashmap.h"
|
|
#include "platform/syslog.h"
|
|
#include "platform/text_buffer.h"
|
|
#include "platform/utils.h"
|
|
|
|
namespace dart {
|
|
namespace bin {
|
|
|
|
#if defined(DART_PRECOMPILED_RUNTIME)
|
|
/**
|
|
* Global state used to control and store generation of application snapshots.
|
|
*/
|
|
static const uint8_t* app_snapshot_data = nullptr;
|
|
static const uint8_t* app_snapshot_text = nullptr;
|
|
|
|
#define SAVE_ERROR_AND_RETURN(result) \
|
|
if (Dart_IsError(result)) { \
|
|
*error = Utils::StrDup(Dart_GetError(result)); \
|
|
return false; \
|
|
}
|
|
|
|
#define SAVE_ERROR_AND_EXIT(result) \
|
|
*error = Utils::StrDup(Dart_GetError(result)); \
|
|
if (Dart_IsCompilationError(result)) { \
|
|
*exit_code = kCompilationErrorExitCode; \
|
|
} else if (Dart_IsApiError(result)) { \
|
|
*exit_code = kApiErrorExitCode; \
|
|
} else { \
|
|
*exit_code = kErrorExitCode; \
|
|
} \
|
|
Dart_ExitScope(); \
|
|
Dart_ShutdownIsolate(); \
|
|
return nullptr;
|
|
|
|
#define CHECK_RESULT(result) \
|
|
if (Dart_IsError(result)) { \
|
|
SAVE_ERROR_AND_EXIT(result); \
|
|
}
|
|
|
|
#define CHECK_RESULT_CLEANUP(result, cleanup) \
|
|
if (Dart_IsError(result)) { \
|
|
delete (cleanup); \
|
|
SAVE_ERROR_AND_EXIT(result); \
|
|
}
|
|
|
|
#define DART_DEV_ISOLATE_NAME "dartdev"
|
|
|
|
// Helper class to ensure we enter a new Dart Scope and exit it.
|
|
class DartScope {
|
|
public:
|
|
DartScope() { Dart_EnterScope(); }
|
|
~DartScope() { Dart_ExitScope(); }
|
|
};
|
|
|
|
static Dart_Handle SetupCoreLibraries(Dart_Isolate isolate,
|
|
IsolateData* isolate_data,
|
|
bool is_isolate_group_start,
|
|
const char** resolved_packages_config) {
|
|
auto isolate_group_data = isolate_data->isolate_group_data();
|
|
const auto packages_file = isolate_data->packages_file();
|
|
const auto script_uri = isolate_group_data->script_url;
|
|
|
|
Dart_Handle result;
|
|
|
|
// Prepare builtin and other core libraries for use to resolve URIs.
|
|
// Set up various closures, e.g: printing, timers etc.
|
|
// Set up package configuration for URI resolution.
|
|
result = DartUtils::SetupCoreLibraries(
|
|
/*is_service_isolate=*/false, /*trace_loading=*/false,
|
|
/*profile_microtasks=*/false,
|
|
DartIoSettings{
|
|
.namespace_root = Options::namespc() != nullptr
|
|
? DartUtils::NewString(Options::namespc())
|
|
: nullptr,
|
|
.script_uri = script_uri,
|
|
.disable_exit = Options::exit_disabled()});
|
|
if (Dart_IsError(result)) return result;
|
|
|
|
// Setup packages config if specified.
|
|
result = DartUtils::SetupPackageConfig(packages_file);
|
|
if (Dart_IsError(result)) return result;
|
|
if (!Dart_IsNull(result) && resolved_packages_config != nullptr) {
|
|
result = Dart_StringToCString(result, resolved_packages_config);
|
|
if (Dart_IsError(result)) return result;
|
|
ASSERT(*resolved_packages_config != nullptr);
|
|
}
|
|
|
|
result = Dart_SetEnvironmentCallback(DartUtils::EnvironmentCallback);
|
|
if (Dart_IsError(result)) return result;
|
|
|
|
// Setup the native resolver as the snapshot does not carry it.
|
|
VmService::SetNativeResolver();
|
|
|
|
return Dart_Null();
|
|
}
|
|
|
|
static bool OnIsolateInitialize(void** child_callback_data, char** error) {
|
|
Dart_Isolate isolate = Dart_CurrentIsolate();
|
|
ASSERT(isolate != nullptr);
|
|
|
|
auto isolate_group_data =
|
|
reinterpret_cast<IsolateGroupData*>(Dart_CurrentIsolateGroupData());
|
|
|
|
auto isolate_data = new IsolateData(isolate_group_data);
|
|
*child_callback_data = isolate_data;
|
|
|
|
DartScope scope; // Enter a new scope.
|
|
const auto script_uri = isolate_group_data->script_url;
|
|
const bool isolate_run_app_snapshot =
|
|
isolate_group_data->RunFromAppSnapshot();
|
|
Dart_Handle result = SetupCoreLibraries(isolate, isolate_data,
|
|
/*group_start=*/false,
|
|
/*resolved_packages_config=*/nullptr);
|
|
SAVE_ERROR_AND_RETURN(result);
|
|
if (isolate_run_app_snapshot) {
|
|
result = Loader::InitForSnapshot(script_uri, isolate_data);
|
|
SAVE_ERROR_AND_RETURN(result);
|
|
} else {
|
|
result = DartUtils::ResolveScript(Dart_NewStringFromCString(script_uri));
|
|
SAVE_ERROR_AND_RETURN(result);
|
|
|
|
if (isolate_group_data->kernel_buffer() != nullptr) {
|
|
// Various core-library parts will send requests to the Loader to resolve
|
|
// relative URIs and perform other related tasks. We need Loader to be
|
|
// initialized for this to work because loading from Kernel binary
|
|
// bypasses normal source code loading paths that initialize it.
|
|
const char* resolved_script_uri = nullptr;
|
|
result = Dart_StringToCString(result, &resolved_script_uri);
|
|
SAVE_ERROR_AND_RETURN(result);
|
|
result = Loader::InitForSnapshot(resolved_script_uri, isolate_data);
|
|
SAVE_ERROR_AND_RETURN(result);
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static Dart_Isolate IsolateSetupHelper(Dart_Isolate isolate,
|
|
bool is_dartdev_isolate,
|
|
const char* script_uri,
|
|
const char* packages_config,
|
|
bool isolate_run_app_snapshot,
|
|
Dart_IsolateFlags* flags,
|
|
char** error,
|
|
int* exit_code) {
|
|
Dart_EnterScope();
|
|
|
|
// Set up the library tag handler for the isolate group shared by all
|
|
// isolates in the group.
|
|
Dart_Handle result = Dart_SetLibraryTagHandler(Loader::LibraryTagHandler);
|
|
CHECK_RESULT(result);
|
|
result = Dart_SetDeferredLoadHandler(Loader::DeferredLoadHandler);
|
|
CHECK_RESULT(result);
|
|
|
|
auto isolate_data = reinterpret_cast<IsolateData*>(Dart_IsolateData(isolate));
|
|
|
|
const char* resolved_packages_config = nullptr;
|
|
result = SetupCoreLibraries(isolate, isolate_data,
|
|
/*is_isolate_group_start=*/true,
|
|
&resolved_packages_config);
|
|
CHECK_RESULT(result);
|
|
|
|
if (isolate_run_app_snapshot) {
|
|
Dart_Handle result = Loader::InitForSnapshot(script_uri, isolate_data);
|
|
CHECK_RESULT(result);
|
|
} else {
|
|
UNREACHABLE();
|
|
}
|
|
|
|
// Make the isolate runnable so that it is ready to handle messages.
|
|
Dart_ExitScope();
|
|
Dart_ExitIsolate();
|
|
*error = Dart_IsolateMakeRunnable(isolate);
|
|
if (*error != nullptr) {
|
|
Dart_EnterIsolate(isolate);
|
|
Dart_ShutdownIsolate();
|
|
return nullptr;
|
|
}
|
|
|
|
return isolate;
|
|
}
|
|
|
|
// Returns newly created Isolate on success, nullptr on failure.
|
|
static Dart_Isolate CreateIsolateGroupAndSetupHelper(
|
|
bool is_dartdev_isolate,
|
|
const char* script_uri,
|
|
const char* name,
|
|
const char* packages_config,
|
|
Dart_IsolateFlags* flags,
|
|
void* callback_data,
|
|
char** error,
|
|
int* exit_code) {
|
|
int64_t start = Dart_TimelineGetMicros();
|
|
ASSERT(script_uri != nullptr);
|
|
uint8_t* kernel_buffer = nullptr;
|
|
intptr_t kernel_buffer_size = 0;
|
|
AppSnapshot* app_snapshot = nullptr;
|
|
|
|
const uint8_t* snapshot_data = nullptr;
|
|
const uint8_t* snapshot_text = nullptr;
|
|
if (is_dartdev_isolate) {
|
|
snapshot_data = app_snapshot_data;
|
|
snapshot_text = app_snapshot_text;
|
|
} else {
|
|
// AOT: All isolates need to be run from AOT compiled snapshots.
|
|
app_snapshot = Snapshot::TryReadAppSnapshot(
|
|
script_uri, /*force_load_from_memory*/ false, /*decode_uri*/ true);
|
|
if (app_snapshot == nullptr || !app_snapshot->IsAOT()) {
|
|
*error = Utils::SCreate(
|
|
"The uri(%s) provided to `Isolate.spawnUri()` does not "
|
|
"contain a valid AOT snapshot.",
|
|
script_uri);
|
|
return nullptr;
|
|
}
|
|
|
|
app_snapshot->SetBuffers(&snapshot_data, &snapshot_text);
|
|
}
|
|
|
|
bool isolate_run_app_snapshot = true;
|
|
|
|
auto isolate_group_data = new IsolateGroupData(
|
|
script_uri, /*asset_resolution_base=*/nullptr, packages_config,
|
|
app_snapshot, isolate_run_app_snapshot);
|
|
if (kernel_buffer != nullptr) {
|
|
isolate_group_data->SetKernelBufferNewlyOwned(kernel_buffer,
|
|
kernel_buffer_size);
|
|
}
|
|
|
|
Dart_Isolate isolate = nullptr;
|
|
|
|
IsolateData* isolate_data = nullptr;
|
|
isolate_data = new IsolateData(isolate_group_data);
|
|
isolate =
|
|
Dart_CreateIsolateGroup(script_uri, name, snapshot_data, snapshot_text,
|
|
flags, isolate_group_data, isolate_data, error);
|
|
Dart_Isolate created_isolate = nullptr;
|
|
if (isolate == nullptr) {
|
|
delete isolate_data;
|
|
delete isolate_group_data;
|
|
} else {
|
|
created_isolate = IsolateSetupHelper(
|
|
isolate, is_dartdev_isolate, script_uri, packages_config,
|
|
isolate_run_app_snapshot, flags, error, exit_code);
|
|
}
|
|
int64_t end = Dart_TimelineGetMicros();
|
|
Dart_RecordTimelineEvent("CreateIsolateGroupAndSetupHelper", start, end,
|
|
/*flow_id_count=*/0, nullptr,
|
|
Dart_Timeline_Event_Duration,
|
|
/*argument_count=*/0, nullptr, nullptr);
|
|
return created_isolate;
|
|
}
|
|
|
|
#undef CHECK_RESULT
|
|
|
|
static Dart_Isolate CreateIsolateGroupAndSetup(const char* script_uri,
|
|
const char* main,
|
|
const char* package_root,
|
|
const char* package_config,
|
|
Dart_IsolateFlags* flags,
|
|
void* callback_data,
|
|
char** error) {
|
|
// The VM should never call the isolate helper with a nullptr flags.
|
|
ASSERT(flags != nullptr);
|
|
ASSERT(flags->version == DART_FLAGS_CURRENT_VERSION);
|
|
ASSERT(package_root == nullptr);
|
|
|
|
if (error != nullptr) {
|
|
*error = nullptr;
|
|
}
|
|
|
|
#if defined(DART_HOST_OS_LINUX)
|
|
// This would also be true in Linux, except that Google3 overrides the default
|
|
// ELF interpreter to one that apparently doesn't create proper mappings.
|
|
flags->snapshot_is_dontneed_safe = false;
|
|
#else
|
|
flags->snapshot_is_dontneed_safe = true;
|
|
#endif
|
|
|
|
int exit_code = 0;
|
|
|
|
if (strcmp(script_uri, DART_VM_SERVICE_ISOLATE_NAME) == 0) {
|
|
// We do not start the service isolate in the Dart CLI mode of execution.
|
|
// If profiling or debugging of the individual tools is desired it is
|
|
// possible to do that using the 'dartaotruntime' or 'dartvm' executables.
|
|
return nullptr;
|
|
}
|
|
|
|
bool is_dartdev_isolate = false;
|
|
return CreateIsolateGroupAndSetupHelper(is_dartdev_isolate, script_uri, main,
|
|
package_config, flags, callback_data,
|
|
error, &exit_code);
|
|
}
|
|
|
|
static void OnIsolateShutdown(void* isolate_group_data, void* isolate_data) {
|
|
Dart_EnterScope();
|
|
Dart_Handle sticky_error = Dart_GetStickyError();
|
|
if (!Dart_IsNull(sticky_error) && !Dart_IsFatalError(sticky_error)) {
|
|
Syslog::PrintErr("%s\n", Dart_GetError(sticky_error));
|
|
}
|
|
Dart_ExitScope();
|
|
}
|
|
|
|
static void DeleteIsolateData(void* isolate_group_data, void* callback_data) {
|
|
auto isolate_data = reinterpret_cast<IsolateData*>(callback_data);
|
|
delete isolate_data;
|
|
}
|
|
|
|
static void DeleteIsolateGroupData(void* callback_data) {
|
|
auto isolate_group_data = reinterpret_cast<IsolateGroupData*>(callback_data);
|
|
delete isolate_group_data;
|
|
}
|
|
|
|
static constexpr const char* kStdoutStreamId = "Stdout";
|
|
static constexpr const char* kStderrStreamId = "Stderr";
|
|
|
|
static bool ServiceStreamListenCallback(const char* stream_id) {
|
|
if (strcmp(stream_id, kStdoutStreamId) == 0) {
|
|
SetCaptureStdout(true);
|
|
return true;
|
|
} else if (strcmp(stream_id, kStderrStreamId) == 0) {
|
|
SetCaptureStderr(true);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
static void ServiceStreamCancelCallback(const char* stream_id) {
|
|
if (strcmp(stream_id, kStdoutStreamId) == 0) {
|
|
SetCaptureStdout(false);
|
|
} else if (strcmp(stream_id, kStderrStreamId) == 0) {
|
|
SetCaptureStderr(false);
|
|
} else {
|
|
UNREACHABLE();
|
|
}
|
|
}
|
|
|
|
static bool FileModifiedCallback(const char* url, int64_t since) {
|
|
auto path = File::UriToPath(url);
|
|
if (path == nullptr) {
|
|
// If it isn't a file on local disk, we don't know if it has been
|
|
// modified.
|
|
return true;
|
|
}
|
|
int64_t data[File::kStatSize];
|
|
File::Stat(nullptr, path.get(), data);
|
|
if (data[File::kType] == File::kDoesNotExist) {
|
|
return true;
|
|
}
|
|
return data[File::kModifiedTime] > since;
|
|
}
|
|
|
|
static void EmbedderInformationCallback(Dart_EmbedderInformation* info) {
|
|
info->version = DART_EMBEDDER_INFORMATION_CURRENT_VERSION;
|
|
info->name = "Dart VM";
|
|
Process::GetRSSInformation(&(info->max_rss), &(info->current_rss));
|
|
}
|
|
|
|
#define CHECK_RESULT(result) \
|
|
if (Dart_IsError(result)) { \
|
|
const int exit_code = Dart_IsCompilationError(result) \
|
|
? kCompilationErrorExitCode \
|
|
: kErrorExitCode; \
|
|
ErrorExit(exit_code, "%s\n", Dart_GetError(result)); \
|
|
}
|
|
|
|
static bool CheckForInvalidPath(const char* path) {
|
|
// TODO(zichangguo): "\\?\" is a prefix for paths on Windows.
|
|
// Arguments passed are parsed as an URI. "\\?\" causes problems as a part
|
|
// of URIs. This is a temporary workaround to prevent VM from crashing.
|
|
// Issue: https://github.com/dart-lang/sdk/issues/42779
|
|
if (strncmp(path, R"(\\?\)", 4) == 0) {
|
|
Syslog::PrintErr(R"(\\?\ prefix is not supported)");
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
class DartDev {
|
|
public:
|
|
// Return codes from dartdev.
|
|
// Note: keep in sync with pkg/dartdev/lib/vm_interop_handler.dart
|
|
typedef enum {
|
|
DartDev_Result_Unknown = -1,
|
|
DartDev_Result_Run = 1,
|
|
DartDev_Result_RunExec = 2,
|
|
DartDev_Result_Exit = 3,
|
|
DartDev_Result_SetEnvironmentVariable = 4,
|
|
} DartDev_Result;
|
|
|
|
static CStringUniquePtr ResolvedDartVmPath() {
|
|
#if defined(DART_HOST_OS_WINDOWS)
|
|
const char* filename = "dartvm.exe";
|
|
#else
|
|
const char* filename = "dartvm";
|
|
#endif // defined(DART_HOST_OS_WINDOWS)
|
|
auto try_resolve_path = [&](CStringUniquePtr dir_prefix) {
|
|
// |dir_prefix| includes the last path separator.
|
|
// Assume 'dartvm' and 'dart' executables are in the same directory.
|
|
char* dartvm_path = Utils::SCreate("%s%s", dir_prefix.get(), filename);
|
|
if (File::Exists(nullptr, dartvm_path)) {
|
|
return CStringUniquePtr(dartvm_path);
|
|
}
|
|
free(dartvm_path);
|
|
return CStringUniquePtr(nullptr);
|
|
};
|
|
|
|
auto result =
|
|
try_resolve_path(EXEUtils::GetDirectoryPrefixFromResolvedExeName());
|
|
if (result == nullptr) {
|
|
result =
|
|
try_resolve_path(EXEUtils::GetDirectoryPrefixFromUnresolvedExeName());
|
|
}
|
|
return result;
|
|
}
|
|
|
|
static CStringUniquePtr ResolvedSnapshotPath() {
|
|
const char* filename = "dartdev_aot.dart.snapshot";
|
|
|
|
auto try_resolve_path = [&](CStringUniquePtr dir_prefix) {
|
|
// |dir_prefix| includes the last path separator.
|
|
// First assume we're in dart-sdk/bin.
|
|
char* snapshot_path =
|
|
Utils::SCreate("%ssnapshots/%s", dir_prefix.get(), filename);
|
|
if (File::Exists(nullptr, snapshot_path)) {
|
|
return CStringUniquePtr(snapshot_path);
|
|
}
|
|
free(snapshot_path);
|
|
|
|
// If we're not in dart-sdk/bin, we might be in one of the $SDK/out*/
|
|
// directories, Try to use a snapshot from that directory.
|
|
snapshot_path = Utils::SCreate("%s%s", dir_prefix.get(), filename);
|
|
if (File::Exists(nullptr, snapshot_path)) {
|
|
return CStringUniquePtr(snapshot_path);
|
|
}
|
|
free(snapshot_path);
|
|
return CStringUniquePtr(nullptr);
|
|
};
|
|
|
|
auto result =
|
|
try_resolve_path(EXEUtils::GetDirectoryPrefixFromResolvedExeName());
|
|
if (result == nullptr) {
|
|
result =
|
|
try_resolve_path(EXEUtils::GetDirectoryPrefixFromUnresolvedExeName());
|
|
}
|
|
return result;
|
|
}
|
|
|
|
// Invoke the Dart VM directly bypassing dartdev.
|
|
static void InvokeDartVM(int argc, char** argv, bool argv_converted) {
|
|
auto dartvm_path = DartDev::ResolvedDartVmPath();
|
|
if (dartvm_path.get() == nullptr ||
|
|
!CheckForInvalidPath(dartvm_path.get())) {
|
|
// Free environment if any.
|
|
Syslog::PrintErr("Unable to locate the Dart VM executable");
|
|
Options::Cleanup();
|
|
Platform::Exit(kErrorExitCode);
|
|
}
|
|
int idx = 0;
|
|
char err_msg[256];
|
|
err_msg[0] = '\0';
|
|
intptr_t num_args = argc + 3;
|
|
char** exec_argv = new char*[num_args];
|
|
#if defined(DART_HOST_OS_WINDOWS)
|
|
char* exec_name = StringUtilsWin::ArgumentEscape(dartvm_path.get());
|
|
#else
|
|
char* exec_name = Utils::StrDup(dartvm_path.get());
|
|
#endif
|
|
exec_argv[idx] = exec_name;
|
|
const size_t kPathBufSize = PATH_MAX + 1;
|
|
char dart_path[kPathBufSize];
|
|
Platform::ResolveExecutablePathInto(dart_path, kPathBufSize);
|
|
idx += 1;
|
|
#if defined(DART_HOST_OS_WINDOWS)
|
|
char* dart_name =
|
|
Utils::SCreate("--resolved_executable_name=%s", dart_path);
|
|
exec_argv[idx] = StringUtilsWin::ArgumentEscape(dart_name);
|
|
free(dart_name);
|
|
idx += 1;
|
|
dart_name =
|
|
Utils::SCreate("--executable_name=%s", Platform::GetExecutableName());
|
|
exec_argv[idx] = StringUtilsWin::ArgumentEscape(dart_name);
|
|
free(dart_name);
|
|
#else
|
|
exec_argv[idx] = Utils::SCreate("--resolved_executable_name=%s", dart_path);
|
|
idx += 1;
|
|
exec_argv[idx] =
|
|
Utils::SCreate("--executable_name=%s", Platform::GetExecutableName());
|
|
#endif
|
|
for (intptr_t i = 1; i < argc; ++i) {
|
|
#if defined(DART_HOST_OS_WINDOWS)
|
|
exec_argv[i + idx] = StringUtilsWin::ArgumentEscape(argv[i]);
|
|
#else
|
|
exec_argv[i + idx] = Utils::StrDup(argv[i]);
|
|
#endif // defined(DART_HOST_OS_WINDOWS)
|
|
}
|
|
// Null terminate the exec_argv array.
|
|
exec_argv[num_args - 1] = nullptr;
|
|
|
|
// Exec the script to be run and pass the arguments.
|
|
int ret =
|
|
Process::Exec(nullptr, exec_name, const_cast<const char**>(exec_argv),
|
|
(num_args - 1), nullptr, err_msg, sizeof(err_msg));
|
|
// Exec process done.
|
|
if (ret != 0) {
|
|
Syslog::PrintErr("%s\n", err_msg);
|
|
}
|
|
// Free copied argument strings if converted.
|
|
if (argv_converted) {
|
|
for (int i = 0; i < argc; i++) {
|
|
free(argv[i]);
|
|
}
|
|
}
|
|
for (int i = 0; i < argc; i++) {
|
|
free(exec_argv[i]);
|
|
}
|
|
delete[] exec_argv;
|
|
|
|
// Free environment if any.
|
|
Options::Cleanup();
|
|
Platform::Exit(ret);
|
|
}
|
|
|
|
// Process the DartDev_Result_Run result message produced by
|
|
// VmInteropHandler in pkg/dartdev/lib/src/vm_interop_handler.dart
|
|
static void RunResultCallback(Dart_CObject* message) {
|
|
result_ = DartDev_Result_Run;
|
|
ASSERT(GetArrayItem(message, 1)->type == Dart_CObject_kString);
|
|
auto item2 = GetArrayItem(message, 2);
|
|
|
|
ASSERT(item2->type == Dart_CObject_kString ||
|
|
item2->type == Dart_CObject_kNull);
|
|
|
|
auto item3 = GetArrayItem(message, 3);
|
|
|
|
// ignoring mark_main_isolate_as_system_isolate
|
|
ASSERT(item3->type == Dart_CObject_kBool);
|
|
|
|
script_name_ = Utils::StrDup(GetArrayItem(message, 1)->value.as_string);
|
|
|
|
ASSERT(GetArrayItem(message, 4)->type == Dart_CObject_kArray);
|
|
Dart_CObject* args = GetArrayItem(message, 4);
|
|
argc_ = args->value.as_array.length;
|
|
Dart_CObject** dart_args = args->value.as_array.values;
|
|
|
|
auto deleter = [](char** args) {
|
|
for (intptr_t i = 0; i < argc_; ++i) {
|
|
free(args[i]);
|
|
}
|
|
delete[] args;
|
|
};
|
|
argv_ =
|
|
std::unique_ptr<char*[], void (*)(char**)>(new char*[argc_], deleter);
|
|
for (intptr_t i = 0; i < argc_; ++i) {
|
|
argv_[i] = Utils::StrDup(dart_args[i]->value.as_string);
|
|
}
|
|
}
|
|
|
|
// Process the DartDev_Result_RunExec result message produced by
|
|
// VmInteropHandler in pkg/dartdev/lib/src/vm_interop_handler.dart
|
|
static void RunExecResultCallback(Dart_CObject* message) {
|
|
result_ = DartDev_Result_RunExec;
|
|
auto dartvm_path = DartDev::ResolvedDartVmPath();
|
|
if (dartvm_path.get() == nullptr ||
|
|
!CheckForInvalidPath(dartvm_path.get())) {
|
|
Syslog::PrintErr("Unable to locate the Dart VM executable");
|
|
Platform::Exit(kErrorExitCode);
|
|
}
|
|
ASSERT(GetArrayItem(message, 1)->type == Dart_CObject_kString);
|
|
auto item2 = GetArrayItem(message, 2);
|
|
|
|
ASSERT(item2->type == Dart_CObject_kString ||
|
|
item2->type == Dart_CObject_kNull);
|
|
|
|
package_config_override_ = nullptr;
|
|
|
|
if (item2->type == Dart_CObject_kString) {
|
|
package_config_override_ = Utils::StrDup(item2->value.as_string);
|
|
}
|
|
|
|
intptr_t num_vm_options = dart_vm_options_->count();
|
|
const char** vm_options = dart_vm_options_->arguments();
|
|
ASSERT(GetArrayItem(message, 4)->type == Dart_CObject_kArray);
|
|
Dart_CObject* args = GetArrayItem(message, 4);
|
|
intptr_t argc = args->value.as_array.length;
|
|
Dart_CObject** dart_args = args->value.as_array.values;
|
|
auto item3 = GetArrayItem(message, 3);
|
|
ASSERT(item3->type == Dart_CObject_kBool);
|
|
const bool mark_main_isolate_as_system_isolate = item3->value.as_bool;
|
|
auto deleter = [](char** args) {
|
|
for (intptr_t i = 0; i < argc_; ++i) {
|
|
free(args[i]);
|
|
}
|
|
delete[] args;
|
|
};
|
|
// Total count of arguments to be passed to the script being execed.
|
|
if (mark_main_isolate_as_system_isolate) {
|
|
argc_ = argc + num_vm_options + 5;
|
|
} else {
|
|
argc_ = argc + num_vm_options + 4;
|
|
}
|
|
if (package_config_override_ != nullptr) {
|
|
argc_++;
|
|
}
|
|
|
|
// Array of arguments to be passed to the script being execed.
|
|
argv_ = std::unique_ptr<char*[], void (*)(char**)>(new char*[argc_ + 1],
|
|
deleter);
|
|
|
|
intptr_t idx = 0;
|
|
// Copy in name of the executable to run (should be the dart vm).
|
|
#if defined(DART_HOST_OS_WINDOWS)
|
|
script_name_ = StringUtilsWin::ArgumentEscape(dartvm_path.get());
|
|
#else
|
|
script_name_ = Utils::StrDup(dartvm_path.get());
|
|
#endif
|
|
argv_[idx++] = script_name_;
|
|
// Copy in VM options if any.
|
|
// Copy in any vm options that need to be passed to the execed process.
|
|
for (intptr_t i = 0; i < num_vm_options; ++i) {
|
|
#if defined(DART_HOST_OS_WINDOWS)
|
|
argv_[i + idx] = StringUtilsWin::ArgumentEscape(vm_options[i]);
|
|
#else
|
|
argv_[i + idx] = Utils::StrDup(vm_options[i]);
|
|
#endif
|
|
}
|
|
idx += num_vm_options;
|
|
{
|
|
const size_t kPathBufSize = PATH_MAX + 1;
|
|
char dart_path[kPathBufSize];
|
|
Platform::ResolveExecutablePathInto(dart_path, kPathBufSize);
|
|
#if defined(DART_HOST_OS_WINDOWS)
|
|
char* dart_name =
|
|
Utils::SCreate("--resolved_executable_name=%s", dart_path);
|
|
argv_[idx++] = StringUtilsWin::ArgumentEscape(dart_name);
|
|
free(dart_name);
|
|
dart_name =
|
|
Utils::SCreate("--executable_name=%s", Platform::GetExecutableName());
|
|
argv_[idx++] = StringUtilsWin::ArgumentEscape(dart_name);
|
|
free(dart_name);
|
|
#else
|
|
argv_[idx++] = Utils::SCreate("--resolved_executable_name=%s", dart_path);
|
|
argv_[idx++] =
|
|
Utils::SCreate("--executable_name=%s", Platform::GetExecutableName());
|
|
#endif
|
|
}
|
|
if (mark_main_isolate_as_system_isolate) {
|
|
argv_[idx++] = Utils::StrDup("--mark_main_isolate_as_system_isolate");
|
|
}
|
|
if (package_config_override_ != nullptr) {
|
|
#if defined(DART_HOST_OS_WINDOWS)
|
|
char* packages_arg =
|
|
Utils::SCreate("--packages=%s", package_config_override_);
|
|
argv_[idx++] = StringUtilsWin::ArgumentEscape(packages_arg);
|
|
free(packages_arg);
|
|
#else
|
|
argv_[idx++] = Utils::SCreate("--packages=%s", package_config_override_);
|
|
#endif
|
|
}
|
|
// Copy in name of the script to run.
|
|
argv_[idx++] = Utils::StrDup(GetArrayItem(message, 1)->value.as_string);
|
|
// Copy in the dart options that need to be passed to the script.
|
|
for (intptr_t i = 0; i < argc; ++i) {
|
|
argv_[i + idx] = Utils::StrDup(dart_args[i]->value.as_string);
|
|
}
|
|
// Null terminate the argv array.
|
|
argv_[argc + idx] = nullptr;
|
|
}
|
|
|
|
// Process the DartDev_Result_Exit result message produced by
|
|
// VmInteropHandler in pkg/dartdev/lib/src/vm_interop_handler.dart
|
|
static void ExitResultCallback(Dart_CObject* message) {
|
|
ASSERT(GetArrayItem(message, 1)->type == Dart_CObject_kInt32);
|
|
int32_t dartdev_exit_code = GetArrayItem(message, 1)->value.as_int32;
|
|
|
|
// If we're given a non-zero exit code, DartDev is signaling for us to
|
|
// shutdown.
|
|
Process::SetGlobalExitCode(dartdev_exit_code);
|
|
|
|
// If DartDev hasn't signaled for us to do anything else, we can assume
|
|
// there's nothing else for the VM to run and that we can exit.
|
|
if (result_ == DartDev_Result_Unknown || dartdev_exit_code != 0) {
|
|
result_ = DartDev_Result_Exit;
|
|
}
|
|
// Notify the dartdev runner that it can proceed with processing
|
|
// the result from execution of dartdev.
|
|
{
|
|
MonitorLocker locker(monitor_);
|
|
exited_ = true;
|
|
locker.Notify();
|
|
}
|
|
}
|
|
|
|
static void SetEnvironmentVariableCallback(Dart_CObject* message) {
|
|
ASSERT(GetArrayItem(message, 1)->type == Dart_CObject_kString);
|
|
const char* name = GetArrayItem(message, 1)->value.as_string;
|
|
const char* value = nullptr;
|
|
if (GetArrayItem(message, 2)->type == Dart_CObject_kString) {
|
|
value = GetArrayItem(message, 2)->value.as_string;
|
|
}
|
|
Platform::SetEnvironmentVariable(name, value);
|
|
}
|
|
|
|
// Callback that processes the result from execution of dartdev
|
|
//
|
|
static void ResultCallback(Dart_Port dest_port_id, Dart_CObject* message) {
|
|
// These messages are produced in
|
|
// pkg/dartdev/lib/src/vm_interop_handler.dart.
|
|
ASSERT(message->type == Dart_CObject_kArray);
|
|
int32_t type = GetArrayItem(message, 0)->value.as_int32;
|
|
switch (type) {
|
|
case DartDev_Result_Run: {
|
|
RunResultCallback(message);
|
|
break;
|
|
}
|
|
case DartDev_Result_RunExec: {
|
|
RunExecResultCallback(message);
|
|
break;
|
|
}
|
|
case DartDev_Result_Exit: {
|
|
ExitResultCallback(message);
|
|
break;
|
|
}
|
|
case DartDev_Result_SetEnvironmentVariable: {
|
|
SetEnvironmentVariableCallback(message);
|
|
break;
|
|
}
|
|
default:
|
|
UNREACHABLE();
|
|
}
|
|
}
|
|
|
|
static void RunDartDev(const char* script_name,
|
|
CommandLineOptions* dart_vm_options,
|
|
CommandLineOptions* dart_options) {
|
|
ASSERT(script_name != nullptr);
|
|
const char* base_name = strrchr(script_name, '/');
|
|
if (base_name == nullptr) {
|
|
base_name = script_name;
|
|
} else {
|
|
base_name++; // Skip '/'.
|
|
}
|
|
const intptr_t kMaxNameLength = 64;
|
|
char name[kMaxNameLength];
|
|
Utils::SNPrint(name, kMaxNameLength, "dart:%s", base_name);
|
|
Platform::SetProcessName(name);
|
|
|
|
dart_vm_options_ = dart_vm_options;
|
|
|
|
// Call CreateIsolateGroupAndSetup which creates an isolate and loads up
|
|
// the specified application script.
|
|
Dart_IsolateFlags flags;
|
|
Dart_IsolateFlagsInitialize(&flags);
|
|
#if defined(DART_HOST_OS_LINUX)
|
|
// This would also be true in Linux, except that Google3 overrides the
|
|
// default ELF interpreter to one that apparently doesn't create proper
|
|
// mappings.
|
|
flags.snapshot_is_dontneed_safe = false;
|
|
#else
|
|
flags.snapshot_is_dontneed_safe = true;
|
|
#endif
|
|
flags.is_system_isolate = true;
|
|
SpawnIsolate(script_name, "_startIsolate",
|
|
/*is_dartdev_isolate*/ true,
|
|
/*package_config_override*/ nullptr, &flags, dart_options);
|
|
|
|
// Wait for the callbacks on the native port to be done before we
|
|
// proceed.
|
|
{
|
|
MonitorLocker locker(monitor_);
|
|
while (!exited_) {
|
|
locker.Wait();
|
|
}
|
|
}
|
|
|
|
/* Process the result returned by the dartdev isolate. */
|
|
switch (result_) {
|
|
case DartDev_Result_Run: {
|
|
flags.is_system_isolate = false;
|
|
SpawnIsolate(script_name_, "_startMainIsolate",
|
|
/*is_dartdev_isolate*/ false, package_config_override_,
|
|
&flags, dart_options);
|
|
free(script_name_);
|
|
free(package_config_override_);
|
|
break;
|
|
}
|
|
case DartDev_Result_RunExec: {
|
|
RunExec(script_name_);
|
|
break;
|
|
}
|
|
case DartDev_Result_Exit: {
|
|
// Nothing to do here, the process will terminate with the exit code
|
|
// set earlier.
|
|
break;
|
|
}
|
|
default:
|
|
UNREACHABLE();
|
|
}
|
|
}
|
|
|
|
private:
|
|
static void SpawnIsolate(const char* script_name,
|
|
const char* entry_point,
|
|
bool is_dartdev_isolate,
|
|
const char* package_config_override,
|
|
Dart_IsolateFlags* flags,
|
|
CommandLineOptions* dart_options) {
|
|
// Start a new Isolate with the specified AOT snapshot.
|
|
int exit_code = 0;
|
|
char* error = nullptr;
|
|
|
|
Dart_Isolate isolate = CreateIsolateGroupAndSetupHelper(
|
|
is_dartdev_isolate, script_name, "main",
|
|
Options::packages_file() == nullptr ? package_config_override
|
|
: Options::packages_file(),
|
|
flags, nullptr /* callback_data */, &error, &exit_code);
|
|
|
|
if (isolate == nullptr) {
|
|
if (error != nullptr) {
|
|
Syslog::PrintErr("Isolate spawning failed: %s\n", error);
|
|
free(error);
|
|
}
|
|
error = nullptr;
|
|
Process::TerminateExitCodeHandler();
|
|
error = Dart_Cleanup();
|
|
if (error != nullptr) {
|
|
Syslog::PrintErr("Dart_Cleanup failed: %s\n", error);
|
|
free(error);
|
|
}
|
|
dart::embedder::Cleanup();
|
|
Platform::Exit((exit_code != 0) ? exit_code : kErrorExitCode);
|
|
}
|
|
|
|
Dart_EnterIsolate(isolate);
|
|
ASSERT(isolate == Dart_CurrentIsolate());
|
|
ASSERT(isolate != nullptr);
|
|
Dart_Handle result;
|
|
|
|
Dart_EnterScope();
|
|
|
|
Dart_Handle send_port = Dart_Null();
|
|
Dart_Port send_port_id = ILLEGAL_PORT;
|
|
if (is_dartdev_isolate) {
|
|
// Create a SendPort that DartDev can use to communicate its results over.
|
|
send_port_id =
|
|
Dart_NewNativePort(DART_DEV_ISOLATE_NAME, ResultCallback, false);
|
|
ASSERT(send_port_id != ILLEGAL_PORT);
|
|
send_port = Dart_NewSendPort(send_port_id);
|
|
CHECK_RESULT(send_port);
|
|
}
|
|
|
|
// Lookup the library of the root script.
|
|
Dart_Handle root_lib = Dart_RootLibrary();
|
|
|
|
if (Dart_IsNull(root_lib)) {
|
|
ErrorExit(kErrorExitCode, "Unable to find root library for '%s'\n",
|
|
script_name);
|
|
}
|
|
|
|
// Create a closure for the main entry point which is in the exported
|
|
// namespace of the root library or invoke a getter of the same name
|
|
// in the exported namespace and return the resulting closure.
|
|
Dart_Handle main_closure =
|
|
Dart_GetField(root_lib, Dart_NewStringFromCString("main"));
|
|
CHECK_RESULT(main_closure);
|
|
if (!Dart_IsClosure(main_closure)) {
|
|
ErrorExit(kErrorExitCode, "Unable to find 'main' in root library '%s'\n",
|
|
script_name);
|
|
}
|
|
|
|
Dart_Handle isolate_lib =
|
|
Dart_LookupLibrary(Dart_NewStringFromCString("dart:isolate"));
|
|
if (is_dartdev_isolate) {
|
|
const intptr_t kNumIsolateArgs = 4;
|
|
Dart_Handle isolate_args[kNumIsolateArgs];
|
|
isolate_args[0] = main_closure; // entryPoint
|
|
isolate_args[1] = dart_options->CreateRuntimeOptions(); // args
|
|
isolate_args[2] = send_port;
|
|
isolate_args[3] = Dart_True(); // isSpawnUri
|
|
result = Dart_Invoke(isolate_lib, Dart_NewStringFromCString(entry_point),
|
|
kNumIsolateArgs, isolate_args);
|
|
} else {
|
|
// Call _startIsolate in the isolate library to enable dispatching the
|
|
// initial startup message.
|
|
dart_options->Reset();
|
|
dart_options->AddArguments(const_cast<const char**>(argv_.get()), argc_);
|
|
const intptr_t kNumIsolateArgs = 2;
|
|
Dart_Handle isolate_args[kNumIsolateArgs];
|
|
isolate_args[0] = main_closure; // entryPoint
|
|
isolate_args[1] = dart_options->CreateRuntimeOptions(); // args
|
|
result = Dart_Invoke(isolate_lib, Dart_NewStringFromCString(entry_point),
|
|
kNumIsolateArgs, isolate_args);
|
|
}
|
|
CHECK_RESULT(result);
|
|
|
|
// Keep handling messages until the last active receive port is closed.
|
|
result = Dart_RunLoop();
|
|
CHECK_RESULT(result);
|
|
|
|
if (is_dartdev_isolate) {
|
|
// DartDev is done processing the command. Close the native port, this
|
|
// will ensure we exit from the event handler loop and exit dartdev
|
|
// isolate.
|
|
Dart_CloseNativePort(send_port_id);
|
|
}
|
|
Dart_ExitScope();
|
|
|
|
// Shutdown the isolate.
|
|
Dart_ShutdownIsolate();
|
|
}
|
|
|
|
static void RunExec(const char* script_name) {
|
|
// Exec the JIT Dart VM with the specified script file.
|
|
char err_msg[256];
|
|
err_msg[0] = '\0';
|
|
int ret = Process::Exec(nullptr, script_name,
|
|
const_cast<const char**>(argv_.get()), argc_,
|
|
nullptr, err_msg, sizeof(err_msg));
|
|
if (ret != 0) {
|
|
Syslog::PrintErr("%s.\n", err_msg);
|
|
Process::SetGlobalExitCode(ret);
|
|
} else {
|
|
Process::SetGlobalExitCode(ret);
|
|
}
|
|
}
|
|
|
|
static Dart_CObject* GetArrayItem(Dart_CObject* message, intptr_t index) {
|
|
return message->value.as_array.values[index];
|
|
}
|
|
|
|
static Monitor* monitor_;
|
|
static bool exited_;
|
|
static DartDev_Result result_;
|
|
static char* script_name_;
|
|
static char* package_config_override_;
|
|
static CommandLineOptions* dart_vm_options_;
|
|
static std::unique_ptr<char*[], void (*)(char**)> argv_;
|
|
static intptr_t argc_;
|
|
};
|
|
|
|
Monitor* DartDev::monitor_ = new Monitor();
|
|
bool DartDev::exited_ = false;
|
|
DartDev::DartDev_Result DartDev::result_ = DartDev::DartDev_Result_Unknown;
|
|
char* DartDev::script_name_ = nullptr;
|
|
char* DartDev::package_config_override_ = nullptr;
|
|
CommandLineOptions* DartDev::dart_vm_options_ = nullptr;
|
|
std::unique_ptr<char*[], void (*)(char**)> DartDev::argv_ =
|
|
std::unique_ptr<char*[], void (*)(char**)>(nullptr, [](char**) {});
|
|
intptr_t DartDev::argc_ = 0;
|
|
|
|
#undef CHECK_RESULT
|
|
|
|
static void FreeConvertedArgs(int argc, char** argv, bool argv_converted) {
|
|
// Free copied argument strings if converted.
|
|
if (argv_converted) {
|
|
for (int i = 0; i < argc; i++) {
|
|
free(argv[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
void main(int argc, char** argv) {
|
|
#if !defined(DART_HOST_OS_WINDOWS)
|
|
// Very early so any crashes during startup can also be symbolized.
|
|
EXEUtils::LoadDartProfilerSymbols(argv[0]);
|
|
#endif
|
|
|
|
const int EXTRA_VM_ARGUMENTS = 10;
|
|
// An invocation line is as follows
|
|
// dart <vm_opts> <cmd-name> <vm-opts-to-cmd> <script_name> <dart-options>
|
|
|
|
// vm-opts : Set of VM options that need to be passed to the AOT runtime
|
|
// running in this dartdev process.
|
|
CommandLineOptions vm_options(argc + EXTRA_VM_ARGUMENTS);
|
|
|
|
// vm-opts-to-cmd : Set of VM options that need to be passed to the runtime
|
|
// that executes the dartdev command.
|
|
CommandLineOptions dart_vm_options(argc + EXTRA_VM_ARGUMENTS);
|
|
|
|
// dart-options : Set of options to be passed to the Dart program
|
|
CommandLineOptions dart_options(argc + EXTRA_VM_ARGUMENTS);
|
|
|
|
// Perform platform specific initialization.
|
|
if (!Platform::Initialize()) {
|
|
Syslog::PrintErr("Initialization failed\n");
|
|
Platform::Exit(kErrorExitCode);
|
|
}
|
|
|
|
// Save the console state so we can restore it at shutdown.
|
|
Console::SaveConfig();
|
|
|
|
// On Windows, the argv strings are code page encoded and not
|
|
// utf8. We need to convert them to utf8.
|
|
bool argv_converted = ShellUtils::GetUtf8Argv(argc, argv);
|
|
|
|
// When running from the command line we assume that we are optimizing for
|
|
// throughput, and therefore use a larger new gen semi space size and a faster
|
|
// new gen growth factor unless others have been specified.
|
|
if (kWordSize <= 4) {
|
|
vm_options.AddArgument("--new_gen_semi_max_size=16");
|
|
} else {
|
|
vm_options.AddArgument("--new_gen_semi_max_size=32");
|
|
}
|
|
vm_options.AddArgument("--new_gen_growth_factor=4");
|
|
|
|
// Parse command line arguments.
|
|
bool skip_dartdev;
|
|
bool success = Options::ParseDartDevArguments(
|
|
argc, argv, &vm_options, &dart_vm_options, &dart_options, &skip_dartdev);
|
|
if (!success) {
|
|
FreeConvertedArgs(argc, argv, argv_converted);
|
|
if (Options::help_option()) {
|
|
Options::PrintUsage();
|
|
Platform::Exit(0);
|
|
} else if (Options::version_option()) {
|
|
Options::PrintVersion();
|
|
Platform::Exit(0);
|
|
} else {
|
|
Options::PrintUsage();
|
|
Platform::Exit(kErrorExitCode);
|
|
}
|
|
}
|
|
if (skip_dartdev) {
|
|
// We are skipping execution of dartdev as no Dart command line has
|
|
// been specified, in this case we directly exec the Dart JIT VM to
|
|
// run the specified script and pass in the original command line
|
|
// arguments.
|
|
DartDev::InvokeDartVM(argc, argv, argv_converted);
|
|
}
|
|
|
|
DartUtils::SetEnvironment(Options::environment());
|
|
|
|
if (Options::suppress_core_dump()) {
|
|
Platform::SetCoreDumpResourceLimit(0);
|
|
}
|
|
|
|
Loader::InitOnce();
|
|
|
|
auto [app_snapshot, script_name] =
|
|
Snapshot::TryReadSDKSnapshot("dartdev_aot.dart.snapshot");
|
|
if (app_snapshot == nullptr) {
|
|
FreeConvertedArgs(argc, argv, argv_converted);
|
|
Platform::Exit(kErrorExitCode);
|
|
}
|
|
app_snapshot->SetBuffers(&app_snapshot_data, &app_snapshot_text);
|
|
|
|
vm_options.AddArgument("--precompilation");
|
|
|
|
char* error = nullptr;
|
|
if (!dart::embedder::InitOnce(&error)) {
|
|
Syslog::PrintErr("dartdev embedder initialization failed: %s\n", error);
|
|
free(error);
|
|
FreeConvertedArgs(argc, argv, argv_converted);
|
|
delete app_snapshot;
|
|
Platform::Exit(kErrorExitCode);
|
|
}
|
|
|
|
error = Dart_SetVMFlags(vm_options.count(), vm_options.arguments());
|
|
if (error != nullptr) {
|
|
for (int i = 0; i < argc; i++) {
|
|
Syslog::PrintErr("argv[%d]: %s\n", i, argv[i]);
|
|
}
|
|
Syslog::PrintErr("Setting VM flags failed: %s\n", error);
|
|
free(error);
|
|
FreeConvertedArgs(argc, argv, argv_converted);
|
|
delete app_snapshot;
|
|
Platform::Exit(kErrorExitCode);
|
|
}
|
|
|
|
// Initialize the Dart VM.
|
|
Dart_InitializeParams init_params;
|
|
memset(&init_params, 0, sizeof(init_params));
|
|
init_params.version = DART_INITIALIZE_PARAMS_CURRENT_VERSION;
|
|
init_params.create_group = CreateIsolateGroupAndSetup;
|
|
init_params.initialize_isolate = OnIsolateInitialize;
|
|
init_params.shutdown_isolate = OnIsolateShutdown;
|
|
init_params.cleanup_isolate = DeleteIsolateData;
|
|
init_params.cleanup_group = DeleteIsolateGroupData;
|
|
init_params.file_open = DartUtils::OpenFile;
|
|
init_params.file_read = DartUtils::ReadFile;
|
|
init_params.file_write = DartUtils::WriteFile;
|
|
init_params.file_close = DartUtils::CloseFile;
|
|
init_params.entropy_source = DartUtils::EntropySource;
|
|
init_params.start_kernel_isolate = false;
|
|
|
|
error = Dart_Initialize(&init_params);
|
|
if (error != nullptr) {
|
|
dart::embedder::Cleanup();
|
|
Syslog::PrintErr("VM initialization failed: %s\n", error);
|
|
free(error);
|
|
FreeConvertedArgs(argc, argv, argv_converted);
|
|
delete app_snapshot;
|
|
Platform::Exit(kErrorExitCode);
|
|
}
|
|
|
|
Dart_SetServiceStreamCallbacks(&ServiceStreamListenCallback,
|
|
&ServiceStreamCancelCallback);
|
|
Dart_SetFileModifiedCallback(&FileModifiedCallback);
|
|
Dart_SetEmbedderInformationCallback(&EmbedderInformationCallback);
|
|
|
|
// Run dartdev as the main isolate.
|
|
// The result from the running the dartdev isolate could result in one of
|
|
// these options
|
|
// - Exit the process due to some command parsing errors
|
|
// - Run the Dart script in a JIT mode by execing the JIT runtime
|
|
// - Run the Dart AOT snapshot by creating a new Isolate
|
|
DartDev::RunDartDev(script_name.get(), &dart_vm_options, &dart_options);
|
|
|
|
// Terminate process exit-code handler.
|
|
Process::TerminateExitCodeHandler();
|
|
|
|
error = Dart_Cleanup();
|
|
if (error != nullptr) {
|
|
Syslog::PrintErr("VM cleanup failed: %s\n", error);
|
|
free(error);
|
|
}
|
|
const intptr_t global_exit_code = Process::GlobalExitCode();
|
|
dart::embedder::Cleanup();
|
|
|
|
delete app_snapshot;
|
|
|
|
// Free copied argument strings if converted.
|
|
if (argv_converted) {
|
|
for (int i = 0; i < argc; i++) {
|
|
free(argv[i]);
|
|
}
|
|
}
|
|
|
|
// Free environment if any.
|
|
Options::Cleanup();
|
|
|
|
Platform::Exit(global_exit_code);
|
|
}
|
|
#else
|
|
void main(int argc, char** argv) {
|
|
Platform::Exit(kErrorExitCode);
|
|
}
|
|
#endif // defined(DART_PRECOMPILED_RUNTIME)
|
|
|
|
} // namespace bin
|
|
} // namespace dart
|
|
|
|
int main(int argc, char** argv) {
|
|
dart::bin::main(argc, argv);
|
|
UNREACHABLE();
|
|
}
|