Skip to content

Commit 29a9573

Browse files
committed
Be more conservative about holding a ref to a cloned object
If we clone an object before passing to/from native code, we generally don't need to hold a reference to that object in the struct that owns the method. The one exception we include here is if the object being passed is either a trait or holds a reference to a trait. Its not clear if this is required but it seems like a potential sharp edge.
1 parent a596b45 commit 29a9573

File tree

3 files changed

+25
-14
lines changed

3 files changed

+25
-14
lines changed

bindingstypes.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
class TypeInfo:
2-
def __init__(self, is_native_primitive, rust_obj, java_ty, java_fn_ty_arg, java_hu_ty, c_ty, is_const, passed_as_ptr, is_ptr, nonnull_ptr, var_name, arr_len, arr_access, subty=None, contains_trait=False):
2+
def __init__(self, is_native_primitive, rust_obj, java_ty, java_fn_ty_arg, java_hu_ty, c_ty, is_const, passed_as_ptr, is_ptr, nonnull_ptr, var_name, arr_len, arr_access, is_trait, subty=None, contains_trait=False):
33
self.is_native_primitive = is_native_primitive
44
self.rust_obj = rust_obj
55
self.java_ty = java_ty
@@ -16,6 +16,7 @@ def __init__(self, is_native_primitive, rust_obj, java_ty, java_fn_ty_arg, java_
1616
self.subty = subty
1717
self.pass_by_ref = is_ptr
1818
self.requires_clone = None
19+
self.is_trait = is_trait
1920
self.contains_trait = contains_trait
2021

2122
def get_full_rust_ty(self):

gen_type_mapping.py

+14-8
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,7 @@ def _do_map_type_with_info(self, ty_info, print_void, ret_arr_len, is_free, hold
300300
else:
301301
from_hu_conv = (self.consts.get_ptr(ty_info.var_name), self.consts.add_ref("this", ty_info.var_name))
302302
opaque_arg_conv = ty_info.rust_obj + " " + ty_info.var_name + "_conv;\n"
303-
opaque_arg_conv = opaque_arg_conv + ty_info.var_name + "_conv.inner = untag_ptr(" + ty_info.var_name + ");\n"
303+
opaque_arg_conv += ty_info.var_name + "_conv.inner = untag_ptr(" + ty_info.var_name + ");\n"
304304
opaque_arg_conv += ty_info.var_name + "_conv.is_owned = ptr_is_owned(" + ty_info.var_name + ");\n"
305305
opaque_arg_conv += "CHECK_INNER_FIELD_ACCESS_OR_NULL(" + ty_info.var_name + "_conv);"
306306

@@ -313,6 +313,8 @@ def _do_map_type_with_info(self, ty_info, print_void, ret_arr_len, is_free, hold
313313
# whereas in the first we prefer to clone in C to avoid additional Java code as much as possible.
314314
if holds_ref:
315315
opaque_arg_conv += "\n" + ty_info.var_name + "_conv = " + ty_info.rust_obj.replace("LDK", "") + "_clone(&" + ty_info.var_name + "_conv);"
316+
if not ty_info.pass_by_ref and not ty_info.contains_trait and not ty_info.is_trait:
317+
from_hu_conv = (from_hu_conv[0], "")
316318
elif is_nullable:
317319
from_hu_conv = (ty_info.var_name + " == null ? " + self.consts.native_zero_ptr + " : " + ty_info.var_name + ".clone_ptr()", "")
318320
else:
@@ -415,18 +417,23 @@ def _do_map_type_with_info(self, ty_info, print_void, ret_arr_len, is_free, hold
415417
to_hu_conv = self.consts.var_decl_statement(ty_info.java_hu_ty, "ret_hu_conv", "new " + ty_info.java_hu_ty + "(null, " + ty_info.var_name + ")") + ";\n" + self.consts.add_ref("ret_hu_conv", "this") + ";",
416418
to_hu_conv_name = "ret_hu_conv", from_hu_conv = from_hu_conv)
417419
needs_full_clone = not is_free and (not ty_info.is_ptr or ty_info.requires_clone == True) and ty_info.requires_clone != False
420+
from_hu_add_ref = ""
421+
if ty_info.contains_trait or ty_info.is_trait or needs_full_clone:
422+
from_hu_add_ref = self.consts.add_ref("this", ty_info.var_name)
418423
if needs_full_clone:
419-
if "res" in ty_info.var_name: # XXX: This is a stupid hack
420-
needs_full_clone = False
421424
if needs_full_clone and (ty_info.rust_obj.replace("LDK", "") + "_clone") in self.clone_fns:
422425
# arg_conv is used when converting a function argument from java normally (with holds_ref set),
423426
# and when converting a java value being returned from a trait method (with holds_ref unset).
424427
# In the second case, we need to clone before returning to C (as once we return the GC can free the object),
425428
# whereas in the first we prefer to clone in C to avoid additional Java code as much as possible.
426429
if holds_ref:
427430
base_conv += "\n" + ty_info.var_name + "_conv = " + ty_info.rust_obj.replace("LDK", "") + "_clone((" + ty_info.rust_obj + "*)untag_ptr(" + ty_info.var_name + "));"
431+
if not ty_info.pass_by_ref and not ty_info.contains_trait and not ty_info.is_trait:
432+
from_hu_add_ref = ""
428433
else:
429-
from_hu_conv = (ty_info.var_name + ".clone_ptr()", "")
434+
if not ty_info.pass_by_ref and not ty_info.contains_trait and not ty_info.is_trait:
435+
from_hu_add_ref = ""
436+
from_hu_conv = (ty_info.var_name + ".clone_ptr()", from_hu_add_ref)
430437
base_conv += "\n" + "FREE(untag_ptr(" + ty_info.var_name + "));"
431438
elif needs_full_clone:
432439
base_conv = base_conv + "\n// WARNING: we may need a move here but no clone is available for " + ty_info.rust_obj
@@ -454,8 +461,7 @@ def _do_map_type_with_info(self, ty_info, print_void, ret_arr_len, is_free, hold
454461
ret_conv = (ret_conv[0] + "*" + ty_info.var_name + "_copy = ", "")
455462
ret_conv = (ret_conv[0], ";\n" + self.consts.ptr_c_ty + " " + ty_info.var_name + "_ref = tag_ptr(" + ty_info.var_name + "_copy, true);")
456463
if from_hu_conv is None:
457-
from_hu_conv = (self.consts.get_ptr(ty_info.var_name), "")
458-
from_hu_conv = (from_hu_conv[0], self.consts.add_ref("this", ty_info.var_name))
464+
from_hu_conv = (self.consts.get_ptr(ty_info.var_name), from_hu_add_ref)
459465
fully_qualified_ty = self.consts.fully_qualified_hu_ty_path(ty_info)
460466
to_hu_call = fully_qualified_ty + ".constr_from_ptr(" + ty_info.var_name + ")"
461467
return ConvInfo(ty_info = ty_info, arg_name = ty_info.var_name,
@@ -472,7 +478,7 @@ def _do_map_type_with_info(self, ty_info, print_void, ret_arr_len, is_free, hold
472478
else:
473479
ret_conv = (ty_info.rust_obj + "* " + ty_info.var_name + "_conv = MALLOC(sizeof(" + ty_info.rust_obj + "), \"" + ty_info.rust_obj + "\");\n*" + ty_info.var_name + "_conv = ", ";")
474480
if from_hu_conv is None:
475-
from_hu_conv = (self.consts.get_ptr(ty_info.var_name), "")
481+
from_hu_conv = (self.consts.get_ptr(ty_info.var_name), from_hu_add_ref)
476482
return ConvInfo(ty_info = ty_info, arg_name = ty_info.var_name,
477483
arg_conv = base_conv, arg_conv_name = ty_info.var_name + "_conv", arg_conv_cleanup = None,
478484
ret_conv = ret_conv, ret_conv_name = "tag_ptr(" + ty_info.var_name + "_conv, true)",
@@ -498,7 +504,7 @@ def _do_map_type_with_info(self, ty_info, print_void, ret_arr_len, is_free, hold
498504
else:
499505
to_hu_conv_sfx = ""
500506
if from_hu_conv is None:
501-
from_hu_conv = (self.consts.get_ptr(ty_info.var_name), "")
507+
from_hu_conv = (self.consts.get_ptr(ty_info.var_name), from_hu_add_ref)
502508
return ConvInfo(ty_info = ty_info, arg_name = ty_info.var_name,
503509
arg_conv = base_conv, arg_conv_name = ty_info.var_name + "_conv", arg_conv_cleanup = None,
504510
ret_conv = ret_conv, ret_conv_name = ret_conv_name,

genbindings.py

+9-5
Original file line numberDiff line numberDiff line change
@@ -262,15 +262,16 @@ def java_c_types(fn_arg, ret_arr_len):
262262
if is_ptr:
263263
res.pass_by_ref = True
264264
java_ty = consts.java_arr_ty_str(res.java_ty)
265+
is_trait = res.rust_obj in trait_structs
265266
if res.is_native_primitive or res.passed_as_ptr:
266267
return TypeInfo(rust_obj=fn_arg.split(" ")[0], java_ty=java_ty, java_hu_ty=res.java_hu_ty + "[]",
267268
java_fn_ty_arg="[" + res.java_fn_ty_arg, c_ty=res.c_ty + "Array", passed_as_ptr=False, is_ptr=is_ptr,
268-
nonnull_ptr=nonnull_ptr, is_const=is_const,
269+
nonnull_ptr=nonnull_ptr, is_const=is_const, is_trait = is_trait,
269270
var_name=res.var_name, arr_len="datalen", arr_access="data", subty=res, is_native_primitive=False)
270271
else:
271272
return TypeInfo(rust_obj=fn_arg.split(" ")[0], java_ty=java_ty, java_hu_ty=res.java_hu_ty + "[]",
272273
java_fn_ty_arg="[" + res.java_fn_ty_arg, c_ty=consts.ptr_arr, passed_as_ptr=False, is_ptr=is_ptr,
273-
nonnull_ptr=nonnull_ptr, is_const=is_const,
274+
nonnull_ptr=nonnull_ptr, is_const=is_const, is_trait = is_trait,
274275
var_name=res.var_name, arr_len="datalen", arr_access="data", subty=res, is_native_primitive=False)
275276

276277
is_primitive = False
@@ -428,6 +429,7 @@ def java_c_types(fn_arg, ret_arr_len):
428429

429430
var_is_arr = var_is_arr_regex.match(fn_arg)
430431
subty = None
432+
is_trait = rust_obj in trait_structs
431433
if var_is_arr is not None or ret_arr_len is not None:
432434
assert(not take_by_ptr)
433435
assert(not is_ptr)
@@ -453,16 +455,18 @@ def java_c_types(fn_arg, ret_arr_len):
453455
if var_is_arr.group(1) == "":
454456
return TypeInfo(rust_obj=rust_obj, java_ty=java_ty, java_hu_ty=java_hu_ty, java_fn_ty_arg="[" + fn_ty_arg, c_ty=c_ty, is_const=is_const,
455457
passed_as_ptr=False, is_ptr=False, nonnull_ptr=nonnull_ptr, var_name="arg", subty=subty,
456-
arr_len=var_is_arr.group(2), arr_access=arr_access, is_native_primitive=False, contains_trait=contains_trait)
458+
arr_len=var_is_arr.group(2), arr_access=arr_access, is_native_primitive=False,
459+
is_trait=is_trait, contains_trait=contains_trait)
457460
return TypeInfo(rust_obj=rust_obj, java_ty=java_ty, java_hu_ty=java_hu_ty, java_fn_ty_arg="[" + fn_ty_arg, c_ty=c_ty, is_const=is_const,
458461
passed_as_ptr=False, is_ptr=False, nonnull_ptr=nonnull_ptr, var_name=var_is_arr.group(1), subty=subty,
459-
arr_len=var_is_arr.group(2), arr_access=arr_access, is_native_primitive=False, contains_trait=contains_trait)
462+
arr_len=var_is_arr.group(2), arr_access=arr_access, is_native_primitive=False,
463+
is_trait=is_trait, contains_trait=contains_trait)
460464

461465
if java_hu_ty is None:
462466
java_hu_ty = java_ty
463467
return TypeInfo(rust_obj=rust_obj, java_ty=java_ty, java_hu_ty=java_hu_ty, java_fn_ty_arg=fn_ty_arg, c_ty=c_ty, passed_as_ptr=is_ptr or take_by_ptr,
464468
is_const=is_const, is_ptr=is_ptr, nonnull_ptr=nonnull_ptr, var_name=fn_arg, arr_len=arr_len, arr_access=arr_access, is_native_primitive=is_primitive,
465-
contains_trait=contains_trait, subty=subty)
469+
contains_trait=contains_trait, subty=subty, is_trait=is_trait)
466470

467471
fn_ptr_regex = re.compile("^extern const ([A-Za-z_0-9\* ]*) \(\*(.*)\)\((.*)\);$")
468472
fn_ret_arr_regex = re.compile("(.*) \(\*(.*)\((.*)\)\)\[([0-9]*)\];$")

0 commit comments

Comments
 (0)