From a44ec3b883c1d1eccb14379093e6078d4cea36ef Mon Sep 17 00:00:00 2001 From: Brendan Hansen Date: Mon, 2 May 2022 14:09:02 -0500 Subject: [PATCH] added foreign block info --- core/type_info/type_info.onyx | 35 +++++++ include/astnodes.h | 5 + include/wasm_emit.h | 3 + modules/ncurses/build.onyx | 37 ++++++++ modules/ncurses/build.sh | 2 +- modules/ncurses/module.onyx | 66 ++++++------- modules/ncurses/ncurses.c | 35 ++++--- modules/ncurses/onyx_ncurses.so | Bin 216176 -> 216184 bytes scripts/c_binding.onyx | 163 +++++++++++++++++++------------- src/builtins.c | 12 ++- src/onyx.c | 4 + src/parser.c | 5 + src/symres.c | 7 +- src/wasm_emit.c | 23 +++++ src/wasm_type_table.h | 148 +++++++++++++++++++++++++++++ 15 files changed, 420 insertions(+), 125 deletions(-) create mode 100644 modules/ncurses/build.onyx 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 e3be48003cbb007ba3792594380468bb36564e22..3ba7d3cf6961855261e7c7b45640a28b4ee6317f 100755 GIT binary patch delta 18870 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 delta 19585 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 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 -- 2.25.1