-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Standalone Dart runtime library for embedders
For now we use a static library, but I am planning to add support for a shared library in a follow-up CL. Tested: locally on macOS and Linux, also ci should at least build samples. Change-Id: I277239359de226c56633884f350b22a030759ab6 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/392640 Commit-Queue: Ivan Inozemtsev <iinozemtsev@google.com> Reviewed-by: Slava Egorov <vegorov@google.com>
- Loading branch information
1 parent
76717f2
commit 53ba9af
Showing
6 changed files
with
250 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
# 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. | ||
|
||
import("../../utils/application_snapshot.gni") | ||
|
||
# All samples. | ||
group("all") { | ||
deps = [ ":run_kernel" ] | ||
} | ||
|
||
# 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" ] | ||
} | ||
|
||
# Kernel snapshot of ./hello.dart. | ||
application_snapshot("hello_kernel") { | ||
main_dart = "hello.dart" | ||
dart_snapshot_kind = "kernel" | ||
training_args = [] # Not used | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
# Dart VM Embedding examples | ||
|
||
Examples of using Dart VM and executing Dart code from C++ binaries. | ||
|
||
## run_kernel.cc | ||
|
||
To run the example: | ||
|
||
```sh | ||
./tools/build.py --no-rbe --mode=release samples/embedder:run_kernel && out/ReleaseX64/run_kernel | ||
``` | ||
|
||
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: | ||
|
||
```sh | ||
dart compile kernel --no-link-platform my.dart | ||
out/ReleaseX64/run_kernel my.dill | ||
``` | ||
|
||
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). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
// 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. | ||
|
||
import 'package:collection/collection.dart'; | ||
|
||
void main(List<String>? args) { | ||
final greetee = args?.singleOrNull ?? 'world'; | ||
print('Hello, $greetee!'); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,154 @@ | ||
// 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); | ||
return std::string(bytes, length); | ||
} | ||
|
||
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. | ||
CheckError(dart::embedder::InitOnce(&error), 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_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(); | ||
} |