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:
committed by
Commit Queue
parent
79df09999e
commit
6e33c95463
+129
-10
@@ -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
@@ -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`.
|
||||
|
||||
@@ -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!");
|
||||
}
|
||||
|
||||
@@ -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_ */
|
||||
@@ -0,0 +1,8 @@
|
||||
void main(List<String> args) {
|
||||
throw 'Unimplemented';
|
||||
}
|
||||
|
||||
@pragma('vm:entry-point', 'call')
|
||||
String getValue() {
|
||||
return 'program1';
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
void main(List<String> args) {
|
||||
throw 'Unimplemented';
|
||||
}
|
||||
|
||||
@pragma('vm:entry-point', 'call')
|
||||
void printValue(String value) {
|
||||
print('program2 received: $value');
|
||||
}
|
||||
@@ -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(¶ms, 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();
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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;
|
||||
Reference in New Issue
Block a user