Files
sdk/samples/embedder/timer.cc
T
Tess Strickland acd16c6aa7 [pkg/vm] Add tool for generating DartEngine shims from entry points.
This is an initial cut of a tool for automatically creating shims for
C/C++ programs using the entry point annotations in Dart code. The tool
has two required arguments:

* the .dill file containing the kernel representation of the Dart code
* the base path of the header and implementation files to create

With a base path of 'dir/name', the header file is created as
'dir/name.h' and the implementation file is created as 'dir/name.cc'.
In addition, 'dir/name.h' is used as a basis for creating a
#ifndef/#define/#endif header guard around the header contents.


The created shims are specific to a single package, either

* a user-specified package, provided via '-p'/'--package', or
* the package of the main method

If the user does not specify a package and there is no main method
in the .dill file, the tool fails.


Each shim takes the following arguments in order when applicable:

* the isolate in which to perform the requested operation,
* the instantiated type of the generic class (for invoking, setting, or
  getting constructors, static methods, and static fields)
* the instance (for invoking, getting, or setting instance methods and
  fields)
* the type arguments (for retrieving nullable or non-nullable
  instantiated types of a generic class)
* the arguments (for invoking, setting, or getting constructors,
  methods, and fields)


The generated shims:

* cache the package library, types for non-generic classes, and
  types for generic classes instantiated with default type arguments.
  The cached persistent handles are cleared if any of the methods
  are called with a different isolate from the one used to populate
  the cache.
* automatically handle conversions between C int64_t <=> Dart int
  and C double <=> Dart double.


By default, shims are not created for allocation or initializing
uninitialized instances. To create such shims, use the '-u' command
line argument.


Currently, shims are not created for methods that take optional
or named arguments. To report an error if a shim cannot be created
for any entry points, use the '-e' command line argument.

TEST=tests/standalone/embedder_samples_test

Change-Id: Ibdf3b52d900ba98038528178485f295c5868ac9d
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/410500
Reviewed-by: Ivan Inozemtsev <iinozemtsev@google.com>
Commit-Queue: Tess Strickland <sstrickl@google.com>
2025-03-20 03:53:10 -07:00

202 lines
5.7 KiB
C++

// 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.
//
// Generated with:
// dart pkg/vm/tools/generate_entry_point_shims.dart \
// out/ReleaseX64/gen/samples/embedder/timer_aot.dart.dill \
// samples/embedder/timer
#include "timer.h"
#include <iostream>
#include <string>
#include <string_view>
#include <unordered_map>
#include <vector>
namespace {
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;
}
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;
}
double DoubleFromHandle(Dart_Handle handle) {
CheckError(handle, "DoubleFromHandle received an error");
if (!Dart_IsDouble(handle)) {
std::cerr << "DoubleFromHandle handle is not an double" << std::endl;
std::exit(1);
}
double result;
Dart_Handle to_double_result = Dart_DoubleValue(handle, &result);
CheckError(to_double_result, "Dart_DoubleValue");
return result;
}
class PackageState {
public:
static PackageState* instance() {
static PackageState* instance = new PackageState();
return instance;
}
Dart_Handle PackageLibrary() {
ValidateCurrentIsolate();
Dart_Handle result = package_library_;
if (package_library_ == nullptr) {
result = Dart_RootLibrary();
if (!Dart_IsError(result)) {
package_library_ = Dart_NewPersistentHandle(result);
}
}
return result;
}
Dart_Handle TypeWithDefaults(std::string name) {
ValidateCurrentIsolate();
auto search = default_types_.find(name);
Dart_Handle result;
if (search == default_types_.end()) {
Dart_Handle lib = PackageLibrary();
result = Dart_GetClass(lib, Dart_NewStringFromCString(name.c_str()));
if (!Dart_IsError(result)) {
Dart_PersistentHandle handle = Dart_NewPersistentHandle(result);
default_types_.emplace(std::make_pair(name, handle));
}
} else {
result = search->second;
}
return result;
}
private:
PackageState() : default_types_() {}
void ValidateCurrentIsolate() {
Dart_Isolate current = Dart_CurrentIsolate();
if (isolate_ != current) {
isolate_ = current;
if (package_library_ != nullptr) {
Dart_DeletePersistentHandle(package_library_);
package_library_ = nullptr;
}
for (const auto& [str, handle] : default_types_) {
Dart_DeletePersistentHandle(handle);
}
default_types_.clear();
}
}
// Ensure the helper methods defined above won't trigger unused
// function warnings.
template <typename T>
static inline void USE(T&&) {}
void UseHelperFunctions() {
USE(IntFromHandle);
USE(DoubleFromHandle);
}
Dart_Isolate isolate_ = nullptr;
Dart_PersistentHandle package_library_ = nullptr;
std::unordered_map<std::string, Dart_PersistentHandle> default_types_;
};
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;
};
} // namespace
#ifdef __cplusplus
#define PACKAGE_EXTERN_C extern "C"
#else
#define PACKAGE_EXTERN_C extern
#endif
#if defined(__CYGWIN__)
#error Tool chain and platform not supported.
#elif defined(_WIN32)
#define PACKAGE_EXPORT PACKAGE_EXTERN_C __declspec(dllexport)
#else
#if __GNUC__ >= 4
#define PACKAGE_EXPORT \
PACKAGE_EXTERN_C __attribute__((visibility("default"))) __attribute((used))
#else
#error Tool chain not supported.
#endif
#endif
PACKAGE_EXPORT void Call_startTimer(Dart_Isolate dart_isolate,
int64_t v_millis) {
IsolateScope isolate_scope(dart_isolate);
DartScope scope;
std::vector parameter_list{Dart_NewInteger(v_millis)};
CheckError(Dart_Invoke(PackageState::instance()->PackageLibrary(),
Dart_NewStringFromCString("startTimer"), 1,
parameter_list.data()));
}
PACKAGE_EXPORT void Call_stopTimer(Dart_Isolate dart_isolate) {
IsolateScope isolate_scope(dart_isolate);
DartScope scope;
CheckError(Dart_Invoke(PackageState::instance()->PackageLibrary(),
Dart_NewStringFromCString("stopTimer"), 0, nullptr));
}
PACKAGE_EXPORT void Call_resetTimer(Dart_Isolate dart_isolate) {
IsolateScope isolate_scope(dart_isolate);
DartScope scope;
CheckError(Dart_Invoke(PackageState::instance()->PackageLibrary(),
Dart_NewStringFromCString("resetTimer"), 0, nullptr));
}
PACKAGE_EXPORT int64_t Get_ticks(Dart_Isolate dart_isolate) {
IsolateScope isolate_scope(dart_isolate);
DartScope scope;
return IntFromHandle(Dart_GetField(PackageState::instance()->PackageLibrary(),
Dart_NewStringFromCString("ticks")));
}
#undef PACKAGE_EXPORT
#undef PACKAGE_EXTERN_C