コード例 #1
0
ファイル: BizExvoker.cs プロジェクト: xHailFirex/BizHawk
            public DelegateStorage(Type type)
            {
                var methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Public)
                              .Select(m => new
                {
                    Info = m,
                    Attr = m.GetCustomAttributes(true).OfType <BizExportAttribute>().FirstOrDefault()
                })
                              .Where(a => a.Attr != null);

                var typeBuilder = ImplModuleBuilder.DefineType($"Bizhawk.BizExvokeHolder{type.Name}", TypeAttributes.Class | TypeAttributes.Public | TypeAttributes.Sealed);

                foreach (var a in methods)
                {
                    MethodBuilder unused;
                    var           delegateType = BizInvokeUtilities.CreateDelegateType(a.Info, a.Attr.CallingConvention, typeBuilder, out unused).CreateType();
                    DelegateTypes.Add(new StoredDelegateInfo(a.Info, delegateType, a.Attr.EntryPoint ?? a.Info.Name));
                }
                StorageType  = typeBuilder.CreateType();
                OriginalType = type;
            }
コード例 #2
0
        /// <summary>
        /// create a method implementation that uses GetDelegateForFunctionPointer internally
        /// </summary>
        private static Action <object, IImportResolver, ICallingConventionAdapter> ImplementMethodDelegate(
            TypeBuilder type,
            MethodInfo baseMethod,
            CallingConvention nativeCall,
            string entryPointName,
            FieldInfo?monitorField,
            bool nonTrivialAdapter)
        {
            // create the delegate type
            var delegateType = BizInvokeUtilities.CreateDelegateType(baseMethod, nativeCall, type, out var delegateInvoke);

            var paramInfos = baseMethod.GetParameters();
            var paramTypes = paramInfos.Select(p => p.ParameterType).ToArray();
            var returnType = baseMethod.ReturnType;

            if (paramTypes.Concat(new[] { returnType }).Any(typeof(Delegate).IsAssignableFrom))
            {
                // this isn't a problem if CallingConventionAdapters.Waterbox is a no-op, but it is otherwise:  we don't
                // have a custom marshaller set up so the user needs to manually pump the callingconventionadapter
                if (nonTrivialAdapter)
                {
                    throw new InvalidOperationException(
                              "Compatibility call mode cannot use ICallingConventionAdapters for automatically marshalled delegate types!");
                }
            }

            // define a field on the class to hold the delegate
            var field = type.DefineField(
                $"DelegateField{baseMethod.Name}",
                delegateType,
                FieldAttributes.Public);

            var method = type.DefineMethod(
                baseMethod.Name,
                MethodAttributes.Virtual | MethodAttributes.Public,
                CallingConventions.HasThis,
                returnType,
                paramTypes);

            var il = method.GetILGenerator();

            Label exc = new Label();

            if (monitorField != null)             // monitor: enter and then begin try
            {
                il.Emit(OpCodes.Ldarg_0);
                il.Emit(OpCodes.Ldfld, monitorField);
                il.Emit(OpCodes.Callvirt, MInfo_IMonitor_Enter);
                exc = il.BeginExceptionBlock();
            }

            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Ldfld, field);
            for (int i = 0; i < paramTypes.Length; i++)
            {
                il.Emit(OpCodes.Ldarg, (short)(i + 1));
            }

            il.Emit(OpCodes.Callvirt, delegateInvoke);

            if (monitorField != null)             // monitor: finally exit
            {
                LocalBuilder?loc = null;
                if (returnType != typeof(void))
                {
                    loc = il.DeclareLocal(returnType);
                    il.Emit(OpCodes.Stloc, loc);
                }

                il.Emit(OpCodes.Leave, exc);
                il.BeginFinallyBlock();
                il.Emit(OpCodes.Ldarg_0);
                il.Emit(OpCodes.Ldfld, monitorField);
                il.Emit(OpCodes.Callvirt, MInfo_IMonitor_Exit);
                il.EndExceptionBlock();

                if (returnType != typeof(void))
                {
                    il.Emit(OpCodes.Ldloc, loc !);
                }
            }

            il.Emit(OpCodes.Ret);

            type.DefineMethodOverride(method, baseMethod);

            return((o, dll, adapter) =>
            {
                var entryPtr = dll.GetProcAddrOrThrow(entryPointName);
                var interopDelegate = adapter.GetDelegateForFunctionPointer(entryPtr, delegateType.CreateType());
                o.GetType().GetField(field.Name).SetValue(o, interopDelegate);
            });
        }