From: Brendan Hansen Date: Mon, 2 May 2022 19:09:02 +0000 (-0500) Subject: added foreign block info X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=a44ec3b883c1d1eccb14379093e6078d4cea36ef;p=onyx.git added foreign block info --- diff --git a/core/type_info/type_info.onyx b/core/type_info/type_info.onyx index 254753c1..ca84d3cd 100644 --- a/core/type_info/type_info.onyx +++ b/core/type_info/type_info.onyx @@ -187,3 +187,38 @@ get_type_info :: (t: type_expr) -> ^Type_Info { return type_table[cast(i32) t]; } + + + + +// +// I have a small feeling I am going to rename "type_info" at some point soon, +// which makes including this here make even more sense. +// + +// +// Foreign Blocks +// Because foreign blocks can generate a lot of data, and their data is only +// really helpful in a handful of cases, you need to pass "--generate-foreign-bindings" +// to have these arrays filled out. +// + +foreign_block :: #distinct u32 + +foreign_blocks: [] ^Foreign_Block; + +Foreign_Block :: struct { + module_name: str; + funcs: [] Foreign_Function; + + Foreign_Function :: struct { + name: str; + type: type_expr; + } +} + +get_foreign_block :: (f: foreign_block) -> ^Foreign_Block { + if ~~f < cast(i32) 0 || ~~f >= cast(i32) foreign_blocks.count do return null; + + return foreign_blocks[cast(i32) f]; +} \ No newline at end of file diff --git a/include/astnodes.h b/include/astnodes.h index f7cb2740..358c67f5 100644 --- a/include/astnodes.h +++ b/include/astnodes.h @@ -1329,6 +1329,8 @@ struct AstForeignBlock { Scope* scope; OnyxToken *module_name; bh_arr(struct Entity *) captured_entities; + + u32 foreign_block_number; }; typedef enum EntityState { @@ -1507,6 +1509,7 @@ struct CompileOptions { b32 use_post_mvp_features : 1; b32 use_multi_threading : 1; + b32 generate_foreign_info : 1; Runtime runtime; @@ -1591,6 +1594,8 @@ extern AstType *builtin_callsite_type; extern AstType *builtin_any_type; extern AstType *builtin_code_type; extern AstTyped *type_table_node; +extern AstTyped *foreign_blocks_node; +extern AstType *foreign_block_type; extern AstFunction *builtin_initialize_data_segments; extern AstFunction *builtin_run_init_procedures; extern bh_arr(AstFunction *) init_procedures; diff --git a/include/wasm_emit.h b/include/wasm_emit.h index 71141188..c9f10ab0 100644 --- a/include/wasm_emit.h +++ b/include/wasm_emit.h @@ -645,6 +645,9 @@ typedef struct OnyxWasmModule { bh_arr(ForRemoveInfo) for_remove_info; + bh_arr(AstForeignBlock *) foreign_blocks; + u32 next_foreign_block_idx; + // NOTE: Used internally as a map from strings that represent function types, // 0x7f 0x7f : 0x7f ( (i32, i32) -> i32 ) // to the function type index if it has been created. diff --git a/modules/ncurses/build.onyx b/modules/ncurses/build.onyx new file mode 100644 index 00000000..ccdf0321 --- /dev/null +++ b/modules/ncurses/build.onyx @@ -0,0 +1,37 @@ +#load "core/std" +#load "scripts/c_binding" +#load "./module" + +use package core +use package c_binding + +main :: () { + result := build_c_binding(.{ + output_file = "modules/ncurses/ncurses.c", + foreign_block = (package ncurses).foreign_block, + + cast_map = .[ + .{ (package ncurses).WINDOW, "WINDOW *" }, + ], + + preamble = .[ +""" +#include "ncurses.h" + +#define __get_stdscr() ((unsigned long int) stdscr) + +void __get_yx (WINDOW *w, int *y, int *x) { getyx(w, *y, *x); } +void __get_par_yx(WINDOW *w, int *y, int *x) { getparyx(w, *y, *x); } +void __get_beg_yx(WINDOW *w, int *y, int *x) { getbegyx(w, *y, *x); } +void __get_max_yx(WINDOW *w, int *y, int *x) { getmaxyx(w, *y, *x); } +""" + ], + }); + + if !result { + println("Failed to make c-file."); + os.exit(1); + } else { + println("Sucessfully made ncurses.c"); + } +} \ No newline at end of file diff --git a/modules/ncurses/build.sh b/modules/ncurses/build.sh index caff9ee2..2412b380 100755 --- a/modules/ncurses/build.sh +++ b/modules/ncurses/build.sh @@ -1,4 +1,4 @@ #!/bin/sh -onyx run scripts/c_binding.onyx modules/ncurses/module.onyx > modules/ncurses/ncurses.c +onyx run modules/ncurses/build.onyx --generate-foreign-info gcc -shared -fPIC -I include -I lib/common/include -O2 modules/ncurses/ncurses.c -o modules/ncurses/onyx_ncurses.so -lncurses diff --git a/modules/ncurses/module.onyx b/modules/ncurses/module.onyx index 5908a1f3..2ce78887 100644 --- a/modules/ncurses/module.onyx +++ b/modules/ncurses/module.onyx @@ -2,32 +2,18 @@ package ncurses use package core {cptr, conv, string} - -#library "onyx_ncurses" -#foreign "onyx_ncurses" { - -/* -use CBindings -CBindings :: struct { - name :: "onyx_ncurses" - file_prefix :: """ -#include "ncurses.h" - -WINDOW *__get_stdscr() { - return stdscr; +#local Building_Library :: #defined ((package runtime).Generated_Foreign_Info) + +#if Building_Library { + // "Forward" the foreign block info to the public scope + // if foreign block information was generated. + foreign_block :: __foreign_block +} else { + // Otherwise, require the library to be included. + #library "onyx_ncurses" } -void __get_yx (WINDOW *w, int *y, int *x) { getyx(w, *y, *x); } -void __get_par_yx(WINDOW *w, int *y, int *x) { getparyx(w, *y, *x); } -void __get_beg_yx(WINDOW *w, int *y, int *x) { getbegyx(w, *y, *x); } -void __get_max_yx(WINDOW *w, int *y, int *x) { getmaxyx(w, *y, *x); } - -""" - cast_map :: (#type struct {type: type_expr; name: str;}).[ - .{ WINDOW, "WINDOW *" }, - ] -*/ - +#local __foreign_block :: #foreign "onyx_ncurses" { // initscr initscr :: () -> WINDOW --- endwin :: () -> i32 --- @@ -356,7 +342,7 @@ void __get_max_yx(WINDOW *w, int *y, int *x) { getmaxyx(w, *y, *x); } getmouse :: (@out event: ^MEvent) -> i32 --- ungetmouse :: (@out event: ^MEvent) -> i32 --- mousemask :: (newmask: mmask_t, @out oldmask: ^mmask_t) -> mmask_t --- - wenclone :: (w: WINDOW, y, x: i32) -> bool --- + wenclose :: (w: WINDOW, y, x: i32) -> bool --- mouse_trafo :: (py, px: ^i32, to_screen: bool) -> bool --- wmouse_trafo :: (w: WINDOW, py, px: ^i32, to_screen: bool) -> bool --- mouseinterval :: (erval: i32) -> i32 --- @@ -376,6 +362,21 @@ void __get_max_yx(WINDOW *w, int *y, int *x) { getmaxyx(w, *y, *x); } NCURSES_ACS :: (a: i32) -> chtype --- } +// Types have to always be included +WINDOW :: #distinct u64 +SCREEN :: #distinct u64 +chtype :: u32 +attr_t :: u32 + +mmask_t :: u64 +MEvent :: struct { + id: u16; + x, y, z: i32; + bstate: mmask_t; +} + + +#if !Building_Library { stdscr :: __get_stdscr getyx :: __get_yx @@ -431,18 +432,6 @@ mvwprintw :: (w: WINDOW, y, x: i32, fmt: str, args: ..any) { mvwaddnstr(w, y, x, to_output); } -WINDOW :: #distinct u64 -SCREEN :: #distinct u64 -chtype :: u32 -attr_t :: u32 - -mmask_t :: u64 -MEvent :: struct { - id: u16; - x, y, z: i32; - bstate: mmask_t; -} - BUTTON1_RELEASED :: 0x01 << (0 * 6) BUTTON1_PRESSED :: 0x02 << (0 * 6) BUTTON1_CLICKED :: 0x04 << (0 * 6) @@ -601,3 +590,6 @@ KEY_SUSPEND :: 0627 /* suspend key */ KEY_UNDO :: 0630 /* undo key */ KEY_MOUSE :: 0631 /* Mouse event has occurred */ + + +} // !Building_Library \ No newline at end of file diff --git a/modules/ncurses/ncurses.c b/modules/ncurses/ncurses.c index 029c211c..275ef36d 100644 --- a/modules/ncurses/ncurses.c +++ b/modules/ncurses/ncurses.c @@ -1,9 +1,7 @@ #include "ncurses.h" -WINDOW *__get_stdscr() { - return stdscr; -} +#define __get_stdscr() ((unsigned long int) stdscr) void __get_yx (WINDOW *w, int *y, int *x) { getyx(w, *y, *x); } void __get_par_yx(WINDOW *w, int *y, int *x) { getparyx(w, *y, *x); } @@ -11,7 +9,6 @@ void __get_beg_yx(WINDOW *w, int *y, int *x) { getbegyx(w, *y, *x); } void __get_max_yx(WINDOW *w, int *y, int *x) { getmaxyx(w, *y, *x); } - #define ONYX_LIBRARY_NAME onyx_ncurses #include "onyx_library.h" @@ -522,7 +519,7 @@ ONYX_DEF(addchstr, (WASM_I32), (WASM_I32)) { return NULL; } -ONYX_DEF(addchnstr, (WASM_I32, WASM_I32), (WASM_I32)) { +ONYX_DEF(addchnstr, (WASM_I32,WASM_I32), (WASM_I32)) { results->data[0] = WASM_I32_VAL(addchnstr(ONYX_PTR(P(0, i32)), P(1, i32))); return NULL; } @@ -532,7 +529,7 @@ ONYX_DEF(waddchstr, (WASM_I64, WASM_I32), (WASM_I32)) { return NULL; } -ONYX_DEF(waddchnstr, (WASM_I64, WASM_I32, WASM_I32), (WASM_I32)) { +ONYX_DEF(waddchnstr, (WASM_I64, WASM_I32,WASM_I32), (WASM_I32)) { results->data[0] = WASM_I32_VAL(waddchnstr((WINDOW *) P(0, i64), ONYX_PTR(P(1, i32)), P(2, i32))); return NULL; } @@ -542,7 +539,7 @@ ONYX_DEF(mvaddchstr, (WASM_I32, WASM_I32, WASM_I32), (WASM_I32)) { return NULL; } -ONYX_DEF(mvaddchnstr, (WASM_I32, WASM_I32, WASM_I32, WASM_I32), (WASM_I32)) { +ONYX_DEF(mvaddchnstr, (WASM_I32, WASM_I32, WASM_I32,WASM_I32), (WASM_I32)) { results->data[0] = WASM_I32_VAL(mvaddchnstr(P(0, i32), P(1, i32), ONYX_PTR(P(2, i32)), P(3, i32))); return NULL; } @@ -552,7 +549,7 @@ ONYX_DEF(mvwaddchstr, (WASM_I64, WASM_I32, WASM_I32, WASM_I32), (WASM_I32)) { return NULL; } -ONYX_DEF(mvwaddchnstr, (WASM_I64, WASM_I32, WASM_I32, WASM_I32, WASM_I32), (WASM_I32)) { +ONYX_DEF(mvwaddchnstr, (WASM_I64, WASM_I32, WASM_I32, WASM_I32,WASM_I32), (WASM_I32)) { results->data[0] = WASM_I32_VAL(mvwaddchnstr((WINDOW *) P(0, i64), P(1, i32), P(2, i32), ONYX_PTR(P(3, i32)), P(4, i32))); return NULL; } @@ -562,7 +559,7 @@ ONYX_DEF(addstr, (WASM_I32), (WASM_I32)) { return NULL; } -ONYX_DEF(addnstr, (WASM_I32, WASM_I32), (WASM_I32)) { +ONYX_DEF(addnstr, (WASM_I32,WASM_I32), (WASM_I32)) { results->data[0] = WASM_I32_VAL(addnstr(ONYX_PTR(P(0, i32)), P(1, i32))); return NULL; } @@ -572,7 +569,7 @@ ONYX_DEF(waddstr, (WASM_I64, WASM_I32), (WASM_I32)) { return NULL; } -ONYX_DEF(waddnstr, (WASM_I64, WASM_I32, WASM_I32), (WASM_I32)) { +ONYX_DEF(waddnstr, (WASM_I64, WASM_I32,WASM_I32), (WASM_I32)) { results->data[0] = WASM_I32_VAL(waddnstr((WINDOW *) P(0, i64), ONYX_PTR(P(1, i32)), P(2, i32))); return NULL; } @@ -582,7 +579,7 @@ ONYX_DEF(mvaddstr, (WASM_I32, WASM_I32, WASM_I32), (WASM_I32)) { return NULL; } -ONYX_DEF(mvaddnstr, (WASM_I32, WASM_I32, WASM_I32, WASM_I32), (WASM_I32)) { +ONYX_DEF(mvaddnstr, (WASM_I32, WASM_I32, WASM_I32,WASM_I32), (WASM_I32)) { results->data[0] = WASM_I32_VAL(mvaddnstr(P(0, i32), P(1, i32), ONYX_PTR(P(2, i32)), P(3, i32))); return NULL; } @@ -592,7 +589,7 @@ ONYX_DEF(mvwaddstr, (WASM_I64, WASM_I32, WASM_I32, WASM_I32), (WASM_I32)) { return NULL; } -ONYX_DEF(mvwaddnstr, (WASM_I64, WASM_I32, WASM_I32, WASM_I32, WASM_I32), (WASM_I32)) { +ONYX_DEF(mvwaddnstr, (WASM_I64, WASM_I32, WASM_I32, WASM_I32,WASM_I32), (WASM_I32)) { results->data[0] = WASM_I32_VAL(mvwaddnstr((WINDOW *) P(0, i64), P(1, i32), P(2, i32), ONYX_PTR(P(3, i32)), P(4, i32))); return NULL; } @@ -892,7 +889,7 @@ ONYX_DEF(getstr, (WASM_I32), (WASM_I32)) { return NULL; } -ONYX_DEF(getnstr, (WASM_I32, WASM_I32), (WASM_I32)) { +ONYX_DEF(getnstr, (WASM_I32,WASM_I32), (WASM_I32)) { results->data[0] = WASM_I32_VAL(getnstr(ONYX_PTR(P(0, i32)), P(1, i32))); return NULL; } @@ -902,7 +899,7 @@ ONYX_DEF(wgetstr, (WASM_I64, WASM_I32), (WASM_I32)) { return NULL; } -ONYX_DEF(wgetnstr, (WASM_I64, WASM_I32, WASM_I32), (WASM_I32)) { +ONYX_DEF(wgetnstr, (WASM_I64, WASM_I32,WASM_I32), (WASM_I32)) { results->data[0] = WASM_I32_VAL(wgetnstr((WINDOW *) P(0, i64), ONYX_PTR(P(1, i32)), P(2, i32))); return NULL; } @@ -912,7 +909,7 @@ ONYX_DEF(mvgetstr, (WASM_I32, WASM_I32, WASM_I32), (WASM_I32)) { return NULL; } -ONYX_DEF(mvgetnstr, (WASM_I32, WASM_I32, WASM_I32, WASM_I32), (WASM_I32)) { +ONYX_DEF(mvgetnstr, (WASM_I32, WASM_I32, WASM_I32,WASM_I32), (WASM_I32)) { results->data[0] = WASM_I32_VAL(mvgetnstr(P(0, i32), P(1, i32), ONYX_PTR(P(2, i32)), P(3, i32))); return NULL; } @@ -922,7 +919,7 @@ ONYX_DEF(mvwgetstr, (WASM_I64, WASM_I32, WASM_I32, WASM_I32), (WASM_I32)) { return NULL; } -ONYX_DEF(mvwgetnstr, (WASM_I64, WASM_I32, WASM_I32, WASM_I32, WASM_I32), (WASM_I32)) { +ONYX_DEF(mvwgetnstr, (WASM_I64, WASM_I32, WASM_I32, WASM_I32,WASM_I32), (WASM_I32)) { results->data[0] = WASM_I32_VAL(mvwgetnstr((WINDOW *) P(0, i64), P(1, i32), P(2, i32), ONYX_PTR(P(3, i32)), P(4, i32))); return NULL; } @@ -1297,8 +1294,8 @@ ONYX_DEF(mousemask, (WASM_I64, WASM_I32), (WASM_I64)) { return NULL; } -ONYX_DEF(wenclone, (WASM_I64, WASM_I32, WASM_I32), (WASM_I32)) { - results->data[0] = WASM_I32_VAL(wenclone((WINDOW *) P(0, i64), P(1, i32), P(2, i32))); +ONYX_DEF(wenclose, (WASM_I64, WASM_I32, WASM_I32), (WASM_I32)) { + results->data[0] = WASM_I32_VAL(wenclose((WINDOW *) P(0, i64), P(1, i32), P(2, i32))); return NULL; } @@ -1616,7 +1613,7 @@ ONYX_LIBRARY { ONYX_FUNC(getmouse) ONYX_FUNC(ungetmouse) ONYX_FUNC(mousemask) - ONYX_FUNC(wenclone) + ONYX_FUNC(wenclose) ONYX_FUNC(mouse_trafo) ONYX_FUNC(wmouse_trafo) ONYX_FUNC(mouseinterval) diff --git a/modules/ncurses/onyx_ncurses.so b/modules/ncurses/onyx_ncurses.so index e3be4800..3ba7d3cf 100755 Binary files a/modules/ncurses/onyx_ncurses.so and b/modules/ncurses/onyx_ncurses.so differ diff --git a/scripts/c_binding.onyx b/scripts/c_binding.onyx index b4249abe..e506eeea 100644 --- a/scripts/c_binding.onyx +++ b/scripts/c_binding.onyx @@ -1,62 +1,91 @@ -#load "core/std" +package c_binding use package core use package simd -CBindings :: (package ncurses).CBindings +#if !#defined((package runtime).Generated_Foreign_Info) { + #error "Please run this script with the '--generate-foreign-info' flag." +} + +Cast_Mapping :: struct { + type: type_expr; + name: str; +} -#if !#defined(CBindings) { - #error "Expected to find CBindings structure"; +Binding_Config :: struct { + foreign_block: type_info.foreign_block; + preamble: [] str; + output_file: str; + cast_map: [] Cast_Mapping; } +build_c_binding :: (use binding_config: Binding_Config) -> bool { + for file: os.with_file(output_file, .Write) { + writer := io.writer_make(file); + fb := type_info.get_foreign_block(foreign_block); + write_file_introduction(^writer, preamble, fb.module_name); -main :: (args: [] cstr) { - println(CBindings.file_prefix); + for fb.funcs { + write_function_body(^writer, it, cast_map); + } + + write_library_block(^writer, fb.funcs); + } - printf(""" + return true; +} + +write_file_introduction :: (writer: ^io.Writer, preamble: [] str, name: str) { + for text: preamble { + io.write_format(writer, "{}\n", text); + } + + io.write_format(writer, """ #define ONYX_LIBRARY_NAME {} #include "onyx_library.h" #define P(i, k) (params->data[i].of.k) -""", CBindings.name); +""", name); +} +write_function_body :: (writer, ff, cast_map) => { use type_info; - bind_info := cast(^Type_Info_Struct) get_type_info(CBindings); - for bind_info.methods { - method_type := it.func.type; - method_info := cast (^Type_Info_Function) get_type_info(method_type); - assert(method_info.kind == .Function, "Expected function type."); - - printf("ONYX_DEF({}, (", it.name); - i := 0; - for method_info.parameter_types { - print_type_encoding(it); - - if i != method_info.parameter_types.count - 1 { - print(", "); - } - i += 1; - } - print("), ("); - print_type_encoding(method_info.return_type); - print(")) {\n"); - print_body(it.name, method_info); - print("}\n\n"); + method_type := ff.type; + method_info := cast (^Type_Info_Function) get_type_info(method_type); + assert(method_info.kind == .Function, "Expected function type."); + + io.write_format(writer, "ONYX_DEF({}, (", ff.name); + i := 0; + for method_info.parameter_types { + io.write(writer, type_encoding(it)); + + if i != method_info.parameter_types.count - 1 { + io.write(writer, ", "); + } + i += 1; } - print("\n\n"); - print("ONYX_LIBRARY {\n"); - for bind_info.methods { - printf(" ONYX_FUNC({})\n", it.name); + io.write(writer, "), ("); + io.write(writer, type_encoding(method_info.return_type)); + io.write(writer, ")) {\n"); + print_body(writer, ff.name, method_info, cast_map); + io.write(writer, "}\n\n"); +} + +write_library_block :: (writer, funcs) => { + io.write(writer, "\n\n"); + io.write(writer, "ONYX_LIBRARY {\n"); + for funcs { + io.write_format(writer, " ONYX_FUNC({})\n", it.name); } - print(" NULL\n"); - print("};"); + io.write(writer, " NULL\n"); + io.write(writer, "};"); } -print_body :: (method_name, method_info) => { +print_body :: (writer, method_name, method_info, cast_map) => { use type_info; call := io.dynamic_string_stream_make(); defer io.dynamic_string_stream_free(^call); @@ -73,7 +102,7 @@ print_body :: (method_name, method_info) => { } else { matched := false; - for^ m: CBindings.cast_map { + for^ m: cast_map { if m.type == it { io.write_format(^callw, "({}) P({}, {})", m.name, param_num, type_to_wasm_type(it)); matched = true; @@ -91,14 +120,14 @@ print_body :: (method_name, method_info) => { call_str := call->to_str(); wasm_return_type := type_to_wasm_type(method_info.return_type); switch wasm_return_type { - case "" do printf(" {}({});\n", method_name, call_str[0..call_str.count-2]); - case "i32" do printf(" results->data[0] = WASM_I32_VAL({}({}));\n", method_name, call_str[0..call_str.count-2]); - case "i64" do printf(" results->data[0] = WASM_I64_VAL({}({}));\n", method_name, call_str[0..call_str.count-2]); - case "f32" do printf(" results->data[0] = WASM_F32_VAL({}({}));\n", method_name, call_str[0..call_str.count-2]); - case "f64" do printf(" results->data[0] = WASM_F64_VAL({}({}));\n", method_name, call_str[0..call_str.count-2]); + case "" do io.write_format(writer, " {}({});\n", method_name, call_str[0..call_str.count-2]); + case "i32" do io.write_format(writer, " results->data[0] = WASM_I32_VAL({}({}));\n", method_name, call_str[0..call_str.count-2]); + case "i64" do io.write_format(writer, " results->data[0] = WASM_I64_VAL({}({}));\n", method_name, call_str[0..call_str.count-2]); + case "f32" do io.write_format(writer, " results->data[0] = WASM_F32_VAL({}({}));\n", method_name, call_str[0..call_str.count-2]); + case "f64" do io.write_format(writer, " results->data[0] = WASM_F64_VAL({}({}));\n", method_name, call_str[0..call_str.count-2]); } - printf(" return NULL;\n"); + io.write_format(writer, " return NULL;\n"); } type_to_wasm_type :: (t: type_expr) -> str { @@ -147,47 +176,49 @@ type_to_wasm_type :: (t: type_expr) -> str { return ""; } -print_type_encoding :: (t: type_expr) { +type_encoding :: (t: type_expr) -> str { use type_info; param_info := get_type_info(t); switch param_info.kind { case .Basic do switch t { - case bool do print("WASM_I32"); - case i8 do print("WASM_I32"); - case u8 do print("WASM_I32"); - case i16 do print("WASM_I32"); - case u16 do print("WASM_I32"); - case i32 do print("WASM_I32"); - case u32 do print("WASM_I32"); - case i64 do print("WASM_I64"); - case u64 do print("WASM_I64"); - - case f32 do print("WASM_F32"); - case f64 do print("WASM_F64"); - - case rawptr do print("WASM_I32"); // This will have to depend on the pointer size... + case bool do return "WASM_I32"; + case i8 do return "WASM_I32"; + case u8 do return "WASM_I32"; + case i16 do return "WASM_I32"; + case u16 do return "WASM_I32"; + case i32 do return "WASM_I32"; + case u32 do return "WASM_I32"; + case i64 do return "WASM_I64"; + case u64 do return "WASM_I64"; + + case f32 do return "WASM_F32"; + case f64 do return "WASM_F64"; + + case rawptr do return "WASM_I32"; // This will have to depend on the pointer size... - case i8x16, i16x8, i32x4, i64x2, f32x4, f64x2, v128 do print("WASM_V128"); + case i8x16, i16x8, i32x4, i64x2, f32x4, f64x2, v128 do return "WASM_V128"; - case type_expr do print("WASM_I32"); + case type_expr do return "WASM_I32"; } - case .Pointer do print("WASM_I32"); // This will also have to depend on the pointer size... + case .Pointer do return "WASM_I32"; // This will also have to depend on the pointer size... case .Function do assert(false, "Passing functions between wasm and c is not yet supported."); - case .Array do print("WASM_I32"); - case .Slice do print("WASM_I32, WASM_I32"); - case .Enum do print_type_encoding((cast(^Type_Info_Enum) param_info).backing_type); - case .Distinct do print_type_encoding((cast(^Type_Info_Distinct) param_info).base_type); + case .Array do return "WASM_I32"; + case .Slice do return "WASM_I32,WASM_I32"; + case .Enum do return type_encoding((cast(^Type_Info_Enum) param_info).backing_type); + case .Distinct do return type_encoding((cast(^Type_Info_Distinct) param_info).base_type); case .Struct { s_info := cast(^Type_Info_Struct) param_info; if s_info.members.count == 1 { - print_type_encoding(s_info.members[0].type); + return type_encoding(s_info.members[0].type); return; } assert(false, "Passing structures between wasm and c is not yet supported."); } } + + return ""; } diff --git a/src/builtins.c b/src/builtins.c index 94d412ed..7227d9fb 100644 --- a/src/builtins.c +++ b/src/builtins.c @@ -61,6 +61,8 @@ AstType *builtin_any_type; AstType *builtin_code_type; AstTyped *type_table_node = NULL; +AstTyped *foreign_blocks_node = NULL; +AstType *foreign_block_type = NULL; AstFunction *builtin_initialize_data_segments = NULL; AstFunction *builtin_run_init_procedures = NULL; bh_arr(AstFunction *) init_procedures = NULL; @@ -457,7 +459,9 @@ void initialize_builtins(bh_allocator a) { p = package_lookup("builtin.type_info"); if (p != NULL) { - type_table_node = (AstTyped *) symbol_raw_resolve(p->scope, "type_table"); + type_table_node = (AstTyped *) symbol_raw_resolve(p->scope, "type_table"); + foreign_blocks_node = (AstTyped *) symbol_raw_resolve(p->scope, "foreign_blocks"); + foreign_block_type = (AstType *) symbol_raw_resolve(p->scope, "foreign_block"); } fori (i, 0, Binary_Op_Count) { @@ -531,5 +535,11 @@ void introduce_build_options(bh_allocator a) { arch_type->type_node = Arch_Type; add_entities_for_node(NULL, (AstNode *) arch_type, NULL, NULL); symbol_builtin_introduce(p->scope, "arch", (AstNode *) arch_type); + + if (context.options->generate_foreign_info) { + AstNumLit* foreign_info = make_int_literal(a, 1); + foreign_info->type_node = (AstType *) &basic_type_bool; + symbol_builtin_introduce(p->scope, "Generated_Foreign_Info", (AstNode *) foreign_info); + } } diff --git a/src/onyx.c b/src/onyx.c index 09ed47bc..f0db9310 100644 --- a/src/onyx.c +++ b/src/onyx.c @@ -50,6 +50,7 @@ static const char* docstring = "Onyx compiler version " VERSION "\n" "\t--wasm-mvp Use only WebAssembly MVP features.\n" "\t--multi-threaded Enables multi-threading for this compilation.\n" "\t--doc \n" + "\t--generate-foreign-info\n" "\n" "Developer flags:\n" "\t--print-function-mappings Prints a mapping from WASM function index to source location.\n" @@ -151,6 +152,9 @@ static CompileOptions compile_opts_parse(bh_allocator alloc, int argc, char *arg else if (!strcmp(argv[i], "--multi-threaded")) { options.use_multi_threading = 1; } + else if (!strcmp(argv[i], "--generate-foreign-info")) { + options.generate_foreign_info = 1; + } else if (!strcmp(argv[i], "-I")) { bh_arr_push(options.included_folders, argv[++i]); } diff --git a/src/parser.c b/src/parser.c index cf0b5b79..80ba0f8b 100644 --- a/src/parser.c +++ b/src/parser.c @@ -2817,6 +2817,11 @@ static AstForeignBlock* parse_foreign_block(OnyxParser* parser, OnyxToken *token fb->token = token; fb->module_name = expect_token(parser, Token_Type_Literal_String); + // + // This has a fun implication that there cannot be foreign blocks in the builtin + // or type_info packages, as those are loaded before foreign_block_type has a value. + fb->type_node = foreign_block_type; + bh_arr_new(global_heap_allocator, fb->captured_entities, 4); bh_arr_push(parser->alternate_entity_placement_stack, &fb->captured_entities); diff --git a/src/symres.c b/src/symres.c index 51b5bf36..16a03db6 100644 --- a/src/symres.c +++ b/src/symres.c @@ -1624,7 +1624,12 @@ void symres_entity(Entity* ent) { case Entity_Type_Macro: ss = symres_macro(ent->macro); break; case Entity_Type_Constraint_Check: ss = symres_constraint(ent->constraint); break; case Entity_Type_Polymorph_Query: ss = symres_polyquery(ent->poly_query); break; - case Entity_Type_Foreign_Block: ss = symres_foreign_block(ent->foreign_block); break; + case Entity_Type_Foreign_Block: ss = symres_foreign_block(ent->foreign_block); + if (context.options->generate_foreign_info) { + next_state = Entity_State_Check_Types; + ss = Symres_Success; + } + break; default: break; } diff --git a/src/wasm_emit.c b/src/wasm_emit.c index bf140889..3d4bbae9 100644 --- a/src/wasm_emit.c +++ b/src/wasm_emit.c @@ -2987,6 +2987,12 @@ EMIT_FUNC(expression, AstTyped* expr) { break; } + case Ast_Kind_Foreign_Block: { + AstForeignBlock *fb = (AstForeignBlock *) expr; + WID(WI_I32_CONST, fb->foreign_block_number); + break; + } + default: bh_printf("Unhandled case: %d\n", expr->kind); DEBUG_HERE; @@ -3721,6 +3727,13 @@ static void emit_memory_reservation(OnyxWasmModule* mod, AstMemRes* memres) { return; } + if (foreign_blocks_node != NULL && (AstMemRes *) foreign_blocks_node == memres) { + u64 foreign_blocks_location = build_foreign_blocks(mod); + memres->addr = foreign_blocks_location; + + return; + } + if (memres->threadlocal) { memres->addr = mod->next_tls_offset; bh_align(memres->addr, alignment); @@ -3860,6 +3873,9 @@ OnyxWasmModule onyx_wasm_module_create(bh_allocator alloc) { .libraries = NULL, .library_paths = NULL, + + .foreign_blocks = NULL, + .next_foreign_block_idx = 0, }; bh_arena* eid = bh_alloc(global_heap_allocator, sizeof(bh_arena)); @@ -3892,6 +3908,7 @@ OnyxWasmModule onyx_wasm_module_create(bh_allocator alloc) { bh_arr_new(global_heap_allocator, module.deferred_stmts, 4); bh_arr_new(global_heap_allocator, module.local_allocations, 4); bh_arr_new(global_heap_allocator, module.stack_leave_patches, 4); + bh_arr_new(global_heap_allocator, module.foreign_blocks, 4); if (context.options->use_multi_threading) { WasmImport mem_import = { @@ -3997,6 +4014,12 @@ void emit_entity(Entity* ent) { break; } + case Entity_Type_Foreign_Block: { + ent->foreign_block->foreign_block_number = module->next_foreign_block_idx++; + bh_arr_push(module->foreign_blocks, (AstForeignBlock *) ent->foreign_block); + break; + } + case Entity_Type_Function: emit_function(module, ent->function); break; case Entity_Type_Global: emit_global(module, ent->global); break; diff --git a/src/wasm_type_table.h b/src/wasm_type_table.h index b080855c..4e50e8e1 100644 --- a/src/wasm_type_table.h +++ b/src/wasm_type_table.h @@ -596,5 +596,153 @@ u64 build_type_table(OnyxWasmModule* module) { return global_data_ptr; +#undef WRITE_SLICE +#undef WRITE_PTR #undef PATCH } + + + +static b32 build_foreign_blocks(OnyxWasmModule* module) { + bh_arr(u32) base_patch_locations=NULL; + bh_arr_new(global_heap_allocator, base_patch_locations, 256); + +#define PATCH (bh_arr_push(base_patch_locations, foreign_buffer.length)) +#define WRITE_PTR(val) \ + bh_buffer_align(&foreign_buffer, POINTER_SIZE); \ + PATCH; \ + if (POINTER_SIZE == 4) bh_buffer_write_u32(&foreign_buffer, val); \ + if (POINTER_SIZE == 8) bh_buffer_write_u64(&foreign_buffer, val); +#define WRITE_SLICE(ptr, count) \ + WRITE_PTR(ptr); \ + if (POINTER_SIZE == 4) bh_buffer_write_u32(&foreign_buffer, count); \ + if (POINTER_SIZE == 8) bh_buffer_write_u64(&foreign_buffer, count); + + // This is the data behind the "type_table" slice in type_info.onyx + #if (POINTER_SIZE == 4) + #define Foreign_Block_Type u32 + #else + #define Foreign_Block_Type u64 + #endif + u32 block_count = bh_arr_length(module->foreign_blocks); + Foreign_Block_Type* foreign_info = bh_alloc_array(global_heap_allocator, Foreign_Block_Type, block_count); // HACK + memset(foreign_info, 0, block_count * sizeof(Foreign_Block_Type)); + + bh_buffer foreign_buffer; + bh_buffer_init(&foreign_buffer, global_heap_allocator, 4096); + + // + // This is necessary because 0 is an invalid offset to store in this + // buffer, as 0 will map to NULL. This could be a single byte insertion, + // but 64 bytes keeps better alignment. + bh_buffer_write_u64(&foreign_buffer, 0); + + u32 index = 0; + bh_arr_each(AstForeignBlock *, pfb, module->foreign_blocks) { + AstForeignBlock *fb = *pfb; + + u32 funcs_length = 0; + + u32 *name_offsets = bh_alloc_array(global_scratch_allocator, u32, shlen(fb->scope->symbols)); + u32 *name_lengths = bh_alloc_array(global_scratch_allocator, u32, shlen(fb->scope->symbols)); + u32 *func_types = bh_alloc_array(global_scratch_allocator, u32, shlen(fb->scope->symbols)); + + fori (i, 0, shlen(fb->scope->symbols)) { + AstFunction *func = (AstFunction *) fb->scope->symbols[i].value; + if (func->kind != Ast_Kind_Function) continue; + + u32 func_name_base = foreign_buffer.length; + u32 func_name_length = func->foreign_name->length; + bh_buffer_append(&foreign_buffer, func->foreign_name->text, func_name_length); + + name_offsets[funcs_length] = func_name_base; + name_lengths[funcs_length] = func_name_length; + func_types[funcs_length] = func->type->id; + funcs_length++; + } + + bh_buffer_align(&foreign_buffer, 8); + u32 funcs_base = foreign_buffer.length; + + fori (i, 0, (i64) funcs_length) { + bh_buffer_align(&foreign_buffer, POINTER_SIZE); + WRITE_SLICE(name_offsets[i], name_lengths[i]); + bh_buffer_write_u32(&foreign_buffer, func_types[i]); + } + + u32 name_base = foreign_buffer.length; + u32 name_length = fb->module_name->length; + bh_buffer_append(&foreign_buffer, fb->module_name->text, name_length); + bh_buffer_align(&foreign_buffer, 8); + + foreign_info[index] = foreign_buffer.length; + WRITE_SLICE(name_base, name_length); + WRITE_SLICE(funcs_base, funcs_length); + index++; + } + + + if (context.options->verbose_output == 1) { + bh_printf("Foreign blocks size: %d bytes.\n", foreign_buffer.length); + } + + u32 offset = module->next_datum_offset; + bh_align(offset, 8); + + u64 foreign_blocks_location = offset; + + WasmDatum foreign_blocks_data = { + .offset = offset, + .length = block_count * POINTER_SIZE, + .data = foreign_info, + }; + bh_arr_push(module->data, foreign_blocks_data); + + offset += foreign_blocks_data.length; + + fori (i, 0, block_count) { + foreign_info[i] += offset; + } + + bh_arr_each(u32, patch_loc, base_patch_locations) { + if (POINTER_SIZE == 4) { + u32* loc = bh_pointer_add(foreign_buffer.data, *patch_loc); + if (*loc == 0) continue; + + *loc += offset; + } + if (POINTER_SIZE == 8) { + u64* loc = bh_pointer_add(foreign_buffer.data, *patch_loc); + if (*loc == 0) continue; + + *loc += offset; + } + } + + WasmDatum foreign_blocks_info_data = { + .offset = offset, + .length = foreign_buffer.length, + .data = foreign_buffer.data, + }; + bh_arr_push(module->data, foreign_blocks_info_data); + offset += foreign_blocks_info_data.length; + + u64 global_data_ptr = offset; + + Foreign_Block_Type* tmp_data = bh_alloc(global_heap_allocator, 2 * POINTER_SIZE); + tmp_data[0] = foreign_blocks_location; + tmp_data[1] = block_count; + WasmDatum foreign_blocks_global_data = { + .offset = offset, + .length = 2 * POINTER_SIZE, + .data = tmp_data, + }; + bh_arr_push(module->data, foreign_blocks_global_data); + offset += foreign_blocks_global_data.length; + + module->next_datum_offset = offset; + + return global_data_ptr; + +#undef PATCH +} \ No newline at end of file