Created
May 26, 2019 03:05
-
-
Save chancila/6e8c42ad7d41c735a0f0063a6688d78c to your computer and use it in GitHub Desktop.
Hello Dart
This file contains hidden or 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
#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(¶ms); | |
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