+ # 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 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:
+ if isinstance(var, ConvInfo):
+ out_c = out_c + ", " + var.c_ty + " " + var.arg_name
+ else:
+ out_c = out_c + ", jobject " + var[1]
+ out_c = out_c + ") {\n"
+
+ out_c = out_c + "\tjclass c = (*env)->GetObjectClass(env, o);\n"
+ out_c = out_c + "\tCHECK(c != NULL);\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 + "\tDO_ASSERT((*env)->GetJavaVM(env, &calls->vm) == 0);\n"
+ 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 != "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"
+
+ for var in flattened_field_vars:
+ if isinstance(var, ConvInfo) and var.arg_conv is not None:
+ out_c = out_c + "\n\t" + var.arg_conv.replace("\n", "\n\t") +"\n"
+ 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 != "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.cloned = " + struct_name + "_JCalls_cloned,\n"
+ for var in field_vars:
+ if isinstance(var, ConvInfo):
+ if var.arg_conv_name is not None:
+ out_c = out_c + "\t\t." + var.arg_name + " = " + var.arg_conv_name + ",\n"
+ out_c = out_c + "\t\t.set_" + var.arg_name + " = NULL,\n"
+ else:
+ out_c = out_c + "\t\t." + var.var_name + " = " + var.var_name + ",\n"
+ out_c = out_c + "\t\t.set_" + var.var_name + " = NULL,\n"
+ else:
+ out_c += "\t\t." + var[1] + " = " + var[0] + "_init(env, clz, " + var[1]
+ for suparg in var[2]:
+ if isinstance(suparg, ConvInfo):
+ out_c = out_c + ", " + suparg.arg_name
+ else:
+ out_c = out_c + ", " + suparg[1]
+ out_c += "),\n"
+ out_c = out_c + "\t};\n"
+ for var in flattened_field_vars:
+ if not isinstance(var, ConvInfo):
+ out_c = out_c + "\tcalls->" + var[1] + " = ret." + var[1] + ".this_arg;\n"
+ out_c = out_c + "\treturn ret;\n"
+ out_c = out_c + "}\n"
+
+ out_c = out_c + self.c_fn_ty_pfx + "int64_t " + self.c_fn_name_define_pfx(struct_name + "_new", True) + "jobject o"
+ for var in flattened_field_vars:
+ if isinstance(var, ConvInfo):
+ out_c = out_c + ", " + var.c_ty + " " + var.arg_name
+ else:
+ out_c = out_c + ", jobject " + 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(env, clz, o"
+ for var in flattened_field_vars:
+ if isinstance(var, ConvInfo):
+ out_c = out_c + ", " + var.arg_name
+ else:
+ out_c = out_c + ", " + var[1]
+ out_c = out_c + ");\n"
+ out_c = out_c + "\treturn (uint64_t)res_ptr;\n"
+ out_c = out_c + "}\n"
+
+ for var in flattened_field_vars:
+ if not isinstance(var, ConvInfo):
+ out_java_trait += "\n\t/**\n"
+ out_java_trait += "\t * Gets the underlying " + var[1] + ".\n"
+ out_java_trait += "\t */\n"
+ underscore_name = ''.join('_' + c.lower() if c.isupper() else c for c in var[1]).strip('_')
+ out_java_trait += "\tpublic " + var[1] + " get_" + underscore_name + "() {\n"
+ out_java_trait += "\t\t" + var[1] + " res = new " + var[1] + "(null, bindings." + struct_name + "_get_" + var[1] + "(this.ptr));\n"
+ out_java_trait += "\t\tthis.ptrs_to.add(res);\n"
+ out_java_trait += "\t\treturn res;\n"
+ out_java_trait += "\t}\n"
+ out_java_trait += "\n"
+
+ out_java += "\tpublic static native long " + struct_name + "_get_" + var[1] + "(long arg);\n"
+
+ out_c += "JNIEXPORT int64_t JNICALL Java_org_ldk_impl_bindings_" + struct_name + "_1get_1" + var[1] + "(JNIEnv *env, jclass clz, int64_t arg) {\n"
+ out_c += "\t" + struct_name + " *inp = (" + struct_name + " *)(arg & ~1);\n"
+ out_c += "\tuint64_t res_ptr = (uint64_t)&inp->" + var[1] + ";\n"
+ out_c += "\tDO_ASSERT((res_ptr & 1) == 0);\n"
+ out_c += "\treturn (int64_t)(res_ptr | 1);\n"
+ out_c += "}\n"
+
+ return (out_java, out_java_trait, out_c)
+
+ 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_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):
+ java_hu_type = struct_name.replace("LDK", "").replace("COption", "Option")
+ out_java_enum = ""
+ out_java = ""
+ out_c = ""
+
+ out_java_enum += (self.hu_struct_file_prefix)
+ out_java_enum += "\n/**\n * " + enum_doc_comment.replace("\n", "\n * ") + "\n */\n"
+ out_java_enum += "@SuppressWarnings(\"unchecked\") // We correctly assign various generic arrays\n"
+ out_java_enum += ("public class " + java_hu_type + " extends CommonBase {\n")
+ out_java_enum += ("\tprivate " + java_hu_type + "(Object _dummy, long ptr) { super(ptr); }\n")
+ out_java_enum += ("\t@Override @SuppressWarnings(\"deprecation\")\n")
+ out_java_enum += ("\tprotected void finalize() throws Throwable {\n")
+ out_java_enum += ("\t\tsuper.finalize();\n")
+ out_java_enum += ("\t\tif (ptr != 0) { bindings." + struct_name.replace("LDK", "") + "_free(ptr); }\n")
+ out_java_enum += ("\t}\n")
+ out_java_enum += ("\tstatic " + java_hu_type + " constr_from_ptr(long ptr) {\n")
+ out_java_enum += ("\t\tbindings." + struct_name + " raw_val = bindings." + struct_name + "_ref_from_ptr(ptr);\n")
+ java_hu_subclasses = ""
+
+ init_meth_jty_strs = {}
+
+ out_java += ("\tpublic static class " + struct_name + " {\n")
+ out_java += ("\t\tprivate " + struct_name + "() {}\n")
+ for var in variant_list:
+ out_java += ("\t\tpublic final static class " + var.var_name + " extends " + struct_name + " {\n")
+ if var.var_docs is not None:
+ java_hu_subclasses += "\t/**\n\t * " + var.var_docs.replace("\n", "\n\t * ") + "\n\t */\n"
+ java_hu_subclasses += "\tpublic final static class " + var.var_name + " extends " + java_hu_type + " {\n"
+ out_java_enum += ("\t\tif (raw_val.getClass() == bindings." + struct_name + "." + var.var_name + ".class) {\n")
+ out_java_enum += ("\t\t\treturn new " + var.var_name + "(ptr, (bindings." + struct_name + "." + var.var_name + ")raw_val);\n")
+ init_meth_jty_str = ""
+ init_meth_params = ""
+ init_meth_body = ""
+ hu_conv_body = ""
+ for idx, (field_ty, field_docs) in enumerate(var.fields):
+ if idx > 0:
+ init_meth_params = init_meth_params + ", "
+
+ java_ty = field_ty.java_ty
+ if field_ty.java_fn_ty_arg.startswith("L") and field_ty.java_fn_ty_arg.endswith(";"):
+ # If this is a simple enum, we have to reference it in the low-level bindings differently:
+ java_ty = field_ty.java_fn_ty_arg.strip("L;").replace("/", ".")
+ out_java += "\t\t\tpublic " + java_ty + " " + field_ty.arg_name + ";\n"
+ if field_docs is not None:
+ java_hu_subclasses += "\t\t/**\n\t\t * " + field_docs.replace("\n", "\n\t\t * ") + "\n\t\t*/\n"
+ java_hu_subclasses += "\t\t"
+ if field_ty.nullable:
+ java_hu_subclasses += "@Nullable "
+ java_hu_subclasses += "public final " + self.fully_qualified_hu_ty_path(field_ty) + " " + field_ty.arg_name + ";\n"
+ init_meth_params = init_meth_params + java_ty + " " + field_ty.arg_name
+
+ init_meth_body = init_meth_body + "this." + field_ty.arg_name + " = " + field_ty.arg_name + "; "
+ if field_ty.to_hu_conv is not None:
+ hu_conv_body = hu_conv_body + "\t\t\t" + field_ty.java_ty + " " + field_ty.arg_name + " = obj." + field_ty.arg_name + ";\n"
+ hu_conv_body = hu_conv_body + "\t\t\t" + field_ty.to_hu_conv.replace("\n", "\n\t\t\t") + "\n"
+ hu_conv_body = hu_conv_body + "\t\t\tthis." + field_ty.arg_name + " = " + field_ty.to_hu_conv_name + ";\n"
+ else:
+ hu_conv_body = hu_conv_body + "\t\t\tthis." + field_ty.arg_name + " = obj." + field_ty.arg_name + ";\n"
+ init_meth_jty_str = init_meth_jty_str + field_ty.java_fn_ty_arg
+ out_java += ("\t\t\t" + var.var_name + "(" + init_meth_params + ") { ")
+ out_java += (init_meth_body)
+ out_java += ("}\n")
+ out_java += ("\t\t}\n")
+ out_java_enum += ("\t\t}\n")
+ java_hu_subclasses = java_hu_subclasses + "\t\tprivate " + var.var_name + "(long ptr, bindings." + struct_name + "." + var.var_name + " obj) {\n\t\t\tsuper(null, ptr);\n"
+ java_hu_subclasses = java_hu_subclasses + hu_conv_body
+ java_hu_subclasses = java_hu_subclasses + "\t\t}\n\t}\n"
+ init_meth_jty_strs[var.var_name] = init_meth_jty_str
+ out_java += ("\t\tstatic native void init();\n")
+ out_java += ("\t}\n")
+ out_java_enum += ("\t\tassert false; return null; // Unreachable without extending the (internal) bindings interface\n\t}\n\n")
+ out_java_enum += (java_hu_subclasses)
+ out_java += ("\tstatic { " + struct_name + ".init(); }\n")
+ out_java += ("\tpublic static native " + struct_name + " " + struct_name + "_ref_from_ptr(long ptr);\n");
+
+ out_c += (self.c_complex_enum_pfx(struct_name, [x.var_name for x in variant_list], init_meth_jty_strs))
+
+ out_c += (self.c_fn_ty_pfx + self.c_complex_enum_pass_ty(struct_name) + " " + self.c_fn_name_define_pfx(struct_name + "_ref_from_ptr", True) + self.ptr_c_ty + " ptr) {\n")
+ out_c += ("\t" + struct_name + " *obj = (" + struct_name + "*)(ptr & ~1);\n")
+ out_c += ("\tswitch(obj->tag) {\n")
+ for var in variant_list:
+ out_c += ("\t\tcase " + struct_name + "_" + var.var_name + ": {\n")
+ c_params = []
+ for idx, (field_map, field_docs) in enumerate(var.fields):
+ if field_map.ret_conv is not None:
+ out_c += ("\t\t\t" + field_map.ret_conv[0].replace("\n", "\n\t\t\t"))
+ if var.tuple_variant:
+ out_c += "obj->" + camel_to_snake(var.var_name)
+ else:
+ out_c += "obj->" + camel_to_snake(var.var_name) + "." + field_map.arg_name
+ out_c += (field_map.ret_conv[1].replace("\n", "\n\t\t\t") + "\n")
+ c_params.append(field_map.ret_conv_name)
+ else:
+ if var.tuple_variant:
+ c_params.append("obj->" + camel_to_snake(var.var_name))
+ else:
+ c_params.append("obj->" + camel_to_snake(var.var_name) + "." + field_map.arg_name)
+ out_c += ("\t\t\treturn " + self.c_constr_native_complex_enum(struct_name, var.var_name, c_params) + ";\n")
+ out_c += ("\t\t}\n")
+ out_c += ("\t\tdefault: abort();\n")
+ out_c += ("\t}\n}\n")
+ return (out_java, out_java_enum, out_c)
+
+ def map_opaque_struct(self, struct_name, struct_doc_comment):
+ 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"
+ out_opaque_struct_human += "@SuppressWarnings(\"unchecked\") // We correctly assign various generic arrays\n"
+ hu_name = struct_name.replace("LDKC2Tuple", "TwoTuple").replace("LDKC3Tuple", "ThreeTuple").replace("LDK", "")
+ out_opaque_struct_human += ("public class " + hu_name + " extends CommonBase")
+ if struct_name.startswith("LDKLocked"):
+ out_opaque_struct_human += (" implements AutoCloseable")
+ out_opaque_struct_human += (" {\n")
+ out_opaque_struct_human += ("\t" + hu_name + "(Object _dummy, long ptr) { super(ptr); }\n")
+ if struct_name.startswith("LDKLocked"):
+ out_opaque_struct_human += ("\t@Override public void close() {\n")
+ else:
+ out_opaque_struct_human += ("\t@Override @SuppressWarnings(\"deprecation\")\n")
+ out_opaque_struct_human += ("\tprotected void finalize() throws Throwable {\n")
+ out_opaque_struct_human += ("\t\tsuper.finalize();\n")
+ out_opaque_struct_human += ("\t\tif (ptr != 0) { bindings." + struct_name.replace("LDK","") + "_free(ptr); }\n")
+ out_opaque_struct_human += ("\t}\n\n")
+ return out_opaque_struct_human
+
+ def map_tuple(self, struct_name):
+ return self.map_opaque_struct(struct_name, "A Tuple")
+
+ def map_result(self, struct_name, res_map, err_map):
+ human_ty = struct_name.replace("LDKCResult", "Result")
+ java_hu_struct = ""
+ java_hu_struct += self.hu_struct_file_prefix
+ java_hu_struct += "public class " + human_ty + " extends CommonBase {\n"
+ java_hu_struct += "\tprivate " + human_ty + "(Object _dummy, long ptr) { super(ptr); }\n"
+ java_hu_struct += "\tprotected void finalize() throws Throwable {\n"
+ java_hu_struct += "\t\tif (ptr != 0) { bindings." + struct_name.replace("LDK","") + "_free(ptr); } super.finalize();\n"
+ java_hu_struct += "\t}\n\n"
+ java_hu_struct += "\tstatic " + human_ty + " constr_from_ptr(long ptr) {\n"
+ java_hu_struct += "\t\tif (bindings." + struct_name.replace("LDK", "") + "_is_ok(ptr)) {\n"
+ java_hu_struct += "\t\t\treturn new " + human_ty + "_OK(null, ptr);\n"
+ java_hu_struct += "\t\t} else {\n"
+ java_hu_struct += "\t\t\treturn new " + human_ty + "_Err(null, ptr);\n"
+ java_hu_struct += "\t\t}\n"
+ java_hu_struct += "\t}\n"
+
+ java_hu_struct += "\tpublic static final class " + human_ty + "_OK extends " + human_ty + " {\n"
+
+ if res_map.java_hu_ty != "void":
+ java_hu_struct += "\t\tpublic final " + res_map.java_hu_ty + " res;\n"
+ java_hu_struct += "\t\tprivate " + human_ty + "_OK(Object _dummy, long ptr) {\n"
+ java_hu_struct += "\t\t\tsuper(_dummy, ptr);\n"
+ if res_map.java_hu_ty == "void":
+ pass
+ elif res_map.to_hu_conv is not None:
+ java_hu_struct += "\t\t\t" + res_map.java_ty + " res = bindings." + struct_name.replace("LDK", "") + "_get_ok(ptr);\n"
+ java_hu_struct += "\t\t\t" + res_map.to_hu_conv.replace("\n", "\n\t\t\t")
+ java_hu_struct += "\n\t\t\tthis.res = " + res_map.to_hu_conv_name + ";\n"
+ else:
+ java_hu_struct += "\t\t\tthis.res = bindings." + struct_name.replace("LDK", "") + "_get_ok(ptr);\n"
+ java_hu_struct += "\t\t}\n"
+ java_hu_struct += "\t}\n\n"
+
+ java_hu_struct += "\tpublic static final class " + human_ty + "_Err extends " + human_ty + " {\n"
+ if err_map.java_hu_ty != "void":
+ java_hu_struct += "\t\tpublic final " + err_map.java_hu_ty + " err;\n"
+ java_hu_struct += "\t\tprivate " + human_ty + "_Err(Object _dummy, long ptr) {\n"
+ java_hu_struct += "\t\t\tsuper(_dummy, ptr);\n"
+ if err_map.java_hu_ty == "void":
+ pass
+ elif err_map.to_hu_conv is not None:
+ java_hu_struct += "\t\t\t" + err_map.java_ty + " err = bindings." + struct_name.replace("LDK", "") + "_get_err(ptr);\n"
+ java_hu_struct += "\t\t\t" + err_map.to_hu_conv.replace("\n", "\n\t\t\t")
+ java_hu_struct += "\n\t\t\tthis.err = " + err_map.to_hu_conv_name + ";\n"
+ else:
+ java_hu_struct += "\t\t\tthis.err = bindings." + struct_name.replace("LDK", "") + "_get_err(ptr);\n"
+ java_hu_struct += "\t\t}\n"
+
+ java_hu_struct += "\t}\n\n"
+ return java_hu_struct
+
+ def map_function(self, argument_types, c_call_string, method_name, meth_n, return_type_info, struct_meth, default_constructor_args, takes_self, takes_self_as_ref, args_known, type_mapping_generator, doc_comment):
+ out_java = ""
+ out_c = ""
+ out_java_struct = None
+
+ out_java += ("\tpublic static native ")
+ out_c += (self.c_fn_ty_pfx)
+ out_c += (return_type_info.c_ty)
+ out_java += (return_type_info.java_ty)
+ if return_type_info.ret_conv is not None:
+ ret_conv_pfx, ret_conv_sfx = return_type_info.ret_conv
+ out_java += (" " + method_name + "(")
+ have_args = len(argument_types) > 1 or (len(argument_types) > 0 and argument_types[0].c_ty != "void")
+ out_c += (" " + self.c_fn_name_define_pfx(method_name, have_args))
+
+ for idx, arg_conv_info in enumerate(argument_types):
+ if idx != 0:
+ out_java += (", ")
+ out_c += (", ")
+ if arg_conv_info.c_ty != "void":
+ out_c += (arg_conv_info.c_ty + " " + arg_conv_info.arg_name)
+ out_java += (arg_conv_info.java_ty + " " + arg_conv_info.arg_name)
+
+ out_java_struct = ""
+ extra_java_struct_out = ""
+ if not args_known:
+ out_java_struct += ("\t// Skipped " + method_name + "\n")
+ else:
+ if doc_comment is not None:
+ out_java_struct += "\t/**\n\t * " + doc_comment.replace("\n", "\n\t * ") + "\n\t */\n"
+ if return_type_info.nullable:
+ out_java_struct += "\t@Nullable\n"
+ if not takes_self:
+ if meth_n == "new":
+ out_java_struct += "\tpublic static " + return_type_info.java_hu_ty + " of("
+ elif meth_n == "default":
+ out_java_struct += "\tpublic static " + return_type_info.java_hu_ty + " with_default("
+ else:
+ out_java_struct += "\tpublic static " + return_type_info.java_hu_ty + " " + meth_n + "("
+ elif meth_n == "clone_ptr" or (struct_meth.startswith("LDKCResult") and (meth_n == "get_ok" or meth_n == "get_err")):
+ out_java_struct += ("\t" + return_type_info.java_hu_ty + " " + meth_n + "(")
+ else:
+ if meth_n == "hash" and return_type_info.java_hu_ty == "long":
+ extra_java_struct_out = "\t@Override public int hashCode() {\n"
+ extra_java_struct_out += "\t\treturn (int)this.hash();\n"
+ extra_java_struct_out += "\t}\n"
+ elif meth_n == "eq" and return_type_info.java_hu_ty == "boolean":
+ extra_java_struct_out = "\t@Override public boolean equals(Object o) {\n"
+ extra_java_struct_out += "\t\tif (!(o instanceof " + struct_meth + ")) return false;\n"
+ extra_java_struct_out += "\t\treturn this.eq((" + struct_meth + ")o);\n"
+ extra_java_struct_out += "\t}\n"
+ out_java_struct += ("\tpublic " + return_type_info.java_hu_ty + " " + meth_n + "(")
+ for idx, arg in enumerate(argument_types):
+ if idx != 0:
+ if not takes_self or idx > 1:
+ out_java_struct += ", "
+ elif takes_self:
+ continue
+ if arg.java_ty != "void":
+ if arg.arg_name in default_constructor_args:
+ assert not arg.nullable
+ for explode_idx, explode_arg in enumerate(default_constructor_args[arg.arg_name]):
+ if explode_idx != 0:
+ out_java_struct += (", ")
+ out_java_struct += (
+ explode_arg.java_hu_ty + " " + arg.arg_name + "_" + explode_arg.arg_name)
+ else:
+ if arg.nullable:
+ out_java_struct += "@Nullable "
+ ty_string = arg.java_hu_ty
+ if arg.java_fn_ty_arg[0] == "L" and arg.java_fn_ty_arg[len(arg.java_fn_ty_arg) - 1] == ";":
+ ty_string = arg.java_fn_ty_arg.strip("L;").replace("/", ".")
+ out_java_struct += ty_string + " " + arg.arg_name
+ out_java += (");\n")
+ out_c += (") {\n")
+ if out_java_struct is not None:
+ out_java_struct += (") {\n")
+ for info in argument_types:
+ if info.arg_conv is not None:
+ out_c += ("\t" + info.arg_conv.replace('\n', "\n\t") + "\n")
+ if return_type_info.ret_conv is not None:
+ out_c += ("\t" + ret_conv_pfx.replace('\n', '\n\t'))
+ elif return_type_info.c_ty != "void":
+ out_c += ("\t" + return_type_info.c_ty + " ret_val = ")
+ else:
+ out_c += ("\t")
+ if c_call_string is None:
+ out_c += (method_name + "(")
+ else:
+ out_c += (c_call_string)
+ for idx, info in enumerate(argument_types):
+ if info.arg_conv_name is not None:
+ if idx != 0:
+ out_c += (", ")
+ elif c_call_string is not None:
+ continue
+ out_c += (info.arg_conv_name)
+ out_c += (")")
+ if return_type_info.ret_conv is not None:
+ out_c += (ret_conv_sfx.replace('\n', '\n\t'))
+ else:
+ out_c += (";")
+ for info in argument_types:
+ if info.arg_conv_cleanup is not None:
+ out_c += ("\n\t" + info.arg_conv_cleanup.replace("\n", "\n\t"))
+ if return_type_info.ret_conv is not None:
+ out_c += ("\n\treturn " + return_type_info.ret_conv_name + ";")
+ elif return_type_info.c_ty != "void":
+ out_c += ("\n\treturn ret_val;")
+ out_c += ("\n}\n\n")
+
+ if args_known:
+ out_java_struct += ("\t\t")
+ if return_type_info.java_ty != "void":
+ out_java_struct += (return_type_info.java_ty + " ret = ")
+ out_java_struct += ("bindings." + method_name + "(")
+ for idx, info in enumerate(argument_types):
+ if idx != 0:
+ out_java_struct += (", ")
+ if idx == 0 and takes_self:
+ out_java_struct += ("this.ptr")
+ elif info.arg_name in default_constructor_args:
+ out_java_struct += ("bindings." + info.java_hu_ty + "_new(")
+ for explode_idx, explode_arg in enumerate(default_constructor_args[info.arg_name]):
+ if explode_idx != 0:
+ out_java_struct += (", ")
+ expl_arg_name = info.arg_name + "_" + explode_arg.arg_name
+ if explode_arg.from_hu_conv is not None:
+ out_java_struct += (
+ explode_arg.from_hu_conv[0].replace(explode_arg.arg_name, expl_arg_name))
+ else:
+ out_java_struct += (expl_arg_name)
+ out_java_struct += (")")
+ elif info.from_hu_conv is not None:
+ out_java_struct += (info.from_hu_conv[0])
+ else:
+ out_java_struct += (info.arg_name)
+ out_java_struct += (");\n")
+
+ # This is completely nuts. The OpenJDK JRE JIT will optimize out a object which is on
+ # the stack, calling its finalizer immediately even if member methods are *actively
+ # executing* on the same object, as long as said object is on the stack. There is no
+ # concrete specification for when the optimizer is allowed to do this, and when it is
+ # not, so there is absolutely no way to be certain that this fix suffices.
+ #
+ # Instead, the "Java Language Specification" says only that an object is reachable
+ # (i.e. will not yet be finalized) if it "can be accessed in any potential continuing
+ # computation from any live thread". To any sensible reader this would mean actively
+ # executing a member function on an object would make it not eligible for finalization.
+ # But, no, dear reader, this statement does not say that. Well, okay, it says that,
+ # very explicitly in fact, but those are just, like, words, man.
+ #
+ # In the seemingly non-normative text further down, a few examples of things the
+ # optimizer can do are given, including "if the values in an object's fields are
+ # stored in registers[, t]he may then access the registers instead of the object, and
+ # never access the object again[, implying] that the object is garbage". This appears
+ # to fully contradict both the above statement, the API documentation in java.lang.ref
+ # regarding when a reference is "strongly reachable", and basic common sense. There is
+ # no concrete set of limitations stated, however, seemingly implying the JIT could
+ # decide your code would run faster by simply garbage collecting everything
+ # immediately, ensuring your code finishes soon, just by SEGFAULT. Thus, we're really
+ # entirely flying blind here. We add some fences and hope that its sufficient, but
+ # with no specification to rely on, we cannot be certain of anything.
+ #
+ # TL;DR: The Java Language "Specification" provides no real guarantees on when an
+ # object will be considered available for garbage collection once the JIT kicks in, so
+ # we put in some fences and hope to god the JIT doesn't get smarter/more broken.
+ for idx, info in enumerate(argument_types):
+ if idx == 0 and takes_self:
+ out_java_struct += ("\t\tReference.reachabilityFence(this);\n")
+ elif info.arg_name in default_constructor_args:
+ for explode_idx, explode_arg in enumerate(default_constructor_args[info.arg_name]):
+ expl_arg_name = info.arg_name + "_" + explode_arg.arg_name
+ out_java_struct += ("\t\tReference.reachabilityFence(" + expl_arg_name + ");\n")
+ elif info.c_ty != "void":
+ out_java_struct += ("\t\tReference.reachabilityFence(" + info.arg_name + ");\n")
+
+ if return_type_info.java_ty == "long" and return_type_info.java_hu_ty != "long":
+ out_java_struct += "\t\tif (ret >= 0 && ret <= 4096) { return null; }\n"
+
+ if return_type_info.to_hu_conv is not None:
+ if not takes_self:
+ out_java_struct += ("\t\t" + return_type_info.to_hu_conv.replace("\n", "\n\t\t").replace("this",
+ return_type_info.to_hu_conv_name) + "\n")
+ else:
+ out_java_struct += ("\t\t" + return_type_info.to_hu_conv.replace("\n", "\n\t\t") + "\n")
+
+ for idx, info in enumerate(argument_types):
+ if idx == 0 and takes_self:
+ pass
+ elif info.arg_name in default_constructor_args:
+ for explode_arg in default_constructor_args[info.arg_name]:
+ expl_arg_name = info.arg_name + "_" + explode_arg.arg_name
+ if explode_arg.from_hu_conv is not None and return_type_info.to_hu_conv_name:
+ out_java_struct += ("\t\t" + explode_arg.from_hu_conv[1].replace(explode_arg.arg_name,
+ expl_arg_name).replace(
+ "this", return_type_info.to_hu_conv_name) + ";\n")
+ elif info.from_hu_conv is not None and info.from_hu_conv[1] != "":
+ if not takes_self and return_type_info.to_hu_conv_name is not None:
+ out_java_struct += (
+ "\t\t" + info.from_hu_conv[1].replace("this", return_type_info.to_hu_conv_name).replace("\n", "\n\t\t") + ";\n")
+ else:
+ out_java_struct += ("\t\t" + info.from_hu_conv[1].replace("\n", "\n\t\t") + ";\n")
+
+ if takes_self and not takes_self_as_ref:
+ out_java_struct += "\t\t" + argument_types[0].from_hu_conv[1].replace("\n", "\n\t\t").replace("this_arg", "this") + ";\n"
+ if return_type_info.to_hu_conv_name is not None:
+ out_java_struct += ("\t\treturn " + return_type_info.to_hu_conv_name + ";\n")
+ elif return_type_info.java_ty != "void" and return_type_info.rust_obj != "LDK" + struct_meth:
+ out_java_struct += ("\t\treturn ret;\n")
+ out_java_struct += ("\t}\n\n")
+
+ return (out_java, out_c, out_java_struct + extra_java_struct_out)
+
+ def cleanup(self):
+ pass