Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion src/AddressBook/ABRecord.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,15 @@ internal ABRecord (NativeHandle handle, bool owns)
}

public static ABRecord? FromHandle (IntPtr handle)
{
return FromHandle (handle, false);
}

internal static ABRecord? FromHandle (IntPtr handle, bool owns)
{
if (handle == IntPtr.Zero)
return null;
return FromHandle (handle, null, false);
return FromHandle (handle, null, owns);
}

internal static ABRecord FromHandle (IntPtr handle, ABAddressBook? addressbook, bool owns = true)
Expand Down
7 changes: 6 additions & 1 deletion src/AudioToolbox/MusicSequence.cs
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,11 @@ protected override void Dispose (bool disposing)
static readonly Dictionary<IntPtr, WeakReference> sequenceMap = new Dictionary<IntPtr, WeakReference> (Runtime.IntPtrEqualityComparer);

internal static MusicSequence Lookup (IntPtr handle)
{
return Lookup (handle, false);
}

internal static MusicSequence Lookup (IntPtr handle, bool owns)
{
lock (sequenceMap) {
if (sequenceMap.TryGetValue (handle, out var weakRef)) {
Expand All @@ -120,7 +125,7 @@ internal static MusicSequence Lookup (IntPtr handle)
}
sequenceMap.Remove (handle);
}
var ms = new MusicSequence (handle, false);
var ms = new MusicSequence (handle, owns);
sequenceMap [handle] = new WeakReference (ms);
return ms;
}
Expand Down
12 changes: 12 additions & 0 deletions src/Foundation/NSArray.cs
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,18 @@ static public T [] ArrayFromHandleFunc<T> (NativeHandle handle, Func<NativeHandl
return ret;
}

/// <summary>Create a managed array from a pointer to a native NSArray instance.</summary>
/// <param name="handle">The pointer to the native NSArray instance.</param>
/// <param name="createObject">A callback that returns an instance of the type T for a given pointer (for an element in the NSArray).</param>
/// <param name="releaseHandle">Whether the native NSArray instance should be released before returning or not.</param>
public static T [] ArrayFromHandleFunc<T> (NativeHandle handle, Func<NativeHandle, T> createObject, bool releaseHandle)
{
var rv = ArrayFromHandleFunc<T> (handle, createObject);
if (releaseHandle && handle != NativeHandle.Zero)
NSObject.DangerousRelease (handle);
return rv;
}

