X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=csharp_strings.py;h=a73ee2035d310be2568fa48f71b94ab9994ea3e4;hb=HEAD;hp=b1ae3d20e2349c9547af623411744accbc3a26b2;hpb=afc50e5d491a11364849383b75a8f939df703bac;p=ldk-java diff --git a/csharp_strings.py b/csharp_strings.py index b1ae3d20..3e5e247d 100644 --- a/csharp_strings.py +++ b/csharp_strings.py @@ -3,7 +3,9 @@ from enum import Enum import sys class Target(Enum): - CSHARP = 1, + WINDOWS = 1, + LINUX = 2, + PTHREAD = 3, def first_to_lower(string: str) -> str: first = string[0] @@ -150,6 +152,28 @@ public class CommonBase { } }""" + self.witness_program_defn = """public class WitnessProgram : CommonBase { + /** The witness program bytes themselves */ + public readonly byte[] program; + /** The witness version */ + public readonly WitnessVersion version; + + internal WitnessProgram(object _dummy, long ptr) : base(ptr) { + this.program = InternalUtils.decodeUint8Array(bindings.WitnessProgram_get_program(ptr)); + this.version = new WitnessVersion(bindings.WitnessProgram_get_version(ptr)); + } + static private long check_args(byte[] program, WitnessVersion version) { + if (program.Length < 2 || program.Length > 40) throw new ArgumentException(); + if (version.getVal() == 0 && program.Length != 20 && program.Length != 32) throw new ArgumentException(); + return InternalUtils.encodeUint8Array(program); + } + public WitnessProgram(byte[] program, WitnessVersion version) : + this(null, bindings.WitnessProgram_new(version.getVal(), check_args(program, version))) {} + + ~WitnessProgram() { + if (ptr != 0) { bindings.WitnessProgram_free(ptr); } + } +}""" self.c_file_pfx = """ // On OSX jlong (ie long long) is not equivalent to int64_t, so we override here @@ -166,7 +190,25 @@ public class CommonBase { self.c_file_pfx = self.c_file_pfx + "#include \n#define DEBUG_PRINT(...) fprintf(stderr, __VA_ARGS__)\n" - if not DEBUG or sys.platform == "darwin": + if self.target == Target.WINDOWS: + self.c_file_pfx = self.c_file_pfx + """#include +static HANDLE process_heap = NULL; +static inline void* init_heap() { + if (UNLIKELY(process_heap == NULL)) { + // Assume pointer writes wont tear, which is true where we need it. + process_heap = GetProcessHeap(); + } +} +static inline void* MALLOC(size_t a, const char* _) { + init_heap(); + return HeapAlloc(process_heap, HEAP_ZERO_MEMORY, a); +} +#define do_MALLOC(a, b, _c) MALLOC(a, b) +#define FREE(p) if ((uint64_t)(p) > 4096) { init_heap(); HeapFree(process_heap, 0, p); } +#define CHECK_ACCESS(p) +#define CHECK_INNER_FIELD_ACCESS_OR_NULL(v) +""" + elif not DEBUG or self.target != Target.LINUX: self.c_file_pfx = self.c_file_pfx + """#define do_MALLOC(a, _b, _c) malloc(a) #define MALLOC(a, _) malloc(a) #define FREE(p) if ((uint64_t)(p) > 4096) { free(p); } @@ -192,7 +234,7 @@ void __attribute__((constructor)) debug_log_version() { } """ - if sys.platform != "darwin": + if self.target == Target.LINUX: self.c_file_pfx += """ // Running a leak check across all the allocations and frees of the JDK is a mess, // so instead we implement our own naive leak checker here, relying on the -wrap @@ -350,6 +392,18 @@ _Static_assert(offsetof(LDKCVec_u8Z, datalen) == offsetof(LDKu8slice, datalen), _Static_assert(sizeof(void*) <= 8, "Pointers must fit into 64 bits"); +// Int types across Windows/Linux are different, so make sure we're using the right headers. +_Static_assert(sizeof(void*) == sizeof(uintptr_t), "stdints must be correct"); +_Static_assert(sizeof(void*) == sizeof(intptr_t), "stdints must be correct"); +_Static_assert(sizeof(uint64_t) == 8, "stdints must be correct"); +_Static_assert(sizeof(int64_t) == 8, "stdints must be correct"); +_Static_assert(sizeof(uint32_t) == 4, "stdints must be correct"); +_Static_assert(sizeof(int32_t) == 4, "stdints must be correct"); +_Static_assert(sizeof(uint16_t) == 2, "stdints must be correct"); +_Static_assert(sizeof(int16_t) == 2, "stdints must be correct"); +_Static_assert(sizeof(uint8_t) == 1, "stdints must be correct"); +_Static_assert(sizeof(int8_t) == 1, "stdints must be correct"); + #define DECL_ARR_TYPE(ty, name) \\ struct name##array { \\ uint64_t arr_len; /* uint32_t would suffice but we want to align uint64_ts as well */ \\ @@ -391,11 +445,11 @@ static inline LDKStr str_ref_to_owned_c(const jstring str) { typedef bool jboolean; int64_t CS_LDK_allocate_buffer(int64_t len) { - return MALLOC(len, "C#-requested buffer"); + return (int64_t)MALLOC(len, "C#-requested buffer"); } void CS_LDK_free_buffer(int64_t buf) { - FREE(buf); + FREE((void*)buf); } jstring CS_LDK_get_ldk_c_bindings_version() { @@ -522,12 +576,12 @@ int CS_LDK_register_{fn_suffix}_invoker(invoker_{fn_suffix} invoker) {{ return "InternalUtils.getArrayLength(" + arr_name + ")" def get_java_arr_elem(self, elem_ty, arr_name, idx): - if elem_ty.c_ty == "int64_t" or elem_ty.c_ty == "uint64_t" or elem_ty.c_ty.endswith("Array") or elem_ty.c_ty == "uintptr_t": + if elem_ty.c_ty == "int64_t" or elem_ty.c_ty == "uint64_t": + return "InternalUtils.getU64ArrayElem(" + arr_name + ", " + idx + ")" + elif elem_ty.c_ty.endswith("Array") or elem_ty.c_ty == "uintptr_t" or elem_ty.rust_obj == "LDKStr": return "InternalUtils.getU64ArrayElem(" + arr_name + ", " + idx + ")" elif elem_ty.rust_obj == "LDKU5": return "InternalUtils.getU8ArrayElem(" + arr_name + ", " + idx + ")" - elif elem_ty.rust_obj == "LDKStr": - return "InternalUtils.getU32ArrayElem(" + arr_name + ", " + idx + ")" else: assert False @@ -915,7 +969,10 @@ public class {struct_name.replace("LDK","")} : CommonBase {{ for arg_info in fn_line.args_ty: fn_suffix += ty_to_c(arg_info.java_ty, arg_info) fn_java_callback_args += ", " + arg_info.java_ty + " " + chr(ord("a") + idx) - fn_c_callback_args += ", " + arg_info.c_ty + " " + chr(ord("a") + idx) + if arg_info.c_ty.endswith("Array") or arg_info.c_ty == "jstring": + fn_c_callback_args += ", int64_t " + chr(ord("a") + idx) + else: + fn_c_callback_args += ", " + arg_info.c_ty + " " + chr(ord("a") + idx) if idx != 0: fn_callback_call_args += ", " fn_callback_call_args += chr(ord("a") + idx) @@ -933,13 +990,16 @@ public class {struct_name.replace("LDK","")} : CommonBase {{ out_c += "\tuint64_t ret = js_invoke_function_" + fn_suffix + "(j_calls->instance_ptr, " + str(self.function_ptr_counter) if fn_suffix not in self.function_ptrs: - self.function_ptrs[fn_suffix] = {"args": [fn_java_callback_args, fn_c_callback_args], "ret": [fn_line.ret_ty_info.java_ty, fn_line.ret_ty_info.c_ty]} + caller_ret_c_ty = fn_line.ret_ty_info.c_ty + if fn_line.ret_ty_info.c_ty.endswith("Array") or fn_line.ret_ty_info.c_ty == "jstring": + caller_ret_c_ty = "int64_t" + self.function_ptrs[fn_suffix] = {"args": [fn_java_callback_args, fn_c_callback_args], "ret": [fn_line.ret_ty_info.java_ty, caller_ret_c_ty]} self.function_ptrs[fn_suffix][self.function_ptr_counter] = (struct_name, fn_line.fn_name, fn_callback_call_args) self.function_ptr_counter += 1 for idx, arg_info in enumerate(fn_line.args_ty): if arg_info.ret_conv is not None: - if arg_info.c_ty.endswith("Array"): + if arg_info.c_ty.endswith("Array") or arg_info.c_ty == "jstring": out_c += ", (int64_t)" + arg_info.ret_conv_name else: out_c += ", " + arg_info.ret_conv_name @@ -1119,7 +1179,7 @@ public class {struct_name.replace("LDK","")} : CommonBase {{ out_opaque_struct_human = "" out_opaque_struct_human += self.hu_struct_file_prefix out_opaque_struct_human += "\n/**\n * " + struct_doc_comment.replace("\n", "\n * ") + "\n */\n" - hu_name = struct_name.replace("LDKC2Tuple", "TwoTuple").replace("LDKC3Tuple", "ThreeTuple").replace("LDK", "") + hu_name = struct_name.replace("LDKC2Tuple", "TwoTuple").replace("LDKC3Tuple", "ThreeTuple").replace("LDKC4Tuple", "FourTuple").replace("LDK", "") out_opaque_struct_human += ("public class " + hu_name + " : CommonBase") if struct_name.startswith("LDKLocked") or struct_name.startswith("LDKReadOnly"): out_opaque_struct_human += (", IDisposable") @@ -1424,10 +1484,11 @@ public class {struct_name.replace("LDK","")} : CommonBase {{ }} }} public delegate {jret} {fn_suffix}_callback(int obj_ptr, int fn_id{jargs}); + static {fn_suffix}_callback {fn_suffix}_callback_inst = c_callback_{fn_suffix}; """) bindings.write(self.native_meth_decl(f"register_{fn_suffix}_invoker", "int") + f"({fn_suffix}_callback callee);\n") # Easiest way to get a static run is just define a variable, even if we dont care - bindings.write(f"\tstatic int _run_{fn_suffix}_registration = register_{fn_suffix}_invoker(c_callback_{fn_suffix});") + bindings.write(f"\tstatic int _run_{fn_suffix}_registration = register_{fn_suffix}_invoker({fn_suffix}_callback_inst);") bindings.write(""" }