added: `#foreign #dyncall` blocks
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Fri, 10 Mar 2023 21:16:57 +0000 (15:16 -0600)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Fri, 10 Mar 2023 21:16:57 +0000 (15:16 -0600)
compiler/include/astnodes.h
compiler/src/parser.c
compiler/src/symres.c
compiler/src/wasm_emit.c
compiler/src/wasm_runtime.c

index 2a43446c66e5e713a6f38ba09058e8a91219b3bb..778dd0a28a6640579f9962fe9851751656426e49 100644 (file)
@@ -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 {
index c6cbccceb96c15ce2d580232b141964cbb36c264..1a81139f91c77f1598c5b275318c5d384508bfb9 100644 (file)
@@ -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);
 
     //
index 5e81c28dbf710540402a93bc957dfe0e06afc9c0..0ce2c63facc51a6bc74fec58fbbeb6b47d601ed2 100644 (file)
@@ -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;
index 076d3a2958d282b9cec62404f39256baaa4b0470..f73fba2d242adf03f50e384ffe4e5d52a903d56f 100644 (file)
@@ -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);
index f36ad33d75485fd77909c778dd448d14c90e781b..7eee52a6588a34aba0cfdd835499c22361068352 100644 (file)
@@ -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);