[vm] Avoid allocating Monitor/Mutex/... with global initializer, use Init()/Cleanup() functions instead

This CL adds a `dart::embedder::Cleanup()` (we already have `dart::embedder::InitOnce()`).
This allows us to allocate the global state and also tear it down.

As a side-effect this will also not allocate those variables if not
needed, which should fix b/151210948

Change-Id: I3c5c619586380bf27ee863ba026bbc631f243d85
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/139640
Commit-Queue: Martin Kustermann <kustermann@google.com>
Reviewed-by: Vyacheslav Egorov <vegorov@google.com>
This commit is contained in:
Martin Kustermann
2020-03-17 08:49:52 +00:00
committed by commit-bot@chromium.org
parent db5dc11b9b
commit 0ae869771a
13 changed files with 339 additions and 28 deletions
+16
View File
@@ -7,6 +7,8 @@
#include "bin/dartutils.h"
#include "bin/eventhandler.h"
#include "bin/isolate_data.h"
#include "bin/process.h"
#include "bin/secure_socket_filter.h"
#include "bin/thread.h"
#include "bin/utils.h"
#include "bin/vmservice_impl.h"
@@ -37,10 +39,24 @@ bool InitOnce(char** error) {
return false;
}
bin::TimerUtils::InitOnce();
bin::Process::Init();
#if !defined(DART_IO_SECURE_SOCKET_DISABLED)
bin::SSLFilter::Init();
#endif
bin::EventHandler::Start();
return true;
}
void Cleanup() {
bin::Process::ClearAllSignalHandlers();
bin::EventHandler::Stop();
#if !defined(DART_IO_SECURE_SOCKET_DISABLED)
bin::SSLFilter::Cleanup();
#endif
bin::Process::Cleanup();
}
Dart_Isolate CreateKernelServiceIsolate(const IsolateCreationData& data,
const uint8_t* buffer,
intptr_t buffer_size,
+9
View File
@@ -10,6 +10,7 @@
#include "bin/io_natives.h"
#include "bin/platform.h"
#include "bin/process.h"
#include "bin/secure_socket_filter.h"
#include "bin/thread.h"
#include "bin/utils.h"
@@ -19,11 +20,19 @@ namespace bin {
void BootstrapDartIo() {
// Bootstrap 'dart:io' event handler.
TimerUtils::InitOnce();
Process::Init();
#if !defined(DART_IO_SECURE_SOCKET_DISABLED)
SSLFilter::Init();
#endif
EventHandler::Start();
}
void CleanupDartIo() {
EventHandler::Stop();
#if !defined(DART_IO_SECURE_SOCKET_DISABLED)
SSLFilter::Cleanup();
#endif
Process::Cleanup();
}
void SetSystemTempDirectory(const char* system_temp) {
+5 -6
View File
@@ -860,8 +860,7 @@ bool RunMainIsolate(const char* script_name, CommandLineOptions* dart_options) {
Syslog::PrintErr("VM cleanup failed: %s\n", error);
free(error);
}
Process::ClearAllSignalHandlers();
EventHandler::Stop();
dart::embedder::Cleanup();
Platform::Exit((exit_code != 0) ? exit_code : kErrorExitCode);
}
main_isolate = isolate;
@@ -1190,7 +1189,7 @@ void main(int argc, char** argv) {
error = Dart_Initialize(&init_params);
if (error != NULL) {
EventHandler::Stop();
dart::embedder::Cleanup();
Syslog::PrintErr("VM initialization failed: %s\n", error);
free(error);
Platform::Exit(kErrorExitCode);
@@ -1214,8 +1213,8 @@ void main(int argc, char** argv) {
Syslog::PrintErr("VM cleanup failed: %s\n", error);
free(error);
}
Process::ClearAllSignalHandlers();
EventHandler::Stop();
const intptr_t global_exit_code = Process::GlobalExitCode();
dart::embedder::Cleanup();
delete app_snapshot;
free(app_script_uri);
@@ -1230,7 +1229,7 @@ void main(int argc, char** argv) {
// Free environment if any.
Options::DestroyEnvironment();
Platform::Exit(Process::GlobalExitCode());
Platform::Exit(global_exit_code);
}
} // namespace bin
+3
View File
@@ -87,6 +87,9 @@ enum ProcessStartMode {
class Process {
public:
static void Init();
static void Cleanup();
// Start a new process providing access to stdin, stdout, stderr and
// process exit streams.
static int Start(Namespace* namespc,
+58 -4
View File
@@ -35,7 +35,7 @@ namespace dart {
namespace bin {
int Process::global_exit_code_ = 0;
Mutex* Process::global_exit_code_mutex_ = new Mutex();
Mutex* Process::global_exit_code_mutex_ = nullptr;
Process::ExitHook Process::exit_hook_ = NULL;
// ProcessInfo is used to map a process id to the file descriptor for
@@ -68,6 +68,9 @@ class ProcessInfo {
// started from Dart.
class ProcessInfoList {
public:
static void Init();
static void Cleanup();
static void AddProcess(pid_t pid, intptr_t fd) {
MutexLocker locker(mutex_);
ProcessInfo* info = new ProcessInfo(pid, fd);
@@ -119,7 +122,7 @@ class ProcessInfoList {
};
ProcessInfo* ProcessInfoList::active_processes_ = NULL;
Mutex* ProcessInfoList::mutex_ = new Mutex();
Mutex* ProcessInfoList::mutex_ = nullptr;
// The exit code handler sets up a separate thread which waits for child
// processes to terminate. That separate thread can then get the exit code from
@@ -127,6 +130,9 @@ Mutex* ProcessInfoList::mutex_ = new Mutex();
// event loop.
class ExitCodeHandler {
public:
static void Init();
static void Cleanup();
// Notify the ExitCodeHandler that another process exists.
static void ProcessStarted() {
// Multiple isolates could be starting processes at the same
@@ -241,7 +247,7 @@ class ExitCodeHandler {
bool ExitCodeHandler::running_ = false;
int ExitCodeHandler::process_count_ = 0;
bool ExitCodeHandler::terminate_done_ = false;
Monitor* ExitCodeHandler::monitor_ = new Monitor();
Monitor* ExitCodeHandler::monitor_ = nullptr;
class ProcessStarter {
public:
@@ -953,7 +959,7 @@ int64_t Process::MaxRSS() {
return usage.ru_maxrss * KB;
}
static Mutex* signal_mutex = new Mutex();
static Mutex* signal_mutex = nullptr;
static SignalInfo* signal_handlers = NULL;
static const int kSignalsCount = 7;
static const int kSignals[kSignalsCount] = {
@@ -1057,6 +1063,54 @@ void Process::ClearSignalHandler(intptr_t signal, Dart_Port port) {
}
}
void ProcessInfoList::Init() {
ASSERT(ProcessInfoList::mutex_ == nullptr);
ProcessInfoList::mutex_ = new Mutex();
}
void ProcessInfoList::Cleanup() {
ASSERT(ProcessInfoList::mutex_ != nullptr);
delete ProcessInfoList::mutex_;
ProcessInfoList::mutex_ = nullptr;
}
void ExitCodeHandler::Init() {
ASSERT(ExitCodeHandler::monitor_ == nullptr);
ExitCodeHandler::monitor_ = new Monitor();
}
void ExitCodeHandler::Cleanup() {
ASSERT(ExitCodeHandler::monitor_ != nullptr);
delete ExitCodeHandler::monitor_;
ExitCodeHandler::monitor_ = nullptr;
}
void Process::Init() {
ExitCodeHandler::Init();
ProcessInfoList::Init();
ASSERT(signal_mutex == nullptr);
signal_mutex = new Mutex();
ASSERT(Process::global_exit_code_mutex_ == nullptr);
Process::global_exit_code_mutex_ = new Mutex();
}
void Process::Cleanup() {
ClearAllSignalHandlers();
ASSERT(signal_mutex != nullptr);
delete signal_mutex;
signal_mutex = nullptr;
ASSERT(Process::global_exit_code_mutex_ != nullptr);
delete Process::global_exit_code_mutex_;
Process::global_exit_code_mutex_ = nullptr;
ProcessInfoList::Cleanup();
ExitCodeHandler::Cleanup();
}
} // namespace bin
} // namespace dart
+51 -3
View File
@@ -50,7 +50,7 @@ namespace dart {
namespace bin {
int Process::global_exit_code_ = 0;
Mutex* Process::global_exit_code_mutex_ = new Mutex();
Mutex* Process::global_exit_code_mutex_ = nullptr;
Process::ExitHook Process::exit_hook_ = NULL;
// ProcessInfo is used to map a process id to the file descriptor for
@@ -140,7 +140,7 @@ class ProcessInfoList {
};
ProcessInfo* ProcessInfoList::active_processes_ = NULL;
Mutex* ProcessInfoList::mutex_ = new Mutex();
Mutex* ProcessInfoList::mutex_ = nullptr;
// The exit code handler sets up a separate thread which waits for child
// processes to terminate. That separate thread can then get the exit code from
@@ -297,7 +297,7 @@ class ExitCodeHandler {
zx_handle_t ExitCodeHandler::port_ = ZX_HANDLE_INVALID;
bool ExitCodeHandler::running_ = false;
bool ExitCodeHandler::terminate_done_ = false;
Monitor* ExitCodeHandler::monitor_ = new Monitor();
Monitor* ExitCodeHandler::monitor_ = nullptr;
void Process::TerminateExitCodeHandler() {
ExitCodeHandler::Terminate();
@@ -812,6 +812,54 @@ intptr_t Process::SetSignalHandler(intptr_t signal) {
void Process::ClearSignalHandler(intptr_t signal, Dart_Port port) {}
void ProcessInfoList::Init() {
ASSERT(ProcessInfoList::mutex_ == nullptr);
ProcessInfoList::mutex_ = new Mutex();
}
void ProcessInfoList::Cleanup() {
ASSERT(ProcessInfoList::mutex_ != nullptr);
delete ProcessInfoList::mutex_;
ProcessInfoList::mutex_ = nullptr;
}
void ExitCodeHandler::Init() {
ASSERT(ExitCodeHandler::monitor_ == nullptr);
ExitCodeHandler::monitor_ = new Monitor();
}
void ExitCodeHandler::Cleanup() {
ASSERT(ExitCodeHandler::monitor_ != nullptr);
delete ExitCodeHandler::monitor_;
ExitCodeHandler::monitor_ = nullptr;
}
void Process::Init() {
ExitCodeHandler::Init();
ProcessInfoList::Init();
ASSERT(signal_mutex == nullptr);
signal_mutex = new Mutex();
ASSERT(Process::global_exit_code_mutex_ == nullptr);
Process::global_exit_code_mutex_ = new Mutex();
}
void Process::Cleanup() {
ClearAllSignalHandlers();
ASSERT(signal_mutex != nullptr);
delete signal_mutex;
signal_mutex = nullptr;
ASSERT(Process::global_exit_code_mutex_ != nullptr);
delete Process::global_exit_code_mutex_;
Process::global_exit_code_mutex_ = nullptr;
ProcessInfoList::Cleanup();
ExitCodeHandler::Cleanup();
}
} // namespace bin
} // namespace dart
+58 -4
View File
@@ -35,7 +35,7 @@ namespace dart {
namespace bin {
int Process::global_exit_code_ = 0;
Mutex* Process::global_exit_code_mutex_ = new Mutex();
Mutex* Process::global_exit_code_mutex_ = nullptr;
Process::ExitHook Process::exit_hook_ = NULL;
// ProcessInfo is used to map a process id to the file descriptor for
@@ -68,6 +68,9 @@ class ProcessInfo {
// started from Dart.
class ProcessInfoList {
public:
static void Init();
static void Cleanup();
static void AddProcess(pid_t pid, intptr_t fd) {
MutexLocker locker(mutex_);
ProcessInfo* info = new ProcessInfo(pid, fd);
@@ -119,7 +122,7 @@ class ProcessInfoList {
};
ProcessInfo* ProcessInfoList::active_processes_ = NULL;
Mutex* ProcessInfoList::mutex_ = new Mutex();
Mutex* ProcessInfoList::mutex_ = nullptr;
// The exit code handler sets up a separate thread which waits for child
// processes to terminate. That separate thread can then get the exit code from
@@ -127,6 +130,9 @@ Mutex* ProcessInfoList::mutex_ = new Mutex();
// event loop.
class ExitCodeHandler {
public:
static void Init();
static void Cleanup();
// Notify the ExitCodeHandler that another process exists.
static void ProcessStarted() {
// Multiple isolates could be starting processes at the same
@@ -241,7 +247,7 @@ class ExitCodeHandler {
bool ExitCodeHandler::running_ = false;
int ExitCodeHandler::process_count_ = 0;
bool ExitCodeHandler::terminate_done_ = false;
Monitor* ExitCodeHandler::monitor_ = new Monitor();
Monitor* ExitCodeHandler::monitor_ = nullptr;
class ProcessStarter {
public:
@@ -952,7 +958,7 @@ int64_t Process::MaxRSS() {
return usage.ru_maxrss * KB;
}
static Mutex* signal_mutex = new Mutex();
static Mutex* signal_mutex = nullptr;
static SignalInfo* signal_handlers = NULL;
static const int kSignalsCount = 7;
static const int kSignals[kSignalsCount] = {
@@ -1053,6 +1059,54 @@ void Process::ClearSignalHandler(intptr_t signal, Dart_Port port) {
}
}
void ProcessInfoList::Init() {
ASSERT(ProcessInfoList::mutex_ == nullptr);
ProcessInfoList::mutex_ = new Mutex();
}
void ProcessInfoList::Cleanup() {
ASSERT(ProcessInfoList::mutex_ != nullptr);
delete ProcessInfoList::mutex_;
ProcessInfoList::mutex_ = nullptr;
}
void ExitCodeHandler::Init() {
ASSERT(ExitCodeHandler::monitor_ == nullptr);
ExitCodeHandler::monitor_ = new Monitor();
}
void ExitCodeHandler::Cleanup() {
ASSERT(ExitCodeHandler::monitor_ != nullptr);
delete ExitCodeHandler::monitor_;
ExitCodeHandler::monitor_ = nullptr;
}
void Process::Init() {
ExitCodeHandler::Init();
ProcessInfoList::Init();
ASSERT(signal_mutex == nullptr);
signal_mutex = new Mutex();
ASSERT(Process::global_exit_code_mutex_ == nullptr);
Process::global_exit_code_mutex_ = new Mutex();
}
void Process::Cleanup() {
ClearAllSignalHandlers();
ASSERT(signal_mutex != nullptr);
delete signal_mutex;
signal_mutex = nullptr;
ASSERT(Process::global_exit_code_mutex_ != nullptr);
delete Process::global_exit_code_mutex_;
Process::global_exit_code_mutex_ = nullptr;
ProcessInfoList::Cleanup();
ExitCodeHandler::Cleanup();
}
} // namespace bin
} // namespace dart
+58 -4
View File
@@ -34,7 +34,7 @@ namespace dart {
namespace bin {
int Process::global_exit_code_ = 0;
Mutex* Process::global_exit_code_mutex_ = new Mutex();
Mutex* Process::global_exit_code_mutex_ = nullptr;
Process::ExitHook Process::exit_hook_ = NULL;
// ProcessInfo is used to map a process id to the file descriptor for
@@ -67,6 +67,9 @@ class ProcessInfo {
// started from Dart.
class ProcessInfoList {
public:
static void Init();
static void Cleanup();
static void AddProcess(pid_t pid, intptr_t fd) {
MutexLocker locker(mutex_);
ProcessInfo* info = new ProcessInfo(pid, fd);
@@ -118,7 +121,7 @@ class ProcessInfoList {
};
ProcessInfo* ProcessInfoList::active_processes_ = NULL;
Mutex* ProcessInfoList::mutex_ = new Mutex();
Mutex* ProcessInfoList::mutex_ = nullptr;
// The exit code handler sets up a separate thread which waits for child
// processes to terminate. That separate thread can then get the exit code from
@@ -126,6 +129,9 @@ Mutex* ProcessInfoList::mutex_ = new Mutex();
// event loop.
class ExitCodeHandler {
public:
static void Init();
static void Cleanup();
// Notify the ExitCodeHandler that another process exists.
static void ProcessStarted() {
// Multiple isolates could be starting processes at the same
@@ -237,7 +243,7 @@ class ExitCodeHandler {
bool ExitCodeHandler::running_ = false;
int ExitCodeHandler::process_count_ = 0;
bool ExitCodeHandler::terminate_done_ = false;
Monitor* ExitCodeHandler::monitor_ = new Monitor();
Monitor* ExitCodeHandler::monitor_ = nullptr;
class ProcessStarter {
public:
@@ -976,7 +982,7 @@ int64_t Process::MaxRSS() {
return usage.ru_maxrss;
}
static Mutex* signal_mutex = new Mutex();
static Mutex* signal_mutex = nullptr;
static SignalInfo* signal_handlers = NULL;
static const int kSignalsCount = 7;
static const int kSignals[kSignalsCount] = {
@@ -1089,6 +1095,54 @@ void Process::ClearSignalHandler(intptr_t signal, Dart_Port port) {
}
}
void ProcessInfoList::Init() {
ASSERT(ProcessInfoList::mutex_ == nullptr);
ProcessInfoList::mutex_ = new Mutex();
}
void ProcessInfoList::Cleanup() {
ASSERT(ProcessInfoList::mutex_ != nullptr);
delete ProcessInfoList::mutex_;
ProcessInfoList::mutex_ = nullptr;
}
void ExitCodeHandler::Init() {
ASSERT(ExitCodeHandler::monitor_ == nullptr);
ExitCodeHandler::monitor_ = new Monitor();
}
void ExitCodeHandler::Cleanup() {
ASSERT(ExitCodeHandler::monitor_ != nullptr);
delete ExitCodeHandler::monitor_;
ExitCodeHandler::monitor_ = nullptr;
}
void Process::Init() {
ExitCodeHandler::Init();
ProcessInfoList::Init();
ASSERT(signal_mutex == nullptr);
signal_mutex = new Mutex();
ASSERT(Process::global_exit_code_mutex_ == nullptr);
Process::global_exit_code_mutex_ = new Mutex();
}
void Process::Cleanup() {
ClearAllSignalHandlers();
ASSERT(signal_mutex != nullptr);
delete signal_mutex;
signal_mutex = nullptr;
ASSERT(Process::global_exit_code_mutex_ != nullptr);
delete Process::global_exit_code_mutex_;
Process::global_exit_code_mutex_ = nullptr;
ProcessInfoList::Cleanup();
ExitCodeHandler::Cleanup();
}
} // namespace bin
} // namespace dart
+52 -6
View File
@@ -27,7 +27,7 @@ static const int kReadHandle = 0;
static const int kWriteHandle = 1;
int Process::global_exit_code_ = 0;
Mutex* Process::global_exit_code_mutex_ = new Mutex();
Mutex* Process::global_exit_code_mutex_ = nullptr;
Process::ExitHook Process::exit_hook_ = NULL;
// ProcessInfo is used to map a process id to the process handle,
@@ -84,6 +84,9 @@ class ProcessInfo {
// started from Dart.
class ProcessInfoList {
public:
static void Init();
static void Cleanup();
static void AddProcess(DWORD pid, HANDLE handle, HANDLE pipe) {
// Register a callback to extract the exit code, when the process
// is signaled. The callback runs in a independent thread from the OS pool.
@@ -199,7 +202,7 @@ class ProcessInfoList {
};
ProcessInfo* ProcessInfoList::active_processes_ = NULL;
Mutex* ProcessInfoList::mutex_ = new Mutex();
Mutex* ProcessInfoList::mutex_ = nullptr;
// Types of pipes to create.
enum NamedPipeType { kInheritRead, kInheritWrite, kInheritNone };
@@ -331,12 +334,13 @@ static InitProcThreadAttrListFn init_proc_thread_attr_list = NULL;
static UpdateProcThreadAttrFn update_proc_thread_attr = NULL;
static DeleteProcThreadAttrListFn delete_proc_thread_attr_list = NULL;
static Mutex* initialized_mutex = nullptr;
static bool load_attempted = false;
static bool EnsureInitialized() {
static bool load_attempted = false;
static Mutex* mutex = new Mutex();
HMODULE kernel32_module = GetModuleHandleW(L"kernel32.dll");
if (!load_attempted) {
MutexLocker locker(mutex);
MutexLocker locker(initialized_mutex);
if (load_attempted) {
return (delete_proc_thread_attr_list != NULL);
}
@@ -943,7 +947,7 @@ int64_t Process::MaxRSS() {
}
static SignalInfo* signal_handlers = NULL;
static Mutex* signal_mutex = new Mutex();
static Mutex* signal_mutex = nullptr;
SignalInfo::~SignalInfo() {
FileHandle* file_handle = reinterpret_cast<FileHandle*>(fd_);
@@ -1051,6 +1055,48 @@ void Process::ClearSignalHandler(intptr_t signal, Dart_Port port) {
}
}
void ProcessInfoList::Init() {
ASSERT(ProcessInfoList::mutex_ == nullptr);
ProcessInfoList::mutex_ = new Mutex();
}
void ProcessInfoList::Cleanup() {
ASSERT(ProcessInfoList::mutex_ != nullptr);
delete ProcessInfoList::mutex_;
ProcessInfoList::mutex_ = nullptr;
}
void Process::Init() {
ProcessInfoList::Init();
ASSERT(signal_mutex == nullptr);
signal_mutex = new Mutex();
ASSERT(initialized_mutex == nullptr);
initialized_mutex = new Mutex();
ASSERT(Process::global_exit_code_mutex_ == nullptr);
Process::global_exit_code_mutex_ = new Mutex();
}
void Process::Cleanup() {
ClearAllSignalHandlers();
ASSERT(signal_mutex != nullptr);
delete signal_mutex;
signal_mutex = nullptr;
ASSERT(initialized_mutex != nullptr);
delete initialized_mutex;
initialized_mutex = nullptr;
ASSERT(Process::global_exit_code_mutex_ != nullptr);
delete Process::global_exit_code_mutex_;
Process::global_exit_code_mutex_ = nullptr;
ProcessInfoList::Cleanup();
}
} // namespace bin
} // namespace dart
+4
View File
@@ -10,6 +10,7 @@
#include "bin/file.h"
#include "bin/loader.h"
#include "bin/platform.h"
#include "bin/process.h"
#include "bin/snapshot_utils.h"
#include "bin/thread.h"
#include "bin/utils.h"
@@ -355,6 +356,7 @@ static int Main(int argc, const char** argv) {
}
bin::TimerUtils::InitOnce();
bin::Process::Init();
bin::EventHandler::Start();
char* error = Flags::ProcessCommandLineFlags(dart_argc, dart_argv);
@@ -393,6 +395,7 @@ static int Main(int argc, const char** argv) {
// Apply the filter to all registered benchmarks.
Benchmark::RunAll(argv[0]);
bin::Process::TerminateExitCodeHandler();
error = Dart::Cleanup();
if (error != nullptr) {
Syslog::PrintErr("Failed shutdown VM: %s\n", error);
@@ -403,6 +406,7 @@ static int Main(int argc, const char** argv) {
TestCaseBase::RunAllRaw();
bin::EventHandler::Stop();
bin::Process::Cleanup();
// Print a warning message if no tests or benchmarks were matched.
if (run_matches == 0) {
+12 -1
View File
@@ -30,9 +30,20 @@ namespace bin {
bool SSLFilter::library_initialized_ = false;
// To protect library initialization.
Mutex* SSLFilter::mutex_ = new Mutex();
Mutex* SSLFilter::mutex_ = nullptr;
int SSLFilter::filter_ssl_index;
void SSLFilter::Init() {
ASSERT(SSLFilter::mutex_ == nullptr);
SSLFilter::mutex_ = new Mutex();
}
void SSLFilter::Cleanup() {
ASSERT(SSLFilter::mutex_ != nullptr);
delete SSLFilter::mutex_;
SSLFilter::mutex_ = nullptr;
}
const intptr_t SSLFilter::kInternalBIOSize = 10 * KB;
const intptr_t SSLFilter::kApproximateSize =
sizeof(SSLFilter) + (2 * SSLFilter::kInternalBIOSize);
+3
View File
@@ -23,6 +23,9 @@ extern unsigned int root_certificates_pem_length;
class SSLFilter : public ReferenceCounted<SSLFilter> {
public:
static void Init();
static void Cleanup();
// These enums must agree with those in sdk/lib/io/secure_socket.dart.
enum BufferIndex {
kReadPlaintext,
+10
View File
@@ -12,10 +12,20 @@ namespace dart {
namespace embedder {
// Initialize all subsystems of the embedder.
//
// Must be called before the `Dart_Initialize()` call to initialize the
// Dart VM.
//
// Returns true on success and false otherwise, in which case error would
// contain error message.
DART_WARN_UNUSED_RESULT bool InitOnce(char** error);
// Cleans up all subsystems of the embedder.
//
// Must be called after the `Dart_Cleanup()` call to initialize the
// Dart VM.
void Cleanup();
// Common arguments that are passed to isolate creation callback and to
// API methods that create isolates.
struct IsolateCreationData {