static public T [] ArrayFromHandle<T> (NativeHandle handle, Converter<NativeHandle, T> creator)
{
if (handle == NativeHandle.Zero)
Expand Down
2 changes: 1 addition & 1 deletion src/MediaToolbox/MTAudioProcessingTap.cs
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ delegate void MTAudioProcessingTapProcessCallbackProxy (/* MTAudioProcessingTapR

MTAudioProcessingTapCallbacks callbacks;

internal static MTAudioProcessingTap? FromHandle (IntPtr handle)
internal static MTAudioProcessingTap? FromHandle (IntPtr handle, bool owns)
{
lock (handles){
if (handles.TryGetValue (handle, out var ret))
Expand Down
27 changes: 25 additions & 2 deletions src/ObjCRuntime/Runtime.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1830,6 +1830,18 @@ static IntPtr CreateNSObject (IntPtr type_gchandle, IntPtr handle, NSObject.Flag
{
return GetNSObject ((IntPtr) ptr, MissingCtorResolution.ThrowConstructor1NotFound);
}

/// <summary>Wraps an unmanaged <see cref="NativeHandle" /> into a fully typed <see cref="NSObject" />, or returns an existing wrapper object if one already exists.</summary>
/// <param name="ptr">A pointer to an unmanaged <see cref="NSObject" /> or any class that derives from the Objective-C NSObject class.</param>
/// <param name="owns">Pass true if the caller has a reference to the native object, and wants to give it to the managed wrapper instance. Otherwise pass false (and the native object will be retained if needed).</param>
/// <returns>An instance of a class that derives <see cref="NSObject" />.</returns>
/// <remarks>
/// <para>The runtime create an instance of the most derived managed class.</para>
/// </remarks>
public static NSObject? GetNSObject (NativeHandle ptr, bool owns)
{
return GetNSObject ((IntPtr) ptr, owns, MissingCtorResolution.ThrowConstructor1NotFound);
}
#endif

public static NSObject? GetNSObject (IntPtr ptr)
Expand All @@ -1838,16 +1850,27 @@ static IntPtr CreateNSObject (IntPtr type_gchandle, IntPtr handle, NSObject.Flag
}

internal static NSObject? GetNSObject (IntPtr ptr, MissingCtorResolution missingCtorResolution, bool evenInFinalizerQueue = false)
{
return GetNSObject (ptr, false, missingCtorResolution, evenInFinalizerQueue);
}

internal static NSObject? GetNSObject (IntPtr ptr, bool owns, MissingCtorResolution missingCtorResolution, bool evenInFinalizerQueue = false)
{
if (ptr == IntPtr.Zero)
return null;

var o = TryGetNSObject (ptr, evenInFinalizerQueue);

if (o is not null)
if (o is not null) {
if (owns)
o.DangerousRelease ();
return o;
}

return ConstructNSObject (ptr, Class.GetClassForObject (ptr), missingCtorResolution);
o = ConstructNSObject (ptr, Class.GetClassForObject (ptr), missingCtorResolution);
if (owns)
NSObject.DangerousRelease (ptr);
return o;
}

static public T? GetNSObject<T> (IntPtr ptr) where T : NSObject
Expand Down
9 changes: 9 additions & 0 deletions src/ObjCRuntime/Selector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,15 @@ internal static string GetName (IntPtr handle)
return new Selector (sel, false);
}

/// <summary>Creates a managed Selector instance from a native selector.</summary>
/// <param name="selector">The native selector handle.</param>
/// <param name="owns">Whether the caller owns the native selector handle or not.</param>
/// <remarks>It's not possible to free a selector, so the <paramref name="owns" /> parameter is ignored.</remarks>
public static Selector? FromHandle (NativeHandle selector, bool owns)
{
return FromHandle (selector);
}

public static Selector Register (NativeHandle handle)
{
return new Selector (handle);
Expand Down
1 change: 1 addition & 0 deletions src/bgen/Attributes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ public RetainAttribute (string wrap)
public string WrapName { get; set; }
}

[AttributeUsage (AttributeTargets.ReturnValue, AllowMultiple = false)]
public class ReleaseAttribute : Attribute {
}

Expand Down
2 changes: 2 additions & 0 deletions src/bgen/Caches/TypeCache.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ public class TypeCache {
/* fundamental */
public Type NSObject { get; }
public Type INativeObject { get; }
public Type NativeObject { get; }

/* objcruntime */
public Type BlockLiteral { get; }
Expand Down Expand Up @@ -195,6 +196,7 @@ public TypeCache (MetadataLoadContext universe, Frameworks frameworks, PlatformN
/* fundamental */
NSObject = Lookup (platformAssembly, "Foundation", "NSObject");
INativeObject = Lookup (platformAssembly, "ObjCRuntime", "INativeObject");
NativeObject = Lookup (platformAssembly, "CoreFoundation", "NativeObject");

/* objcruntime */
BlockLiteral = Lookup (platformAssembly, "ObjCRuntime", "BlockLiteral");
Expand Down
58 changes: 22 additions & 36 deletions src/bgen/Generator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@

// Disable until we get around to enable + fix any issues.
#nullable disable
// but allow annotation source code with nullability info.
#pragma warning disable CS8632 // The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.

public partial class Generator : IMemberGatherer {
internal bool IsPublicMode;
Expand Down Expand Up @@ -536,7 +538,7 @@ string GetFromBindAsWrapper (MemberInformation minfo, out string suffix)
return append;
}

public bool HasForcedAttribute (ICustomAttributeProvider cu, out string owns)
public bool HasForcedAttribute (ICustomAttributeProvider cu, out bool owns)
{
var att = AttributeManager.GetCustomAttribute<ForcedTypeAttribute> (cu);

Expand All @@ -547,11 +549,11 @@ public bool HasForcedAttribute (ICustomAttributeProvider cu, out string owns)
}

if (att is null) {
owns = "false";
owns = false;
return false;
}

owns = att.Owns ? "true" : "false";
owns = att.Owns;
return true;
}

Expand Down Expand Up @@ -606,8 +608,7 @@ public TrampolineInfo MakeTrampoline (Type t)
pars.Add (new TrampolineParameterInfo ("IntPtr", "block"));
var parameters = mi.GetParameters ();
foreach (var pi in parameters) {
string isForcedOwns;
var isForced = HasForcedAttribute (pi, out isForcedOwns);
var isForced = HasForcedAttribute (pi, out var isForcedOwns);

if (pi != parameters [0])
invoke.Append (", ");
Expand All @@ -619,7 +620,7 @@ public TrampolineInfo MakeTrampoline (Type t)
if (IsProtocolInterface (pi.ParameterType)) {
invoke.AppendFormat (" Runtime.GetINativeObject<{1}> ({0}, false)!", safe_name, pi.ParameterType);
} else if (isForced) {
invoke.AppendFormat (" Runtime.GetINativeObject<{1}> ({0}, true, {2})!", safe_name, TypeManager.RenderType (pi.ParameterType), isForcedOwns);
invoke.AppendFormat (" Runtime.GetINativeObject<{1}> ({0}, true, {2})!", safe_name, TypeManager.RenderType (pi.ParameterType), isForcedOwns ? "true" : "false");
} else if (IsNSObject (pi.ParameterType)) {
invoke.AppendFormat (" Runtime.GetNSObject<{1}> ({0})!", safe_name, TypeManager.RenderType (pi.ParameterType));
} else {
Expand Down Expand Up @@ -2886,22 +2887,23 @@ void GetReturnsWrappers (MethodInfo mi, MemberInformation minfo, Type declaringT
MarshalInfo mai = new MarshalInfo (this, mi);
MarshalType mt;

var owns = (minfo?.is_return_release == true) || (minfo?.is_forced_owns == true) ? "true" : "false";
if (GetNativeEnumToManagedExpression (mi.ReturnType, out cast_a, out cast_b, out var _, postproc)) {
// we're done here
} else if (mi.ReturnType.IsEnum) {
cast_a = "(" + TypeManager.FormatType (minfo?.type ?? mi.DeclaringType, mi.ReturnType) + ") ";
cast_b = "";
} else if (marshalTypes.TryGetMarshalType (mai.Type, out mt)) {
cast_a = mt.CreateFromRet;
cast_b = mt.ClosingCreate;
cast_b = mt.ClosingCreate?.Replace ("%OWNS%", owns) ?? string.Empty;
} else if (TypeManager.IsWrappedType (mi.ReturnType)) {
// protocol support means we can return interfaces and, as far as .NET knows, they might not be NSObject
if (IsProtocolInterface (mi.ReturnType)) {
cast_a = " Runtime.GetINativeObject<" + TypeManager.FormatType (minfo?.type ?? mi.DeclaringType, mi.ReturnType) + "> (";
cast_b = $", {(minfo?.is_return_release == true ? "true" : "false")})!";
cast_b = $", {owns})!";
} else if (minfo is not null && minfo.is_forced) {
cast_a = " Runtime.GetINativeObject<" + TypeManager.FormatType (minfo.type, mi.ReturnType) + "> (";
cast_b = $", true, {minfo.is_forced_owns})!";
cast_b = $", true, {owns})!";
} else if (minfo is not null && minfo.is_bindAs) {
var bindAs = GetBindAsAttribute (minfo.mi);
var nullableBindAsType = TypeManager.GetUnderlyingNullableType (bindAs.Type);
Expand All @@ -2915,27 +2917,27 @@ void GetReturnsWrappers (MethodInfo mi, MemberInformation minfo, Type declaringT
if (isNullable) {
print ("{0} retvaltmp;", NativeHandleType);
cast_a = "((retvaltmp = ";
cast_b = $") == IntPtr.Zero ? default ({formattedBindAsType}) : ({wrapper}Runtime.GetNSObject<{formattedReturnType}> (retvaltmp)!){suffix})";
cast_b = $") == IntPtr.Zero ? default ({formattedBindAsType}) : ({wrapper}Runtime.GetNSObject<{formattedReturnType}> (retvaltmp, {owns})!){suffix})";
} else {
cast_a = $"{wrapper}Runtime.GetNSObject<{formattedReturnType}> (";
cast_b = $")!{suffix}";
cast_b = $", {owns})!{suffix}";
}
} else {
var enumCast = (bindAsType.IsEnum && !minfo.type.IsArray) ? $"({formattedBindAsType}) " : string.Empty;
print ("{0} retvaltmp;", NativeHandleType);
cast_a = "((retvaltmp = ";
cast_b = $") == IntPtr.Zero ? default ({formattedBindAsType}) : ({enumCast}Runtime.GetNSObject<{formattedReturnType}> (retvaltmp)!{wrapper})){suffix}";
cast_b = $") == IntPtr.Zero ? default ({formattedBindAsType}) : ({enumCast}Runtime.GetNSObject<{formattedReturnType}> (retvaltmp, {owns})!{wrapper})){suffix}";
}
} else {
cast_a = " Runtime.GetNSObject<" + TypeManager.FormatType (minfo?.type ?? declaringType, mi.ReturnType) + "> (";
cast_b = ")!";
cast_b = $", {owns})!";
}
} else if (mi.ReturnType.IsGenericParameter) {
cast_a = " Runtime.GetINativeObject<" + mi.ReturnType.Name + "> (";
cast_b = ", false)!";
cast_b = $", {owns})!";
} else if (mai.Type == TypeCache.System_String && !mai.PlainString) {
cast_a = "CFString.FromHandle (";
cast_b = ")!";
cast_b = $", {owns})!";
} else if (mi.ReturnType.IsSubclassOf (TypeCache.System_Delegate)) {
cast_a = "";
cast_b = "";
Expand All @@ -2951,19 +2953,19 @@ void GetReturnsWrappers (MethodInfo mi, MemberInformation minfo, Type declaringT
print ("{0} retvalarrtmp;", NativeHandleType);
cast_a = "((retvalarrtmp = ";
cast_b = ") == IntPtr.Zero ? null! : (";
cast_b += $"NSArray.ArrayFromHandleFunc <{TypeManager.FormatType (bindAsT.DeclaringType, bindAsT)}> (retvalarrtmp, {GetFromBindAsWrapper (minfo, out suffix)})" + suffix;
cast_b += "))";
cast_b += $"NSArray.ArrayFromHandleFunc <{TypeManager.FormatType (bindAsT.DeclaringType, bindAsT)}> (retvalarrtmp, {GetFromBindAsWrapper (minfo, out suffix)}, {owns})" + suffix;
cast_b += $"))";
} else if (etype == TypeCache.System_String) {
cast_a = "CFArray.StringArrayFromHandle (";
cast_b = ")!";
cast_b = $", {owns})!";
} else if (etype == TypeCache.Selector) {
exceptions.Add (ErrorHelper.CreateError (1066, mai.Type.FullName, mi.DeclaringType.FullName, mi.Name));
} else {
if (NamespaceCache.NamespacesThatConflictWithTypes.Contains (etype.Namespace))
cast_a = "CFArray.ArrayFromHandle<global::" + etype + ">(";
else
cast_a = "CFArray.ArrayFromHandle<" + TypeManager.FormatType (mi.DeclaringType, etype) + ">(";
cast_b = ")!";
cast_b = $", {owns})!";
}
} else if (mi.ReturnType.Namespace == "System" && mi.ReturnType.Name == "nint") {
cast_a = "(nint) ";
Expand Down Expand Up @@ -3418,7 +3420,7 @@ void GenerateTypeLowering (MethodInfo mi, bool null_allowed_override, out String
} else if (isINativeObjectSubclass) {
if (!pi.IsOut)
by_ref_processing.AppendFormat ("if ({0}Value != ({0} is null ? NativeHandle.Zero : {0}.Handle))\n\t", pi.Name.GetSafeParamName ());
by_ref_processing.AppendFormat ("{0} = Runtime.GetINativeObject<{1}> ({0}Value, {2}, {3})!;\n", pi.Name.GetSafeParamName (), TypeManager.RenderType (elementType), isForcedType ? "true" : "false", isForcedType ? isForcedOwns : "false");
by_ref_processing.AppendFormat ("{0} = Runtime.GetINativeObject<{1}> ({0}Value, {2}, {3})!;\n", pi.Name.GetSafeParamName (), TypeManager.RenderType (elementType), isForcedType ? "true" : "false", (isForcedType && isForcedOwns) ? "true" : "false");
} else {
throw ErrorHelper.CreateError (88, mai.Type, mi);
}
Expand Down Expand Up @@ -3650,22 +3652,6 @@ public void GenerateMethodBody (MemberInformation minfo, MethodInfo mi, string s
if (shouldMarshalNativeExceptions)
print ("Runtime.ThrowException (exception_gchandle);");

if (minfo.is_return_release && !IsProtocolInterface (mi.ReturnType)) {

// Make sure we generate the required signature in Messaging only if needed
// bool_objc_msgSendSuper_IntPtr: for respondsToSelector:
if (!send_methods.ContainsKey ("void_objc_msgSend")) {
print (m, "[DllImport (LIBOBJC_DYLIB, EntryPoint=\"objc_msgSendSuper\")]");
print (m, "public extern static void void_objc_msgSend (IntPtr receiever, IntPtr selector);");
RegisterMethodName ("void_objc_msgSend");
}

print ("if (ret is not null)");
indent++;
print ("global::{0}.void_objc_msgSend (ret.Handle, Selector.GetHandle (\"release\"));", NamespaceCache.Messaging);
indent--;
}

Inject<PostSnippetAttribute> (mi);

if (disposes.Length > 0)
Expand Down
4 changes: 2 additions & 2 deletions src/bgen/Models/MarshalType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@ public class MarshalType {
public string CreateFromRet { get; }
public string? ClosingCreate { get; }

public MarshalType (Type t, string? encode = null, string? fetch = null, string? create = null, string? closingCreate = ")")
public MarshalType (Type t, string? encode = null, string? fetch = null, string? create = null, string? closingCreate = ", %OWNS%)")
{
Type = t;
Encoding = encode ?? Generator.NativeHandleType;
ParameterMarshal = fetch ?? "{0}.Handle";
if (create is null) {
CreateFromRet = $"Runtime.GetINativeObject<global::{t.FullName}> (";
ClosingCreate = ", false)!";
ClosingCreate = ", %OWNS%)!";
} else {
CreateFromRet = create;
ClosingCreate = closingCreate;
Expand Down
16 changes: 8 additions & 8 deletions src/bgen/Models/MarshalTypeList.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ public class MarshalTypeList : List<MarshalType> {

public void Load (TypeCache typeCache, Frameworks frameworks)
{
Add (new MarshalType (typeCache.NSObject, create: "Runtime.GetNSObject (", closingCreate: ")!"));
Add (new MarshalType (typeCache.Selector, create: "Selector.FromHandle (", closingCreate: ")!"));
Add (new MarshalType (typeCache.NSObject, create: "Runtime.GetNSObject (", closingCreate: ", %OWNS%)!"));
Add (new MarshalType (typeCache.Selector, create: "Selector.FromHandle (", closingCreate: ", %OWNS%)!"));
Add (new MarshalType (typeCache.BlockLiteral, "BlockLiteral", "{0}", "THIS_IS_BROKEN"));
if (typeCache.MusicSequence is not null)
Add (new MarshalType (typeCache.MusicSequence, create: "global::AudioToolbox.MusicSequence.Lookup ("));
Expand Down Expand Up @@ -42,15 +42,15 @@ public void Load (TypeCache typeCache, Frameworks frameworks)
Add (typeCache.CVImageBuffer);
}
if (frameworks.HaveMediaToolbox)
Add (new MarshalType (typeCache.MTAudioProcessingTap!, create: "MediaToolbox.MTAudioProcessingTap.FromHandle("));
Add (new MarshalType (typeCache.MTAudioProcessingTap!, create: "MediaToolbox.MTAudioProcessingTap.FromHandle (", closingCreate: ", %OWNS%)!"));
if (frameworks.HaveAddressBook) {
Add (typeCache.ABAddressBook);
Add (new MarshalType (typeCache.ABPerson!, create: "(ABPerson) ABRecord.FromHandle (", closingCreate: ")!"));
Add (new MarshalType (typeCache.ABRecord!, create: "ABRecord.FromHandle (", closingCreate: ")!"));
Add (new MarshalType (typeCache.ABPerson!, create: "(ABPerson) ABRecord.FromHandle (", closingCreate: ", %OWNS%)!"));
Add (new MarshalType (typeCache.ABRecord!, create: "ABRecord.FromHandle (", closingCreate: ", %OWNS%)!"));
}
if (frameworks.HaveCoreVideo) {
// owns `false` like ptr ctor https://github.com/xamarin/xamarin-macios/blob/6f68ab6f79c5f1d96d2cbb1e697330623164e46d/src/CoreVideo/CVBuffer.cs#L74-L90
Add (new MarshalType (typeCache.CVPixelBuffer!, create: "Runtime.GetINativeObject<CVPixelBuffer> (", closingCreate: ", false)!"));
Add (new MarshalType (typeCache.CVPixelBuffer!, create: "Runtime.GetINativeObject<CVPixelBuffer> (", closingCreate: ", %OWNS%)!"));
}
Add (typeCache.CGLayer);
if (frameworks.HaveCoreMedia)
Expand All @@ -63,7 +63,7 @@ public void Load (TypeCache typeCache, Frameworks frameworks)
if (frameworks.HaveAudioUnit)
Add (typeCache.AudioComponent);
if (frameworks.HaveCoreMedia) {
Add (new MarshalType (typeCache.CMFormatDescription!, create: "CMFormatDescription.Create (", closingCreate: ")!"));
Add (new MarshalType (typeCache.CMFormatDescription!, create: "CMFormatDescription.Create (", closingCreate: ", %OWNS%)!"));
Add (typeCache.CMAudioFormatDescription);
Add (typeCache.CMVideoFormatDescription);
}
Expand All @@ -77,7 +77,7 @@ public void Load (TypeCache typeCache, Frameworks frameworks)
Add (typeCache.SecProtocolOptions);
Add (typeCache.SecProtocolMetadata);
Add (typeCache.SecAccessControl);
Add (new MarshalType (typeCache.AudioBuffers, create: "new global::AudioToolbox.AudioBuffers (", closingCreate: ", false)"));
Add (new MarshalType (typeCache.AudioBuffers, create: "new global::AudioToolbox.AudioBuffers (", closingCreate: ", %OWNS%)"));
if (frameworks.HaveAudioUnit) {
Add (typeCache.AURenderEventEnumerator);
}
Expand Down
2 changes: 1 addition & 1 deletion src/bgen/Models/MemberInformation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ public class MemberInformation {
// know whether the code is to call the internal static method implementing a
// protocol member (in which case this property is true). See also is_protocol_implementation_method.
public bool call_protocol_implementation_method;
public string is_forced_owns;
public bool is_forced_owns;
public bool is_bindAs => Generator.HasBindAsAttribute (mi);
public bool generate_is_async_overload;

Expand Down
Loading