diff --git a/src/bgen/Generator.cs b/src/bgen/Generator.cs index 48921f6e612c..ecdf6cd844f2 100644 --- a/src/bgen/Generator.cs +++ b/src/bgen/Generator.cs @@ -2899,9 +2899,11 @@ void GetReturnsWrappers (MethodInfo mi, MemberInformation minfo, Type declaringT } } - void GenerateInvoke (bool stret, bool supercall, MethodInfo mi, MemberInformation minfo, string selector, string args, bool assign_to_temp, Type category_type, bool aligned) + void GenerateInvoke (bool stret, bool supercall, MethodInfo mi, MemberInformation minfo, string selector, string args, Type category_type, bool aligned) { - string target_name = (category_type is null && !minfo.is_extension_method && !minfo.is_protocol_implementation_method) ? "this" : "This"; + var isInstanceMethod = category_type is null && !minfo.is_extension_method && + !minfo.is_protocol_implementation_method; + string target_name = isInstanceMethod ? "this" : "This"; string handle = supercall ? ".SuperHandle" : ".Handle"; // If we have supercall == false, we can be a Bind method that has a [Target] @@ -2958,7 +2960,7 @@ void GenerateInvoke (bool stret, bool supercall, MethodInfo mi, MemberInformatio print ($"IntPtr {handleName};"); print ($"{handleName} = global::{NamespaceCache.Messaging}.IntPtr_objc_msgSend (Class.GetHandle (typeof (T)), Selector.GetHandle (\"alloc\"));"); print ($"{handleName} = {sig} ({handleName}, {selector_field}{args});"); - print ($"{(assign_to_temp ? "ret = " : "return ")} global::ObjCRuntime.Runtime.GetINativeObject ({handleName}, true);"); + print ($"ret = global::ObjCRuntime.Runtime.GetINativeObject ({handleName}, true);"); } else { bool returns = mi.ReturnType != TypeCache.System_Void && mi.Name != "Constructor"; string cast_a = "", cast_b = ""; @@ -2973,13 +2975,13 @@ void GenerateInvoke (bool stret, bool supercall, MethodInfo mi, MemberInformatio if (minfo.is_static) print ("{0}{1}{2} (class_ptr, {5}{6}){7};", - returns ? (assign_to_temp ? "ret = " : "return ") : "", + returns ? "ret = " : "", cast_a, sig, target_name, "/*unusued3*/", //supercall ? "Super" : "", selector_field, args, cast_b); else print ("{0}{1}{2} ({3}{4}, {5}{6}){7};", - returns ? (assign_to_temp ? "ret = " : "return ") : "", + returns ? "ret = " : "", cast_a, sig, target_name, handle, selector_field, args, cast_b); @@ -2987,6 +2989,12 @@ void GenerateInvoke (bool stret, bool supercall, MethodInfo mi, MemberInformatio if (postproc.Length > 0) print (postproc.ToString ()); } + + if (!isInstanceMethod) { + // if this is a extension of any kind, ensure that we keep alive the this parameter + // so that it is not collected before the msg send call has completed. + print ("GC.KeepAlive (This);"); + } } void GenerateNewStyleInvoke (bool supercall, MethodInfo mi, MemberInformation minfo, string selector, string args, bool assign_to_temp, Type category_type) @@ -2999,15 +3007,15 @@ void GenerateNewStyleInvoke (bool supercall, MethodInfo mi, MemberInformation mi if (x64_stret) { print ("if (global::ObjCRuntime.Runtime.IsARM64CallingConvention) {"); indent++; - GenerateInvoke (false, supercall, mi, minfo, selector, args, assign_to_temp, category_type, false); + GenerateInvoke (false, supercall, mi, minfo, selector, args, category_type, false); indent--; print ("} else {"); indent++; - GenerateInvoke (x64_stret, supercall, mi, minfo, selector, args, assign_to_temp, category_type, aligned && x64_stret); + GenerateInvoke (x64_stret, supercall, mi, minfo, selector, args, category_type, aligned && x64_stret); indent--; print ("}"); } else { - GenerateInvoke (false, supercall, mi, minfo, selector, args, assign_to_temp, category_type, false); + GenerateInvoke (false, supercall, mi, minfo, selector, args, category_type, false); } return; } @@ -3022,37 +3030,37 @@ void GenerateNewStyleInvoke (bool supercall, MethodInfo mi, MemberInformation mi // First check for arm64 print ("if (global::ObjCRuntime.Runtime.IsARM64CallingConvention) {"); indent++; - GenerateInvoke (false, supercall, mi, minfo, selector, args, assign_to_temp, category_type, false); + GenerateInvoke (false, supercall, mi, minfo, selector, args, category_type, false); indent--; // If we're not arm64, but we're 64-bit, then we're x86_64 print ("} else if (IntPtr.Size == 8) {"); indent++; - GenerateInvoke (x64_stret, supercall, mi, minfo, selector, args, assign_to_temp, category_type, aligned && x64_stret); + GenerateInvoke (x64_stret, supercall, mi, minfo, selector, args, category_type, aligned && x64_stret); indent--; // if we're not 64-bit, but we're on device, then we're 32-bit arm print ("} else if (Runtime.Arch == Arch.DEVICE) {"); indent++; - GenerateInvoke (arm_stret, supercall, mi, minfo, selector, args, assign_to_temp, category_type, aligned && arm_stret); + GenerateInvoke (arm_stret, supercall, mi, minfo, selector, args, category_type, aligned && arm_stret); indent--; // if we're none of the above, we're x86 print ("} else {"); indent++; - GenerateInvoke (x86_stret, supercall, mi, minfo, selector, args, assign_to_temp, category_type, aligned && x86_stret); + GenerateInvoke (x86_stret, supercall, mi, minfo, selector, args, category_type, aligned && x86_stret); indent--; print ("}"); } else { print ("if (IntPtr.Size == 8) {"); indent++; - GenerateInvoke (x64_stret, supercall, mi, minfo, selector, args, assign_to_temp, category_type, aligned && x64_stret); + GenerateInvoke (x64_stret, supercall, mi, minfo, selector, args, category_type, aligned && x64_stret); indent--; print ("} else {"); indent++; - GenerateInvoke (x86_stret, supercall, mi, minfo, selector, args, assign_to_temp, category_type, aligned && x86_stret); + GenerateInvoke (x86_stret, supercall, mi, minfo, selector, args, category_type, aligned && x86_stret); indent--; print ("}"); } } else { - GenerateInvoke (false, supercall, mi, minfo, selector, args, assign_to_temp, category_type, false); + GenerateInvoke (false, supercall, mi, minfo, selector, args, category_type, false); } } @@ -3554,6 +3562,17 @@ public void GenerateMethodBody (MemberInformation minfo, MethodInfo mi, string s var nullableReturn = isClassType ? "?" : string.Empty; print ("{0}{1} ret;", TypeManager.FormatType (minfo.type, mi.ReturnType), nullableReturn); } + } else if (mi.ReturnType != TypeCache.System_Void && mi.Name != "Constructor") { + if (minfo.is_bindAs) { + var bindAsAttrib = GetBindAsAttribute (minfo.mi); + // tricky, e.g. when an nullable `NSNumber[]` is bound as a `float[]`, since FormatType and bindAsAttrib have not clue about the original nullability + print ("{0} ret;", TypeManager.FormatType (bindAsAttrib.Type.DeclaringType, bindAsAttrib.Type)); + } else { + print ("{0} ret;", TypeManager.FormatType (minfo.type, mi.ReturnType)); + } + } else if (minfo.is_ctor && minfo.is_protocol_member) { + // special case because constructors in protocol members will be converted to factory methods + print ($"T? ret;"); } bool needs_temp = use_temp_return || disposes.Length > 0; @@ -3666,6 +3685,12 @@ public void GenerateMethodBody (MemberInformation minfo, MethodInfo mi, string s // we can't be 100% confident that the ObjC API annotations are correct so we always null check inside generated code print ("return ret!;"); } + } else if (minfo.is_ctor && minfo.is_protocol_member) { + // special case since ctrs in protocol members become create methods + print ("return ret;"); + } else if (mi.ReturnType != TypeCache.System_Void && mi.Name != "Constructor") { + // general case if we do return and we are not a constructor. + print ("return ret;"); } if (minfo.is_ctor) WriteMarkDirtyIfDerived (sw, mi.DeclaringType);