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
Scope* scope;
OnyxToken *module_name;
bh_arr(struct Entity *) captured_entities;
+
+ u32 foreign_block_number;
};
typedef enum EntityState {
b32 use_post_mvp_features : 1;
b32 use_multi_threading : 1;
+ b32 generate_foreign_info : 1;
Runtime runtime;
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;
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.
--- /dev/null
+#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
#!/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
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 ---
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 ---
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
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)
KEY_UNDO :: 0630 /* undo key */
KEY_MOUSE :: 0631 /* Mouse event has occurred */
+
+
+} // !Building_Library
\ No newline at end of file
#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); }
void __get_max_yx(WINDOW *w, int *y, int *x) { getmaxyx(w, *y, *x); }
-
#define ONYX_LIBRARY_NAME onyx_ncurses
#include "onyx_library.h"
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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)
-#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);
} 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;
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 {
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 "";
}
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;
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) {
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);
+ }
}
"\t--wasm-mvp Use only WebAssembly MVP features.\n"
"\t--multi-threaded Enables multi-threading for this compilation.\n"
"\t--doc <doc_file>\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"
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]);
}
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);
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;
}
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;
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);
.libraries = NULL,
.library_paths = NULL,
+
+ .foreign_blocks = NULL,
+ .next_foreign_block_idx = 0,
};
bh_arena* eid = bh_alloc(global_heap_allocator, sizeof(bh_arena));
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 = {
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;
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