using CPF.Mac.Foundation; using System; using System.Reflection; using System.Reflection.Emit; using System.Runtime.Serialization; namespace CPF.Mac.ObjCRuntime { internal class NativeConstructorBuilder : NativeImplementationBuilder { private static MethodInfo trygetnsobject = typeof(Runtime).GetMethod("TryGetNSObject", BindingFlags.Static | BindingFlags.Public); private static MethodInfo newobject = typeof(FormatterServices).GetMethod("GetUninitializedObject", BindingFlags.Static | BindingFlags.Public); private static MethodInfo gettype = typeof(Type).GetMethod("GetTypeFromHandle", BindingFlags.Static | BindingFlags.Public); private static MethodInfo retain = typeof(NSObject).GetMethod("Retain", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); private static FieldInfo handlefld = typeof(NSObject).GetField("handle", BindingFlags.Instance | BindingFlags.NonPublic); private static FieldInfo valuefld = typeof(RuntimeTypeHandle).GetField("value", BindingFlags.Instance | BindingFlags.NonPublic); private static IntPtr selInit = CPF.Mac.ObjCRuntime.Selector.GetHandle("init"); private ConstructorInfo cinfo; internal NativeConstructorBuilder(ConstructorInfo cinfo) { ExportAttribute exportAttribute = (ExportAttribute)Attribute.GetCustomAttribute(cinfo, typeof(ExportAttribute)); base.Parameters = cinfo.GetParameters(); if (exportAttribute == null && base.Parameters.Length != 0) { throw new ArgumentException("ConstructorInfo does not have a export attribute"); } if (exportAttribute == null) { base.Selector = selInit; } else { base.Selector = new Selector(exportAttribute.Selector, alloc: true).Handle; } base.Signature = "@@:"; ConvertParameters(base.Parameters, isstatic: true, isstret: false); base.DelegateType = CreateDelegateType(typeof(IntPtr), base.ParameterTypes); this.cinfo = cinfo; } internal override Delegate CreateDelegate() { DynamicMethod dynamicMethod = new DynamicMethod(Guid.NewGuid().ToString(), typeof(IntPtr), base.ParameterTypes, NativeImplementationBuilder.module, skipVisibility: true); ILGenerator iLGenerator = dynamicMethod.GetILGenerator(); Label label = iLGenerator.DefineLabel(); iLGenerator.DeclareLocal(typeof(object)); DeclareLocals(iLGenerator); for (int i = 0; i < base.Parameters.Length; i++) { if (base.Parameters[i].ParameterType.IsByRef && (base.Parameters[i].ParameterType.GetElementType().IsSubclassOf(typeof(NSObject)) || base.Parameters[i].ParameterType.GetElementType() == typeof(NSObject))) { iLGenerator.DeclareLocal(base.Parameters[i].ParameterType.GetElementType()); } } iLGenerator.Emit(OpCodes.Ldarg_0); iLGenerator.Emit(OpCodes.Call, trygetnsobject); iLGenerator.Emit(OpCodes.Brtrue, label); iLGenerator.Emit(OpCodes.Ldtoken, cinfo.DeclaringType); iLGenerator.Emit(OpCodes.Call, gettype); iLGenerator.Emit(OpCodes.Call, newobject); iLGenerator.Emit(OpCodes.Stloc_0); iLGenerator.Emit(OpCodes.Ldloc_0); iLGenerator.Emit(OpCodes.Ldarg_0); iLGenerator.Emit(OpCodes.Stfld, handlefld); ConvertArguments(iLGenerator, 1); iLGenerator.Emit(OpCodes.Ldloc_0); iLGenerator.Emit(OpCodes.Castclass, cinfo.DeclaringType); LoadArguments(iLGenerator, 1); iLGenerator.Emit(OpCodes.Call, cinfo); UpdateByRefArguments(iLGenerator, 1); iLGenerator.Emit(OpCodes.Ldloc_0); iLGenerator.Emit(OpCodes.Call, retain); iLGenerator.Emit(OpCodes.Pop); iLGenerator.MarkLabel(label); iLGenerator.Emit(OpCodes.Ldarg_0); iLGenerator.Emit(OpCodes.Ret); return dynamicMethod.CreateDelegate(base.DelegateType); } } }