successfully loading a library dynamically with "#library"
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Sun, 5 Dec 2021 18:08:18 +0000 (12:08 -0600)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Sun, 5 Dec 2021 18:08:18 +0000 (12:08 -0600)
12 files changed:
include/astnodes.h
include/onyx_library.h
include/wasm_emit.h
modules/test_library/module.onyx
modules/test_library/test_library.c
src/astnodes.c
src/checker.c
src/entities.c
src/parser.c
src/symres.c
src/wasm_emit.c
src/wasm_runtime.c

index 66deb9a877e2b0b24248ff033e7a292118d49ec3..3f9ce101eeff79ea25dd7033f7f9dc79aa4d1ea5 100644 (file)
@@ -41,6 +41,7 @@
     NODE(DirectiveDefined)     \
     NODE(DirectiveTag)         \
     NODE(DirectiveInit)        \
+    NODE(DirectiveLibrary)     \
                                \
     NODE(Return)               \
     NODE(Jump)                 \
@@ -207,6 +208,7 @@ typedef enum AstKind {
     Ast_Kind_Directive_Defined,
     Ast_Kind_Directive_Tag,
     Ast_Kind_Directive_Init,
+    Ast_Kind_Directive_Library,
     Ast_Kind_Call_Site,
 
     Ast_Kind_Code_Block,
@@ -1268,6 +1270,13 @@ struct AstMacro {
     AstTyped* body;
 };
 
+struct AstDirectiveLibrary {
+    AstNode_base;
+
+    AstTyped *library_symbol; // This should resolve to a string literal
+    char *library_name;
+};
+
 typedef enum EntityState {
     Entity_State_Error,
     
@@ -1365,6 +1374,7 @@ typedef struct Entity {
         AstUse                *use;
         AstInterface          *interface;
         AstConstraint         *constraint;
+        AstDirectiveLibrary   *library;
     };
 } Entity;
 
index 2f7e8a5eaa9ec737f31be8206555c54be286d58e..d19a8209097caee9c960aa4f7c84fac1faa1b48f 100644 (file)
@@ -54,3 +54,5 @@ typedef struct WasmFuncDefinition {
 #define FLOAT WASM_F32
 #define DOUBLE WASM_F64
 #define PTR WASM_I32
+
+#define ONYX_PTR(p) (wasm_memory_data(wasm_memory) + p)
\ No newline at end of file
index 5e80b0384cef3b006dc21a5a3c5d8b5c7ddbcab3..3892b3522fc4de5759288c7c1a714539bab48b3f 100644 (file)
@@ -652,6 +652,7 @@ typedef struct OnyxWasmModule {
     bh_arr(WasmFunc)      funcs;
     bh_arr(WasmDatum)     data;
     bh_arr(i32)           elems;
+    bh_arr(char *)        libraries;
 
     // NOTE: Set of things used when compiling; not part of the actual module
     u32 export_count;
index b0f3d387add02cd7aeb038395b4de082ef323c79..aad1e54352e4a73541c2e8162d668b681985ba0c 100644 (file)
@@ -1,6 +1,6 @@
 package test_library
 
-// #library "test_library"
+#library "test_library"
 
 foo :: () -> void #foreign "test_library" "foo" ---
 add :: (a, b: i32) -> i32 #foreign "test_library" "add" ---
index 16e1b0f6e603f2761d5d3969991c755ebf89c866..d7917764831b0efb5121e500f66442182fb77f64 100644 (file)
@@ -1,11 +1,19 @@
 #include "onyx_library.h"
 #include <stdio.h>
 #include <unistd.h>
+#include <GLFW/glfw3.h>
 
 #define ONYX_LIBRARY_NAME test_library
 
 ONYX_DEF(foo, (), ()) {
     printf("This worked!\n");
+    glfwInit();
+    GLFWwindow *window = glfwCreateWindow(800, 600, "WOOT!", NULL, NULL);
+    while (!glfwWindowShouldClose(window)) {
+        glfwPollEvents();
+        glfwSwapBuffers(window);
+    }
+    glfwDestroyWindow(window);
     return NULL;
 }
 
@@ -17,7 +25,7 @@ ONYX_DEF(add, (INT, INT), (INT)) {
 }
 
 ONYX_DEF(print_string, (PTR, INT), ()) {
-    char *start = wasm_memory_data(wasm_memory) + params->data[0].of.i32;
+    char *start = ONYX_PTR(params->data[0].of.i32);
     int  length = params->data[1].of.i32;
 
     write(1, start, length);
index 77fe25f81ab43ce865f50d629bf7eece3780e408..1b8498927251d1a8fe0461d0cea44d98d1d484d2 100644 (file)
@@ -93,6 +93,7 @@ static const char* ast_node_names[] = {
     "DEFINED",
     "TAG",
     "INIT",
+    "LIBRARY",
     "CALL SITE",
 
     "CODE BLOCK",
index 20cc4723a429c8d6d6b41d249ff187987f368454..92dd8079a3fb0e5b51de8f49e3d2ba77fdeec608 100644 (file)
@@ -2495,6 +2495,21 @@ CheckStatus check_process_directive(AstNode* directive) {
         return Check_Complete;
     }
 
+    if (directive->kind == Ast_Kind_Directive_Library) {
+        AstDirectiveLibrary *library = (AstDirectiveLibrary *) directive;
+
+        if (library->library_symbol->kind != Ast_Kind_StrLit) {
+            ERROR_(library->token->pos, "#library directive expected compile-time known string for library name. Got '%s'.",
+                onyx_ast_node_kind_string(library->library_symbol->kind));
+        }
+
+        AstStrLit *symbol = (AstStrLit *) library->library_symbol;
+        char* temp_name     = bh_alloc_array(global_scratch_allocator, char, symbol->token->length);
+        i32   temp_name_len = string_process_escape_seqs(temp_name, symbol->token->text, symbol->token->length);
+        library->library_name = bh_strdup(global_heap_allocator, temp_name);
+        return Check_Success;
+    }
+
     return Check_Success;
 }
 
index 3f707abe51a6dc1df84ac9c9c00e6046220ce5b9..e9f9994b3c1564fe2925e5304618e69995a4c416 100644 (file)
@@ -344,7 +344,8 @@ void add_entities_for_node(bh_arr(Entity *) *target_arr, AstNode* node, Scope* s
         case Ast_Kind_Directive_Add_Overload:
         case Ast_Kind_Directive_Tag:
         case Ast_Kind_Directive_Operator:
-        case Ast_Kind_Directive_Init: {
+        case Ast_Kind_Directive_Init:
+        case Ast_Kind_Directive_Library: {
             ent.type = Entity_Type_Process_Directive;
             ent.expr = (AstTyped *) node;
             ENTITY_INSERT(ent);
index 05832ab1755b5f055ea7177bb334e461df3de6ba..bd044b6408896997509f7667e347e1170058f3b0 100644 (file)
@@ -3069,6 +3069,15 @@ static void parse_top_level_statement(OnyxParser* parser) {
                 parse_init_directive(parser, parser->curr - 2);
                 return;
             }
+            else if (parse_possible_directive(parser, "library")) {
+                // :LinearTokenDependent
+                AstDirectiveLibrary *library = make_node(AstDirectiveLibrary, Ast_Kind_Directive_Library);
+                library->token = parser->curr - 2;
+                library->library_symbol = parse_expression(parser, 0);
+
+                ENTITY_SUBMIT(library);
+                return;
+            }
             else {
                 OnyxToken* directive_token = expect_token(parser, '#');
                 OnyxToken* symbol_token = expect_token(parser, Token_Type_Symbol);
index 24b341bf82be462913c1979d20aedd066b434354..e4abdb42cd92f5345383c1853de31f2aab8dfb0c 100644 (file)
@@ -1274,6 +1274,12 @@ static SymresStatus symres_process_directive(AstNode* directive) {
 
             break;
         }
+
+        case Ast_Kind_Directive_Library: {
+            AstDirectiveLibrary *library = (AstDirectiveLibrary *) directive;
+            SYMRES(expression, &library->library_symbol);
+            break;
+        }
     }
 
     return Symres_Success;
index 5dc35c52a76aef70120eb05109527959008dc89c..ffdaec2200ac7a674ba48bae265f92131dfe7a28 100644 (file)
@@ -3746,6 +3746,8 @@ OnyxWasmModule onyx_wasm_module_create(bh_allocator alloc) {
         .foreign_function_count = 0,
 
         .null_proc_func_idx = -1,
+
+        .libraries = NULL,
     };
 
     bh_arena* eid = bh_alloc(global_heap_allocator, sizeof(bh_arena));
@@ -3759,6 +3761,7 @@ OnyxWasmModule onyx_wasm_module_create(bh_allocator alloc) {
     bh_arr_new(alloc, module.globals, 4);
     bh_arr_new(alloc, module.data, 4);
     bh_arr_new(alloc, module.elems, 4);
+    bh_arr_new(alloc, module.libraries, 4);
 
     bh_arr_new(global_heap_allocator, module.return_location_stack, 4);
     bh_arr_new(global_heap_allocator, module.structured_jump_target, 16);
@@ -3874,6 +3877,10 @@ void emit_entity(Entity* ent) {
             if (ent->expr->kind == Ast_Kind_Directive_Export) {
                 emit_export_directive(module, (AstDirectiveExport *) ent->expr);
             }
+
+            if (ent->expr->kind == Ast_Kind_Directive_Library) {
+                bh_arr_push(module->libraries, ent->library->library_name);
+            }
             break;
         }
 
index 816093ddba1cca28d4172e819cf335a2093fa709..735691d7f481c08694b9461a11b173538fbd543b 100644 (file)
@@ -3,6 +3,7 @@
 #include "astnodes.h"
 #include "wasm.h"
 #include "wasmer.h"
+#include "onyx_library.h"
 
 #ifdef _BH_LINUX
     #include <pthread.h>
@@ -107,7 +108,7 @@ static i32 onyx_run_thread(void *data) {
     i32 thread_id = thread->id;
 
     { // Call the _thread_start procedure
-        wasm_val_t args[]    = { WASM_I32_VAL(thread_id), WASM_I32_VAL(thread->tls_base), WASM_I32_VAL (thread->funcidx), WASM_I32_VAL(thread->dataptr) };
+        wasm_val_t args[]    = { WASM_I32_VAL(thread_id), WASM_I32_VAL(thread->tls_base), WASM_I32_VAL(thread->funcidx), WASM_I32_VAL(thread->dataptr) };
         wasm_val_vec_t results;
         wasm_val_vec_t args_array = WASM_ARRAY_VEC(args);
 
@@ -206,7 +207,7 @@ typedef struct OnyxProcess {
 } OnyxProcess;
 
 WASM_INTEROP(onyx_process_spawn_impl) {
-    char* process_str = (char *) wasm_memory_data(wasm_memory) + params->data[0].of.i32;
+    char* process_str = ONYX_PTR(params->data[0].of.i32);
     i32   process_len = params->data[1].of.i32;
     i32   args_ptr    = params->data[2].of.i32;
     i32   args_len    = params->data[3].of.i32;
@@ -217,19 +218,18 @@ WASM_INTEROP(onyx_process_spawn_impl) {
     memcpy(process_path, process_str, process_len);
     process_path[process_len] = '\0';
 
-    OnyxProcess *process = bh_alloc_item(global_heap_allocator, OnyxProcess);
+    OnyxProcess *process = malloc(sizeof(OnyxProcess));
     memset(process, 0, sizeof(*process));
     process->magic_number = ONYX_PROCESS_MAGIC_NUMBER;
 
     #ifdef _BH_LINUX
-        char **process_args = bh_alloc_array(global_scratch_allocator, char *, args_len + 2);
-        byte_t* data = wasm_memory_data(wasm_memory);
-        byte_t* array_loc = data + args_ptr;
+        char **process_args = alloca(sizeof(char *) * (args_len + 2));
+        byte_t* array_loc = ONYX_PTR(args_ptr);
         fori (i, 0, args_len) {
-            char *arg_str = data + *(i32 *) (array_loc + i * 2 * POINTER_SIZE);
+            char *arg_str = ONYX_PTR(*(i32 *) (array_loc + i * 2 * POINTER_SIZE));
             i32   arg_len = *(i32 *) (array_loc + i * 2 * POINTER_SIZE + POINTER_SIZE);
 
-            char *arg = bh_alloc_array(global_scratch_allocator, char, arg_len + 1);
+            char *arg = alloca(sizeof(char) * (arg_len + 1));
             memcpy(arg, arg_str, arg_len);
             arg[arg_len] = '\0';
             process_args[i + 1] = arg;
@@ -287,8 +287,7 @@ WASM_INTEROP(onyx_process_spawn_impl) {
         memset(cmdLine, 0, 2048);
         strncat(cmdLine, process_path, 2047);
 
-        byte_t* data = wasm_memory_data(wasm_memory);
-        byte_t* array_loc = data + args_ptr;
+        byte_t* array_loc = ONYX_PTR(args_ptr);
         fori (i, 0, args_len) {
             char *arg_str = data + *(i32 *) (array_loc + i * 2 * POINTER_SIZE);
             i32   arg_len = *(i32 *) (array_loc + i * 2 * POINTER_SIZE + 4);
@@ -355,7 +354,7 @@ WASM_INTEROP(onyx_process_read_impl) {
 
     i32 output_ptr = params->data[1].of.i32;
     i32 output_len = params->data[2].of.i32;
-    u8 *buffer = wasm_memory_data(wasm_memory) + output_ptr;
+    u8 *buffer = ONYX_PTR(output_ptr);
 
     i32 bytes_read;
     #ifdef _BH_LINUX
@@ -381,7 +380,7 @@ WASM_INTEROP(onyx_process_write_impl) {
 
     i32 input_ptr = params->data[1].of.i32;
     i32 input_len = params->data[2].of.i32;
-    u8 *buffer = wasm_memory_data(wasm_memory) + input_ptr;
+    u8 *buffer = ONYX_PTR(input_ptr);
 
     i32 bytes_written;
     #ifdef _BH_LINUX
@@ -494,13 +493,11 @@ WASM_INTEROP(onyx_process_destroy_impl) {
          }
     #endif
 
-    bh_free(global_heap_allocator, process);
+    free(process);
 
     return NULL;
 }
 
-#include "onyx_library.h"
-
 typedef void *(*LibraryLinker)();
 static bh_arr(WasmFuncDefinition **) linkable_functions = NULL;
 
@@ -517,16 +514,30 @@ static void onyx_load_library(char *name) {
     }
 
     library_load = (LibraryLinker) dlsym(handle, library_load_name);
+    if (library_load == NULL) {
+        printf("ERROR RESOLVING '%s': %s\n", library_load_name, dlerror());
+        return;
+    }
     #endif
 
     WasmFuncDefinition** funcs = library_load();
     bh_arr_push(linkable_functions, funcs);
 }
 
+// NOCHECKIN TEMPORARY HACK
+// NOCHECKIN TEMPORARY HACK
+// NOCHECKIN TEMPORARY HACK
+#include "wasm_emit.h"
+
 // Returns 1 if successful
 b32 onyx_run_wasm(bh_buffer wasm_bytes) {
     bh_arr_new(global_heap_allocator, linkable_functions, 4);
-    onyx_load_library("test_library");
+
+    // NOCHECKIN TEMPORARY HACK
+    OnyxWasmModule* onyx_wasm_module = (OnyxWasmModule *) context.wasm_module;
+    bh_arr_each(char *, library_name, onyx_wasm_module->libraries) {
+        onyx_load_library(*library_name);
+    }
 
     wasm_instance_t* instance = NULL;
     wasmer_features_t* features = NULL;