Add support for flushing microtasks in dart_engine.h

Also add a sample for calling Dart functions which return/accept futures.

Change-Id: I932d0577709f4e068ccd3212797751ecb347c4f9
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/408281
Commit-Queue: Ivan Inozemtsev <iinozemtsev@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
This commit is contained in:
Ivan Inozemtsev
2025-02-12 11:10:25 -08:00
committed by Commit Queue
parent a6f06e8c9f
commit 51ea42537a
17 changed files with 478 additions and 38 deletions
+4
View File
@@ -72,5 +72,9 @@ DART_EXPORT void DartEngine_HandleMessage(Dart_Isolate isolate) {
Engine::instance()->HandleMessage(isolate);
}
DART_EXPORT Dart_Handle DartEngine_DrainMicrotasksQueue() {
return Engine::instance()->DrainMicrotasksQueue();
}
} // namespace engine
} // namespace dart
+41 -14
View File
@@ -4,7 +4,6 @@
#include "engine/engine.h"
#include <memory>
#include <utility>
#include "bin/dartutils.h"
#include "include/dart_api.h"
#include "include/dart_embedder_api.h"
@@ -16,6 +15,8 @@
namespace dart {
namespace engine {
constexpr char kRunPendingImmediateCallback[] = "_runPendingImmediateCallback";
using platform::MutexLocker;
Engine* Engine::instance() {
@@ -195,8 +196,8 @@ Dart_Isolate Engine::StartIsolate(DartEngine_SnapshotData snapshot,
Dart_Handle core_libs_result =
bin::DartUtils::PrepareForScriptLoading(false, false);
if (Dart_IsError(core_libs_result)) {
Dart_ShutdownIsolate();
*error = Utils::StrDup(Dart_GetError(core_libs_result));
Dart_ShutdownIsolate();
return nullptr;
}
@@ -210,12 +211,27 @@ Dart_Isolate Engine::StartIsolate(DartEngine_SnapshotData snapshot,
snapshot.kernel_buffer, snapshot.kernel_buffer_size);
if (Dart_IsError(library)) {
Dart_ShutdownIsolate();
*error = Utils::StrDup(Dart_GetError(library));
Dart_ShutdownIsolate();
return nullptr;
}
}
Dart_Handle isolate_library = Dart_LookupLibrary(
Dart_NewStringFromCString(bin::DartUtils::kIsolateLibURL));
if (Dart_IsError(isolate_library)) {
*error = Utils::StrDup(Dart_GetError(isolate_library));
Dart_ShutdownIsolate();
return nullptr;
}
std::shared_ptr<Engine::IsolateData> isolate_data = DataForIsolate(isolate);
isolate_data->isolate_library = Dart_NewPersistentHandle(isolate_library);
isolate_data->drain_microtasks_function_name = Dart_NewPersistentHandle(
Dart_NewStringFromCString(kRunPendingImmediateCallback));
isolate_data->scheduler.context = nullptr;
isolate_data->scheduler.schedule_callback = nullptr;
Dart_ExitScope();
Dart_ExitIsolate();
is_running_ = true;
@@ -232,9 +248,12 @@ void Engine::Shutdown() {
is_running_ = false;
for (auto isolate : isolates_) {
std::shared_ptr<Engine::IsolateData> isolate_data = DataForIsolate(isolate);
LockIsolate(isolate);
Dart_EnterIsolate(isolate);
Dart_SetMessageNotifyCallback(nullptr);
Dart_DeletePersistentHandle(isolate_data->isolate_library);
Dart_DeletePersistentHandle(isolate_data->drain_microtasks_function_name);
Dart_ShutdownIsolate();
UnlockIsolate(isolate);
}
@@ -277,17 +296,30 @@ void Engine::HandleMessage(Dart_Isolate isolate) {
UnlockIsolate(isolate);
}
Mutex& Engine::MutexForIsolate(Dart_Isolate isolate) {
Dart_Handle Engine::DrainMicrotasksQueue() {
std::shared_ptr<Engine::IsolateData> isolate_data =
DataForIsolate(Dart_CurrentIsolate());
return Dart_Invoke(isolate_data->isolate_library,
isolate_data->drain_microtasks_function_name, 0, nullptr);
}
std::shared_ptr<Engine::IsolateData> Engine::DataForIsolate(
Dart_Isolate isolate) {
MutexLocker ml(&engine_state_);
return mutexes_[isolate];
auto it = isolate_data_.find(isolate);
if (it == isolate_data_.end()) {
it = isolate_data_.emplace(isolate, std::make_shared<Engine::IsolateData>())
.first;
}
return it->second;
}
void Engine::LockIsolate(Dart_Isolate isolate) {
MutexForIsolate(isolate).Lock();
DataForIsolate(isolate)->mutex.Lock();
}
void Engine::UnlockIsolate(Dart_Isolate isolate) {
MutexForIsolate(isolate).Unlock();
DataForIsolate(isolate)->mutex.Unlock();
}
void Engine::NotifyMessage(Dart_Isolate isolate) {
@@ -313,11 +345,7 @@ void Engine::NotifyMessage(Dart_Isolate isolate) {
return;
}
DartEngine_MessageScheduler scheduler;
{
MutexLocker ml(&engine_state_);
scheduler = schedulers_[isolate];
}
DartEngine_MessageScheduler scheduler = DataForIsolate(isolate)->scheduler;
if (scheduler.schedule_callback == nullptr) {
scheduler = default_scheduler_;
@@ -341,8 +369,7 @@ void Engine::SetDefaultMessageScheduler(DartEngine_MessageScheduler scheduler) {
void Engine::SetMessageScheduler(DartEngine_MessageScheduler scheduler,
Dart_Isolate isolate) {
MutexLocker ml(&engine_state_);
schedulers_[isolate] = scheduler;
DataForIsolate(isolate)->scheduler = scheduler;
}
} // namespace engine
+15 -7
View File
@@ -6,7 +6,6 @@
#define RUNTIME_ENGINE_ENGINE_H_
#include <memory>
#include <queue>
#include <unordered_map>
#include <vector>
#include "include/dart_engine.h"
@@ -54,6 +53,9 @@ class Engine {
// Calls Dart_HandleMessage, managing an isolate lock and Dart scope.
void HandleMessage(Dart_Isolate isolate);
// Drains the microtasks queue, requires an active isolate.
Dart_Handle DrainMicrotasksQueue();
// Sets a callback to be called when Dart_HandleMessage returns an error.
void SetHandleMessageErrorCallback(
DartEngine_HandleMessageErrorCallback callback);
@@ -85,6 +87,14 @@ class Engine {
static void HandleMessageCallback(Dart_Isolate isolate);
private:
// Engine's internal data for isolate.
struct IsolateData {
DartEngine_MessageScheduler scheduler;
Mutex mutex;
Dart_PersistentHandle isolate_library;
Dart_PersistentHandle drain_microtasks_function_name;
};
// Set to false once shutdown starts.
bool is_running_ = false;
@@ -114,19 +124,17 @@ class Engine {
// All isolates, started via Engine::StartIsolate.
std::vector<Dart_Isolate> isolates_;
// Stores per-isolate mutexes, used by Engine::LockIsolate/UnlockIsolate.
std::unordered_map<Dart_Isolate, Mutex> mutexes_;
// Stores per-isolate engine state.
std::unordered_map<Dart_Isolate, std::shared_ptr<IsolateData>> isolate_data_;
// Default scheduler.
DartEngine_MessageScheduler default_scheduler_;
// Per-isolate message schedulers.
std::unordered_map<Dart_Isolate, DartEngine_MessageScheduler> schedulers_;
// Callback to notify about Dart_HandleMessage errors.
DartEngine_HandleMessageErrorCallback handle_message_error_callback_;
// Helper function to get an element from mutexes_.
Mutex& MutexForIsolate(Dart_Isolate isolate);
// Helper function to get an element from isolate_data_.
std::shared_ptr<IsolateData> DataForIsolate(Dart_Isolate isolate);
};
} // namespace engine
+11
View File
@@ -109,6 +109,17 @@ typedef void (*DartEngine_HandleMessageErrorCallback)(
DART_EXPORT void DartEngine_SetHandleMessageErrorCallback(
DartEngine_HandleMessageErrorCallback handle_message_error_callback);
/**
* Drains the microtasks queue. Requires to be an active isolate.
*
* Normally the microtasks queue is drained after handling each
* isolate message, but when the engine calls into Dart, it might be
* required to manually drain the microtasks queue.
*
* \return Dart_Handle invocation result.
*/
DART_EXPORT Dart_Handle DartEngine_DrainMicrotasksQueue();
/**
* Handles a single message for an isolate.
*/
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.cs.allow-jit</key>
<true/>
<key>com.apple.security.cs.disable-library-validation</key>
<true/>
</dict>
</plist>
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.cs.allow-jit</key>
<true/>
<key>com.apple.security.cs.disable-library-validation</key>
<true/>
</dict>
</plist>
+11
View File
@@ -15,6 +15,7 @@ group("all") {
group("aot") {
deps = [
":run_futures_aot",
":run_main_aot",
":run_timer_aot",
":run_timer_async_aot",
@@ -24,6 +25,7 @@ group("aot") {
group("kernel") {
deps = [
":run_futures_kernel",
":run_main_kernel",
":run_timer_async_kernel",
":run_timer_kernel",
@@ -150,3 +152,12 @@ sample("run_timer_async") {
snapshots("timer") {
main_dart = "timer.dart"
}
snapshots("futures") {
main_dart = "futures.dart"
}
sample("run_futures") {
sources = [ "run_futures.cc" ]
snapshots = [ ":futures" ]
}
+129
View File
@@ -0,0 +1,129 @@
// 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.
import 'dart:async';
import 'dart:ffi';
void main() async {
print(
'returnRegularFuture returns: '
'${await returnRegularFuture(5)}',
);
print(
'sumIntStream(useAsyncStar = false) returns: '
'${await sumIntStream(5, 1, false)}',
);
print(
'sumIntStream(useAsyncStar = true) returns: '
'${await sumIntStream(5, 1, true)}',
);
}
Future<int> returnRegularFuture(int delayMs) async {
await Future.delayed(Duration(milliseconds: 5));
return 256;
}
Future<int> returnMicrotaskFuture(int delayMs) => Future.microtask(() async {
await Future.delayed(Duration(milliseconds: delayMs));
return 256;
});
Stream<int> produceIntStreamWithAsyncStar(int count, int delayMs) async* {
final delay = Duration(milliseconds: delayMs);
for (var i = 0; i < count; i++) {
await Future.delayed(delay);
yield i;
}
}
Stream<int> produceIntStreamWithController(int count, int delayMs) {
final delay = Duration(milliseconds: delayMs);
final sc = StreamController<int>();
(() async {
for (var i = 0; i < count; i++) {
await Future.delayed(delay);
sc.add(i);
}
sc.close();
})();
return sc.stream;
}
Future<int> sumIntStream(int count, int delayMs, bool useAsyncStar) async {
final stream =
useAsyncStar
? produceIntStreamWithAsyncStar(count, delayMs)
: produceIntStreamWithController(count, delayMs);
var sum = 0;
await for (var value in stream) {
sum += value;
}
return sum;
}
Future<int> awaitAndMultiply(Future<int> a, Future<int> b) async =>
(await a) * (await b);
class AwaitAndMultiplyCall {
final _a = Completer<int>();
final _b = Completer<int>();
Future<int> getA() => _a.future;
Future<int> getB() => _b.future;
@pragma('vm:entry-point', 'call')
void setA(int value) => _a.complete(value);
@pragma('vm:entry-point', 'call')
void setB(int value) => _b.complete(value);
}
@pragma('vm:entry-point', 'call')
AwaitAndMultiplyCall awaitAndMultiplyC(int callbackPtr, int contextPtr) {
final call = AwaitAndMultiplyCall();
() async {
Pointer<NativeFunction<Void Function(Pointer<Opaque>, Int64)>>.fromAddress(
callbackPtr,
).asFunction<void Function(Pointer<Opaque>, int)>()(
Pointer<Opaque>.fromAddress(contextPtr),
await awaitAndMultiply(call.getA(), call.getB()),
);
}();
return call;
}
@pragma('vm:entry-point', 'call')
// C-friendly wrapper over [returnRegularFuture].
void returnRegularFutureC(
int delayMs,
bool useMicrotask,
int callbackPtr,
int contextPtr,
) async =>
Pointer<NativeFunction<Void Function(Pointer<Opaque>, Int64)>>.fromAddress(
callbackPtr,
).asFunction<void Function(Pointer<Opaque>, int)>()(
Pointer<Opaque>.fromAddress(contextPtr),
await (useMicrotask
? returnMicrotaskFuture(delayMs)
: returnRegularFuture(delayMs)),
);
@pragma('vm:entry-point', 'call')
// C-friendly wrapper over [sumIntStream].
void sumIntStreamC(
int count,
int delayMs,
bool useAsyncStar,
int callbackPtr,
int contextPtr,
) async =>
Pointer<NativeFunction<Void Function(Pointer<Opaque>, Int64)>>.fromAddress(
callbackPtr,
).asFunction<void Function(Pointer<Opaque>, int)>()(
Pointer<Opaque>.fromAddress(contextPtr),
await sumIntStream(count, delayMs, useAsyncStar),
);
+25 -13
View File
@@ -73,22 +73,34 @@ inline int64_t IntFromHandle(Dart_Handle handle) {
return result;
}
class DartScope {
public:
DartScope() { Dart_EnterScope(); }
virtual ~DartScope() { Dart_ExitScope(); }
private:
DartScope(const DartScope&) = delete;
void operator=(const DartScope&) = delete;
};
class IsolateScope {
public:
explicit IsolateScope(Dart_Isolate isolate) {
DartEngine_AcquireIsolate(isolate);
}
virtual ~IsolateScope() { DartEngine_ReleaseIsolate(); }
private:
IsolateScope(const IsolateScope&) = delete;
void operator=(const IsolateScope&) = delete;
};
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;
}
IsolateScope isolate_scope(isolate);
DartScope dart_scope;
inline void WithIsolate(Dart_Isolate isolate, std::function<void()> body) {
DartEngine_AcquireIsolate(isolate);
Dart_EnterScope();
body();
Dart_ExitScope();
DartEngine_ReleaseIsolate();
return body();
}
#endif /* SAMPLES_EMBEDDER_HELPERS_H_ */
+4
View File
@@ -1,3 +1,7 @@
// 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.
void main(List<String> args) {
throw 'Unimplemented';
}
+4
View File
@@ -1,3 +1,7 @@
// 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.
void main(List<String> args) {
throw 'Unimplemented';
}
+188
View File
@@ -0,0 +1,188 @@
// 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 <chrono>
#include <future>
#include <iostream>
#include <thread>
#include "helpers.h"
#include "include/dart_api.h"
#include "include/dart_engine.h"
void ScheduleDartMessage(Dart_Isolate isolate, void* context) {
std::ignore = std::async(DartEngine_HandleMessage, isolate);
}
void FulfillIntPromise(void* context, int64_t value) {
auto promise = reinterpret_cast<std::promise<int64_t>*>(context);
promise->set_value(value);
delete promise;
}
// Helper to call Dart function `returnRegularFutureC`.
std::future<int64_t> ReturnRegularFuture(Dart_Isolate isolate,
int64_t delay_ms,
bool use_microtask) {
auto promise = new std::promise<int64_t>();
auto result = promise->get_future();
IsolateScope isolate_scope(isolate);
DartScope dart_scope;
// args
Dart_Handle args[] = {
Dart_NewInteger(delay_ms), Dart_NewBoolean(use_microtask),
Dart_NewInteger(
reinterpret_cast<intptr_t>(&FulfillIntPromise)), // callback
Dart_NewInteger(reinterpret_cast<intptr_t>(promise)) // context
};
// call
CheckError(Dart_Invoke(Dart_RootLibrary(),
Dart_NewStringFromCString("returnRegularFutureC"), 4,
args));
CheckError(DartEngine_DrainMicrotasksQueue(), "draining microtasks queue");
return result;
}
// Helper to call Dart function `sumIntStreamC`.
std::future<int64_t> SumIntStream(Dart_Isolate isolate,
int count,
int64_t delay_ms,
bool use_async_star) {
auto promise = new std::promise<int64_t>();
auto result = promise->get_future();
IsolateScope isolate_scope(isolate);
DartScope dart_scope;
// args
Dart_Handle args[] = {
Dart_NewInteger(count), Dart_NewInteger(delay_ms),
Dart_NewBoolean(use_async_star),
Dart_NewInteger(
reinterpret_cast<intptr_t>(&FulfillIntPromise)), // callback
Dart_NewInteger(reinterpret_cast<intptr_t>(promise)) // context
};
// call
CheckError(Dart_Invoke(Dart_RootLibrary(),
Dart_NewStringFromCString("sumIntStreamC"), 5, args));
CheckError(DartEngine_DrainMicrotasksQueue(), "draining microtasks queue");
return result;
}
class AwaitAndMultiplyCall {
public:
AwaitAndMultiplyCall(Dart_Isolate isolate,
Dart_PersistentHandle handle,
std::future<int64_t>&& result)
: result(std::move(result)), isolate_(isolate), handle_(handle) {}
void CompleteA(int64_t value) {
IsolateScope isolate_scope(isolate_);
DartScope dart_scope;
Dart_Handle args[] = {Dart_NewInteger(value)};
CheckError(
Dart_Invoke(handle_, Dart_NewStringFromCString("setA"), 1, args));
CheckError(DartEngine_DrainMicrotasksQueue(), "draining microtasks queue");
}
void CompleteB(int64_t value) {
IsolateScope isolate_scope(isolate_);
DartScope dart_scope;
Dart_Handle args[] = {Dart_NewInteger(value)};
CheckError(
Dart_Invoke(handle_, Dart_NewStringFromCString("setB"), 1, args));
CheckError(DartEngine_DrainMicrotasksQueue(), "draining microtasks queue");
}
std::future<int64_t> result;
void Release() {
IsolateScope isolate_scope(isolate_);
DartScope dart_scope;
Dart_DeletePersistentHandle(handle_);
}
private:
Dart_Isolate isolate_;
Dart_PersistentHandle handle_;
};
AwaitAndMultiplyCall AwaitAndMultiply(Dart_Isolate isolate) {
auto promise = new std::promise<int64_t>();
auto future = promise->get_future();
IsolateScope isolate_scope(isolate);
DartScope dart_scope;
Dart_Handle args[] = {
Dart_NewInteger(reinterpret_cast<intptr_t>(&FulfillIntPromise)),
Dart_NewInteger(reinterpret_cast<intptr_t>(promise)),
};
Dart_PersistentHandle call_handle = Dart_NewPersistentHandle(CheckError(
Dart_Invoke(Dart_RootLibrary(),
Dart_NewStringFromCString("awaitAndMultiplyC"), 2, args)));
CheckError(DartEngine_DrainMicrotasksQueue(), "draining microtasks queue");
return AwaitAndMultiplyCall(isolate, call_handle, std::move(future));
}
int main(int argc, char** argv) {
if (argc == 1) {
std::cerr << "Must specify snapshot path" << std::endl;
std::exit(1);
}
char* error = nullptr;
//
// Set up message handling and start isolate.
//
DartEngine_MessageScheduler scheduler{ScheduleDartMessage, nullptr};
DartEngine_SetDefaultMessageScheduler(scheduler);
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 functions.
//
auto result1 = ReturnRegularFuture(isolate, 5, false).get();
std::cout << "returnRegularFutureC(useMicrotask = false) returns: " << result1
<< std::endl;
auto result2 = ReturnRegularFuture(isolate, 5, true).get();
std::cout << "returnRegularFutureC(useMicrotask = true) returns: " << result2
<< std::endl;
auto result3 = SumIntStream(isolate, 5, 5, false).get();
std::cout << "sumIntStream(useAsyncStar = false) returns: " << result3
<< std::endl;
auto result4 = SumIntStream(isolate, 5, 5, true).get();
std::cout << "sumIntStream(useAsyncStar = true) returns: " << result4
<< std::endl;
auto call = AwaitAndMultiply(isolate);
std::this_thread::sleep_for(std::chrono::milliseconds(1));
call.CompleteB(5);
std::this_thread::sleep_for(std::chrono::milliseconds(1));
call.CompleteA(20);
auto result5 = call.result.get();
std::cout << "awaitAndMultiply(5, 20) = " << result5 << std::endl;
call.Release();
//
// Shutdown
//
DartEngine_Shutdown();
}
+6 -2
View File
@@ -1,3 +1,7 @@
// 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 <condition_variable>
#include <iostream>
#include <mutex>
@@ -9,7 +13,7 @@
// Calls `startTimer` from timer.dart
void StartTimer(Dart_Isolate isolate, uint32_t millis) {
WithIsolate(isolate, [&]() {
WithIsolate<void>(isolate, [&]() {
std::initializer_list<Dart_Handle> args{Dart_NewInteger(millis)};
CheckError(
Dart_Invoke(Dart_RootLibrary(), Dart_NewStringFromCString("startTimer"),
@@ -20,7 +24,7 @@ void StartTimer(Dart_Isolate isolate, uint32_t millis) {
// Calls `stopTimer` from timer.dart
void StopTimer(Dart_Isolate isolate) {
WithIsolate(isolate, [&]() {
WithIsolate<void>(isolate, [&]() {
CheckError(Dart_Invoke(Dart_RootLibrary(),
Dart_NewStringFromCString("stopTimer"), 0, nullptr),
"calling stopTimer");
+6 -2
View File
@@ -1,3 +1,7 @@
// 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.
// 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>
@@ -9,7 +13,7 @@
// Calls `startTimer` from timer.dart
void StartTimer(Dart_Isolate isolate, uint32_t millis) {
WithIsolate(isolate, [&]() {
WithIsolate<void>(isolate, [&]() {
std::initializer_list<Dart_Handle> args{Dart_NewInteger(millis)};
CheckError(
Dart_Invoke(Dart_RootLibrary(), Dart_NewStringFromCString("startTimer"),
@@ -20,7 +24,7 @@ void StartTimer(Dart_Isolate isolate, uint32_t millis) {
// Calls `stopTimer` from timer.dart
void StopTimer(Dart_Isolate isolate) {
WithIsolate(isolate, [&]() {
WithIsolate<void>(isolate, [&]() {
CheckError(Dart_Invoke(Dart_RootLibrary(),
Dart_NewStringFromCString("stopTimer"), 0, nullptr),
"calling stopTimer");
+4
View File
@@ -1,3 +1,7 @@
// 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"
+4
View File
@@ -1,3 +1,7 @@
// 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.
import 'dart:async';
void main() {
@@ -44,6 +44,9 @@ void main() {
checkSample('$out/run_timer_async_kernel', [
'$out/gen/timer_kernel.dart.snapshot',
]);
checkSample('$out/run_futures_kernel', [
'$out/gen/futures_kernel.dart.snapshot',
]);
// AOT Samples aren't built on some platforms.
checkSample('$out/run_main_aot', [
@@ -59,4 +62,7 @@ void main() {
checkSample('$out/run_timer_async_aot', [
'$out/timer_aot.snapshot',
], skipIfNotBuilt: true);
checkSample('$out/run_futures_aot', [
'$out/futures_aot.snapshot',
], skipIfNotBuilt: true);
}