Skip to content

Instantly share code, notes, and snippets.

@chancila
Created May 26, 2019 03:05
Show Gist options
  • Save chancila/6e8c42ad7d41c735a0f0063a6688d78c to your computer and use it in GitHub Desktop.
Save chancila/6e8c42ad7d41c735a0f0063a6688d78c to your computer and use it in GitHub Desktop.
Hello Dart
#include <forge/logging.h>
#include <forge/utility/assert.h>
#include <boost/filesystem.hpp>
#include <bin/dart_io_api.h>
#include <cstdio>
#include <dart_api.h>
#include <random>
#include <spdlog/sinks/stdout_color_sinks.h>
#include <string_view>
#include <type_traits>
// const char script[] = "import dart:io\n"
// "void main() { stdout.writeln(\"test\") }";
extern "C" {
extern uint8_t kDartVmSnapshotData[];
extern uint8_t kDartVmSnapshotInstructions[];
extern uint8_t kDartCoreIsolateSnapshotData[];
extern uint8_t kDartCoreIsolateSnapshotInstructions[];
extern const uint8_t kKernelServiceDill[];
extern intptr_t kKernelServiceDillSize;
extern const uint8_t kPlatformStrongDill[];
extern intptr_t kPlatformStrongDillSize;
}
#define FG_ASSERT_NOT_ERROR(e) FG_ALWAYS_ASSERT(!Dart_IsError(e))
void merp_print(Dart_NativeArguments args) {
intptr_t length = 0;
uint8_t* chars = NULL;
Dart_Handle str = Dart_GetNativeArgument(args, 0);
Dart_Handle result = Dart_StringToUTF8(str, &chars, &length);
if (Dart_IsError(result)) {
Dart_PropagateError(result);
}
auto logger = forge::log::js_logger();
logger->debug(std::string_view((const char *)chars, length));
}
void NotifyServerState(Dart_NativeArguments args) {
auto logger = forge::log::js_logger();
logger->debug("notify server state callback");
}
void Shutdown(Dart_NativeArguments args) {
// NO-OP.
}
Dart_NativeFunction NativeEntryResolver(Dart_Handle name,
int num_of_arguments,
bool* auto_setup_scope) {
const char* function_name = NULL;
Dart_Handle err = Dart_StringToCString(name, &function_name);
FG_ALWAYS_ASSERT(!Dart_IsError(err));
auto logger = forge::log::js_logger();
logger->debug("Resolve Entry {}", function_name);
if (function_name == std::string_view("Builtin_PrintString")) {
return merp_print;
} else if (function_name == std::string_view("VMServiceIO_NotifyServerState")) {
return NotifyServerState;
} else if (function_name == std::string_view("VMServiceIO_Shutdown")) {
return Shutdown;
}
return dart::bin::LookupIONative(name, num_of_arguments, auto_setup_scope);
}
const uint8_t* NativeEntrySymbol(Dart_NativeFunction nf) {
auto logger = forge::log::js_logger();
logger->debug("Symbol Lookup {}", (void*)nf);
return dart::bin::LookupIONativeSymbol(nf);
}
Dart_Handle
LibraryTagHandler(Dart_LibraryTag tag, Dart_Handle library, Dart_Handle url) {
auto logger = forge::log::js_logger();
const char* url_string = NULL;
Dart_Handle result = Dart_StringToCString(url, &url_string);
FG_ALWAYS_ASSERT(result);
logger->debug("loading {}", url_string);
return nullptr;
}
#include <forge/utility/expected.h>
namespace lawn {
template <typename T, typename E>
using Expected = forge::Expected<T, E>;
Dart_Handle to_dart(const char* s) {
auto result = Dart_NewStringFromCString(s);
FG_ASSERT_NOT_ERROR(result);
return result;
}
template <typename T, std::enable_if_t<std::is_integral_v<T>, bool> = false>
Dart_Handle to_dart(T value) {
if constexpr (std::is_same_v<std::remove_cv_t<T>, bool>) {
if (value) {
return Dart_True();
} else {
return Dart_False();
}
} else if (std::is_signed_v<T>) {
return Dart_NewInteger(value);
} else {
return Dart_NewIntegerFromUint64(value);
}
}
namespace bootstrap {
void initialize_internal(Dart_Handle internal_lib, Dart_Handle builtin_lib) {
Dart_Handle print =
Dart_Invoke(builtin_lib, lawn::to_dart("_getPrintClosure"), 0, NULL);
FG_ASSERT_NOT_ERROR(print);
Dart_Handle result =
Dart_SetField(internal_lib, lawn::to_dart("_printClosure"), print);
FG_ASSERT_NOT_ERROR(result);
}
void initialize_core(Dart_Handle core_lib,
Dart_Handle io_lib,
bool is_service_isolate) {
if (!is_service_isolate) {
Dart_Handle uri_base =
Dart_Invoke(io_lib, to_dart("_getUriBaseClosure"), 0, NULL);
FG_ASSERT_NOT_ERROR(uri_base);
Dart_Handle result =
Dart_SetField(core_lib, to_dart("_uriBaseClosure"), uri_base);
FG_ASSERT_NOT_ERROR(result);
}
}
void initialize_async(Dart_Handle async_lib, Dart_Handle isolate_lib) {
Dart_Handle schedule_immediate_closure =
Dart_Invoke(isolate_lib,
lawn::to_dart("_getIsolateScheduleImmediateClosure"),
0,
NULL);
FG_ASSERT_NOT_ERROR(schedule_immediate_closure);
FG_ASSERT_NOT_ERROR(
Dart_Invoke(async_lib,
lawn::to_dart("_setScheduleImmediateClosure"),
1,
&schedule_immediate_closure));
}
void initialize_io(Dart_Handle io_lib) {
// TODO
}
void initialize_dart_libs(bool is_service_isolate = false) {
constexpr auto get_lib = [](const char* n) {
auto result = Dart_LookupLibrary(Dart_NewStringFromCString(n));
FG_ASSERT_NOT_ERROR(result);
return result;
};
// auto core_lib = get_lib("dart:core");
auto async_lib = get_lib("dart:async");
auto isolate_lib = get_lib("dart:isolate");
auto internal_lib = get_lib("dart:_internal");
auto builtin_lib = get_lib("dart:_builtin");
auto io_lib = get_lib("dart:io");
auto core_lib = get_lib("dart:core");
// TODO maybe cli?
initialize_internal(internal_lib, builtin_lib);
initialize_core(core_lib, io_lib, is_service_isolate);
initialize_async(async_lib, isolate_lib);
initialize_io(io_lib);
FG_ASSERT_NOT_ERROR(
Dart_Invoke(isolate_lib, to_dart("_setupHooks"), 0, NULL));
FG_ASSERT_NOT_ERROR(Dart_Invoke(io_lib, to_dart("_setupHooks"), 0, NULL));
FG_ASSERT_NOT_ERROR(Dart_SetNativeResolver(
builtin_lib, &NativeEntryResolver, &NativeEntrySymbol));
FG_ASSERT_NOT_ERROR(Dart_SetNativeResolver(
io_lib, &NativeEntryResolver, &NativeEntrySymbol));
}
} // namespace bootstrap
} // namespace lawn
Dart_Isolate isolate_create_callback(const char* script_uri,
const char* main,
const char* package_root,
const char* package_config,
Dart_IsolateFlags* flags,
void* callback_data,
char** error) {
auto logger = forge::log::js_logger();
logger->debug("isolate_create_callback {} | {}", script_uri, main);
if (std::string_view(script_uri) == DART_KERNEL_ISOLATE_NAME) {
logger->debug("loading kernel service");
auto result = Dart_CreateIsolateFromKernel(script_uri,
main,
kKernelServiceDill,
kKernelServiceDillSize,
flags,
callback_data,
error);
FG_ALWAYS_ASSERT(result);
Dart_EnterScope();
auto script = Dart_LoadScriptFromKernel(kKernelServiceDill,
kKernelServiceDillSize);
FG_ASSERT_NOT_ERROR(script);
lawn::bootstrap::initialize_dart_libs();
Dart_ExitScope();
Dart_ExitIsolate();
return result;
}
if (std::string_view(script_uri) == DART_VM_SERVICE_ISOLATE_NAME) {
logger->debug("loading service isolate");
flags->load_vmservice_library = true;
auto result = Dart_CreateIsolateFromKernel(script_uri,
main,
kPlatformStrongDill,
kPlatformStrongDillSize,
flags,
callback_data,
error);
Dart_EnterScope();
lawn::bootstrap::initialize_dart_libs(true);
auto lib = Dart_LookupLibrary(lawn::to_dart("dart:vmservice_io"));
FG_ASSERT_NOT_ERROR(lib);
FG_ASSERT_NOT_ERROR(Dart_SetRootLibrary(lib));
FG_ASSERT_NOT_ERROR(Dart_SetNativeResolver(
lib, &NativeEntryResolver, &NativeEntrySymbol));
FG_ASSERT_NOT_ERROR(Dart_SetLibraryTagHandler(LibraryTagHandler));
Dart_EnterScope();
Dart_ExitIsolate();
FG_ALWAYS_ASSERT(!Dart_IsolateMakeRunnable(result));
Dart_EnterIsolate(result);
Dart_EnterScope();
lib = Dart_RootLibrary();
FG_ASSERT_NOT_ERROR(lib);
FG_ASSERT_NOT_ERROR(Dart_SetField(
lib, lawn::to_dart("_ip"), lawn::to_dart("127.0.0.1")));
FG_ASSERT_NOT_ERROR(
Dart_SetField(lib, lawn::to_dart("_port"), lawn::to_dart(0)));
FG_ASSERT_NOT_ERROR(Dart_SetField(
lib, lawn::to_dart("_autoStart"), lawn::to_dart(true)));
FG_ASSERT_NOT_ERROR(Dart_SetField(
lib, lawn::to_dart("_originCheckDisabled"), lawn::to_dart(true)));
FG_ASSERT_NOT_ERROR(Dart_SetField(
lib, lawn::to_dart("_authCodesDisabled"), lawn::to_dart(true)));
FG_ASSERT_NOT_ERROR(Dart_SetField(
lib, lawn::to_dart("_isWindows"), lawn::to_dart(false)));
// if (deterministic) {
// result = Dart_SetField(library, DartUtils::NewString("_deterministic"),
// Dart_True());
// SHUTDOWN_ON_ERROR(result);
// }
auto io_lib = Dart_LookupLibrary(lawn::to_dart("dart:io"));
FG_ASSERT_NOT_ERROR(io_lib);
auto signal_watch = Dart_Invoke(
io_lib, lawn::to_dart("_getWatchSignalInternal"), 0, nullptr);
FG_ASSERT_NOT_ERROR(signal_watch);
FG_ASSERT_NOT_ERROR(
Dart_SetField(lib, lawn::to_dart("_signalWatch"), signal_watch));
Dart_ExitScope();
Dart_ExitIsolate();
return result;
}
return nullptr;
}
void isolate_shutdown_callback(void* callback_data) {}
void isolate_cleanup_callback(void* callback_data) {}
void thread_exit_callback() {}
void entroy_source_callback(uint8_t* buffer, intptr_t length) {
auto dist = std::uniform_int_distribution<uint8_t>();
auto device = std::random_device();
for (intptr_t i = 0; i < length; i++) {
buffer[i] = dist(device);
}
}
Dart_Handle get_vm_service_assets_callback() {
std::string m;
boost::filesystem::load_string_file(
"/Users/chancila/src/dart-sdk/sdk/xcodebuild/DebugX64/gen/runtime/"
"observatory/observatory_archive.tar",
m);
Dart_Handle array = Dart_NewTypedData(Dart_TypedData_kUint8, m.size());
Dart_TypedData_Type td_type;
void* td_data;
intptr_t td_len;
Dart_Handle result =
Dart_TypedDataAcquireData(array, &td_type, &td_data, &td_len);
FG_ASSERT_NOT_ERROR(result);
FG_ALWAYS_ASSERT(td_type == Dart_TypedData_kUint8);
FG_ALWAYS_ASSERT(td_len == m.size());
FG_ALWAYS_ASSERT(td_data != NULL);
memmove(td_data, m.data(), td_len);
result = Dart_TypedDataReleaseData(array);
FG_ASSERT_NOT_ERROR(result);
return array;
}
static bool ServiceStreamListenCallback(const char* stream_id) {
dart::bin::SetCaptureStdout(true);
dart::bin::SetCaptureStderr(true);
return true;
}
static void ServiceStreamCancelCallback(const char* stream_id) {}
int main(int argc, char* args[]) {
auto dart_logger = spdlog::stdout_color_mt("dart");
dart_logger->set_pattern("[%H:%M:%S %z][%t][%n] %v");
dart_logger->set_level(spdlog::level::debug);
forge::log::set_js_logger(dart_logger);
char* orr = nullptr;
dart::bin::BootstrapDartIo();
FG_ALWAYS_ASSERT(!orr);
// dart::bin::BootstrapDartIo();
Dart_InitializeParams params = {};
params.version = DART_INITIALIZE_PARAMS_CURRENT_VERSION;
params.vm_snapshot_data = kDartVmSnapshotData;
params.vm_snapshot_instructions = kDartVmSnapshotInstructions;
params.create = isolate_create_callback;
params.shutdown = isolate_shutdown_callback;
params.cleanup = isolate_cleanup_callback;
params.thread_exit = thread_exit_callback;
// Dart_FileOpenCallback file_open;
// Dart_FileReadCallback file_read;
// Dart_FileWriteCallback file_write;
// Dart_FileCloseCallback file_close;
params.entropy_source = dart::bin::GetEntropy;
params.get_service_assets = get_vm_service_assets_callback;
params.start_kernel_isolate = true;
const char* dart_args[] = {
"--new_gen_semi_max_size=32",
"--new_gen_growth_factor=4",
"--pause_isolates_on_start",
};
auto flag_result = Dart_SetVMFlags(2, dart_args);
dart_logger->debug("VM flags result {}", flag_result == nullptr);
auto init_result = Dart_Initialize(&params);
FG_ALWAYS_ASSERT(!init_result);
Dart_SetServiceStreamCallbacks(&ServiceStreamListenCallback,
&ServiceStreamCancelCallback);
Dart_SetDartLibrarySourcesKernel(kPlatformStrongDill,
kPlatformStrongDillSize);
dart_logger->debug("init result {}", init_result == nullptr);
Dart_IsolateFlags flags;
Dart_IsolateFlagsInitialize(&flags);
FG_ALWAYS_ASSERT(
Dart_IsKernel(kPlatformStrongDill, kPlatformStrongDillSize));
char* error;
auto platform_isolate =
Dart_CreateIsolateFromKernel("main.dart",
"main",
kPlatformStrongDill,
kPlatformStrongDillSize,
&flags,
nullptr,
&error);
FG_ALWAYS_ASSERT(platform_isolate);
Dart_EnterScope();
auto finalize_result = Dart_FinalizeLoading(false);
FG_ASSERT_NOT_ERROR(finalize_result);
FG_ASSERT_NOT_ERROR(Dart_SetLibraryTagHandler(LibraryTagHandler));
lawn::bootstrap::initialize_dart_libs();
auto compile_result = Dart_CompileToKernel("main.dart",
kPlatformStrongDill,
kPlatformStrongDillSize,
false,
nullptr);
if (compile_result.status) {
dart_logger->debug("failed to compile main dart {}",
compile_result.error);
dart_logger->flush();
return -1;
}
FG_ASSERT_NOT_ERROR(Dart_LoadScriptFromKernel(compile_result.kernel,
compile_result.kernel_size));
Dart_ExitScope();
Dart_ExitIsolate();
auto morp = Dart_IsolateMakeRunnable(platform_isolate);
FG_ALWAYS_ASSERT(!morp);
Dart_EnterIsolate(platform_isolate);
Dart_EnterScope();
Dart_Handle root_lib = Dart_RootLibrary();
FG_ASSERT_NOT_ERROR(root_lib);
Dart_Handle main_closure =
Dart_GetField(root_lib, Dart_NewStringFromCString("main"));
FG_ASSERT_NOT_ERROR(main_closure);
FG_ALWAYS_ASSERT(Dart_IsClosure(main_closure));
const intptr_t kNumIsolateArgs = 2;
Dart_Handle isolate_args[kNumIsolateArgs];
isolate_args[0] = main_closure; // entryPoint
isolate_args[1] = Dart_Null();
auto isolate_lib =
Dart_LookupLibrary(Dart_NewStringFromCString("dart:isolate"));
auto invoke_result =
Dart_Invoke(isolate_lib,
Dart_NewStringFromCString("_startMainIsolate"),
2,
isolate_args);
if (Dart_IsError(invoke_result)) {
dart_logger->debug("failed to call main {}",
Dart_GetError(invoke_result));
}
FG_ASSERT_NOT_ERROR(Dart_NewSendPort(Dart_GetMainPortId()));
FG_ASSERT_NOT_ERROR(Dart_RunLoop());
dart_logger->flush();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment