예제 #1
0
        internal unsafe static uint GetTokenReference(Type type, bool throw_exception = true)
        {
            if (type.IsGenericType)
            {
                type = type.GetGenericTypeDefinition();
            }

            var asm_name = type.Module.Assembly.GetName().Name;

            // First check if there's a full token reference to this type
            var token = GetFullTokenReference(asm_name, type.Module.MetadataToken, type.MetadataToken);

            if (token != uint.MaxValue)
            {
                return(token);
            }

            // If type.Module.MetadataToken != 1, then the token must be a full token, which is not the case because we've already checked, so throw an exception.
            if (type.Module.MetadataToken != 1)
            {
                if (!throw_exception)
                {
                    return(Runtime.INVALID_TOKEN_REF);
                }
                throw ErrorHelper.CreateError(8025, $"Failed to compute the token reference for the type '{type.AssemblyQualifiedName}' because its module's metadata token is {type.Module.MetadataToken} when expected 1.");
            }

            var map = Runtime.options->RegistrationMap;

            // Find the assembly index in our list of registered assemblies.
            int assembly_index = -1;

            for (int i = 0; i < map->assembly_count; i++)
            {
                var name_ptr = Marshal.ReadIntPtr(map->assembly, (int)i * IntPtr.Size);
                if (Runtime.StringEquals(name_ptr, asm_name))
                {
                    assembly_index = i;
                    break;
                }
            }
            // If the assembly isn't registered, then the token must be a full token (which it isn't, because we've already checked).
            if (assembly_index == -1)
            {
                if (!throw_exception)
                {
                    return(Runtime.INVALID_TOKEN_REF);
                }
                throw ErrorHelper.CreateError(8025, $"Failed to compute the token reference for the type '{type.AssemblyQualifiedName}' because the assembly couldn't be found in the list of registered assemblies.");
            }

            if (assembly_index > 127)
            {
                if (!throw_exception)
                {
                    return(Runtime.INVALID_TOKEN_REF);
                }
                throw ErrorHelper.CreateError(8025, $"Failed to compute the token reference for the type '{type.AssemblyQualifiedName}' because the assembly index {assembly_index} is not valid (must be <= 127).");
            }

            return((uint)((type.MetadataToken << 8) + (assembly_index << 1)));
        }
예제 #2
0
        internal static IntPtr GetBlockForDelegate(MethodInfo minfo, object @delegate, uint token_ref, string signature)
        {
            if (@delegate is null)
            {
                return(IntPtr.Zero);
            }

            if (!(@delegate is Delegate))
            {
                throw ErrorHelper.CreateError(8016, $"Unable to convert delegate to block for the return value for the method {minfo.DeclaringType.FullName}.{minfo.Name}, because the input isn't a delegate, it's a {@delegate.GetType ().FullName}. {Constants.PleaseFileBugReport}");
            }

            Type delegateProxyType = GetDelegateProxyType(minfo, token_ref, out var baseMethod);

            if (baseMethod is null)
            {
                baseMethod = minfo;                 // 'baseMethod' is only used in error messages, and if it's null, we just use the closest alternative we have (minfo).
            }
            if (delegateProxyType == null)
            {
                throw ErrorHelper.CreateError(8012, $"Invalid DelegateProxyAttribute for the return value for the method {baseMethod.DeclaringType.FullName}.{baseMethod.Name}: DelegateType is null. {Constants.PleaseFileBugReport}");
            }

            var delegateProxyField = delegateProxyType.GetField("Handler", BindingFlags.NonPublic | BindingFlags.Static);

            if (delegateProxyField is null)
            {
                throw ErrorHelper.CreateError(8013, $"Invalid DelegateProxyAttribute for the return value for the method {baseMethod.DeclaringType.FullName}.{baseMethod.Name}: DelegateType ({delegateProxyType.FullName}) specifies a type without a 'Handler' field. {Constants.PleaseFileBugReport}");
            }

            var handlerDelegate = delegateProxyField.GetValue(null);

            if (handlerDelegate is null)
            {
                throw ErrorHelper.CreateError(8014, $"Invalid DelegateProxyAttribute for the return value for the method {baseMethod.DeclaringType.FullName}.{baseMethod.Name}: The DelegateType's ({delegateProxyType.FullName}) 'Handler' field is null. {Constants.PleaseFileBugReport}");
            }

            if (!(handlerDelegate is Delegate))
            {
                throw ErrorHelper.CreateError(8015, $"Invalid DelegateProxyAttribute for the return value for the method {baseMethod.DeclaringType.FullName}.{baseMethod.Name}: The DelegateType's ({delegateProxyType.FullName}) 'Handler' field is not a delegate, it's a {handlerDelegate.GetType ().FullName}. {Constants.PleaseFileBugReport}");
            }

            // We now have the information we need to create the block.
            // 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.
            BlockLiteral block = new BlockLiteral();

            if (signature is null)
            {
                if (Runtime.DynamicRegistrationSupported)
                {
                    block.SetupBlock((Delegate)handlerDelegate, (Delegate)@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((Delegate)handlerDelegate, (Delegate)@delegate, true, signature);
            }
            var rv = _Block_copy(ref block);

            block.CleanupBlock();
            return(rv);
        }
예제 #3
0
        internal static IntPtr GetBlockForDelegate(MethodInfo minfo, object @delegate, string signature)
        {
            if (@delegate == null)
            {
                return(IntPtr.Zero);
            }

            if (!(@delegate is Delegate))
            {
                throw ErrorHelper.CreateError(8016, "Unable to convert delegate to block for the return value for the method {0}.{1}, because the input isn't a delegate, it's a {1}. Please file a bug at http://bugzilla.xamarin.com.", minfo.DeclaringType.FullName, minfo.Name, @delegate.GetType().FullName);
            }

            var baseMethod = minfo.GetBaseDefinition();

            var delegateProxies = baseMethod.ReturnTypeCustomAttributes.GetCustomAttributes(typeof(DelegateProxyAttribute), false);

            if (delegateProxies.Length == 0)
            {
                throw ErrorHelper.CreateError(8011, "Unable to locate the delegate to block conversion attribute ([DelegateProxy]) for the return value for the method {0}.{1}. Please file a bug at http://bugzilla.xamarin.com.", baseMethod.DeclaringType.FullName, baseMethod.Name);
            }

            var delegateProxy = (DelegateProxyAttribute)delegateProxies [0];

            if (delegateProxy.DelegateType == null)
            {
                throw ErrorHelper.CreateError(8012, "Invalid DelegateProxyAttribute for the return value for the method {0}.{1}: DelegateType is null. Please file a bug at http://bugzilla.xamarin.com.", baseMethod.DeclaringType.FullName, baseMethod.Name);
            }

            var delegateProxyField = delegateProxy.DelegateType.GetField("Handler", BindingFlags.NonPublic | BindingFlags.Static);

            if (delegateProxyField == null)
            {
                throw ErrorHelper.CreateError(8013, "Invalid DelegateProxyAttribute for the return value for the method {0}.{1}: DelegateType ({2}) specifies a type without a 'Handler' field. Please file a bug at http://bugzilla.xamarin.com.", baseMethod.DeclaringType.FullName, baseMethod.Name, delegateProxy.DelegateType.FullName);
            }

            var handlerDelegate = delegateProxyField.GetValue(null);

            if (handlerDelegate == null)
            {
                throw ErrorHelper.CreateError(8014, "Invalid DelegateProxyAttribute for the return value for the method {0}.{1}: The DelegateType's ({2}) 'Handler' field is null. Please file a bug at http://bugzilla.xamarin.com.", baseMethod.DeclaringType.FullName, baseMethod.Name, delegateProxy.DelegateType.FullName);
            }

            if (!(handlerDelegate is Delegate))
            {
                throw ErrorHelper.CreateError(8015, "Invalid DelegateProxyAttribute for the return value for the method {0}.{1}: The DelegateType's ({2}) 'Handler' field is not a delegate, it's a {3}. Please file a bug at http://bugzilla.xamarin.com.", baseMethod.DeclaringType.FullName, baseMethod.Name, delegateProxy.DelegateType.FullName, handlerDelegate.GetType().FullName);
            }

            // We now have the information we need to create the block.
            // 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.
            BlockLiteral block = new BlockLiteral();

            if (signature == null)
            {
                if (Runtime.DynamicRegistrationSupported)
                {
                    block.SetupBlock((Delegate)handlerDelegate, (Delegate)@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((Delegate)handlerDelegate, (Delegate)@delegate, true, signature);
            }
            var rv = _Block_copy(ref block);

            block.CleanupBlock();
            return(rv);
        }
예제 #4
0
        // Return value: NULL or a MonoObject* that must be released with xamarin_mono_object_safe_release.
        // Any MonoObject* ref parameters must also be retained and must be released with xamarin_mono_object_release.
        static object InvokeMethod(MethodBase method, object instance, IntPtr native_parameters)
        {
            var methodParameters = method.GetParameters();
            var parameters       = new object [methodParameters.Length];
            var inputParameters  = new object [methodParameters.Length];
            var nativeParameters = new IntPtr [methodParameters.Length];

            // Copy native array of void* to managed array of IntPtr to make the subsequent code simpler.
            unsafe {
                IntPtr *nativeParams = (IntPtr *)native_parameters;
                for (var i = 0; i < methodParameters.Length; i++)
                {
                    nativeParameters [i] = nativeParams [i];
                }
            }

            // Log our input
            log_coreclr($"InvokeMethod ({method.DeclaringType.FullName}::{method}, {instance}, 0x{native_parameters.ToString ("x")})");
            for (var i = 0; i < methodParameters.Length; i++)
            {
                var nativeParam = nativeParameters [i];
                var p           = methodParameters [i];
                var paramType   = p.ParameterType;
                if (paramType.IsByRef)
                {
                    paramType = paramType.GetElementType();
                }
                log_coreclr($"    Argument #{i + 1}: Type = {p.ParameterType.FullName} IsByRef: {p.ParameterType.IsByRef} IsOut: {p.IsOut} IsClass: {paramType.IsClass} IsInterface: {paramType.IsInterface} NativeParameter: 0x{nativeParam.ToString ("x")}");
            }

            // Process the arguments, and convert to what MethodBase.Invoke expects
            for (var i = 0; i < methodParameters.Length; i++)
            {
                var nativeParam = nativeParameters [i];
                var p           = methodParameters [i];
                var paramType   = p.ParameterType;
                var isByRef     = paramType.IsByRef;
                if (isByRef)
                {
                    paramType = paramType.GetElementType();
                }
                log_coreclr($"    Marshalling #{i + 1}: IntPtr => 0x{nativeParam.ToString ("x")} => {p.ParameterType.FullName} [...]");

                if (paramType == typeof(IntPtr))
                {
                    log_coreclr($"        IntPtr");
                    if (isByRef)
                    {
                        if (p.IsOut)
                        {
                            parameters [i] = Marshal.AllocHGlobal(IntPtr.Size);
                        }
                        else
                        {
                            parameters [i] = nativeParam == IntPtr.Zero ? IntPtr.Zero : Marshal.ReadIntPtr(nativeParam);
                        }
                    }
                    else
                    {
                        parameters [i] = nativeParam == IntPtr.Zero ? IntPtr.Zero : Marshal.ReadIntPtr(nativeParam);
                    }
                    log_coreclr($"            => 0x{((IntPtr) parameters [i]).ToString ("x")}");
                }
                else if (paramType.IsClass || paramType.IsInterface || (paramType.IsValueType && IsNullable(paramType)))
                {
                    log_coreclr($"        IsClass/IsInterface/IsNullable IsByRef: {isByRef} IsOut: {p.IsOut} ParameterType: {paramType}");
                    if (nativeParam != IntPtr.Zero)
                    {
                        unsafe {
                            MonoObject *mono_obj = (MonoObject *)nativeParam;
                            // dereference if it's a byref type
                            if (isByRef)
                            {
                                mono_obj = *(MonoObject **)mono_obj;
                            }
                            // get the object
                            parameters [i] = GetMonoObjectTarget(mono_obj);
                        }
                    }
                    log_coreclr($"            => {(parameters [i] == null ? "<null>" : parameters [i].GetType ().FullName)}");
                }
                else if (paramType.IsValueType)
                {
                    log_coreclr($"        IsValueType IsByRef: {isByRef} IsOut: {p.IsOut} nativeParam: 0x{nativeParam.ToString ("x")} ParameterType: {paramType}");
                    if (nativeParam != IntPtr.Zero)
                    {
                        // We need to unwrap nullable types and enum types to their underlying struct type.
                        var  structType = paramType;
                        Type enumType   = null;
                        if (IsNullable(structType))
                        {
                            structType = Nullable.GetUnderlyingType(structType);
                        }
                        if (structType.IsEnum)
                        {
                            enumType   = structType;
                            structType = Enum.GetUnderlyingType(structType);
                        }
                        // convert the pointer to the corresponding structure
                        var vt = PtrToStructure(nativeParam, structType);
                        // convert the structure to the enum type if that's what we need
                        if (enumType != null)
                        {
                            vt = Enum.ToObject(enumType, vt);
                        }
                        parameters [i] = vt;
                    }
                    log_coreclr($"            => {(parameters [i] == null ? "<null>" : parameters [i].ToString ())}");
                }
                else
                {
                    throw ErrorHelper.CreateError(8037, Errors.MX8037 /* Don't know how to marshal the parameter of type {p.ParameterType.FullName} for parameter {p.Name} in call to {method} */, p.ParameterType.FullName, p.Name, method);
                }
            }

            // Make a copy of the array of parameters, so that we can figure out if there were any ref parameters that the method modified.
            parameters.CopyTo(inputParameters, 0);

            // Call the actual method
            log_coreclr($"    Invoking...");

            object rv = null;

            try {
                rv = method.Invoke(instance, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance, null, parameters, null);
            } catch (TargetInvocationException tie) {
                var ex = tie.InnerException ?? tie;
                // This will re-throw the original exception and preserve the stacktrace.
                ExceptionDispatchInfo.Capture(ex).Throw();
            }

            // Copy any byref parameters back out again
            var byrefParameterCount = 0;

            for (var i = 0; i < methodParameters.Length; i++)
            {
                var p = methodParameters [i];
                if (!p.IsOut && !p.ParameterType.IsByRef)
                {
                    continue;
                }

                byrefParameterCount++;

                log_coreclr($"    Marshalling #{i + 1} back (Type: {p.ParameterType.FullName}) value: {(parameters [i] == null ? "<null>" : parameters [i].GetType ().FullName)}");

                var parameterType = p.ParameterType.GetElementType();
                var isMonoObject  = parameterType.IsClass || parameterType.IsInterface || (parameterType.IsValueType && IsNullable(parameterType));

                var nativeParam = nativeParameters [i];

                if (nativeParam == IntPtr.Zero)
                {
                    log_coreclr($"    No output pointer was provided.");
                    continue;
                }

                if (parameters [i] == inputParameters [i])
                {
                    log_coreclr($"        The argument didn't change, no marshalling required");
                    if (parameters [i] != null && parameterType != typeof(IntPtr) && isMonoObject)
                    {
                        // byref parameters must be retained
                        xamarin_mono_object_retain(Marshal.ReadIntPtr(nativeParam));
                    }
                    continue;
                }

                if (parameterType == typeof(IntPtr))
                {
                    Marshal.WriteIntPtr(nativeParam, (IntPtr)parameters [i]);
                    log_coreclr($"        IntPtr: 0x{((IntPtr) parameters [i]).ToString ("x")} => Type: {parameters [i]?.GetType ()} nativeParam: 0x{nativeParam.ToString ("x")}");
                }
                else if (isMonoObject)
                {
                    var ptr = GetMonoObject(parameters [i]);
                    Marshal.WriteIntPtr(nativeParam, ptr);
                    log_coreclr($"        IsClass/IsInterface/IsNullable: {(parameters [i] == null ? "<null>" : parameters [i].GetType ().FullName)}  nativeParam: 0x{nativeParam.ToString ("x")} -> MonoObject: 0x{ptr.ToString ("x")}");
                }
                else if (parameterType.IsValueType)
                {
                    StructureToPtr(parameters [i], nativeParam);
                    log_coreclr($"        IsValueType: {(parameters [i] == null ? "<null>" : parameters [i].ToString ())} nativeParam: 0x{nativeParam.ToString ("x")}");
                }
                else
                {
                    throw ErrorHelper.CreateError(8038, Errors.MX8038 /* Don't know how to marshal back the parameter of type {p.ParameterType.FullName} for parameter {p.Name} in call to {method} */, p.ParameterType.FullName, p.Name, method);
                }
            }

            // we're done!
            log_coreclr($"    Invoke complete with {byrefParameterCount} ref parameters and return value of type {rv?.GetType ()}");

            return(rv);
        }