X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=typescript_strings.py;h=0453a79aae2c4661b37709a9fcb9d2b3a12ee2f4;hb=caf86199f09538269930ee679d2852a73671d46f;hp=4cdea4285b43bec3ee4d00b8ec7b3a81838364a3;hpb=0ad910f3687d1d30d31c47e9210952ef090558e3;p=ldk-java diff --git a/typescript_strings.py b/typescript_strings.py index 4cdea428..0453a79a 100644 --- a/typescript_strings.py +++ b/typescript_strings.py @@ -20,7 +20,7 @@ class Consts: uint8_t = ['number', 'Uint8Array'], uint16_t = ['number', 'Uint16Array'], uint32_t = ['number', 'Uint32Array'], - uint64_t = ['number'], + uint64_t = ['BigInt'], ) self.wasm_decoding_map = dict( @@ -36,43 +36,7 @@ class Consts: default = 'const {var_name}_hu_conv: {human_type} = new {human_type}(null, {var_name});', ) - self.bindings_header = self.wasm_import_header(target) + """ -export class VecOrSliceDef { - public dataptr: number; - public datalen: number; - public stride: number; - public constructor(dataptr: number, datalen: number, stride: number) { - this.dataptr = dataptr; - this.datalen = datalen; - this.stride = stride; - } -} - -/* -TODO: load WASM file -static { - System.loadLibrary(\"lightningjni\"); - init(java.lang.Enum.class, VecOrSliceDef.class); - init_class_cache(); -} - -static native void init(java.lang.Class c, java.lang.Class slicedef); -static native void init_class_cache(); - -public static native boolean deref_bool(long ptr); -public static native long deref_long(long ptr); -public static native void free_heap_ptr(long ptr); -public static native byte[] read_bytes(long ptr, long len); -public static native byte[] get_u8_slice_bytes(long slice_ptr); -public static native long bytes_to_u8_vec(byte[] bytes); -public static native long new_txpointer_copy_data(byte[] txdata); -public static native void txpointer_free(long ptr); -public static native byte[] txpointer_get_buffer(long ptr); -public static native long vec_slice_len(long vec); -public static native long new_empty_slice_vec(); -*/ - -""" + self.bindings_header = self.wasm_import_header(target) self.bindings_version_file = "" @@ -116,7 +80,7 @@ export default class CommonBase { /** The script_pubkey in this output */ public script_pubkey: Uint8Array; /** The value, in satoshis, of this output */ - public value: number; + public value: BigInt; /* @internal */ public constructor(_dummy: object, ptr: number) { @@ -124,7 +88,7 @@ export default class CommonBase { this.script_pubkey = bindings.TxOut_get_script_pubkey(ptr); this.value = bindings.TxOut_get_value(ptr); } - public constructor_new(value: number, script_pubkey: Uint8Array): TxOut { + public constructor_new(value: BigInt, script_pubkey: Uint8Array): TxOut { return new TxOut(null, bindings.TxOut_new(script_pubkey, value)); } }""" @@ -139,10 +103,15 @@ void *memset(void *s, int c, size_t n); void *memcpy(void *dest, const void *src, size_t n); int memcmp(const void *s1, const void *s2, size_t n); -void __attribute__((noreturn)) abort(void); +extern void __attribute__((noreturn)) abort(void); static inline void assert(bool expression) { if (!expression) { abort(); } } + +uint32_t __attribute__((export_name("test_bigint_pass_deadbeef0badf00d"))) test_bigint_pass_deadbeef0badf00d(uint64_t val) { + return val == 0xdeadbeef0badf00dULL; +} + """ if not DEBUG: @@ -310,10 +279,10 @@ static inline LDKStr str_ref_to_owned_c(const jstring str) { typedef bool jboolean; -uint32_t __attribute__((visibility("default"))) TS_malloc(uint32_t size) { +uint32_t __attribute__((export_name("TS_malloc"))) TS_malloc(uint32_t size) { return (uint32_t)MALLOC(size, "JS-Called malloc"); } -void __attribute__((visibility("default"))) TS_free(uint32_t ptr) { +void __attribute__((export_name("TS_free"))) TS_free(uint32_t ptr) { FREE((void*)ptr); } """ @@ -367,8 +336,8 @@ import * as InternalUtils from '../InternalUtils.mjs' assert False # Only called if above is None def get_native_arr_ptr_call(self, ty_info): if ty_info.subty is not None: - return "(" + ty_info.subty.c_ty + "*)(", " + 4)" - return "(" + ty_info.c_ty + "*)(", " + 4)" + return "(" + ty_info.subty.c_ty + "*)(((uint8_t*)", ") + 4)" + return "(" + ty_info.c_ty + "*)(((uint8_t*)", ") + 4)" def get_native_arr_entry_call(self, ty_info, arr_name, idxc, entry_access): return None def cleanup_native_arr_ref_contents(self, arr_name, dest_name, arr_len, ty_info): @@ -386,25 +355,15 @@ import * as InternalUtils from '../InternalUtils.mjs' return "str_ref_to_owned_c(" + var_name + ")" def c_fn_name_define_pfx(self, fn_name, have_args): - return " __attribute__((visibility(\"default\"))) TS_" + fn_name + "(" + return " __attribute__((export_name(\"TS_" + fn_name + "\"))) TS_" + fn_name + "(" def wasm_import_header(self, target): res = """ const imports: any = {}; imports.env = {}; -imports.env.tableBase = 0; -imports.env.table = new WebAssembly.Table({initial: 4, element: 'anyfunc'}); - -imports.env["abort"] = function () { - console.error("ABORT"); -}; -imports.env["js_invoke_function"] = function(fn: number, arg1: number, arg2: number, arg3: number, arg4: number, arg5: number, arg6: number, arg7: number, arg8: number, arg9: number, arg10: number) { - console.log('function called from wasm:', fn, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10); -}; -imports.env["js_free_function_ptr"] = function(fn: number) { - console.log("function ptr free'd from wasm:", fn); -}; +var js_objs: Array> = []; +var js_invoke: Function; imports.wasi_snapshot_preview1 = { "fd_write" : () => { @@ -432,8 +391,12 @@ let isWasmInitialized: boolean = false; res += """import * as fs from 'fs'; export async function initializeWasm(path: string) { const source = fs.readFileSync(path); + imports.env["js_invoke_function"] = js_invoke; const { instance: wasmInstance } = await WebAssembly.instantiate(source, imports); wasm = wasmInstance.exports; + if (!wasm.test_bigint_pass_deadbeef0badf00d(BigInt("0xdeadbeef0badf00d"))) { + throw new Error(\"Currently need BigInt-as-u64 support, try ----experimental-wasm-bigint"); + } isWasmInitialized = true; }; """ @@ -441,8 +404,12 @@ export async function initializeWasm(path: string) { res += """ export async function initializeWasm(uri: string) { const stream = fetch(uri); + imports.env["js_invoke_function"] = js_invoke; const { instance: wasmInstance } = await WebAssembly.instantiateStreaming(stream, imports); wasm = wasmInstance.exports; + if (!wasm.test_bigint_pass_deadbeef0badf00d(BigInt("0xdeadbeef0badf00d"))) { + throw new Error(\"Currently need BigInt-as-u64 support, try ----experimental-wasm-bigint"); + } isWasmInitialized = true; }; @@ -773,15 +740,24 @@ export class {struct_name.replace("LDK","")} extends CommonBase {{ out_typescript_bindings += f", {var[1]}: {var[0]}" out_typescript_bindings += f"""): number {{ - throw new Error('unimplemented'); // TODO: bind to WASM - }} + if(!isWasmInitialized) {{ + throw new Error("initializeWasm() must be awaited first!"); + }} + var new_obj_idx = js_objs.length; + for (var i = 0; i < js_objs.length; i++) {{ + if (js_objs[i] == null || js_objs[i] == undefined) {{ new_obj_idx = i; break; }} + }} + js_objs[i] = new WeakRef(impl); + return wasm.TS_{struct_name}_new(i); +}} """ out_typescript_bindings += '\n// OUT_TYPESCRIPT_BINDINGS :: MAP_TRAIT :: END\n\n\n' # Now that we've written out our java code (and created java_meths), generate C out_c = "typedef struct " + struct_name + "_JCalls {\n" - out_c = out_c + "\tatomic_size_t refcnt;\n" + out_c += "\tatomic_size_t refcnt;\n" + out_c += "\tuint32_t instance_ptr;\n" for var in flattened_field_var_conversions: if isinstance(var, ConvInfo): # We're a regular ol' field @@ -789,9 +765,6 @@ export class {struct_name.replace("LDK","")} extends CommonBase {{ else: # We're a supertrait out_c = out_c + "\t" + var[0] + "_JCalls* " + var[1] + ";\n" - for fn in field_function_lines: - if fn.fn_name != "free" and fn.fn_name != "cloned": - out_c = out_c + "\tuint32_t " + fn.fn_name + "_meth;\n" out_c = out_c + "} " + struct_name + "_JCalls;\n" for fn_line in field_function_lines: @@ -799,9 +772,6 @@ export class {struct_name.replace("LDK","")} extends CommonBase {{ out_c = out_c + "static void " + struct_name + "_JCalls_free(void* this_arg) {\n" out_c = out_c + "\t" + struct_name + "_JCalls *j_calls = (" + struct_name + "_JCalls*) this_arg;\n" out_c = out_c + "\tif (atomic_fetch_sub_explicit(&j_calls->refcnt, 1, memory_order_acquire) == 1) {\n" - for fn in field_function_lines: - if fn.fn_name != "free" and fn.fn_name != "cloned": - out_c = out_c + "\t\tjs_free_function_ptr(j_calls->" + fn.fn_name + "_meth);\n" out_c = out_c + "\t\tFREE(j_calls);\n" out_c = out_c + "\t}\n}\n" @@ -828,15 +798,18 @@ export class {struct_name.replace("LDK","")} extends CommonBase {{ if fn_line.ret_ty_info.c_ty.endswith("Array"): out_c += "\t" + fn_line.ret_ty_info.c_ty + " ret = (" + fn_line.ret_ty_info.c_ty + ")" - out_c += "js_invoke_function_" + str(len(fn_line.args_ty)) + "(j_calls->" + fn_line.fn_name + "_meth" + out_c += "js_invoke_function_" + str(len(fn_line.args_ty)) + "(j_calls->instance_ptr, " + str(self.function_ptr_counter) elif fn_line.ret_ty_info.java_ty == "void": - out_c = out_c + "\tjs_invoke_function_" + str(len(fn_line.args_ty)) + "(j_calls->" + fn_line.fn_name + "_meth" + out_c = out_c + "\tjs_invoke_function_" + str(len(fn_line.args_ty)) + "(j_calls->instance_ptr, " + str(self.function_ptr_counter) elif fn_line.ret_ty_info.java_ty == "String": - out_c = out_c + "\tjstring ret = (jstring)js_invoke_function_" + str(len(fn_line.args_ty)) + "(j_calls->" + fn_line.fn_name + "_meth" + out_c = out_c + "\tjstring ret = (jstring)js_invoke_function_" + str(len(fn_line.args_ty)) + "(j_calls->instance_ptr, " + str(self.function_ptr_counter) elif not fn_line.ret_ty_info.passed_as_ptr: - out_c = out_c + "\treturn js_invoke_function_" + str(len(fn_line.args_ty)) + "(j_calls->" + fn_line.fn_name + "_meth" + out_c = out_c + "\treturn js_invoke_function_" + str(len(fn_line.args_ty)) + "(j_calls->instance_ptr, " + str(self.function_ptr_counter) else: - out_c = out_c + "\tuint32_t ret = js_invoke_function_" + str(len(fn_line.args_ty)) + "(j_calls->" + fn_line.fn_name + "_meth" + out_c = out_c + "\tuint32_t ret = js_invoke_function_" + str(len(fn_line.args_ty)) + "(j_calls->instance_ptr, " + str(self.function_ptr_counter) + + self.function_ptrs[self.function_ptr_counter] = (struct_name, fn_line.fn_name) + self.function_ptr_counter += 1 for idx, arg_info in enumerate(fn_line.args_ty): if arg_info.ret_conv is not None: @@ -858,17 +831,17 @@ export class {struct_name.replace("LDK","")} extends CommonBase {{ out_c = out_c + "\tatomic_fetch_add_explicit(&j_calls->" + var[1] + "->refcnt, 1, memory_order_release);\n" out_c = out_c + "}\n" - out_c = out_c + "static inline " + struct_name + " " + struct_name + "_init (/*TODO: JS Object Reference */void* o" + out_c = out_c + "static inline " + struct_name + " " + struct_name + "_init (JSValue o" for var in flattened_field_var_conversions: if isinstance(var, ConvInfo): out_c = out_c + ", " + var.c_ty + " " + var.arg_name else: - out_c = out_c + ", /*TODO: JS Object Reference */void* " + var[1] + out_c = out_c + ", JSValue " + var[1] out_c = out_c + ") {\n" out_c = out_c + "\t" + struct_name + "_JCalls *calls = MALLOC(sizeof(" + struct_name + "_JCalls), \"" + struct_name + "_JCalls\");\n" out_c = out_c + "\tatomic_init(&calls->refcnt, 1);\n" - out_c = out_c + "\t//TODO: Assign calls->o from o\n" + out_c = out_c + "\tcalls->instance_ptr = o;\n" for (fn_name, java_meth_descr) in java_meths: if fn_name != "free" and fn_name != "cloned": @@ -910,12 +883,12 @@ export class {struct_name.replace("LDK","")} extends CommonBase {{ out_c = out_c + "\treturn ret;\n" out_c = out_c + "}\n" - out_c = out_c + self.c_fn_ty_pfx + "long " + self.c_fn_name_define_pfx(struct_name + "_new", True) + "/*TODO: JS Object Reference */void* o" + out_c = out_c + self.c_fn_ty_pfx + "long " + self.c_fn_name_define_pfx(struct_name + "_new", True) + "JSValue o" for var in flattened_field_var_conversions: if isinstance(var, ConvInfo): out_c = out_c + ", " + var.c_ty + " " + var.arg_name else: - out_c = out_c + ", /*TODO: JS Object Reference */ void* " + var[1] + out_c = out_c + ", JSValue " + var[1] out_c = out_c + ") {\n" out_c = out_c + "\t" + struct_name + " *res_ptr = MALLOC(sizeof(" + struct_name + "), \"" + struct_name + "\");\n" out_c = out_c + "\t*res_ptr = " + struct_name + "_init(o" @@ -1267,3 +1240,34 @@ export class {human_ty} extends CommonBase {{ for struct in self.struct_file_suffixes: with open(self.outdir + "/structs/" + struct + self.file_ext, "a") as src: src.write(self.struct_file_suffixes[struct]) + + with open(self.outdir + "/bindings.mts", "a") as bindings: + bindings.write(""" + +js_invoke = function(obj_ptr: number, fn_id: number, arg1: number, arg2: number, arg3: number, arg4: number, arg5: number, arg6: number, arg7: number, arg8: number, arg9: number, arg10: number) { + const weak: WeakRef = js_objs[obj_ptr]; + if (weak == null || weak == undefined) { + console.error("Got function call on unknown/free'd JS object!"); + throw new Error("Got function call on unknown/free'd JS object!"); + } + const obj: object = weak.deref(); + if (obj == null || obj == undefined) { + console.error("Got function call on GC'd JS object!"); + throw new Error("Got function call on GC'd JS object!"); + } + var fn; +""") + bindings.write("\tswitch (fn_id) {\n") + for f in self.function_ptrs: + bindings.write(f"\t\tcase {str(f)}: fn = Object.getOwnPropertyDescriptor(obj, \"{self.function_ptrs[f][1]}\"); break;\n") + + bindings.write("""\t\tdefault: + console.error("Got unknown function call from C!"); + throw new Error("Got unknown function call from C!"); + } + if (fn == null || fn == undefined) { + console.error("Got function call on incorrect JS object!"); + throw new Error("Got function call on incorrect JS object!"); + } + return fn.value.bind(obj)(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10); +}""")