X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=typescript_strings.py;h=c0a0cccbf0ed816764fb3a285cf6dae2620400ba;hb=0b84bd29ac3af544cb8c88a7f581dee337a89ac3;hp=40c888a3efcc5252c1a2de81f466d3d1c44ce007;hpb=06ca6ec8721e91d572ce3cc8630e2550d22eae08;p=ldk-java diff --git a/typescript_strings.py b/typescript_strings.py index 40c888a3..c0a0cccb 100644 --- a/typescript_strings.py +++ b/typescript_strings.py @@ -73,21 +73,15 @@ imports.wasi_snapshot_preview1 = { // This is called before fd_write to format + print panic messages console.log("wasi_snapshot_preview1:environ_sizes_get"); const out_count_view = new Uint32Array(wasm.memory.buffer, environ_var_count_ptr, 1); - out_count_view[0] = 1; + out_count_view[0] = 0; const out_len_view = new Uint32Array(wasm.memory.buffer, environ_len_ptr, 1); - out_len_view[0] = "RUST_BACKTRACE=1".length + 1; // Note that string must be NULL-terminated + out_len_view[0] = 0; return 0; }, "environ_get": (environ_ptr: number, environ_buf_ptr: number) => { // This is called before fd_write to format + print panic messages console.log("wasi_snapshot_preview1:environ_get"); - const out_ptrs = new Uint32Array(wasm.memory.buffer, environ_ptr, 2); - out_ptrs[0] = environ_buf_ptr; - out_ptrs[1] = "RUST_BACKTRACE=1".length; - const out_environ = new Uint8Array(wasm.memory.buffer, environ_buf_ptr, out_ptrs[1]); - for (var i = 0; i < out_ptrs[1]; i++) { out_environ[i] = "RUST_BACKTRACE=1".codePointAt(i); } - out_environ[out_ptrs[1]] = 0; - return 0; + return 58; // Note supported - we said there were 0 environment entries! }, "proc_exit" : () => { console.log("wasi_snapshot_preview1:proc_exit"); @@ -123,12 +117,14 @@ export async function initializeWasm(uri: string) { if (decodeString(wasm.TS_get_lib_version_string()) !== version.get_ldk_java_bindings_version()) throw new Error(\"Compiled LDK library and LDK class failes do not match\"); // Fetching the LDK versions from C also checks that the header and binaries match - if (wasm.TS_get_ldk_c_bindings_version() == 0) + const c_bindings_ver: number = wasm.TS_get_ldk_c_bindings_version(); + const ldk_ver: number = wasm.TS_get_ldk_version(); + if (c_bindings_ver == 0) throw new Error(\"LDK version did not match the header we built against\"); - if (wasm.TS_get_ldk_version() == 0) + if (ldk_ver == 0) throw new Error(\"LDK C bindings version did not match the header we built against\"); - const c_bindings_version: string = decodeString(wasm.TS_get_ldk_c_bindings_version()); - const ldk_version: string = decodeString(wasm.TS_get_ldk_version()); + const c_bindings_version: string = decodeString(c_bindings_ver) + const ldk_version: string = decodeString(ldk_ver); console.log(\"Loaded LDK-Java Bindings with LDK \" + ldk_version + \" and LDK-C-Bindings \" + c_bindings_version); isWasmInitialized = true; @@ -207,6 +203,9 @@ const decodeUint32Array = (arrayPointer: number, free = true) => { return actualArray; } + +export function freeWasmMemory(pointer: number) { wasm.TS_free(pointer); } + /* @internal */ export function getU32ArrayElem(arrayPointer: number, idx: number): number { const actualArrayViewer = new Uint32Array(wasm.memory.buffer, arrayPointer + 4, idx + 1); @@ -232,6 +231,20 @@ export function decodeString(stringPointer: number, free = true): string { return result; } """ + if DEBUG: + self.bindings_header += """ +/* @internal */ +export function getRemainingAllocationCount(): number { + return wasm.TS_allocs_remaining(); +} +/* @internal */ +export function debugPrintRemainingAllocs() { + wasm.TS_print_leaks(); +} +""" + else: + self.bindings_header += "\n/* @internal */ export function getRemainingAllocationCount(): number { return 0; }\n" + self.bindings_header += "/* @internal */ export function debugPrintRemainingAllocs() { }\n" with open(outdir + "/index.mts", 'a') as index: index.write("""import { initializeWasm as bindingsInit } from './bindings.mjs'; @@ -319,11 +332,12 @@ uint32_t __attribute__((export_name("test_bigint_pass_deadbeef0badf00d"))) test_ """ if not DEBUG: - self.c_file_pfx = self.c_file_pfx + """ + self.c_file_pfx += """ void *malloc(size_t size); void free(void *ptr); #define MALLOC(a, _) malloc(a) +#define do_MALLOC(a, _b, _c) malloc(a) #define FREE(p) if ((unsigned long)(p) > 4096) { free(p); } #define DO_ASSERT(a) (void)(a) #define CHECK(a) @@ -331,7 +345,16 @@ void free(void *ptr); #define CHECK_INNER_FIELD_ACCESS_OR_NULL(v) """ else: - self.c_file_pfx = self.c_file_pfx + """ + self.c_file_pfx += """ +extern int snprintf(char *str, size_t size, const char *format, ...); +typedef int32_t ssize_t; +ssize_t write(int fd, const void *buf, size_t count); +#define DEBUG_PRINT(...) do { \\ + char debug_str[1024]; \\ + int s_len = snprintf(debug_str, 1023, __VA_ARGS__); \\ + write(2, debug_str, s_len); \\ +} while (0); + // Always run a, then assert it is true: #define DO_ASSERT(a) do { bool _assert_val = (a); assert(_assert_val); } while(0) // Assert a is true or do nothing @@ -347,43 +370,58 @@ typedef struct allocation { struct allocation* next; void* ptr; const char* struct_name; + int lineno; } allocation; static allocation* allocation_ll = NULL; +static allocation* freed_ll = NULL; -void* __real_malloc(size_t len); -void* __real_calloc(size_t nmemb, size_t len); -static void new_allocation(void* res, const char* struct_name) { +extern void* __real_malloc(size_t len); +extern void* __real_calloc(size_t nmemb, size_t len); +extern void* __real_aligned_alloc(size_t alignment, size_t size); +static void new_allocation(void* res, const char* struct_name, int lineno) { allocation* new_alloc = __real_malloc(sizeof(allocation)); new_alloc->ptr = res; new_alloc->struct_name = struct_name; new_alloc->next = allocation_ll; + new_alloc->lineno = lineno; allocation_ll = new_alloc; } -static void* MALLOC(size_t len, const char* struct_name) { +static void* do_MALLOC(size_t len, const char* struct_name, int lineno) { void* res = __real_malloc(len); - new_allocation(res, struct_name); + new_allocation(res, struct_name, lineno); return res; } +#define MALLOC(len, struct_name) do_MALLOC(len, struct_name, __LINE__) + void __real_free(void* ptr); -static void alloc_freed(void* ptr) { +static void alloc_freed(void* ptr, int lineno) { allocation* p = NULL; allocation* it = allocation_ll; while (it->ptr != ptr) { p = it; it = it->next; if (it == NULL) { - //XXX: fprintf(stderr, "Tried to free unknown pointer %p\\n", ptr); - return; // addrsan should catch malloc-unknown and print more info than we have + p = NULL; + it = freed_ll; + while (it && it->ptr != ptr) { p = it; it = it->next; } + if (it == NULL) { + DEBUG_PRINT("Tried to free unknown pointer %p at line %d.\\n", ptr, lineno); + } else { + DEBUG_PRINT("Tried to free unknown pointer %p at line %d.\\n Possibly double-free from %s, allocated on line %d.", ptr, lineno, it->struct_name, it->lineno); + } + abort(); } } if (p) { p->next = it->next; } else { allocation_ll = it->next; } DO_ASSERT(it->ptr == ptr); - __real_free(it); + it->next = freed_ll; + freed_ll = it; } -static void FREE(void* ptr) { +static void do_FREE(void* ptr, int lineno) { if ((unsigned long)ptr <= 4096) return; // Rust loves to create pointers to the NULL page for dummys - alloc_freed(ptr); + alloc_freed(ptr, lineno); __real_free(ptr); } +#define FREE(ptr) do_FREE(ptr, __LINE__) static void CHECK_ACCESS(const void* ptr) { allocation* it = allocation_ll; @@ -404,25 +442,30 @@ static void CHECK_ACCESS(const void* ptr) { void* __wrap_malloc(size_t len) { void* res = __real_malloc(len); - new_allocation(res, "malloc call"); + new_allocation(res, "malloc call", 0); return res; } void* __wrap_calloc(size_t nmemb, size_t len) { void* res = __real_calloc(nmemb, len); - new_allocation(res, "calloc call"); + new_allocation(res, "calloc call", 0); + return res; +} +void* __wrap_aligned_alloc(size_t alignment, size_t size) { + void* res = __real_aligned_alloc(alignment, size); + new_allocation(res, "aligned_alloc call", 0); return res; } void __wrap_free(void* ptr) { if (ptr == NULL) return; - alloc_freed(ptr); + alloc_freed(ptr, 0); __real_free(ptr); } void* __real_realloc(void* ptr, size_t newlen); void* __wrap_realloc(void* ptr, size_t len) { - if (ptr != NULL) alloc_freed(ptr); + if (ptr != NULL) alloc_freed(ptr, 0); void* res = __real_realloc(ptr, len); - new_allocation(res, "realloc call"); + new_allocation(res, "realloc call", 0); return res; } void __wrap_reallocarray(void* ptr, size_t new_sz) { @@ -430,16 +473,17 @@ void __wrap_reallocarray(void* ptr, size_t new_sz) { DO_ASSERT(false); } -extern int snprintf(char *str, size_t size, const char *format, ...); -typedef int32_t ssize_t; -extern ssize_t write(int fd, const void *buf, size_t count); -void __attribute__((export_name("TS_check_leaks"))) check_leaks() { - char debug_str[1024]; +uint32_t __attribute__((export_name("TS_allocs_remaining"))) allocs_remaining() { + uint32_t count = 0; + for (allocation* a = allocation_ll; a != NULL; a = a->next) { + count++; + } + return count; +} +void __attribute__((export_name("TS_print_leaks"))) print_leaks() { for (allocation* a = allocation_ll; a != NULL; a = a->next) { - int s_len = snprintf(debug_str, 1023, "%s %p remains\\n", a->struct_name, a->ptr); - write(2, debug_str, s_len); + DEBUG_PRINT("%s %p remains. Allocated on line %d\\n", a->struct_name, a->ptr, a->lineno); } - DO_ASSERT(allocation_ll == NULL); } """ self.c_file_pfx = self.c_file_pfx + """ @@ -456,8 +500,8 @@ _Static_assert(sizeof(void*) == 4, "Pointers mut be 32 bits"); ty elems[]; \\ }; \\ typedef struct name##array * name##Array; \\ - static inline name##Array init_##name##Array(size_t arr_len) { \\ - name##Array arr = (name##Array)MALLOC(arr_len * sizeof(ty) + sizeof(uint32_t), "##name array init"); \\ + static inline name##Array init_##name##Array(size_t arr_len, int lineno) { \\ + name##Array arr = (name##Array)do_MALLOC(arr_len * sizeof(ty) + sizeof(uint32_t), #name" array init", lineno); \\ arr->arr_len = arr_len; \\ return arr; \\ } @@ -470,7 +514,7 @@ DECL_ARR_TYPE(char, char); typedef charArray jstring; static inline jstring str_ref_to_ts(const char* chars, size_t len) { - charArray arr = init_charArray(len); + charArray arr = init_charArray(len, __LINE__); memcpy(arr->elems, chars, len); return arr; } @@ -533,7 +577,7 @@ import * as bindings from '../bindings.mjs' def create_native_arr_call(self, arr_len, ty_info): if ty_info.c_ty == "ptrArray": assert ty_info.subty is not None and ty_info.subty.c_ty.endswith("Array") - return "init_" + ty_info.c_ty + "(" + arr_len + ")" + return "init_" + ty_info.c_ty + "(" + arr_len + ", __LINE__)" def set_native_arr_contents(self, arr_name, arr_len, ty_info): if ty_info.c_ty == "int8_tArray": return ("memcpy(" + arr_name + "->elems, ", ", " + arr_len + ")") @@ -542,12 +586,12 @@ import * as bindings from '../bindings.mjs' def get_native_arr_contents(self, arr_name, dest_name, arr_len, ty_info, copy): if ty_info.c_ty == "int8_tArray": if copy: - return "memcpy(" + dest_name + ", " + arr_name + "->elems, " + arr_len + ")" + return "memcpy(" + dest_name + ", " + arr_name + "->elems, " + arr_len + "); FREE(" + arr_name + ")" if ty_info.c_ty == "ptrArray": - return "(void*) " + arr_name + "->elems" + return "(void*) " + arr_name + "->elems /* XXX " + arr_name + " leaks */" else: assert not copy - return arr_name + "->elems" + return arr_name + "->elems /* XXX " + arr_name + " leaks */" def get_native_arr_elem(self, arr_name, idxc, ty_info): assert False # Only called if above is None def get_native_arr_ptr_call(self, ty_info): @@ -590,6 +634,8 @@ import * as bindings from '../bindings.mjs' assert False def constr_hu_array(self, ty_info, arr_len): return "new Array(" + arr_len + ").fill(null)" + def cleanup_converted_native_array(self, ty_info, arr_name): + return "bindings.freeWasmMemory(" + arr_name + ")" def primitive_arr_from_hu(self, mapped_ty, fixed_len, arr_name): inner = arr_name @@ -723,6 +769,7 @@ export enum {struct_name} {{ for fn_line in field_function_lines: java_method_descriptor = "" if fn_line.fn_name != "free" and fn_line.fn_name != "cloned": + out_java_interface += "\t/**" + fn_line.docs.replace("\n", "\n\t * ") + "\n\t */\n" out_java_interface += "\t" + fn_line.fn_name + "(" out_interface_implementation_overrides += f"\t\t\t{fn_line.fn_name} (" @@ -771,9 +818,11 @@ export enum {struct_name} {{ out_interface_implementation_overrides += "\t\t\t\treturn ret;\n" out_interface_implementation_overrides += f"\t\t\t}},\n" + formatted_trait_docs = trait_doc_comment.replace("\n", "\n * ") out_typescript_human = f""" {self.hu_struct_file_prefix} +/** An implementation of {struct_name.replace("LDK","")} */ export interface {struct_name.replace("LDK", "")}Interface {{ {out_java_interface}}} @@ -781,6 +830,9 @@ class {struct_name}Holder {{ held: {struct_name.replace("LDK", "")}; }} +/** + * {formatted_trait_docs} + */ export class {struct_name.replace("LDK","")} extends CommonBase {{ /* @internal */ public bindings_instance?: bindings.{struct_name}; @@ -791,7 +843,8 @@ export class {struct_name.replace("LDK","")} extends CommonBase {{ this.bindings_instance = null; }} - static new_impl(arg: {struct_name.replace("LDK", "")}Interface{impl_constructor_arguments}): {struct_name.replace("LDK", "")} {{ + /** Creates a new instance of {struct_name.replace("LDK","")} from a given implementation */ + public static new_impl(arg: {struct_name.replace("LDK", "")}Interface{impl_constructor_arguments}): {struct_name.replace("LDK", "")} {{ const impl_holder: {struct_name}Holder = new {struct_name}Holder(); let structImplementation = {{ {out_interface_implementation_overrides} }} as bindings.{struct_name}; @@ -801,6 +854,7 @@ export class {struct_name.replace("LDK","")} extends CommonBase {{ impl_holder.held.bindings_instance = structImplementation; {pointer_to_adder} return impl_holder.held; }} + """ self.obj_defined([struct_name.replace("LDK", ""), struct_name.replace("LDK", "") + "Interface"], "structs") @@ -1001,7 +1055,7 @@ export class {struct_name.replace("LDK","")} extends CommonBase {{ out_java_enum += (self.hu_struct_file_prefix) - java_hu_class = "" + java_hu_class = "/**\n * " + enum_doc_comment.replace("\n", "\n * ") + "\n */\n" java_hu_class += "export class " + java_hu_type + " extends CommonBase {\n" java_hu_class += "\tprotected constructor(_dummy: object, ptr: number) { super(ptr, bindings." + bindings_type + "_free); }\n" java_hu_class += "\t/* @internal */\n" @@ -1017,13 +1071,16 @@ export class {struct_name.replace("LDK","")} extends CommonBase {{ out_java += "\tprotected constructor() {}\n" var_idx = 0 for var in variant_list: - java_hu_subclasses = java_hu_subclasses + "export class " + java_hu_type + "_" + var.var_name + " extends " + java_hu_type + " {\n" + java_hu_subclasses += "/** A " + java_hu_type + " of type " + var.var_name + " */\n" + java_hu_subclasses += "export class " + java_hu_type + "_" + var.var_name + " extends " + java_hu_type + " {\n" java_hu_class += f"\t\t\tcase {var_idx}: " java_hu_class += "return new " + java_hu_type + "_" + var.var_name + "(ptr);\n" out_c += f"\t\tcase {struct_name}_{var.var_name}: return {var_idx};\n" hu_conv_body = "" for idx, (field_ty, field_docs) in enumerate(var.fields): - java_hu_subclasses = java_hu_subclasses + "\tpublic " + field_ty.arg_name + f": {field_ty.java_hu_ty};\n" + if field_docs is not None: + java_hu_subclasses += "\t/**\n\t * " + field_docs.replace("\n", "\n\t * ") + "\n\t */\n" + java_hu_subclasses += "\tpublic " + field_ty.arg_name + f": {field_ty.java_hu_ty};\n" if field_ty.to_hu_conv is not None: hu_conv_body += f"\t\tconst {field_ty.arg_name}: {field_ty.java_ty} = bindings.{struct_name}_{var.var_name}_get_{field_ty.arg_name}(ptr);\n" hu_conv_body += f"\t\t" + field_ty.to_hu_conv.replace("\n", "\n\t\t\t") + "\n" @@ -1075,7 +1132,11 @@ export class {struct_name.replace("LDK","")} extends CommonBase {{ out_opaque_struct_human = f"{self.hu_struct_file_prefix}" if struct_name.startswith("LDKLocked"): out_opaque_struct_human += "/** XXX: DO NOT USE THIS - it remains locked until the GC runs (if that ever happens */" + formatted_doc_comment = struct_doc_comment.replace("\n", "\n * ") out_opaque_struct_human += f""" +/** + * {formatted_doc_comment} + */ export class {hu_name} extends CommonBase {implementations}{{ /* @internal */ public constructor(_dummy: object, ptr: number) {{ @@ -1190,6 +1251,9 @@ export function {method_name}({method_argument_string}): {return_java_ty} {{ out_java = self.fn_call_body(method_name, return_type_info.c_ty, return_type_info.java_ty, method_argument_string, native_call_argument_string) out_java_struct = "" + if doc_comment is not None: + out_java_struct = "\t/**\n\t * " + doc_comment.replace("\n", "\n\t * ") + "\n\t */\n" + if not args_known: out_java_struct += ("\t// Skipped " + method_name + "\n") else: