Skip to content

Commit

Permalink
[tools] Add a managed static registrar. Fixes dotnet#17324.
Browse files Browse the repository at this point in the history
  • Loading branch information
rolfbjarne committed Apr 28, 2023
1 parent 940858b commit 9fd4ceb
Show file tree
Hide file tree
Showing 20 changed files with 3,928 additions and 146 deletions.
12 changes: 6 additions & 6 deletions src/CoreFoundation/CFArray.cs
Original file line number Diff line number Diff line change
Expand Up @@ -108,10 +108,10 @@ public NativeHandle GetValue (nint index)
return CFArrayGetValueAtIndex (GetCheckedHandle (), index);
}

internal static unsafe NativeHandle Create (params NativeHandle [] values)
internal static unsafe NativeHandle Create (params NativeHandle []? values)
{
if (values is null)
ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (values));
return NativeHandle.Zero;
fixed (NativeHandle* pv = values) {
return CFArrayCreate (IntPtr.Zero,
(IntPtr) pv,
Expand All @@ -120,10 +120,10 @@ internal static unsafe NativeHandle Create (params NativeHandle [] values)
}
}

public static unsafe NativeHandle Create (params INativeObject [] values)
public static unsafe NativeHandle Create (params INativeObject []? values)
{
if (values is null)
ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (values));
return NativeHandle.Zero;
int c = values.Length;
var _values = c <= 256 ? stackalloc IntPtr [c] : new IntPtr [c];
for (int i = 0; i < c; ++i)
Expand All @@ -132,10 +132,10 @@ public static unsafe NativeHandle Create (params INativeObject [] values)
return CFArrayCreate (IntPtr.Zero, (IntPtr) pv, c, kCFTypeArrayCallbacks_ptr);
}

public static unsafe NativeHandle Create (params string [] values)
public static unsafe NativeHandle Create (params string []? values)
{
if (values is null)
ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (values));
return NativeHandle.Zero;
var c = values.Length;
var _values = c <= 256 ? stackalloc IntPtr [c] : new IntPtr [c];
for (var i = 0; i < c; ++i)
Expand Down
25 changes: 25 additions & 0 deletions src/Foundation/NSArray.cs
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,19 @@ static public T [] ArrayFromHandle<T> (NativeHandle handle) where T : class, INa
return ret;
}

static Array ArrayFromHandle (NativeHandle handle, Type elementType)
{
if (handle == NativeHandle.Zero)
return null;

var c = (int) GetCount (handle);
var rv = Array.CreateInstance (elementType, c);
for (int i = 0; i < c; i++) {
rv.SetValue (UnsafeGetItem (handle, (nuint) i, elementType), i);
}
return rv;
}

static public T [] EnumsFromHandle<T> (NativeHandle handle) where T : struct, IConvertible
{
if (handle == NativeHandle.Zero)
Expand Down Expand Up @@ -395,6 +408,18 @@ static T UnsafeGetItem<T> (NativeHandle handle, nuint index) where T : class, IN
return Runtime.GetINativeObject<T> (val, false);
}

static object UnsafeGetItem (NativeHandle handle, nuint index, Type type)
{
var val = GetAtIndex (handle, index);
// A native code could return NSArray with NSNull.Null elements
// and they should be valid for things like T : NSDate so we handle
// them as just null values inside the array
if (val == NSNull.Null.Handle)
return null;

return Runtime.GetINativeObject (val, false, type);
}

// can return an INativeObject or an NSObject
public T GetItem<T> (nuint index) where T : class, INativeObject
{
Expand Down
8 changes: 8 additions & 0 deletions src/Foundation/NSObject2.cs
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,14 @@ public void Dispose ()
GC.SuppressFinalize (this);
}

static T AllocateNSObject<T> (NativeHandle handle, Flags flags) where T : NSObject
{
var obj = (T) RuntimeHelpers.GetUninitializedObject (typeof (T));
obj.handle = handle;
obj.flags = flags;
return obj;
}

internal static IntPtr CreateNSObject (IntPtr type_gchandle, IntPtr handle, Flags flags)
{
// This function is called from native code before any constructors have executed.
Expand Down
1 change: 1 addition & 0 deletions src/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ DOTNET_REFERENCES = \
/r:$(DOTNET_BCL_DIR)/System.Console.dll \
/r:$(DOTNET_BCL_DIR)/System.Diagnostics.Debug.dll \
/r:$(DOTNET_BCL_DIR)/System.Diagnostics.Tools.dll \
/r:$(DOTNET_BCL_DIR)/System.Diagnostics.StackTrace.dll \
/r:$(DOTNET_BCL_DIR)/System.Drawing.Primitives.dll \
/r:$(DOTNET_BCL_DIR)/System.IO.Compression.dll \
/r:$(DOTNET_BCL_DIR)/System.IO.FileSystem.dll \
Expand Down
253 changes: 253 additions & 0 deletions src/ObjCRuntime/BindAs.cs

Large diffs are not rendered by default.

27 changes: 27 additions & 0 deletions src/ObjCRuntime/Blocks.cs
Original file line number Diff line number Diff line change
Expand Up @@ -456,6 +456,33 @@ unsafe static IntPtr GetBlockForFunctionPointer (MethodInfo delegateInvokeMethod
}
#endif // NET

[EditorBrowsable (EditorBrowsableState.Never)]
[BindingImpl (BindingImplOptions.Optimizable)]
static IntPtr CreateBlockForDelegate (Delegate @delegate, Delegate delegateProxyFieldValue, string /*?*/ signature)
{
if (@delegate is null)
ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (@delegate));

if (delegateProxyFieldValue is null)
ObjCRuntime.ThrowHelper.ThrowArgumentNullException (nameof (delegateProxyFieldValue));

// Note that we must create a heap-allocated block, so we
// start off by creating a stack-allocated block, and then
// call _Block_copy, which will create a heap-allocated block
// with the proper reference count.
using var block = new BlockLiteral ();
if (signature is null) {
if (Runtime.DynamicRegistrationSupported) {
block.SetupBlock (delegateProxyFieldValue, @delegate);
} else {
throw ErrorHelper.CreateError (8026, $"BlockLiteral.GetBlockForDelegate with a null signature is not supported when the dynamic registrar has been linked away (delegate type: {@delegate.GetType ().FullName}).");
}
} else {
block.SetupBlockImpl (delegateProxyFieldValue, @delegate, true, signature);
}
return _Block_copy (&block);
}

[BindingImpl (BindingImplOptions.Optimizable)]
internal static IntPtr GetBlockForDelegate (MethodInfo minfo, object @delegate, uint token_ref, string signature)
{
Expand Down
26 changes: 21 additions & 5 deletions src/ObjCRuntime/Class.cs
Original file line number Diff line number Diff line change
Expand Up @@ -399,7 +399,7 @@ internal static unsafe int FindMapIndex (Runtime.MTClassMap* array, int lo, int

var assembly = ResolveAssembly (assembly_name);
var module = ResolveModule (assembly, module_token);
return ResolveToken (module, token);
return ResolveToken (assembly, module, token);
}

internal static Type? ResolveTypeTokenReference (uint token_reference)
Expand Down Expand Up @@ -442,21 +442,34 @@ internal static unsafe int FindMapIndex (Runtime.MTClassMap* array, int lo, int
var assembly = ResolveAssembly (assembly_name);
var module = ResolveModule (assembly, 0x1);

return ResolveToken (module, token | implicit_token_type);
return ResolveToken (assembly, module, token | implicit_token_type);
}

static MemberInfo? ResolveToken (Module module, uint token)
static MemberInfo? ResolveToken (Assembly assembly, Module? module, uint token)
{
// Finally resolve the token.
var token_type = token & 0xFF000000;
switch (token & 0xFF000000) {
case 0x02000000: // TypeDef
var type = module.ResolveType ((int) token);
Type type;
if (Runtime.IsManagedStaticRegistrar) {
type = RegistrarHelper.LookupRegisteredType (assembly, token & 0x00FFFFFF);
} else if (module is null) {
throw ErrorHelper.CreateError (9999, $"Could not find the module in the assembly {assembly}.");
} else {
type = module.ResolveType ((int) token);
}
#if LOG_TYPELOAD
Console.WriteLine ($"ResolveToken (0x{token:X}) => Type: {type.FullName}");
#endif
return type;
case 0x06000000: // Method
if (Runtime.IsManagedStaticRegistrar)
throw ErrorHelper.CreateError (9999, "Unable to resolve the metadata token 0x{0} when using the managed static registrar", token.ToString ("x")); // FIXME: error number

if (module is null)
throw ErrorHelper.CreateError (9999, $"Could not find the module in the assembly {assembly}.");

var method = module.ResolveMethod ((int) token);
#if LOG_TYPELOAD
Console.WriteLine ($"ResolveToken (0x{token:X}) => Method: {method?.DeclaringType?.FullName}.{method.Name}");
Expand All @@ -467,8 +480,11 @@ internal static unsafe int FindMapIndex (Runtime.MTClassMap* array, int lo, int
}
}

static Module ResolveModule (Assembly assembly, uint token)
static Module? ResolveModule (Assembly assembly, uint token)
{
if (token == Runtime.INVALID_TOKEN_REF)
return null;

foreach (var mod in assembly.GetModules ()) {
if (mod.MetadataToken != token)
continue;
Expand Down
18 changes: 9 additions & 9 deletions src/ObjCRuntime/DynamicRegistrar.cs
Original file line number Diff line number Diff line change
Expand Up @@ -219,12 +219,12 @@ protected override IEnumerable<Type> CollectTypes (Assembly assembly)
return assembly.GetTypes ();
}

protected override BindAsAttribute GetBindAsAttribute (PropertyInfo property)
public override BindAsAttribute GetBindAsAttribute (PropertyInfo property)
{
return property?.GetCustomAttribute<BindAsAttribute> (false);
}

protected override BindAsAttribute GetBindAsAttribute (MethodBase method, int parameter_index)
public override BindAsAttribute GetBindAsAttribute (MethodBase method, int parameter_index)
{
ICustomAttributeProvider provider;

Expand Down Expand Up @@ -343,7 +343,7 @@ protected override Type MakeByRef (Type type)
return type.MakeByRefType ();
}

protected override CategoryAttribute GetCategoryAttribute (Type type)
public override CategoryAttribute GetCategoryAttribute (Type type)
{
return SharedDynamic.GetOneAttribute<CategoryAttribute> (type);
}
Expand Down Expand Up @@ -374,7 +374,7 @@ protected override MethodBase GetBaseMethod (MethodBase method)
return ((MethodInfo) method).GetBaseDefinition ();
}

protected override Type GetElementType (Type type)
public override Type GetElementType (Type type)
{
return type.GetElementType ();
}
Expand Down Expand Up @@ -460,7 +460,7 @@ protected override string GetTypeFullName (Type type)
return type.FullName;
}

protected override bool VerifyIsConstrainedToNSObject (Type type, out Type constrained_type)
public override bool VerifyIsConstrainedToNSObject (Type type, out Type constrained_type)
{
constrained_type = null;

Expand Down Expand Up @@ -523,7 +523,7 @@ protected override string GetAssemblyQualifiedName (Type type)
return type.AssemblyQualifiedName;
}

protected override bool HasReleaseAttribute (MethodBase method)
public override bool HasReleaseAttribute (MethodBase method)
{
var mi = method as MethodInfo;
if (mi == null)
Expand All @@ -539,7 +539,7 @@ public static bool HasThisAttributeImpl (MethodBase method)
return mi.IsDefined (typeof (System.Runtime.CompilerServices.ExtensionAttribute), false);
}

protected override bool HasThisAttribute (MethodBase method)
public override bool HasThisAttribute (MethodBase method)
{
return HasThisAttributeImpl (method);
}
Expand All @@ -554,7 +554,7 @@ protected override bool HasModelAttribute (Type type)
return type.IsDefined (typeof (ModelAttribute), false);
}

protected override bool IsArray (Type type, out int rank)
public override bool IsArray (Type type, out int rank)
{
if (!type.IsArray) {
rank = 0;
Expand Down Expand Up @@ -594,7 +594,7 @@ protected override bool IsDelegate (Type type)
return type.IsSubclassOf (typeof (System.Delegate));
}

protected override bool IsNullable (Type type)
public override bool IsNullable (Type type)
{
if (!type.IsGenericType)
return false;
Expand Down
38 changes: 28 additions & 10 deletions src/ObjCRuntime/Registrar.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1094,41 +1094,41 @@ protected virtual void OnRegisterCategory (ObjCType type, ref List<Exception> ex
protected abstract bool IsStatic (TField field);
protected abstract bool IsStatic (TMethod method);
protected abstract TType MakeByRef (TType type);
protected abstract bool HasThisAttribute (TMethod method);
public abstract bool HasThisAttribute (TMethod method);
protected abstract bool IsConstructor (TMethod method);
protected abstract TType GetElementType (TType type);
public abstract TType GetElementType (TType type);
protected abstract TType GetReturnType (TMethod method);
protected abstract void GetNamespaceAndName (TType type, out string @namespace, out string name);
protected abstract bool TryGetAttribute (TType type, string attributeNamespace, string attributeType, out object attribute);
protected abstract ExportAttribute GetExportAttribute (TProperty property); // Return null if no attribute is found. Must check the base property (i.e. if property is overriding a property in a base class, must check the overridden property for the attribute).
protected abstract ExportAttribute GetExportAttribute (TMethod method); // Return null if no attribute is found. Must check the base method (i.e. if method is overriding a method in a base class, must check the overridden method for the attribute).
protected abstract Dictionary<TMethod, List<TMethod>> PrepareMethodMapping (TType type);
public abstract RegisterAttribute GetRegisterAttribute (TType type); // Return null if no attribute is found. Do not consider base types.
protected abstract CategoryAttribute GetCategoryAttribute (TType type); // Return null if no attribute is found. Do not consider base types.
public abstract CategoryAttribute GetCategoryAttribute (TType type); // Return null if no attribute is found. Do not consider base types.
protected abstract ConnectAttribute GetConnectAttribute (TProperty property); // Return null if no attribute is found. Do not consider inherited properties.
public abstract ProtocolAttribute GetProtocolAttribute (TType type); // Return null if no attribute is found. Do not consider base types.
protected abstract IEnumerable<ProtocolMemberAttribute> GetProtocolMemberAttributes (TType type); // Return null if no attributes found. Do not consider base types.
protected virtual Version GetSdkIntroducedVersion (TType obj, out string message) { message = null; return null; } // returns the sdk version when the type was introduced for the current platform (null if all supported versions)
protected abstract Version GetSDKVersion ();
protected abstract TType GetProtocolAttributeWrapperType (TType type); // Return null if no attribute is found. Do not consider base types.
protected abstract BindAsAttribute GetBindAsAttribute (TMethod method, int parameter_index); // If parameter_index = -1 then get the attribute for the return type. Return null if no attribute is found. Must consider base method.
protected abstract BindAsAttribute GetBindAsAttribute (TProperty property);
public abstract BindAsAttribute GetBindAsAttribute (TMethod method, int parameter_index); // If parameter_index = -1 then get the attribute for the return type. Return null if no attribute is found. Must consider base method.
public abstract BindAsAttribute GetBindAsAttribute (TProperty property);
protected abstract IList<AdoptsAttribute> GetAdoptsAttributes (TType type);
public abstract TType GetNullableType (TType type); // For T? returns T. For T returns null.
protected abstract bool HasReleaseAttribute (TMethod method); // Returns true of the method's return type/value has a [Release] attribute.
public abstract bool HasReleaseAttribute (TMethod method); // Returns true of the method's return type/value has a [Release] attribute.
protected abstract bool IsINativeObject (TType type);
protected abstract bool IsValueType (TType type);
protected abstract bool IsArray (TType type, out int rank);
public abstract bool IsArray (TType type, out int rank);
protected abstract bool IsEnum (TType type, out bool isNativeEnum);
protected abstract bool IsNullable (TType type);
public abstract bool IsNullable (TType type);
protected abstract bool IsDelegate (TType type);
protected abstract bool IsGenericType (TType type);
protected abstract bool IsGenericMethod (TMethod method);
protected abstract bool IsInterface (TType type);
protected abstract bool IsAbstract (TType type);
protected abstract bool IsPointer (TType type);
protected abstract TType GetGenericTypeDefinition (TType type);
protected abstract bool VerifyIsConstrainedToNSObject (TType type, out TType constrained_type);
public abstract bool VerifyIsConstrainedToNSObject (TType type, out TType constrained_type);
protected abstract TType GetEnumUnderlyingType (TType type);
protected abstract IEnumerable<TField> GetFields (TType type); // Must return all instance fields. May return static fields (they are filtered out automatically).
protected abstract TType GetFieldType (TField field);
Expand Down Expand Up @@ -1160,7 +1160,25 @@ public Registrar ()
{
}

protected bool IsArray (TType type)
public bool IsPropertyAccessor (TMethod method, out TProperty property)
{
property = null;

if (method is null)
return false;

if (!method.IsSpecialName)
return false;

var name = method.Name;
if (!name.StartsWith ("get_", StringComparison.Ordinal) && !name.StartsWith ("set_", StringComparison.Ordinal))
return false;

property = FindProperty (method.DeclaringType, name.Substring (4));
return property is not null;
}

public bool IsArray (TType type)
{
int rank;
return IsArray (type, out rank);
Expand Down
Loading

0 comments on commit 9fd4ceb

Please sign in to comment.