From: Brendan Hansen Date: Fri, 10 Mar 2023 21:16:57 +0000 (-0600) Subject: added: `#foreign #dyncall` blocks X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=67215ad5910c7935bcb04120274e17068e0ce15d;p=onyx.git added: `#foreign #dyncall` blocks --- diff --git a/compiler/include/astnodes.h b/compiler/include/astnodes.h index 2a43446c..778dd0a2 100644 --- a/compiler/include/astnodes.h +++ b/compiler/include/astnodes.h @@ -1285,9 +1285,10 @@ struct AstFunction { bh_arr(AstNode *) nodes_that_need_entities_after_clone; - b32 is_exported : 1; - b32 is_foreign : 1; - b32 is_intrinsic : 1; + b32 is_exported : 1; + b32 is_foreign : 1; + b32 is_foreign_dyncall : 1; + b32 is_intrinsic : 1; }; struct AstPolyQuery { @@ -1418,6 +1419,8 @@ struct AstForeignBlock { bh_arr(struct Entity *) captured_entities; u32 foreign_block_number; + + b32 uses_dyncall : 1; }; typedef struct EntityJobData { diff --git a/compiler/src/parser.c b/compiler/src/parser.c index c6cbccce..1a81139f 100644 --- a/compiler/src/parser.c +++ b/compiler/src/parser.c @@ -3056,6 +3056,11 @@ static AstForeignBlock* parse_foreign_block(OnyxParser* parser, OnyxToken *token // :LinearTokenDependent AstForeignBlock *fb = make_node(AstForeignBlock, Ast_Kind_Foreign_Block); fb->token = token; + + if (parse_possible_directive(parser, "dyncall")) { + fb->uses_dyncall = 1; + } + fb->module_name = expect_token(parser, Token_Type_Literal_String); // diff --git a/compiler/src/symres.c b/compiler/src/symres.c index 5e81c28d..0ce2c63f 100644 --- a/compiler/src/symres.c +++ b/compiler/src/symres.c @@ -1702,6 +1702,7 @@ static SymresStatus symres_foreign_block(AstForeignBlock *fb) { ent->function->foreign_name = ent->function->intrinsic_name; // Hmm... This might not be right? ent->function->foreign_module = fb->module_name; ent->function->is_foreign = 1; + ent->function->is_foreign_dyncall = fb->uses_dyncall; ent->function->entity = NULL; ent->function->entity_header = NULL; ent->function->entity_body = NULL; diff --git a/compiler/src/wasm_emit.c b/compiler/src/wasm_emit.c index 076d3a29..f73fba2d 100644 --- a/compiler/src/wasm_emit.c +++ b/compiler/src/wasm_emit.c @@ -56,7 +56,7 @@ static WasmType onyx_type_to_wasm_type(Type* type) { if (basic->size <= 4) return WASM_TYPE_INT32; if (basic->size == 8) return WASM_TYPE_INT64; } - if (basic->flags & Basic_Flag_Pointer) return WASM_TYPE_INT32; + if (basic->flags & Basic_Flag_Pointer) return WASM_TYPE_PTR; if (basic->flags & Basic_Flag_Float) { if (basic->size <= 4) return WASM_TYPE_FLOAT32; if (basic->size == 8) return WASM_TYPE_FLOAT64; @@ -4119,16 +4119,60 @@ static void emit_function(OnyxWasmModule* mod, AstFunction* fd) { debug_end_function(mod); } +static char encode_type_as_dyncall_symbol(Type *t) { + if (t->kind == Type_Kind_Slice) return 's'; + if (t->kind == Type_Kind_Pointer) return 'p'; + if (t->kind == Type_Kind_Enum) return encode_type_as_dyncall_symbol(t->Enum.backing); + if (t->kind == Type_Kind_Basic) { + TypeBasic* basic = &t->Basic; + if (basic->flags & Basic_Flag_Boolean) return 'i'; + if (basic->flags & Basic_Flag_Integer) { + if (basic->size <= 4) return 'i'; + if (basic->size == 8) return 'l'; + } + if (basic->flags & Basic_Flag_Pointer) return 'p'; + if (basic->flags & Basic_Flag_Float) { + if (basic->size <= 4) return 'f'; + if (basic->size == 8) return 'd'; + } + if (basic->flags & Basic_Flag_SIMD) return 'v'; + if (basic->flags & Basic_Flag_Type_Index) return 'i'; + if (basic->size == 0) return 'v'; + } + + return 'v'; +} + static void emit_foreign_function(OnyxWasmModule* mod, AstFunction* fd) { if (!should_emit_function(fd)) return; i32 type_idx = generate_type_idx(mod, fd->type); + char *module, *name; + + if (fd->is_foreign_dyncall) { + module = bh_aprintf(global_heap_allocator, "dyncall:%b", fd->foreign_module->text, fd->foreign_module->length); + + char type_encoding[64] = {0}; + type_encoding[0] = encode_type_as_dyncall_symbol(fd->type->Function.return_type); + + int index = 1; + bh_arr_each(AstParam, param, fd->params) { + type_encoding[index++] = encode_type_as_dyncall_symbol(param->local->type); + } + + name = bh_aprintf(global_heap_allocator, "%b:%s", fd->foreign_name->text, fd->foreign_name->length, type_encoding); + + } else { + module = bh_aprintf(global_heap_allocator, "%b", fd->foreign_module->text, fd->foreign_module->length); + name = bh_aprintf(global_heap_allocator, "%b", fd->foreign_name->text, fd->foreign_name->length); + } + WasmImport import = { .kind = WASM_FOREIGN_FUNCTION, .idx = type_idx, - .mod = bh_aprintf(global_heap_allocator, "%b", fd->foreign_module->text, fd->foreign_module->length), - .name = bh_aprintf(global_heap_allocator, "%b", fd->foreign_name->text, fd->foreign_name->length), + .mod = module, + .name = name, }; bh_arr_push(mod->imports, import); diff --git a/compiler/src/wasm_runtime.c b/compiler/src/wasm_runtime.c index f36ad33d..7eee52a6 100644 --- a/compiler/src/wasm_runtime.c +++ b/compiler/src/wasm_runtime.c @@ -77,30 +77,42 @@ typedef struct LinkLibraryContext { } LinkLibraryContext; -static void *locate_symbol_in_dynamic_library(LinkLibraryContext *ctx, char *libname, char *sym) { - #ifdef _BH_LINUX - char *library_name = bh_lookup_file(libname, ".", ".so", 1, (const char **) ctx->library_paths, 1); - void* handle = dlopen(library_name, RTLD_LAZY); +static void *locate_symbol_in_dynamic_library_raw(char *libname, char *sym) { +#ifdef _BH_LINUX + void* handle = dlopen(libname, RTLD_LAZY); if (handle == NULL) { return NULL; } return dlsym(handle, sym); - #endif +#endif - #ifdef _BH_WINDOWS - char *library_name = bh_lookup_file(libname, ".", ".dll", 1, (const char **) ctx->library_paths, 1); - HMODULE handle = LoadLibraryA(library_name); +#ifdef _BH_WINDOWS + HMODULE handle = LoadLibraryA(libname); if (handle == NULL) { return NULL; } return GetProcAddress(handle, sym); - #endif +#endif return NULL; } +static void *locate_symbol_in_dynamic_library(LinkLibraryContext *ctx, char *libname, char *sym) { + char *library_name; + + #ifdef _BH_LINUX + library_name = bh_lookup_file(libname, ".", ".so", 1, (const char **) ctx->library_paths, 1); + #endif + + #ifdef _BH_WINDOWS + library_name = bh_lookup_file(libname, ".", ".dll", 1, (const char **) ctx->library_paths, 1); + #endif + + return locate_symbol_in_dynamic_library_raw(library_name, sym); +} + typedef void *(*LinkLibraryer)(OnyxRuntime *runtime); static WasmFuncDefinition** onyx_load_library(LinkLibraryContext *ctx, char *name) { @@ -202,11 +214,12 @@ static wasm_trap_t *__wasm_dyncall(void *env, const wasm_val_vec_t *args, wasm_v case 'i': dcArgInt(dcCallVM, args->data[arg_idx++].of.i32); break; case 'l': dcArgLongLong(dcCallVM, args->data[arg_idx++].of.i64); break; case 'f': dcArgFloat(dcCallVM, args->data[arg_idx++].of.f32); break; - case 'd': dcArgFloat(dcCallVM, args->data[arg_idx++].of.f64); break; - case 'p': dcArgPointer(dcCallVM, ONYX_PTR(args->data[arg_idx++].of.i32)); break; - case 'v': break; + case 'd': dcArgDouble(dcCallVM, args->data[arg_idx++].of.f64); break; + case 'p': dcArgPointer(dcCallVM, ONYX_PTR(args->data[arg_idx].of.i32)); arg_idx++; break; + case 'v': arg_idx++; break; case 's': - dcArgPointer(dcCallVM, ONYX_PTR(args->data[arg_idx++].of.i32)); + dcArgPointer(dcCallVM, ONYX_PTR(args->data[arg_idx].of.i32)); + arg_idx++; dcArgInt(dcCallVM, args->data[arg_idx++].of.i32); break; default: assert(("bad dynamic call type", 0)); @@ -215,14 +228,15 @@ static wasm_trap_t *__wasm_dyncall(void *env, const wasm_val_vec_t *args, wasm_v arguments_placed: switch (ctx->types[0]) { - case 'i': res->data[0] = WASM_I32_VAL(dcCallInt(dcCallVM, ctx->func)); break; - case 'l': res->data[0] = WASM_I64_VAL(dcCallLongLong(dcCallVM, ctx->func)); break; - case 'f': res->data[0] = WASM_F32_VAL(dcCallFloat(dcCallVM, ctx->func)); break; - case 'd': res->data[0] = WASM_F64_VAL(dcCallDouble(dcCallVM, ctx->func)); break; - case 'p': res->data[0] = WASM_I64_VAL((u64) dcCallPointer(dcCallVM, ctx->func)); break; - case 'v': dcCallVoid(dcCallVM, ctx->func); + case 'i': res->data[0] = WASM_I32_VAL(dcCallInt(dcCallVM, ctx->func)); break; + case 'l': res->data[0] = WASM_I64_VAL(dcCallLongLong(dcCallVM, ctx->func)); break; + case 'f': res->data[0] = WASM_F32_VAL(dcCallFloat(dcCallVM, ctx->func)); break; + case 'd': res->data[0] = WASM_F64_VAL(dcCallDouble(dcCallVM, ctx->func)); break; + case 'p': res->data[0] = WASM_I64_VAL((u64) dcCallPointer(dcCallVM, ctx->func)); break; + case 'v': dcCallVoid(dcCallVM, ctx->func); break; } + dcReset(dcCallVM); return NULL; } @@ -239,24 +253,26 @@ static wasm_func_t *link_and_prepare_dyncall_function( dcMode(dcCallVM, DC_CALL_C_DEFAULT); } - char lib_name[256]; + char lib_name[256] = {0}; strncpy(lib_name, library_name.data, bh_min(256, library_name.size)); u32 index; - char func_name[256]; + char func_name[256] = {0}; for (index = 0; index < function_name.size; index++) { - if (function_name.data[index] == ':') break; + if (function_name.data[index] == ':') { + index ++; + break; + } + func_name[index] = function_name.data[index]; } - func_name[index++] = '\0'; - char dynamic_types[64]; - for (; index < function_name.size; index++) { - dynamic_types[index] = function_name.data[index]; + char dynamic_types[64] = {0}; + for (u32 write_index = 0; index < function_name.size; write_index++, index++) { + dynamic_types[write_index] = function_name.data[index]; } - dynamic_types[index] = '\0'; - void (*func)() = locate_symbol_in_dynamic_library(lib_ctx, lib_name, func_name); + void (*func)() = locate_symbol_in_dynamic_library_raw(lib_name, func_name); if (!func) return NULL; wasm_functype_t *functype = wasm_externtype_as_functype(type);