Dart Engine

Adds shared libraries for embedding Dart VM and new API (runtime/engine/include/dart_engine.h).

TEST=tests/standalone/embedder_samples_test.dart

Cq-Include-Trybots: luci.dart.try:vm-aot-android-release-arm64c-try,vm-aot-android-release-arm_x64-try,vm-aot-asan-linux-release-x64-try,vm-aot-dwarf-linux-product-x64-try,vm-aot-dyn-linux-debug-x64-try,vm-aot-linux-debug-simarm_x64-try,vm-aot-linux-debug-simriscv32-try,vm-aot-linux-debug-simriscv64-try,vm-aot-linux-debug-x64-try,vm-aot-linux-debug-x64c-try,vm-aot-linux-product-x64-try,vm-aot-linux-release-arm64-try,vm-aot-linux-release-simarm_x64-try,vm-aot-linux-release-x64-try,vm-aot-mac-product-arm64-try,vm-aot-mac-release-arm64-try,vm-aot-mac-release-x64-try,vm-aot-msan-linux-release-x64-try,vm-aot-obfuscate-linux-release-x64-try,vm-aot-optimization-level-linux-release-x64-try,vm-aot-tsan-linux-release-x64-try,vm-aot-ubsan-linux-release-x64-try,vm-aot-win-debug-x64-try,vm-aot-win-debug-x64c-try,vm-aot-win-product-x64-try,vm-aot-win-release-x64-try,vm-appjit-linux-debug-x64-try,vm-appjit-linux-product-x64-try,vm-appjit-linux-release-x64-try,vm-asan-linux-release-arm64-try,vm-asan-linux-release-x64-try,vm-checked-mac-release-arm64-try,vm-eager-optimization-linux-release-ia32-try,vm-eager-optimization-linux-release-x64-try,vm-ffi-android-debug-arm-try,vm-ffi-android-debug-arm64c-try,vm-ffi-android-product-arm-try,vm-ffi-android-product-arm64c-try,vm-ffi-android-release-arm-try,vm-ffi-android-release-arm64c-try,vm-ffi-qemu-linux-release-arm-try,vm-ffi-qemu-linux-release-riscv64-try,vm-fuchsia-release-arm64-try,vm-fuchsia-release-x64-try,vm-gcc-linux-try,vm-linux-debug-ia32-try,vm-linux-debug-simriscv32-try,vm-linux-debug-simriscv64-try,vm-linux-debug-x64-try,vm-linux-debug-x64c-try,vm-linux-release-arm64-try,vm-linux-release-ia32-try,vm-linux-release-simarm-try,vm-linux-release-x64-try,vm-mac-debug-arm64-try,vm-mac-debug-x64-try,vm-mac-release-arm64-try,vm-mac-release-x64-try,vm-msan-linux-release-arm64-try,vm-msan-linux-release-x64-try,vm-msvc-windows-try,vm-reload-linux-debug-x64-try,vm-reload-linux-release-x64-try,vm-reload-rollback-linux-debug-x64-try,vm-reload-rollback-linux-release-x64-try,vm-tsan-linux-release-arm64-try,vm-tsan-linux-release-x64-try,vm-ubsan-linux-release-arm64-try,vm-ubsan-linux-release-x64-try,vm-win-debug-x64-try,vm-win-debug-x64c-try,vm-win-release-ia32-try,vm-win-release-x64-try
Change-Id: Ia4e4d1b871ddef515cfb2f4639bdaa9fe3676936
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/402860
Reviewed-by: Slava Egorov <vegorov@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
Commit-Queue: Martin Kustermann <kustermann@google.com>
This commit is contained in:
Ivan Inozemtsev
2025-01-28 03:53:40 -08:00
committed by Commit Queue
parent 79df09999e
commit 6e33c95463
31 changed files with 1634 additions and 197 deletions
+129 -10
View File
@@ -2,24 +2,143 @@
# 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.
import("../../utils/aot_snapshot.gni")
import("../../utils/application_snapshot.gni")
# All samples.
group("all") {
deps = [ ":run_kernel" ]
deps = [
":aot",
":kernel",
]
}
group("aot") {
deps = [
":run_main_aot",
":run_timer_aot",
":run_timer_async_aot",
":run_two_programs_aot",
]
}
group("kernel") {
deps = [
":run_main_kernel",
":run_timer_async_kernel",
":run_timer_kernel",
":run_two_programs_kernel",
]
}
# Generates a pair of executables for kernel and AOT snapshots.
template("sample") {
executable("${target_name}_kernel") {
# Otherwise build with --no-clang fails.
if (is_linux) {
ldflags = [ "-Wl,--allow-shlib-undefined" ]
}
include_dirs = [
"../../runtime",
"../../runtime/engine",
]
deps = [ "../../runtime/engine:dart_engine_jit_shared" ]
if (defined(invoker.deps)) {
deps += invoker.deps
}
data_deps = []
foreach(snapshot, invoker.snapshots) {
data_deps += [ "${snapshot}_kernel" ]
}
forward_variables_from(invoker,
"*",
[
"snapshots",
"deps",
"data_deps",
])
}
executable("${target_name}_aot") {
# Otherwise build with MSAN fails.
if (is_linux) {
ldflags = [ "-Wl,--allow-shlib-undefined" ]
}
include_dirs = [
"../../runtime",
"../../runtime/engine",
]
deps = [ "../../runtime/engine:dart_engine_aot_shared" ]
if (defined(invoker.deps)) {
deps += invoker.deps
}
data_deps = []
foreach(snapshot, invoker.snapshots) {
data_deps += [ "${snapshot}_aot" ]
}
forward_variables_from(invoker,
"*",
[
"snapshots",
"deps",
"data_deps",
])
}
}
# For a given main_dart generates Kernel and AOT snapshots
template("snapshots") {
# Kernel snapshot
application_snapshot("${target_name}_kernel") {
main_dart = invoker.main_dart
dart_snapshot_kind = "kernel"
training_args = [] # Not used
gen_kernel_args = [ "--link-platform" ]
}
# AOT snapshot
aot_snapshot("${target_name}_aot") {
main_dart = invoker.main_dart
}
}
# Sample binary to run given kernel snapshot.
executable("run_kernel") {
sources = [ "run_kernel.cc" ]
deps = [ "../../runtime/bin:dart_embedder_runtime_jit" ]
include_dirs = [ "../../runtime" ]
data_deps = [ ":hello_kernel" ]
sample("run_main") {
sources = [ "run_main.cc" ]
snapshots = [ ":hello" ]
}
# Kernel snapshot of ./hello.dart.
application_snapshot("hello_kernel") {
snapshots("hello") {
main_dart = "hello.dart"
dart_snapshot_kind = "kernel"
training_args = [] # Not used
}
# Sample binary to run two snapshots simultaneously.
sample("run_two_programs") {
sources = [ "run_two_programs.cc" ]
snapshots = [
":program1",
":program2",
]
}
snapshots("program1") {
main_dart = "program1.dart"
}
snapshots("program2") {
main_dart = "program2.dart"
}
sample("run_timer") {
sources = [ "run_timer.cc" ]
snapshots = [ ":timer" ]
}
sample("run_timer_async") {
sources = [ "run_timer_async.cc" ]
snapshots = [ ":timer" ]
}
snapshots("timer") {
main_dart = "timer.dart"
}
+31 -14
View File
@@ -2,26 +2,43 @@
Examples of using Dart VM and executing Dart code from C++ binaries.
## run_kernel.cc
All examples can run either AOT or Kernel snapshots, depending on
which shared library variant they depend on.
To run the example:
Since snapshot file formats are unstable, the `dart` binary needs to
be of a matching version. The simplest way to ensure this is to build
Dart SDK from the same checkout, see [Building Dart
SDK](https://github.com/dart-lang/sdk/blob/main/docs/Building.md#building).
## `run_main.cc`
This is the simplest example, which just calls a `main` function from a given AOT/Kernel
snapshot. It does not handle isolate messages, so it cannot run Dart
programs with async functions.
To run the example with a Kernel snapshot:
```sh
./tools/build.py --no-rbe --mode=release samples/embedder:run_kernel && out/ReleaseX64/run_kernel
./tools/build.py --mode=release samples/embedder:run_main_kernel && \
out/ReleaseX64/run_main_kernel out/ReleaseX64/gen/hello_kernel.dart.snapshot.
```
The example initializes Dart VM, creates an isolate from a kernel file (by
default it uses kernel-compiled `hello.dart`), launches its `main` function with
args and exits.
You can also compile your own Dart kernel like this:
To run the example with an AOT snapshot:
```sh
dart compile kernel --no-link-platform my.dart
out/ReleaseX64/run_kernel my.dill
./tools/build.py --mode=release samples/embedder:run_main_aot && \
out/ReleaseX64/run_main_aot out/ReleaseX64/hello_aot.snapshot.
```
Since the kernel file format is unstable, the `dart` binary needs to be of a
matching version. The simplest way to ensure this is to build Dart SDK from the
same checkout, see
[Building Dart SDK](https://github.com/dart-lang/sdk/blob/main/docs/Building.md#building).
## `run_two_programs.cc`
This example calls a function from one Dart snapshot and then passes
the returned string to another Dart snapshot.
## `run_timer.cc`
Demonstrates running an isolate event loop in a separate thread.
## `run_timer_async.cc`
Demonstrates a custom message scheduler using `std::async`.
+7 -6
View File
@@ -2,10 +2,11 @@
// 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.
import 'package:collection/collection.dart';
@pragma('vm:entry-point')
void main(List<String>? args) {
final greetee = args?.singleOrNull ?? 'world';
print('Hello, $greetee!');
@pragma('vm:entry-point', 'call')
void main(List<String> args) {
greet(args[0]);
}
void greet(String person) {
print("hi, $person!");
}
+94
View File
@@ -0,0 +1,94 @@
/*
* 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.
*/
#ifndef SAMPLES_EMBEDDER_HELPERS_H_
#define SAMPLES_EMBEDDER_HELPERS_H_
#include <functional>
#include <iostream>
#include <string>
#include <string_view>
#include "include/dart_api.h"
#include "include/dart_engine.h"
// Loads kernel/AOT snapshot from path depending on
// whether we use precompiled runtime.
inline DartEngine_SnapshotData AutoSnapshotFromFile(std::string_view path,
char** error) {
std::string path_string(path);
if (Dart_IsPrecompiledRuntime()) {
return DartEngine_AotSnapshotFromFile(path_string.c_str(), error);
} else {
return DartEngine_KernelFromFile(path_string.c_str(), error);
}
}
inline void CheckError(char* error, std::string_view context = "") {
if (error != nullptr) {
std::cerr << "Error " << context << ": " << error << std::endl;
std::exit(1);
}
}
inline Dart_Handle CheckError(Dart_Handle handle,
std::string_view context = "") {
if (Dart_IsError(handle)) {
std::cerr << "Error " << context << ": " << Dart_GetError(handle)
<< std::endl;
std::exit(1);
}
return handle;
}
inline std::string StringFromHandle(Dart_Handle handle) {
CheckError(handle, "StringFromHandle received an error");
if (!Dart_IsString(handle)) {
std::cerr << "StringFromHandle handle is not a string" << std::endl;
std::exit(1);
}
const char* return_value_tmp;
Dart_Handle to_string_result =
Dart_StringToCString(handle, &return_value_tmp);
CheckError(to_string_result, "Dart_StringToCString");
return std::string(return_value_tmp);
}
inline int64_t IntFromHandle(Dart_Handle handle) {
CheckError(handle, "IntFromHandle received an error");
if (!Dart_IsInteger(handle)) {
std::cerr << "IntFromHandle handle is not an int" << std::endl;
std::exit(1);
}
int64_t result;
Dart_Handle to_int64_result = Dart_IntegerToInt64(handle, &result);
CheckError(to_int64_result, "Dart_IntegerToInt64");
return result;
}
template <typename T>
inline T WithIsolate(Dart_Isolate isolate, std::function<T()> body) {
DartEngine_AcquireIsolate(isolate);
Dart_EnterScope();
T result = body();
Dart_ExitScope();
DartEngine_ReleaseIsolate();
return result;
}
inline void WithIsolate(Dart_Isolate isolate, std::function<void()> body) {
DartEngine_AcquireIsolate(isolate);
Dart_EnterScope();
body();
Dart_ExitScope();
DartEngine_ReleaseIsolate();
}
#endif /* SAMPLES_EMBEDDER_HELPERS_H_ */
+8
View File
@@ -0,0 +1,8 @@
void main(List<String> args) {
throw 'Unimplemented';
}
@pragma('vm:entry-point', 'call')
String getValue() {
return 'program1';
}
+8
View File
@@ -0,0 +1,8 @@
void main(List<String> args) {
throw 'Unimplemented';
}
@pragma('vm:entry-point', 'call')
void printValue(String value) {
print('program2 received: $value');
}
-157
View File
@@ -1,157 +0,0 @@
// Copyright (c) 2024, 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.
// Executes `main` function from given Dart kernel binary (by default uses
// compiled ./hello.dart).
#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <iostream>
#include <vector>
#include "bin/dartutils.h"
#include "bin/dfe.h"
#include "bin/platform.h"
#include "include/dart_api.h"
#include "include/dart_embedder_api.h"
#include "platform/assert.h"
Dart_Handle CheckHandle(Dart_Handle handle,
const char* context = "unknown context") {
if (Dart_IsError(handle)) {
FATAL("Dart error (%s): %s", context, Dart_GetError(handle));
}
return handle;
}
void CheckError(bool condition, const char* error, const char* context) {
if (!condition) {
FATAL("Dart error (%s): %s", context, error);
}
}
void CheckError(const char* error, const char* context) {
if (error != nullptr) {
FATAL("Dart error (%s): %s", context, error);
}
}
Dart_InitializeParams CreateInitializeParams() {
Dart_InitializeParams params;
memset(&params, 0, sizeof(params));
params.version = DART_INITIALIZE_PARAMS_CURRENT_VERSION;
return params;
}
std::string GetExecutablePath() {
const size_t kPathBufSize = PATH_MAX + 1;
char executable_path[kPathBufSize] = {};
intptr_t path_length = dart::bin::Platform::ResolveExecutablePathInto(
executable_path, kPathBufSize);
CheckError(path_length > 0, "empty executable path",
"ResolveExecutablePathInfo");
return std::string(executable_path, path_length);
}
std::string GetDefaultSnapshotPath() {
std::string executable_path = GetExecutablePath();
std::string directory =
executable_path.substr(0, executable_path.find_last_of("/\\"));
return directory + "/gen/hello_kernel.dart.snapshot";
}
std::string ReadSnapshot(std::string_view path) {
std::string path_string{path};
std::ifstream source_file{path_string, std::ios::binary};
ASSERT(source_file.good());
source_file.seekg(0, source_file.end);
uint64_t length = source_file.tellg();
source_file.seekg(0, source_file.beg);
char* bytes = static_cast<char*>(std::malloc(length));
source_file.read(bytes, length);
auto result = std::string(bytes, length);
std::free(bytes);
return result;
}
Dart_Handle ToDartStringList(const std::vector<std::string>& values) {
Dart_Handle string_type =
CheckHandle(dart::bin::DartUtils::GetDartType("dart:core", "String"));
Dart_Handle filler = CheckHandle(Dart_NewStringFromCString(""));
Dart_Handle result =
CheckHandle(Dart_NewListOfTypeFilled(string_type, filler, values.size()));
for (size_t i = 0; i < values.size(); i++) {
Dart_Handle element =
CheckHandle(Dart_NewStringFromCString(values[i].c_str()));
CheckHandle(Dart_ListSetAt(result, i, element));
}
return result;
}
int main(int argc, char** argv) {
std::string snapshot_path =
argc == 1 ? GetDefaultSnapshotPath() : std::string(argv[1]);
std::string snapshot_name =
snapshot_path.substr(snapshot_path.find_last_of("/\\") + 1);
std::string snapshot_data = ReadSnapshot(snapshot_path);
std::string snapshot_uri = "file://" + snapshot_path;
std::cout << "Snapshot path: " << snapshot_path << std::endl;
char* error;
// Start Dart VM.
bool result = dart::embedder::InitOnce(&error);
CheckError(result, error, "dart::embedder::InitOnce");
std::vector<const char*> flags{};
CheckError(Dart_SetVMFlags(flags.size(), flags.data()), "Dart_SetVMFlags");
Dart_InitializeParams initialize_params = CreateInitializeParams();
CheckError(Dart_Initialize(&initialize_params), "Dart_Initialize");
dart::bin::DFE dfe;
dfe.Init();
const uint8_t* platform_buffer = nullptr;
intptr_t platform_buffer_size = 0;
dfe.LoadPlatform(&platform_buffer, &platform_buffer_size);
// Start an isolate from a platform kernel.
Dart_IsolateFlags isolate_flags;
Dart_IsolateFlagsInitialize(&isolate_flags);
Dart_CreateIsolateGroupFromKernel(
/*script_uri=*/snapshot_uri.c_str(),
/*name=*/snapshot_name.c_str(),
/*kernel_buffer=*/platform_buffer,
/*kernel_buffer_size=*/platform_buffer_size,
/*flags=*/&isolate_flags,
/*isolate_group_data=*/nullptr,
/*isolate_data=*/nullptr, &error);
CheckError(error, "Dart_CreateIsolateGroupFromKernel");
Dart_EnterScope();
CheckHandle(dart::bin::DartUtils::PrepareForScriptLoading(
/*is_service_isolate=*/false, /*trace_loading=*/false),
"PrepareForScriptLoading");
// Load kernel snapshot to run `main` from.
Dart_Handle library =
CheckHandle(Dart_LoadLibraryFromKernel(
reinterpret_cast<const uint8_t*>(snapshot_data.c_str()),
snapshot_data.size()),
"Dart_LoadLibraryFromKernel");
// Call main function with args.
std::initializer_list<Dart_Handle> main_args{ToDartStringList({"universe"})};
CheckHandle(Dart_Invoke(library, Dart_NewStringFromCString("main"), 1,
const_cast<Dart_Handle*>(main_args.begin())),
"Dart_Invoke('main')");
Dart_ExitScope();
Dart_ShutdownIsolate();
}
+53
View File
@@ -0,0 +1,53 @@
// 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 <iostream>
#include "helpers.h"
#include "include/dart_api.h"
#include "include/dart_engine.h"
Dart_Handle ToDartStringList(const std::vector<std::string>& values) {
Dart_Handle core_library =
CheckError(Dart_LookupLibrary(Dart_NewStringFromCString("dart:core")));
Dart_Handle string_type = CheckError(Dart_GetNonNullableType(
core_library, Dart_NewStringFromCString("String"), 0, nullptr));
Dart_Handle filler = Dart_NewStringFromCString("");
Dart_Handle result =
CheckError(Dart_NewListOfTypeFilled(string_type, filler, values.size()));
for (size_t i = 0; i < values.size(); i++) {
Dart_Handle element = Dart_NewStringFromCString(values[i].c_str());
CheckError(Dart_ListSetAt(result, i, element));
}
return result;
}
int main(int argc, char** argv) {
if (argc == 1) {
std::cerr << "Must specify snapshot path" << std::endl;
std::exit(1);
}
char* error = nullptr;
DartEngine_SnapshotData snapshot_data = AutoSnapshotFromFile(argv[1], &error);
CheckError(error, "reading snapshot");
Dart_Isolate isolate = DartEngine_CreateIsolate(snapshot_data, &error);
CheckError(error, "starting isolate");
DartEngine_AcquireIsolate(isolate);
Dart_EnterScope();
std::initializer_list<Dart_Handle> main_args{ToDartStringList({"world"})};
CheckError(Dart_Invoke(Dart_RootLibrary(), Dart_NewStringFromCString("main"),
1, const_cast<Dart_Handle*>(main_args.begin())),
"calling main");
Dart_ExitScope();
DartEngine_ReleaseIsolate();
DartEngine_Shutdown();
}
+118
View File
@@ -0,0 +1,118 @@
#include <condition_variable>
#include <iostream>
#include <mutex>
#include <queue>
#include <thread>
#include "helpers.h"
#include "include/dart_api.h"
#include "include/dart_engine.h"
// Calls `startTimer` from timer.dart
void StartTimer(Dart_Isolate isolate, uint32_t millis) {
WithIsolate(isolate, [&]() {
std::initializer_list<Dart_Handle> args{Dart_NewInteger(millis)};
CheckError(
Dart_Invoke(Dart_RootLibrary(), Dart_NewStringFromCString("startTimer"),
1, const_cast<Dart_Handle*>(args.begin())),
"calling startTimer");
});
}
// Calls `stopTimer` from timer.dart
void StopTimer(Dart_Isolate isolate) {
WithIsolate(isolate, [&]() {
CheckError(Dart_Invoke(Dart_RootLibrary(),
Dart_NewStringFromCString("stopTimer"), 0, nullptr),
"calling stopTimer");
});
}
// Gets `ticks` from timer.dart
int64_t GetTicks(Dart_Isolate isolate) {
return WithIsolate<int64_t>(isolate, []() {
return IntFromHandle(
Dart_GetField(Dart_RootLibrary(), Dart_NewStringFromCString("ticks")));
});
}
// Queue-based message handler, running on a separate thread.
class ThreadedMessageHandler {
public:
void Run() {
is_running = true;
while (is_running) {
Dart_Isolate isolate;
{
std::unique_lock notifications_lock(notifications_mutex_);
can_pop_.wait(notifications_lock);
if (notifications_.empty()) {
continue;
}
isolate = notifications_.front();
notifications_.pop();
}
DartEngine_HandleMessage(isolate);
}
}
void Notify(Dart_Isolate isolate) {
std::unique_lock notifications_lock(notifications_mutex_);
notifications_.push(isolate);
can_pop_.notify_one();
}
void Stop() {
is_running = false;
can_pop_.notify_one();
}
static void ScheduleDartMessage(Dart_Isolate isolate, void* context) {
reinterpret_cast<ThreadedMessageHandler*>(context)->Notify(isolate);
}
private:
std::queue<Dart_Isolate> notifications_;
std::condition_variable can_pop_;
std::atomic<bool> is_running;
std::mutex notifications_mutex_;
};
int main(int argc, char** argv) {
if (argc == 1) {
std::cerr << "Must specify snapshot path" << std::endl;
std::exit(1);
}
char* error = nullptr;
// Start an event loop on a separate thread and use it as a default
// scheduler.
ThreadedMessageHandler message_handler;
std::thread message_handler_thread(&ThreadedMessageHandler::Run,
&message_handler);
DartEngine_SetDefaultMessageScheduler(
{ThreadedMessageHandler::ScheduleDartMessage, &message_handler});
// Load snapshot and create an isolate
DartEngine_SnapshotData snapshot_data = AutoSnapshotFromFile(argv[1], &error);
CheckError(error, "reading snapshot");
Dart_Isolate isolate = DartEngine_CreateIsolate(snapshot_data, &error);
CheckError(error, "creating isolate");
// Call Dart function to start a timer.
StartTimer(isolate, 1);
// Wait a bit.
std::this_thread::sleep_for(std::chrono::milliseconds(100));
// Stop the timer.
StopTimer(isolate);
// Get timer value.
std::cout << "Ticks: " << GetTicks(isolate) << std::endl;
// Stop event loop.
message_handler.Stop();
message_handler_thread.join();
DartEngine_Shutdown();
}
+75
View File
@@ -0,0 +1,75 @@
// Same as run_timer.cc, but uses std::async instead of a dedicated event loop
// thread. Used as a demonstration of a custom message scheduler.
#include <future>
#include <iostream>
#include <thread>
#include "helpers.h"
#include "include/dart_api.h"
#include "include/dart_engine.h"
// Calls `startTimer` from timer.dart
void StartTimer(Dart_Isolate isolate, uint32_t millis) {
WithIsolate(isolate, [&]() {
std::initializer_list<Dart_Handle> args{Dart_NewInteger(millis)};
CheckError(
Dart_Invoke(Dart_RootLibrary(), Dart_NewStringFromCString("startTimer"),
1, const_cast<Dart_Handle*>(args.begin())),
"calling startTimer");
});
}
// Calls `stopTimer` from timer.dart
void StopTimer(Dart_Isolate isolate) {
WithIsolate(isolate, [&]() {
CheckError(Dart_Invoke(Dart_RootLibrary(),
Dart_NewStringFromCString("stopTimer"), 0, nullptr),
"calling stopTimer");
});
}
// Gets `ticks` from timer.dart
int64_t GetTicks(Dart_Isolate isolate) {
return WithIsolate<int64_t>(isolate, []() {
return IntFromHandle(
Dart_GetField(Dart_RootLibrary(), Dart_NewStringFromCString("ticks")));
});
}
std::mutex shutdown_mutex;
void ScheduleDartMessage(Dart_Isolate isolate, void* context) {
std::ignore = std::async(DartEngine_HandleMessage, isolate);
}
int main(int argc, char** argv) {
if (argc == 1) {
std::cerr << "Must specify snapshot path" << std::endl;
std::exit(1);
}
char* error = nullptr;
// Start an event loop on a separate thread and use it as a default
// scheduler.
DartEngine_MessageScheduler scheduler{ScheduleDartMessage, nullptr};
DartEngine_SetDefaultMessageScheduler(scheduler);
// Load snapshot and create an isolate
DartEngine_SnapshotData snapshot_data = AutoSnapshotFromFile(argv[1], &error);
CheckError(error, "reading snapshot");
Dart_Isolate isolate = DartEngine_CreateIsolate(snapshot_data, &error);
CheckError(error, "creating isolate");
// Call Dart function to start a timer.
StartTimer(isolate, 1);
// Wait a bit.
std::this_thread::sleep_for(std::chrono::milliseconds(100));
// Stop the timer.
StopTimer(isolate);
// Get timer value.
std::cout << "Ticks: " << GetTicks(isolate) << std::endl;
DartEngine_Shutdown();
}
+50
View File
@@ -0,0 +1,50 @@
#include <iostream>
#include "helpers.h"
#include "include/dart_api.h"
#include "include/dart_engine.h"
int main(int argc, char** argv) {
if (argc < 3) {
std::cerr << "Must specify two snapshot paths" << std::endl;
std::exit(1);
}
char* error = nullptr;
DartEngine_SnapshotData snapshot1 = AutoSnapshotFromFile(argv[1], &error);
CheckError(error, "reading snapshot");
DartEngine_SnapshotData snapshot2 = AutoSnapshotFromFile(argv[2], &error);
CheckError(error, "reading snapshot");
Dart_Isolate isolate1 = DartEngine_CreateIsolate(snapshot1, &error);
CheckError(error, "starting 1st isolate");
Dart_Isolate isolate2 = DartEngine_CreateIsolate(snapshot2, &error);
CheckError(error, "starting 2nd isolate");
DartEngine_AcquireIsolate(isolate1);
Dart_EnterScope();
Dart_Handle invoke_result = Dart_Invoke(
Dart_RootLibrary(), Dart_NewStringFromCString("getValue"), 0, nullptr);
std::string return_value = StringFromHandle(invoke_result);
std::cout << "program1 returned: " << return_value << std::endl;
Dart_ExitScope();
DartEngine_ReleaseIsolate();
DartEngine_AcquireIsolate(isolate2);
Dart_EnterScope();
std::initializer_list<Dart_Handle> args{
Dart_NewStringFromCString(return_value.c_str())};
Dart_Handle invoke_result2 =
Dart_Invoke(Dart_RootLibrary(), Dart_NewStringFromCString("printValue"),
1, const_cast<Dart_Handle*>(args.begin()));
CheckError(invoke_result2);
Dart_ExitScope();
DartEngine_ReleaseIsolate();
DartEngine_Shutdown();
}
+33
View File
@@ -0,0 +1,33 @@
import 'dart:async';
void main() {
throw 'Unimplemented';
}
var _tickCount = 0;
Timer? _timer;
@pragma('vm:entry-point', 'call')
void startTimer(int millis) {
if (_timer == null) {
final period = Duration(milliseconds: millis);
_timer = Timer.periodic(period, (_) {
_tickCount++;
});
print('Started timer with period $period');
}
}
@pragma('vm:entry-point', 'call')
void stopTimer() {
_timer?.cancel();
_timer = null;
}
@pragma('vm:entry-point', 'call')
void resetTimer() {
_tickCount = 0;
}
@pragma('vm:entry-point', 'get')
int get ticks => _tickCount;