X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=java_strings.py;h=7cd486aafeb6ba8d780cf5630bf74706e888fb72;hb=9bd1b30bd6a039a220c473ee054002befa013f32;hp=25eec48e83ca9762522e8a5f322efa512c54efb3;hpb=b1216b13577d42952013c14c88c1155eb6c6499f;p=ldk-java diff --git a/java_strings.py b/java_strings.py index 25eec48e..7cd486aa 100644 --- a/java_strings.py +++ b/java_strings.py @@ -1,5 +1,6 @@ from bindingstypes import * from enum import Enum +import sys class Target(Enum): JAVA = 1, @@ -23,6 +24,12 @@ class Consts: self.bindings_header = """package org.ldk.impl; import org.ldk.enums.*; +import java.io.File; +import java.io.InputStream; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardCopyOption; public class bindings { public static class VecOrSliceDef { @@ -34,7 +41,24 @@ public class bindings { } } static { - System.loadLibrary(\"lightningjni\"); + try { + // Try to load natively first, this works on Android and in testing. + System.loadLibrary(\"lightningjni\"); + } catch (UnsatisfiedLinkError _ignored) { + // Otherwise try to load from the library jar. + File tmpdir = new File(System.getProperty("java.io.tmpdir"), "ldk-java-nativelib"); + tmpdir.mkdir(); // If it fails to create, assume it was there already + tmpdir.deleteOnExit(); + String libname = "liblightningjni_" + System.getProperty("os.name").replaceAll(" ", "") + + "-" + System.getProperty("os.arch").replaceAll(" ", "") + ".nativelib"; + try (InputStream is = bindings.class.getResourceAsStream("/" + libname)) { + Path libpath = new File(tmpdir.toPath().toString(), "liblightningjni.so").toPath(); + Files.copy(is, libpath, StandardCopyOption.REPLACE_EXISTING); + Runtime.getRuntime().load(libpath.toString()); + } catch (IOException e) { + throw new IllegalArgumentException(e); + } + } init(java.lang.Enum.class, VecOrSliceDef.class); init_class_cache(); if (!get_lib_version_string().equals(get_ldk_java_bindings_version())) @@ -126,13 +150,15 @@ void __attribute__((constructor)) spawn_stderr_redirection() { else: self.c_file_pfx = self.c_file_pfx + "#define DEBUG_PRINT(...) fprintf(stderr, __VA_ARGS__)\n" - if not DEBUG: + if not DEBUG or sys.platform == "darwin": self.c_file_pfx = self.c_file_pfx + """#define MALLOC(a, _) malloc(a) #define FREE(p) if ((uint64_t)(p) > 1024) { free(p); } -#define DO_ASSERT(a) (void)(a) +""" + if not DEBUG: + self.c_file_pfx += """#define DO_ASSERT(a) (void)(a) #define CHECK(a) """ - else: + if DEBUG: self.c_file_pfx = self.c_file_pfx + """#include // Always run a, then assert it is true: #define DO_ASSERT(a) do { bool _assert_val = (a); assert(_assert_val); } while(0) @@ -146,7 +172,10 @@ void __attribute__((constructor)) debug_log_version() { DEBUG_PRINT("LDK C Bindings version did not match the header we built against\\n"); DEBUG_PRINT("Loaded LDK-Java Bindings with LDK %s and LDK-C-Bindings %s\\n", check_get_ldk_version(), check_get_ldk_bindings_version()); } +""" + if sys.platform != "darwin": + 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 // linker option to wrap malloc/calloc/realloc/free, tracking everyhing allocated @@ -154,8 +183,8 @@ void __attribute__((constructor)) debug_log_version() { #include """ - if self.target == Target.ANDROID: - self.c_file_pfx = self.c_file_pfx + """ + if self.target == Target.ANDROID: + self.c_file_pfx = self.c_file_pfx + """ #include #include @@ -196,9 +225,9 @@ void backtrace_symbols_fd(void ** buffer, int count, int _fd) { } } """ - else: - self.c_file_pfx = self.c_file_pfx + "#include \n" - self.c_file_pfx = self.c_file_pfx + """ + else: + self.c_file_pfx = self.c_file_pfx + "#include \n" + self.c_file_pfx = self.c_file_pfx + """ #include static mtx_t allocation_mtx; @@ -679,7 +708,7 @@ import java.util.Arrays; java_meths = [] for fn_line in field_fns: java_meth_descr = "(" - if fn_line.fn_name != "free" and fn_line.fn_name != "clone": + if fn_line.fn_name != "free" and fn_line.fn_name != "cloned": out_java = out_java + "\t\t " + fn_line.ret_ty_info.java_ty + " " + fn_line.fn_name + "(" java_trait_constr = java_trait_constr + "\t\t\t@Override public " + fn_line.ret_ty_info.java_ty + " " + fn_line.fn_name + "(" out_java_trait += "\t\t/**\n\t\t * " + fn_line.docs.replace("\n", "\n\t\t * ") + "\n\t\t */\n" @@ -772,7 +801,7 @@ import java.util.Arrays; # We're a supertrait out_c = out_c + "\t" + var[0] + "_JCalls* " + var[1] + ";\n" for fn in field_fns: - if fn.fn_name != "free" and fn.fn_name != "clone": + if fn.fn_name != "free" and fn.fn_name != "cloned": out_c = out_c + "\tjmethodID " + fn.fn_name + "_meth;\n" out_c = out_c + "} " + struct_name + "_JCalls;\n" @@ -788,7 +817,7 @@ import java.util.Arrays; out_c = out_c + "\t}\n}\n" for idx, fn_line in enumerate(field_fns): - if fn_line.fn_name != "free" and fn_line.fn_name != "clone": + if fn_line.fn_name != "free" and fn_line.fn_name != "cloned": assert fn_line.ret_ty_info.ty_info.get_full_rust_ty()[1] == "" out_c = out_c + fn_line.ret_ty_info.ty_info.get_full_rust_ty()[0] + " " + fn_line.fn_name + "_" + struct_name + "_jcall(" if fn_line.self_is_const: @@ -825,6 +854,12 @@ import java.util.Arrays; else: out_c = out_c + ", " + arg_info.arg_name out_c = out_c + ");\n" + + out_c += "\tif ((*env)->ExceptionCheck(env)) {\n" + out_c += "\t\t(*env)->ExceptionDescribe(env);\n" + out_c += "\t\t(*env)->FatalError(env, \"A call to " + fn_line.fn_name + " in " + struct_name + " from rust threw an exception.\");\n" + out_c += "\t}\n" + if fn_line.ret_ty_info.arg_conv is not None: out_c += "\t" + fn_line.ret_ty_info.arg_conv.replace("\n", "\n\t") + "\n" out_c += "\t" + self.deconstruct_jenv().replace("\n", "\n\t").strip() + "\n" @@ -836,15 +871,19 @@ import java.util.Arrays; out_c = out_c + "}\n" - # Write out a clone function whether we need one or not, as we use them in moving to rust - out_c = out_c + "static void* " + struct_name + "_JCalls_clone(const void* this_arg) {\n" - out_c = out_c + "\t" + struct_name + "_JCalls *j_calls = (" + struct_name + "_JCalls*) this_arg;\n" - out_c = out_c + "\tatomic_fetch_add_explicit(&j_calls->refcnt, 1, memory_order_release);\n" + # If we can, write out a clone function whether we need one or not, as we use them in moving to rust + can_clone_with_ptr = True for var in field_vars: - if not isinstance(var, ConvInfo): - out_c = out_c + "\tatomic_fetch_add_explicit(&j_calls->" + var[1] + "->refcnt, 1, memory_order_release);\n" - out_c = out_c + "\treturn (void*) this_arg;\n" - out_c = out_c + "}\n" + if isinstance(var, ConvInfo): + can_clone_with_ptr = False + if can_clone_with_ptr: + out_c = out_c + "static void " + struct_name + "_JCalls_cloned(" + struct_name + "* new_obj) {\n" + out_c = out_c + "\t" + struct_name + "_JCalls *j_calls = (" + struct_name + "_JCalls*) new_obj->this_arg;\n" + out_c = out_c + "\tatomic_fetch_add_explicit(&j_calls->refcnt, 1, memory_order_release);\n" + for var in field_vars: + if not isinstance(var, ConvInfo): + 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 (" + self.c_fn_args_pfx + ", jobject o" for var in flattened_field_vars: @@ -862,7 +901,7 @@ import java.util.Arrays; out_c = out_c + "\tcalls->o = (*env)->NewWeakGlobalRef(env, o);\n" for (fn_name, java_meth_descr) in java_meths: - if fn_name != "free" and fn_name != "clone": + if fn_name != "free" and fn_name != "cloned": out_c = out_c + "\tcalls->" + fn_name + "_meth = (*env)->GetMethodID(env, c, \"" + fn_name + "\", \"" + java_meth_descr + "\");\n" out_c = out_c + "\tCHECK(calls->" + fn_name + "_meth != NULL);\n" @@ -872,12 +911,12 @@ import java.util.Arrays; out_c = out_c + "\n\t" + struct_name + " ret = {\n" out_c = out_c + "\t\t.this_arg = (void*) calls,\n" for fn_line in field_fns: - if fn_line.fn_name != "free" and fn_line.fn_name != "clone": + if fn_line.fn_name != "free" and fn_line.fn_name != "cloned": out_c = out_c + "\t\t." + fn_line.fn_name + " = " + fn_line.fn_name + "_" + struct_name + "_jcall,\n" elif fn_line.fn_name == "free": out_c = out_c + "\t\t.free = " + struct_name + "_JCalls_free,\n" else: - out_c = out_c + "\t\t.clone = " + struct_name + "_JCalls_clone,\n" + out_c = out_c + "\t\t.cloned = " + struct_name + "_JCalls_cloned,\n" for var in field_vars: if isinstance(var, ConvInfo): if var.arg_conv_name is not None: @@ -924,7 +963,7 @@ import java.util.Arrays; def trait_struct_inc_refcnt(self, ty_info): base_conv = "\nif (" + ty_info.var_name + "_conv.free == " + ty_info.rust_obj + "_JCalls_free) {\n" base_conv = base_conv + "\t// If this_arg is a JCalls struct, then we need to increment the refcnt in it.\n" - base_conv = base_conv + "\t" + ty_info.rust_obj + "_JCalls_clone(" + ty_info.var_name + "_conv.this_arg);\n}" + base_conv = base_conv + "\t" + ty_info.rust_obj + "_JCalls_cloned(&" + ty_info.var_name + "_conv);\n}" return base_conv def map_complex_enum(self, struct_name, variant_list, camel_to_snake, enum_doc_comment):