diff --git a/src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs b/src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs index 1959209bd7cc4..f1dfa36b70237 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/RuntimeHandles.cs @@ -141,19 +141,6 @@ internal static bool IsByRef(RuntimeType type) return corElemType == CorElementType.ELEMENT_TYPE_BYREF; } - internal static bool TryGetByRefElementType(RuntimeType type, [NotNullWhen(true)] out RuntimeType? elementType) - { - CorElementType corElemType = GetCorElementType(type); - if (corElemType == CorElementType.ELEMENT_TYPE_BYREF) - { - elementType = GetElementType(type); - return true; - } - - elementType = null; - return false; - } - internal static bool IsPointer(RuntimeType type) { CorElementType corElemType = GetCorElementType(type); diff --git a/src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs index fdfc88b419e4a..a60920aa83c20 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/RuntimeType.CoreCLR.cs @@ -3582,180 +3582,10 @@ public override Type MakeArrayType(int rank) [MethodImpl(MethodImplOptions.InternalCall)] private static extern object AllocateValueType(RuntimeType type, object? value); - private enum CheckValueStatus - { - Success = 0, - ArgumentException, - NotSupported_ByRefLike - } - - /// - /// Verify and optionally convert the value for special cases. - /// - /// True if is a value type, False otherwise - internal bool CheckValue( - ref object? value, - ref ParameterCopyBackAction copyBack, - Binder? binder, - CultureInfo? culture, - BindingFlags invokeAttr) - { - // Already fast-pathed by the caller. - Debug.Assert(!ReferenceEquals(value?.GetType(), this)); - - // Since this cannot be a generic parameter, we use RuntimeTypeHandle.IsValueType here - // because it is faster than IsValueType - Debug.Assert(!IsGenericParameter); - - // Fast path to whether a value can be assigned without conversion. - if (IsInstanceOfType(value)) - { - if (IsNullableOfT) - { - // Pass as a true boxed Nullable, not as a T or null. - value = RuntimeMethodHandle.ReboxToNullable(value, this); - return true; - } - - // Other value types won't get here since Type equality was previous checked. - Debug.Assert(!RuntimeTypeHandle.IsValueType(this)); - - return false; - } - - bool isValueType; - CheckValueStatus result = TryChangeType(ref value, ref copyBack, out isValueType); - if (result == CheckValueStatus.Success) - { - return isValueType; - } - - if (result == CheckValueStatus.ArgumentException && (invokeAttr & BindingFlags.ExactBinding) == 0) - { - Debug.Assert(value != null); - - // Use the binder - if (binder != null && binder != DefaultBinder) - { - value = binder.ChangeType(value, this, culture); - if (IsInstanceOfType(value)) - { - if (IsNullableOfT) - { - // Pass as a true boxed Nullable, not as a T or null. - value = RuntimeMethodHandle.ReboxToNullable(value, this); - copyBack = ParameterCopyBackAction.CopyNullable; - } - else - { - copyBack = ParameterCopyBackAction.Copy; - } - - return IsValueType; // Note the call to IsValueType, not the variable. - } - - result = TryChangeType(ref value, ref copyBack, out isValueType); - if (result == CheckValueStatus.Success) - { - return isValueType; - } - } - } - - switch (result) - { - case CheckValueStatus.ArgumentException: - throw new ArgumentException(SR.Format(SR.Arg_ObjObjEx, value?.GetType(), this)); - case CheckValueStatus.NotSupported_ByRefLike: - throw new NotSupportedException(SR.NotSupported_ByRefLike); - } - - Debug.Fail("Error result not expected"); - return false; - } - - private CheckValueStatus TryChangeType( - ref object? value, - ref ParameterCopyBackAction copyBack, + private CheckValueStatus TryChangeTypeSpecial( + ref object value, out bool isValueType) { - RuntimeType? sigElementType; - if (RuntimeTypeHandle.TryGetByRefElementType(this, out sigElementType)) - { - copyBack = ParameterCopyBackAction.Copy; - Debug.Assert(!sigElementType.IsGenericParameter); - - if (sigElementType.IsInstanceOfType(value)) - { - isValueType = RuntimeTypeHandle.IsValueType(sigElementType); - if (isValueType) - { - if (sigElementType.IsNullableOfT) - { - // Pass as a true boxed Nullable, not as a T or null. - value = RuntimeMethodHandle.ReboxToNullable(value, sigElementType); - copyBack = ParameterCopyBackAction.CopyNullable; - } - else - { - // Make a copy to prevent the boxed instance from being directly modified by the method. - value = AllocateValueType(sigElementType, value); - } - } - - return CheckValueStatus.Success; - } - - if (value == null) - { - isValueType = RuntimeTypeHandle.IsValueType(sigElementType); - if (!isValueType) - { - // Normally we don't get here since 'null' was previosuly checked, but due to binders we can. - return CheckValueStatus.Success; - } - - if (sigElementType.IsByRefLike) - { - return CheckValueStatus.NotSupported_ByRefLike; - } - - // Allocate default. - value = AllocateValueType(sigElementType, value: null); - copyBack = sigElementType.IsNullableOfT ? ParameterCopyBackAction.CopyNullable : ParameterCopyBackAction.Copy; - return CheckValueStatus.Success; - } - - isValueType = false; - return CheckValueStatus.ArgumentException; - } - - if (value == null) - { - isValueType = RuntimeTypeHandle.IsValueType(this); - if (!isValueType) - { - // Normally we don't get here since 'null' was previosuly checked, but due to binders we can. - return CheckValueStatus.Success; - } - - if (IsByRefLike) - { - return CheckValueStatus.NotSupported_ByRefLike; - } - - // Allocate default. - value = AllocateValueType(this, value: null); - return CheckValueStatus.Success; - } - - // Check the strange ones courtesy of reflection: - // - Implicit cast between primitives - // - Enum treated as underlying type - // - Pointer (*) types to IntPtr (if dest is IntPtr) - // - System.Reflection.Pointer to appropriate pointer (*) type (if dest is pointer type) - if (IsPointer || IsEnum || IsPrimitive) - { Pointer? pointer = value as Pointer; RuntimeType srcType = pointer != null ? pointer.GetPointerType() : (RuntimeType)value.GetType(); @@ -3781,38 +3611,6 @@ private CheckValueStatus TryChangeType( isValueType = true; return CheckValueStatus.Success; - } - - isValueType = false; - return CheckValueStatus.ArgumentException; - } - - internal bool TryByRefFastPath(ref object arg, ref bool isValueType) - { - if (RuntimeTypeHandle.TryGetByRefElementType(this, out RuntimeType? sigElementType) && - ReferenceEquals(sigElementType, arg.GetType())) - { - isValueType = sigElementType.IsValueType; - if (isValueType) - { - // Make a copy to prevent the boxed instance from being directly modified by the method. - arg = AllocateValueType(sigElementType, arg); - } - - return true; - } - - return false; - } - - internal static CorElementType GetUnderlyingType(RuntimeType type) - { - if (type.IsActualEnum) - { - type = (RuntimeType)Enum.GetUnderlyingType(type); - } - - return RuntimeTypeHandle.GetCorElementType(type); } #endregion diff --git a/src/libraries/Common/tests/System/Reflection/InvokeEmitTests.cs b/src/libraries/Common/tests/System/Reflection/InvokeEmitTests.cs index c81da708294f1..d6345d3e92314 100644 --- a/src/libraries/Common/tests/System/Reflection/InvokeEmitTests.cs +++ b/src/libraries/Common/tests/System/Reflection/InvokeEmitTests.cs @@ -35,8 +35,7 @@ public static void VerifyInvokeIsUsingEmit_Constructor() private static bool IsEmitInvokeSupported() { // Emit is only used for Invoke when RuntimeFeature.IsDynamicCodeCompiled is true. - return RuntimeFeature.IsDynamicCodeCompiled - && !PlatformDetection.IsMonoRuntime; // Temporary until Mono is updated. + return RuntimeFeature.IsDynamicCodeCompiled; } private static string InterpretedMethodName => PlatformDetection.IsMonoRuntime ? diff --git a/src/libraries/Common/tests/System/Reflection/InvokeInterpretedTests.cs b/src/libraries/Common/tests/System/Reflection/InvokeInterpretedTests.cs index 5d4347e82d885..a197da333f16d 100644 --- a/src/libraries/Common/tests/System/Reflection/InvokeInterpretedTests.cs +++ b/src/libraries/Common/tests/System/Reflection/InvokeInterpretedTests.cs @@ -8,6 +8,7 @@ namespace System.Reflection.Tests public class InvokeInterpretedTests { [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/50957", typeof(PlatformDetection), nameof(PlatformDetection.IsBrowser), nameof(PlatformDetection.IsMonoAOT))] public static void VerifyInvokeIsUsingEmit_Method() { MethodInfo method = typeof(TestClassThatThrows).GetMethod(nameof(TestClassThatThrows.Throw))!; @@ -24,6 +25,7 @@ string InterpretedMethodName() => PlatformDetection.IsMonoRuntime ? } [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/50957", typeof(PlatformDetection), nameof(PlatformDetection.IsBrowser), nameof(PlatformDetection.IsMonoAOT))] public static void VerifyInvokeIsUsingEmit_Constructor() { ConstructorInfo ctor = typeof(TestClassThatThrows).GetConstructor(Type.EmptyTypes)!; diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/ConstructorInvoker.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/ConstructorInvoker.cs index d5f173eac1870..9b581a305afde 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/ConstructorInvoker.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/ConstructorInvoker.cs @@ -10,17 +10,14 @@ internal sealed partial class ConstructorInvoker { private readonly RuntimeConstructorInfo _method; -#if !MONO // Temporary until Mono is updated. private bool _invoked; private bool _strategyDetermined; private InvokerEmitUtil.InvokeFunc? _invokeFunc; -#endif public ConstructorInvoker(RuntimeConstructorInfo constructorInfo) { _method = constructorInfo; -#if !MONO // Temporary until Mono is updated. if (LocalAppContextSwitches.ForceInterpretedInvoke && !LocalAppContextSwitches.ForceEmitInvoke) { // Always use the native invoke; useful for testing. @@ -31,13 +28,9 @@ public ConstructorInvoker(RuntimeConstructorInfo constructorInfo) // Always use emit invoke (if IsDynamicCodeCompiled == true); useful for testing. _invoked = true; } -#endif } [MethodImpl(MethodImplOptions.AggressiveInlining)] -#if MONO // Temporary until Mono is updated. - public unsafe object? InlinedInvoke(object? obj, Span args, BindingFlags invokeAttr) => InterpretedInvoke(obj, args, invokeAttr); -#else public unsafe object? InlinedInvoke(object? obj, IntPtr* args, BindingFlags invokeAttr) { if (_invokeFunc != null && (invokeAttr & BindingFlags.DoNotWrapExceptions) != 0 && obj == null) @@ -46,9 +39,7 @@ public ConstructorInvoker(RuntimeConstructorInfo constructorInfo) } return Invoke(obj, args, invokeAttr); } -#endif -#if !MONO // Temporary until Mono is updated. [DebuggerStepThrough] [DebuggerHidden] private unsafe object? Invoke(object? obj, IntPtr* args, BindingFlags invokeAttr) @@ -102,6 +93,5 @@ public ConstructorInvoker(RuntimeConstructorInfo constructorInfo) return ret; } -#endif } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/InvokerEmitUtil.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/InvokerEmitUtil.cs index 4e4bab9aa36fc..87bccf3173281 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/InvokerEmitUtil.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/InvokerEmitUtil.cs @@ -65,8 +65,11 @@ public static unsafe InvokeFunc CreateInvokeDelegate(MethodBase method) } // Invoke the method. -#if !MONO - il.Emit(OpCodes.Call, Methods.NextCallReturnAddress()); // For CallStack reasons, don't inline target method. + // For CallStack reasons, don't inline target method. +#if MONO + il.Emit(OpCodes.Call, Methods.DisableInline()); +#else + il.Emit(OpCodes.Call, Methods.NextCallReturnAddress()); il.Emit(OpCodes.Pop); #endif @@ -182,7 +185,11 @@ public static MethodInfo Pointer_Box() => public static MethodInfo Type_GetTypeFromHandle() => s_Type_GetTypeFromHandle ??= typeof(Type).GetMethod(nameof(Type.GetTypeFromHandle), new[] { typeof(RuntimeTypeHandle) })!; -#if !MONO +#if MONO + private static MethodInfo? s_DisableInline; + public static MethodInfo DisableInline() => + s_DisableInline ??= typeof(System.Runtime.CompilerServices.JitHelpers).GetMethod(nameof(System.Runtime.CompilerServices.JitHelpers.DisableInline), BindingFlags.NonPublic | BindingFlags.Static)!; +#else private static MethodInfo? s_NextCallReturnAddress; public static MethodInfo NextCallReturnAddress() => s_NextCallReturnAddress ??= typeof(System.StubHelpers.StubHelpers).GetMethod(nameof(System.StubHelpers.StubHelpers.NextCallReturnAddress), BindingFlags.NonPublic | BindingFlags.Static)!; diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/MethodBase.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/MethodBase.cs index 98069a70ef55b..2ab4287267048 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/MethodBase.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/MethodBase.cs @@ -239,14 +239,12 @@ BindingFlags invokeAttr #pragma warning disable 8500 if (isValueType) { -#if !MONO // Temporary until Mono is updated. Debug.Assert(arg != null); Debug.Assert( arg.GetType() == sigType || (sigType.IsPointer && (arg.GetType() == typeof(IntPtr) || arg.GetType() == typeof(UIntPtr))) || (sigType.IsByRef && arg.GetType() == RuntimeTypeHandle.GetElementType(sigType)) || ((sigType.IsEnum || arg.GetType().IsEnum) && RuntimeType.GetUnderlyingType((RuntimeType)arg.GetType()) == RuntimeType.GetUnderlyingType(sigType))); -#endif ByReference valueTypeRef = ByReference.Create(ref copyOfParameters[i]!.GetRawData()); *(ByReference*)(byrefParameters + i) = valueTypeRef; } diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/MethodInvoker.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/MethodInvoker.cs index 3adbad39eb21c..a33ca063fa877 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/MethodInvoker.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/MethodInvoker.cs @@ -11,9 +11,6 @@ internal sealed partial class MethodInvoker private readonly MethodBase _method; [MethodImpl(MethodImplOptions.AggressiveInlining)] -#if MONO // Temporary until Mono is updated. - public unsafe object? InlinedInvoke(object? obj, Span args, BindingFlags invokeAttr) => InterpretedInvoke(obj, args, invokeAttr); -#else public unsafe object? InlinedInvoke(object? obj, IntPtr* args, BindingFlags invokeAttr) { if (_invokeFunc != null && (invokeAttr & BindingFlags.DoNotWrapExceptions) != 0) @@ -22,9 +19,7 @@ internal sealed partial class MethodInvoker } return Invoke(obj, args, invokeAttr); } -#endif -#if !MONO // Temporary until Mono is updated. private bool _invoked; private bool _strategyDetermined; private InvokerEmitUtil.InvokeFunc? _invokeFunc; @@ -80,6 +75,5 @@ internal sealed partial class MethodInvoker return ret; } -#endif } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/RuntimeConstructorInfo.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/RuntimeConstructorInfo.cs index 1fd9c177ddb8a..a16f6f48531ae 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/RuntimeConstructorInfo.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/RuntimeConstructorInfo.cs @@ -160,11 +160,7 @@ internal void ThrowNoInvokeException() culture, invokeAttr); -#if MONO // Temporary until Mono is updated. - Invoker.InlinedInvoke(obj, copyOfParameters, invokeAttr); -#else Invoker.InlinedInvoke(obj, pByRefStorage, invokeAttr); -#endif // Copy modified values out. This should be done only with ByRef or Type.Missing parameters. for (int i = 0; i < argCount; i++) @@ -230,11 +226,7 @@ private static unsafe void InvokeWithManyArguments( culture, invokeAttr); -#if MONO // Temporary until Mono is updated. - ci.Invoker.InlinedInvoke(obj, copyOfParameters, invokeAttr); -#else ci.Invoker.InlinedInvoke(obj, pByRefStorage, invokeAttr); -#endif } finally { @@ -315,11 +307,7 @@ public override object Invoke(BindingFlags invokeAttr, Binder? binder, object?[] culture, invokeAttr); -#if MONO // Temporary until Mono is updated. - retValue = Invoker.InlinedInvoke(obj: null, copyOfParameters, invokeAttr); -#else retValue = Invoker.InlinedInvoke(obj: null, pByRefStorage, invokeAttr); -#endif // Copy modified values out. This should be done only with ByRef or Type.Missing parameters. for (int i = 0; i < argCount; i++) @@ -388,11 +376,7 @@ public override object Invoke(BindingFlags invokeAttr, Binder? binder, object?[] culture, invokeAttr); -#if MONO // Temporary until Mono is updated. - retValue = ci.Invoker.InlinedInvoke(obj: null, copyOfParameters, invokeAttr); -#else retValue = ci.Invoker.InlinedInvoke(obj: null, pByRefStorage, invokeAttr); -#endif } finally { diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.cs index bf534c58e70ed..28d530bcfc6c2 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.cs @@ -157,11 +157,7 @@ private void ThrowNoInvokeException() culture, invokeAttr); -#if MONO // Temporary until Mono is updated. - retValue = Invoker.InlinedInvoke(obj, copyOfParameters, invokeAttr); -#else retValue = Invoker.InlinedInvoke(obj, pByRefStorage, invokeAttr); -#endif // Copy modified values out. This should be done only with ByRef or Type.Missing parameters. for (int i = 0; i < argCount; i++) @@ -228,11 +224,7 @@ private void ThrowNoInvokeException() culture, invokeAttr); -#if MONO // Temporary until Mono is updated. - retValue = mi.Invoker.InlinedInvoke(obj, copyOfParameters, invokeAttr); -#else retValue = mi.Invoker.InlinedInvoke(obj, pByRefStorage, invokeAttr); -#endif } finally { diff --git a/src/libraries/System.Private.CoreLib/src/System/RuntimeType.cs b/src/libraries/System.Private.CoreLib/src/System/RuntimeType.cs index 7472df80e998e..bb257e676a4f0 100644 --- a/src/libraries/System.Private.CoreLib/src/System/RuntimeType.cs +++ b/src/libraries/System.Private.CoreLib/src/System/RuntimeType.cs @@ -827,5 +827,225 @@ internal static void SanityCheckGenericArguments(RuntimeType[] genericArguments, throw new ArgumentException( SR.Format(SR.Argument_NotEnoughGenArguments, genericArguments.Length, genericParameters.Length)); } + + internal static CorElementType GetUnderlyingType(RuntimeType type) + { + if (type.IsActualEnum) + { + type = (RuntimeType)Enum.GetUnderlyingType(type); + } + + return RuntimeTypeHandle.GetCorElementType(type); + } + + internal static bool TryGetByRefElementType(RuntimeType type, [NotNullWhen(true)] out RuntimeType? elementType) + { + CorElementType corElemType = RuntimeTypeHandle.GetCorElementType(type); + if (corElemType == CorElementType.ELEMENT_TYPE_BYREF) + { + elementType = RuntimeTypeHandle.GetElementType(type); + return true; + } + + elementType = null; + return false; + } + + private enum CheckValueStatus + { + Success = 0, + ArgumentException, + NotSupported_ByRefLike + } + + /// + /// Verify and optionally convert the value for special cases. + /// + /// True if is a value type, False otherwise + internal bool CheckValue( + ref object? value, + ref ParameterCopyBackAction copyBack, + Binder? binder, + CultureInfo? culture, + BindingFlags invokeAttr) + { + // Already fast-pathed by the caller. + Debug.Assert(!ReferenceEquals(value?.GetType(), this)); + + // Since this cannot be a generic parameter, we use RuntimeTypeHandle.IsValueType here + // because it is faster than IsValueType + Debug.Assert(!IsGenericParameter); + + // Fast path to whether a value can be assigned without conversion. + if (IsInstanceOfType(value)) + { + if (IsNullableOfT) + { + // Pass as a true boxed Nullable, not as a T or null. + value = RuntimeMethodHandle.ReboxToNullable(value, this); + return true; + } + + // Other value types won't get here since Type equality was previous checked. + Debug.Assert(!RuntimeTypeHandle.IsValueType(this)); + + return false; + } + + bool isValueType; + CheckValueStatus result = TryChangeType(ref value, ref copyBack, out isValueType); + if (result == CheckValueStatus.Success) + { + return isValueType; + } + + if (result == CheckValueStatus.ArgumentException && (invokeAttr & BindingFlags.ExactBinding) == 0) + { + Debug.Assert(value != null); + + // Use the binder + if (binder != null && binder != DefaultBinder) + { + value = binder.ChangeType(value, this, culture); + if (IsInstanceOfType(value)) + { + if (IsNullableOfT) + { + // Pass as a true boxed Nullable, not as a T or null. + value = RuntimeMethodHandle.ReboxToNullable(value, this); + copyBack = ParameterCopyBackAction.CopyNullable; + } + else + { + copyBack = ParameterCopyBackAction.Copy; + } + + return IsValueType; // Note the call to IsValueType, not the variable. + } + + result = TryChangeType(ref value, ref copyBack, out isValueType); + if (result == CheckValueStatus.Success) + { + return isValueType; + } + } + } + + switch (result) + { + case CheckValueStatus.ArgumentException: + throw new ArgumentException(SR.Format(SR.Arg_ObjObjEx, value?.GetType(), this)); + case CheckValueStatus.NotSupported_ByRefLike: + throw new NotSupportedException(SR.NotSupported_ByRefLike); + } + + Debug.Fail("Error result not expected"); + return false; + } + + private CheckValueStatus TryChangeType( + ref object? value, + ref ParameterCopyBackAction copyBack, + out bool isValueType) + { + RuntimeType? sigElementType; + if (TryGetByRefElementType(this, out sigElementType)) + { + copyBack = ParameterCopyBackAction.Copy; + Debug.Assert(!sigElementType.IsGenericParameter); + + if (sigElementType.IsInstanceOfType(value)) + { + isValueType = RuntimeTypeHandle.IsValueType(sigElementType); + if (isValueType) + { + if (sigElementType.IsNullableOfT) + { + // Pass as a true boxed Nullable, not as a T or null. + value = RuntimeMethodHandle.ReboxToNullable(value, sigElementType); + copyBack = ParameterCopyBackAction.CopyNullable; + } + else + { + // Make a copy to prevent the boxed instance from being directly modified by the method. + value = AllocateValueType(sigElementType, value); + } + } + + return CheckValueStatus.Success; + } + + if (value == null) + { + isValueType = RuntimeTypeHandle.IsValueType(sigElementType); + if (!isValueType) + { + // Normally we don't get here since 'null' was previosuly checked, but due to binders we can. + return CheckValueStatus.Success; + } + + if (sigElementType.IsByRefLike) + { + return CheckValueStatus.NotSupported_ByRefLike; + } + + // Allocate default. + value = AllocateValueType(sigElementType, value: null); + copyBack = sigElementType.IsNullableOfT ? ParameterCopyBackAction.CopyNullable : ParameterCopyBackAction.Copy; + return CheckValueStatus.Success; + } + + isValueType = false; + return CheckValueStatus.ArgumentException; + } + + if (value == null) + { + isValueType = RuntimeTypeHandle.IsValueType(this); + if (!isValueType) + { + // Normally we don't get here since 'null' was previosuly checked, but due to binders we can. + return CheckValueStatus.Success; + } + + if (IsByRefLike) + { + return CheckValueStatus.NotSupported_ByRefLike; + } + + // Allocate default. + value = AllocateValueType(this, value: null); + return CheckValueStatus.Success; + } + + // Check the strange ones courtesy of reflection: + // - Implicit cast between primitives + // - Enum treated as underlying type + // - Pointer (*) types to IntPtr (if dest is IntPtr) + // - System.Reflection.Pointer to appropriate pointer (*) type (if dest is pointer type) + if (IsPointer || IsEnum || IsPrimitive) + return TryChangeTypeSpecial(ref value, out isValueType); + + isValueType = false; + return CheckValueStatus.ArgumentException; + } + + internal bool TryByRefFastPath(ref object arg, ref bool isValueType) + { + if (TryGetByRefElementType(this, out RuntimeType? sigElementType) && + ReferenceEquals(sigElementType, arg.GetType())) + { + isValueType = sigElementType.IsValueType; + if (isValueType) + { + // Make a copy to prevent the boxed instance from being directly modified by the method. + arg = AllocateValueType(sigElementType, arg); + } + + return true; + } + + return false; + } } } diff --git a/src/libraries/System.Reflection.TypeExtensions/tests/ConstructorInfo/ConstructorInfoInvokeArrayTests.cs b/src/libraries/System.Reflection.TypeExtensions/tests/ConstructorInfo/ConstructorInfoInvokeArrayTests.cs index 27d0327c53689..f67acdae97ad5 100644 --- a/src/libraries/System.Reflection.TypeExtensions/tests/ConstructorInfo/ConstructorInfoInvokeArrayTests.cs +++ b/src/libraries/System.Reflection.TypeExtensions/tests/ConstructorInfo/ConstructorInfoInvokeArrayTests.cs @@ -8,7 +8,6 @@ namespace System.Reflection.Tests public class ConstructorInfoInvokeArrayTests { [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/67457", TestRuntimes.Mono)] public void Invoke_SZArrayConstructor() { Type type = Type.GetType("System.Object[]"); @@ -109,7 +108,6 @@ public void Invoke_1DArrayConstructor() } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/67457", TestRuntimes.Mono)] public void Invoke_2DArrayConstructor() { Type type = Type.GetType("System.Int32[,]", false); @@ -247,7 +245,6 @@ public void Invoke_LargeDimensionalArrayConstructor() } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/67457", TestRuntimes.Mono)] public void Invoke_JaggedArrayConstructor() { Type type = Type.GetType("System.String[][]"); diff --git a/src/libraries/System.Reflection/tests/ConstructorInfoTests.cs b/src/libraries/System.Reflection/tests/ConstructorInfoTests.cs index 5e41d80f197c4..34d04906a8055 100644 --- a/src/libraries/System.Reflection/tests/ConstructorInfoTests.cs +++ b/src/libraries/System.Reflection/tests/ConstructorInfoTests.cs @@ -113,7 +113,6 @@ public void Invoke_OneDimensionalArray() } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/67457", TestRuntimes.Mono)] public void Invoke_OneDimensionalArray_NegativeLengths_ThrowsOverflowException() { ConstructorInfo[] constructors = GetConstructors(typeof(object[])); diff --git a/src/libraries/System.Runtime/tests/System/Reflection/InvokeRefReturn.cs b/src/libraries/System.Runtime/tests/System/Reflection/InvokeRefReturn.cs index a86592b14ff2f..48ea6f4bdfdf8 100644 --- a/src/libraries/System.Runtime/tests/System/Reflection/InvokeRefReturn.cs +++ b/src/libraries/System.Runtime/tests/System/Reflection/InvokeRefReturn.cs @@ -38,7 +38,6 @@ public static void TestRefReturnNullableNoValue() [Theory] [MemberData(nameof(RefReturnInvokeTestData))] - [ActiveIssue("https://github.com/dotnet/runtime/issues/67457", TestRuntimes.Mono)] public static void TestNullRefReturnInvoke(T value) { TestClass tc = new TestClass(value); @@ -61,7 +60,6 @@ public static unsafe void TestRefReturnOfPointer() } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/67457", TestRuntimes.Mono)] public static unsafe void TestNullRefReturnOfPointer() { TestClassIntPointer tc = new TestClassIntPointer(null); diff --git a/src/mono/System.Private.CoreLib/src/ILLink/ILLink.Descriptors.xml b/src/mono/System.Private.CoreLib/src/ILLink/ILLink.Descriptors.xml index ee6d7863ebd6b..3d13f30e92bbe 100644 --- a/src/mono/System.Private.CoreLib/src/ILLink/ILLink.Descriptors.xml +++ b/src/mono/System.Private.CoreLib/src/ILLink/ILLink.Descriptors.xml @@ -632,11 +632,6 @@ - - - - - diff --git a/src/mono/System.Private.CoreLib/src/Mono/RuntimeStructs.cs b/src/mono/System.Private.CoreLib/src/Mono/RuntimeStructs.cs index fca9cf42dbc32..49989b0ec58ba 100644 --- a/src/mono/System.Private.CoreLib/src/Mono/RuntimeStructs.cs +++ b/src/mono/System.Private.CoreLib/src/Mono/RuntimeStructs.cs @@ -149,11 +149,4 @@ internal enum I64Enum : long internal enum UI64Enum : ulong { } - - internal sealed class NullByRefReturnException : Exception - { - public NullByRefReturnException() - { - } - } } diff --git a/src/mono/System.Private.CoreLib/src/System/Collections/Generic/EqualityComparer.Mono.cs b/src/mono/System.Private.CoreLib/src/System/Collections/Generic/EqualityComparer.Mono.cs index 796c946eebb8d..2d574506e39d5 100644 --- a/src/mono/System.Private.CoreLib/src/System/Collections/Generic/EqualityComparer.Mono.cs +++ b/src/mono/System.Private.CoreLib/src/System/Collections/Generic/EqualityComparer.Mono.cs @@ -39,6 +39,11 @@ private static EqualityComparer CreateComparer() { return (EqualityComparer)(object)(new ByteEqualityComparer()); } + else if (t == typeof(string)) + { + // Specialize for string, as EqualityComparer.Default is on the startup path + return (EqualityComparer)(object)(new GenericEqualityComparer()); + } if (typeof(IEquatable).IsAssignableFrom(t)) { diff --git a/src/mono/System.Private.CoreLib/src/System/Reflection/ConstructorInvoker.Mono.cs b/src/mono/System.Private.CoreLib/src/System/Reflection/ConstructorInvoker.Mono.cs index 49b13afc66511..3bde0806a5c6e 100644 --- a/src/mono/System.Private.CoreLib/src/System/Reflection/ConstructorInvoker.Mono.cs +++ b/src/mono/System.Private.CoreLib/src/System/Reflection/ConstructorInvoker.Mono.cs @@ -7,35 +7,10 @@ namespace System.Reflection { internal partial class ConstructorInvoker { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private unsafe object? InterpretedInvoke(object? obj, Span args, BindingFlags invokeAttr) + private unsafe object? InterpretedInvoke(object? obj, IntPtr *args) { Exception exc; - object? o; - - if ((invokeAttr & BindingFlags.DoNotWrapExceptions) == 0) - { - try - { - o = _method.InternalInvoke(obj, args, out exc); - } - catch (MethodAccessException) - { - throw; - } - catch (OverflowException) - { - throw; - } - catch (Exception e) - { - throw new TargetInvocationException(e); - } - } - else - { - o = _method.InternalInvoke(obj, args, out exc); - } + object? o = _method.InternalInvoke(obj, args, out exc); if (exc != null) throw exc; diff --git a/src/mono/System.Private.CoreLib/src/System/Reflection/MethodInvoker.Mono.cs b/src/mono/System.Private.CoreLib/src/System/Reflection/MethodInvoker.Mono.cs index 2ea61086c7a4f..99df70de828fb 100644 --- a/src/mono/System.Private.CoreLib/src/System/Reflection/MethodInvoker.Mono.cs +++ b/src/mono/System.Private.CoreLib/src/System/Reflection/MethodInvoker.Mono.cs @@ -11,51 +11,23 @@ public MethodInvoker(MethodBase method) { _method = method; -#if USE_NATIVE_INVOKE - // Always use the native invoke; useful for testing. - _strategyDetermined = true; -#elif USE_EMIT_INVOKE - // Always use emit invoke (if IsDynamicCodeCompiled == true); useful for testing. - _invoked = true; -#endif + if (LocalAppContextSwitches.ForceInterpretedInvoke && !LocalAppContextSwitches.ForceEmitInvoke) + { + // Always use the native invoke; useful for testing. + _strategyDetermined = true; + } + else if (LocalAppContextSwitches.ForceEmitInvoke && !LocalAppContextSwitches.ForceInterpretedInvoke) + { + // Always use emit invoke (if IsDynamicCodeCompiled == true); useful for testing. + _invoked = true; + } } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private unsafe object? InterpretedInvoke(object? obj, Span args, BindingFlags invokeAttr) + private unsafe object? InterpretedInvoke(object? obj, IntPtr *args) { Exception? exc; - object? o; - if ((invokeAttr & BindingFlags.DoNotWrapExceptions) == 0) - { - try - { - o = ((RuntimeMethodInfo)_method).InternalInvoke(obj, args, out exc); - } - catch (Mono.NullByRefReturnException) - { - throw new NullReferenceException(); - } - catch (OverflowException) - { - throw; - } - catch (Exception e) - { - throw new TargetInvocationException(e); - } - } - else - { - try - { - o = ((RuntimeMethodInfo)_method).InternalInvoke(obj, args, out exc); - } - catch (Mono.NullByRefReturnException) - { - throw new NullReferenceException(); - } - } + object? o = ((RuntimeMethodInfo)_method).InternalInvoke(obj, args, out exc); if (exc != null) throw exc; diff --git a/src/mono/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.Mono.cs b/src/mono/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.Mono.cs index 08f30f04fca82..6d43a9270910c 100644 --- a/src/mono/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.Mono.cs +++ b/src/mono/System.Private.CoreLib/src/System/Reflection/RuntimeMethodInfo.Mono.cs @@ -140,7 +140,7 @@ internal static ParameterInfo GetReturnParameterInfo(RuntimeMethodInfo method) #region Sync with _MonoReflectionMethod in object-internals.h [StructLayout(LayoutKind.Sequential)] - internal sealed partial class RuntimeMethodInfo : MethodInfo + internal sealed unsafe partial class RuntimeMethodInfo : MethodInfo { #pragma warning disable 649 internal IntPtr mhandle; @@ -382,7 +382,7 @@ internal RuntimeType[] ArgumentTypes * Exceptions thrown by the called method propagate normally. */ [MethodImplAttribute(MethodImplOptions.InternalCall)] - internal extern object? InternalInvoke(object? obj, in Span parameters, out Exception? exc); + internal extern object? InternalInvoke(object? obj, IntPtr *args, out Exception? exc); public override RuntimeMethodHandle MethodHandle { @@ -710,7 +710,7 @@ public override IList GetCustomAttributesData() } #region Sync with _MonoReflectionMethod in object-internals.h [StructLayout(LayoutKind.Sequential)] - internal sealed partial class RuntimeConstructorInfo : ConstructorInfo + internal sealed unsafe partial class RuntimeConstructorInfo : ConstructorInfo { #pragma warning disable 649 internal IntPtr mhandle; @@ -816,7 +816,7 @@ private void InvokeClassConstructor() * to match the types of the method signature. */ [MethodImplAttribute(MethodImplOptions.InternalCall)] - internal extern object InternalInvoke(object? obj, in Span parameters, out Exception exc); + internal extern object InternalInvoke(object? obj, IntPtr *args, out Exception exc); public override RuntimeMethodHandle MethodHandle { diff --git a/src/mono/System.Private.CoreLib/src/System/Runtime/CompilerServices/JitHelpers.cs b/src/mono/System.Private.CoreLib/src/System/Runtime/CompilerServices/JitHelpers.cs index 7dbf6f02b5bc9..40d30c6001599 100644 --- a/src/mono/System.Private.CoreLib/src/System/Runtime/CompilerServices/JitHelpers.cs +++ b/src/mono/System.Private.CoreLib/src/System/Runtime/CompilerServices/JitHelpers.cs @@ -12,5 +12,8 @@ internal static class JitHelpers [Intrinsic] public static int EnumCompareTo(T x, T y) where T : struct, Enum => throw new NotImplementedException(); #pragma warning restore IDE0060 + + [Intrinsic] + internal static void DisableInline () => throw new NotImplementedException(); } } diff --git a/src/mono/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.Mono.cs b/src/mono/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.Mono.cs index 8f3dca0db13be..602ae2999c610 100644 --- a/src/mono/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.Mono.cs +++ b/src/mono/System.Private.CoreLib/src/System/Runtime/InteropServices/Marshal.Mono.cs @@ -118,9 +118,19 @@ public int GetHashCode((Type, string) key) private static Dictionary<(Type, string), ICustomMarshaler>? MarshalerInstanceCache; +#pragma warning disable 8500 +#pragma warning disable 9080 + private static unsafe void SetInvokeArgs(ref string cookie, IntPtr *params_byref) + { + ByReference objRef = ByReference.Create(ref cookie); + *(ByReference*)params_byref = objRef; + } +#pragma warning restore 9080 +#pragma warning restore 8500 + [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2070:UnrecognizedReflectionPattern", Justification = "Implementation detail of MarshalAs.CustomMarshaler")] - internal static ICustomMarshaler? GetCustomMarshalerInstance(Type type, string cookie) + internal static unsafe ICustomMarshaler? GetCustomMarshalerInstance(Type type, string cookie) { var key = (type, cookie); @@ -163,7 +173,10 @@ public int GetHashCode((Type, string) key) Exception? exc; try { - result = (ICustomMarshaler?)getInstanceMethod.InternalInvoke(null, new object[] { cookie }, out exc); + IntPtr byrefStorage = default; + IntPtr *pbyrefStorage = &byrefStorage; + SetInvokeArgs(ref cookie, pbyrefStorage); + result = (ICustomMarshaler?)getInstanceMethod.InternalInvoke(null, pbyrefStorage, out exc); } catch (Exception e) { diff --git a/src/mono/System.Private.CoreLib/src/System/RuntimeMethodHandle.cs b/src/mono/System.Private.CoreLib/src/System/RuntimeMethodHandle.cs index f1b30c29f7df5..4280686a3c4f6 100644 --- a/src/mono/System.Private.CoreLib/src/System/RuntimeMethodHandle.cs +++ b/src/mono/System.Private.CoreLib/src/System/RuntimeMethodHandle.cs @@ -90,7 +90,24 @@ internal bool IsNullHandle() return value == IntPtr.Zero; } - // Temporary placeholder until Mono adds support for supporting boxing true Nullables. - internal static object? ReboxFromNullable(object? src) => src; + [MethodImplAttribute(MethodImplOptions.InternalCall)] + private static extern void ReboxFromNullable (object? src, ObjectHandleOnStack res); + + [MethodImplAttribute(MethodImplOptions.InternalCall)] + private static extern void ReboxToNullable (object? src, QCallTypeHandle destNullableType, ObjectHandleOnStack res); + + internal static object ReboxFromNullable(object? src) + { + object? res = null; + ReboxFromNullable(src, ObjectHandleOnStack.Create(ref res)); + return res!; + } + + internal static object ReboxToNullable(object? src, RuntimeType destNullableType) + { + object? res = null; + ReboxToNullable(src, new QCallTypeHandle(ref destNullableType), ObjectHandleOnStack.Create(ref res)); + return res!; + } } } diff --git a/src/mono/System.Private.CoreLib/src/System/RuntimeType.Mono.cs b/src/mono/System.Private.CoreLib/src/System/RuntimeType.Mono.cs index cbedc793bb2e7..db2ecd2a079bc 100644 --- a/src/mono/System.Private.CoreLib/src/System/RuntimeType.Mono.cs +++ b/src/mono/System.Private.CoreLib/src/System/RuntimeType.Mono.cs @@ -1648,83 +1648,12 @@ internal override FieldInfo GetField(FieldInfo fromNoninstanciated) } } - /// - /// Verify and optionally convert the value for special cases. - /// - /// Not yet implemented in Mono: True if the value should be considered a value type, False otherwise - internal bool CheckValue( - ref object? value, - ref ParameterCopyBackAction copyBack, - Binder? binder, - CultureInfo? culture, - BindingFlags invokeAttr) + // FIXME Reuse with coreclr + private CheckValueStatus TryChangeTypeSpecial( + ref object value, + out bool isValueType) { - // Already fast-pathed by the caller. - Debug.Assert(!ReferenceEquals(value?.GetType(), this)); - - copyBack = ParameterCopyBackAction.Copy; - - CheckValueStatus status = TryConvertToType(ref value); - if (status == CheckValueStatus.Success) - { - return true; - } - - if (status == CheckValueStatus.NotSupported_ByRefLike) - { - throw new NotSupportedException(SR.Format(SR.NotSupported_ByRefLike, value?.GetType(), this)); - } - - if ((invokeAttr & BindingFlags.ExactBinding) == BindingFlags.ExactBinding) - { - throw new ArgumentException(SR.Format(SR.Arg_ObjObjEx, value?.GetType(), this)); - } - - if (binder != null && binder != DefaultBinder) - { - value = binder.ChangeType(value!, this, culture); - return true; - } - - throw new ArgumentException(SR.Format(SR.Arg_ObjObjEx, value?.GetType(), this)); - } - - private enum CheckValueStatus - { - Success = 0, - ArgumentException, - NotSupported_ByRefLike - } - - private CheckValueStatus TryConvertToType(ref object? value) - { - if (IsInstanceOfType(value)) - return CheckValueStatus.Success; - - if (IsByRef) - { - Type elementType = GetElementType(); - if (elementType.IsByRefLike) - { - return CheckValueStatus.NotSupported_ByRefLike; - } - - if (value == null || elementType.IsInstanceOfType(value)) - { - return CheckValueStatus.Success; - } - } - - if (value == null) - { - if (IsByRefLike) - { - return CheckValueStatus.NotSupported_ByRefLike; - } - - return CheckValueStatus.Success; - } - + isValueType = true; if (IsEnum) { Type? type = Enum.GetUnderlyingType(this); @@ -1763,14 +1692,10 @@ private CheckValueStatus TryConvertToType(ref object? value) } } + isValueType = false; return CheckValueStatus.ArgumentException; } - // Stub method to allow for shared code with CoreClr. -#pragma warning disable CA1822, IDE0060 - internal bool TryByRefFastPath(ref object arg, ref bool isValueType) => false; -#pragma warning restore CA1822, IDE0060 - // Binder uses some incompatible conversion rules. For example // int value cannot be used with decimal parameter but in other // ways it's more flexible than normal convertor, for example @@ -2162,6 +2087,16 @@ public override string ToString() [MethodImplAttribute(MethodImplOptions.InternalCall)] private static extern object CreateInstanceInternal(QCallTypeHandle type); + [MethodImpl(MethodImplOptions.InternalCall)] + private static extern void AllocateValueType(QCallTypeHandle type, object? value, ObjectHandleOnStack res); + + internal static object AllocateValueType(RuntimeType type, object? value) + { + object? res = null; + AllocateValueType(new QCallTypeHandle(ref type), value, ObjectHandleOnStack.Create(ref res)); + return res!; + } + [MethodImplAttribute(MethodImplOptions.InternalCall)] private static extern void GetDeclaringMethod(QCallTypeHandle type, ObjectHandleOnStack res); diff --git a/src/mono/mono/component/debugger-agent.c b/src/mono/mono/component/debugger-agent.c index 4a80ea28abe99..2be637db94ea9 100644 --- a/src/mono/mono/component/debugger-agent.c +++ b/src/mono/mono/component/debugger-agent.c @@ -6175,12 +6175,7 @@ mono_do_invoke_method (DebuggerTlsData *tls, Buffer *buf, InvokeData *invoke, gu err = decode_value (sig->params [i], domain, arg_buf [i], p, &p, end, TRUE); if (err != ERR_NONE) break; - if (mono_class_is_nullable (arg_class)) { - args [i] = mono_nullable_box (arg_buf [i], arg_class, error); - mono_error_assert_ok (error); - } else { - args [i] = arg_buf [i]; - } + args [i] = arg_buf [i]; } } diff --git a/src/mono/mono/metadata/class-setup-vtable.c b/src/mono/mono/metadata/class-setup-vtable.c index e9dc6997d89e7..19c32f25fb144 100644 --- a/src/mono/mono/metadata/class-setup-vtable.c +++ b/src/mono/mono/metadata/class-setup-vtable.c @@ -1065,7 +1065,7 @@ handle_dim_conflicts (MonoMethod **vtable, MonoClass *klass, GHashTable *conflic int nentries = 0; MonoMethod *impl = NULL; for (l = entries; l; l = l->next) { - if (l->data) { + if (l->data && l->data != impl) { nentries ++; impl = (MonoMethod*)l->data; } diff --git a/src/mono/mono/metadata/icall-def.h b/src/mono/mono/metadata/icall-def.h index 71670c578440a..f61cc2b688bed 100644 --- a/src/mono/mono/metadata/icall-def.h +++ b/src/mono/mono/metadata/icall-def.h @@ -357,7 +357,7 @@ HANDLES(RASSEM_7, "InternalGetReferencedAssemblies", ves_icall_System_Reflection ICALL_TYPE(MCMETH, "System.Reflection.RuntimeConstructorInfo", MCMETH_1) HANDLES(MCMETH_1, "GetGenericMethodDefinition_impl", ves_icall_RuntimeMethodInfo_GetGenericMethodDefinition, MonoReflectionMethod, 1, (MonoReflectionMethod)) -HANDLES(MCMETH_2, "InternalInvoke", ves_icall_InternalInvoke, MonoObject, 4, (MonoReflectionMethod, MonoObject, MonoSpanOfObjects_ref, MonoExceptionOut)) +HANDLES(MCMETH_2, "InternalInvoke", ves_icall_InternalInvoke, MonoObject, 4, (MonoReflectionMethod, MonoObject, gpointer_ref, MonoExceptionOut)) HANDLES(MCMETH_5, "InvokeClassConstructor", ves_icall_InvokeClassConstructor, void, 1, (MonoQCallTypeHandle)) HANDLES_REUSE_WRAPPER(MCMETH_4, "get_metadata_token", ves_icall_reflection_get_token) @@ -474,8 +474,11 @@ HANDLES_REUSE_WRAPPER(RFH_2, "SetValueInternal", ves_icall_RuntimeFieldInfo_SetV ICALL_TYPE(MHAN, "System.RuntimeMethodHandle", MHAN_1) HANDLES(MHAN_1, "GetFunctionPointer", ves_icall_RuntimeMethodHandle_GetFunctionPointer, gpointer, 1, (MonoMethod_ptr)) +HANDLES(MAHN_3, "ReboxFromNullable", ves_icall_RuntimeMethodHandle_ReboxFromNullable, void, 2, (MonoObject, MonoObjectHandleOnStack)) +HANDLES(MAHN_2, "ReboxToNullable", ves_icall_RuntimeMethodHandle_ReboxToNullable, void, 3, (MonoObject, MonoQCallTypeHandle, MonoObjectHandleOnStack)) -ICALL_TYPE(RT, "System.RuntimeType", RT_1) +ICALL_TYPE(RT, "System.RuntimeType", RT_31) +HANDLES(RT_31, "AllocateValueType", ves_icall_System_RuntimeType_AllocateValueType, void, 3, (MonoQCallTypeHandle, MonoObject, MonoObjectHandleOnStack)) HANDLES(RT_1, "CreateInstanceInternal", ves_icall_System_RuntimeType_CreateInstanceInternal, MonoObject, 1, (MonoQCallTypeHandle)) HANDLES(RT_2, "GetConstructors_native", ves_icall_RuntimeType_GetConstructors_native, GPtrArray_ptr, 2, (MonoQCallTypeHandle, guint32)) HANDLES(RT_30, "GetCorrespondingInflatedMethod", ves_icall_RuntimeType_GetCorrespondingInflatedMethod, MonoReflectionMethod, 2, (MonoQCallTypeHandle, MonoReflectionMethod)) diff --git a/src/mono/mono/metadata/icall.c b/src/mono/mono/metadata/icall.c index dc3a22f72c7cd..8c6c7329042b0 100644 --- a/src/mono/mono/metadata/icall.c +++ b/src/mono/mono/metadata/icall.c @@ -1812,6 +1812,10 @@ guint32 ves_icall_RuntimeTypeHandle_IsInstanceOfType (MonoQCallTypeHandle type_handle, MonoObjectHandle obj, MonoError *error) { MonoType *type = type_handle.type; + + if (m_type_is_byref (type)) + return FALSE; + MonoClass *klass = mono_class_from_mono_type_internal (type); mono_class_init_checked (klass, error); return_val_if_nok (error, FALSE); @@ -1820,6 +1824,49 @@ ves_icall_RuntimeTypeHandle_IsInstanceOfType (MonoQCallTypeHandle type_handle, M return !MONO_HANDLE_IS_NULL (inst); } +void +ves_icall_RuntimeMethodHandle_ReboxToNullable (MonoObjectHandle obj, MonoQCallTypeHandle type_handle, MonoObjectHandleOnStack res, MonoError *error) +{ + MonoType *type = type_handle.type; + MonoClass *klass = mono_class_from_mono_type_internal (type); + + mono_class_init_checked (klass, error); + goto_if_nok (error, error_ret); + + MonoObject *obj_res = mono_object_new_checked (klass, error); + goto_if_nok (error, error_ret); + gpointer dest = mono_object_unbox_internal (obj_res); + + mono_nullable_init (dest, MONO_HANDLE_RAW (obj), klass); + + HANDLE_ON_STACK_SET (res, obj_res); + return; +error_ret: + HANDLE_ON_STACK_SET (res, NULL); +} + +void +ves_icall_RuntimeMethodHandle_ReboxFromNullable (MonoObjectHandle obj, MonoObjectHandleOnStack res, MonoError *error) +{ + if (MONO_HANDLE_IS_NULL (obj)) { + HANDLE_ON_STACK_SET (res, NULL); + return; + } + + MonoVTable *vtable = MONO_HANDLE_GETVAL (obj, vtable); + MonoClass *klass = vtable->klass; + MonoObject *obj_res; + + if (!mono_class_is_nullable (klass)) { + obj_res = MONO_HANDLE_RAW (obj); + } else { + gpointer vbuf = mono_object_unbox_internal (MONO_HANDLE_RAW (obj)); + obj_res = mono_nullable_box (vbuf, klass, error); + } + + HANDLE_ON_STACK_SET (res, obj_res); +} + guint32 ves_icall_RuntimeTypeHandle_GetAttributes (MonoQCallTypeHandle type_handle) { @@ -2114,31 +2161,9 @@ ves_icall_RuntimeFieldInfo_SetValueInternal (MonoReflectionFieldHandle field, Mo MonoGenericClass *gclass = type->data.generic_class; g_assert (!gclass->context.class_inst->is_open); - if (mono_class_is_nullable (mono_class_from_mono_type_internal (type))) { - MonoClass *nklass = mono_class_from_mono_type_internal (type); - - /* - * Convert the boxed vtype into a Nullable structure. - * This is complicated by the fact that Nullables have - * a variable structure. - */ - MonoObjectHandle nullable = mono_object_new_handle (nklass, error); - return_if_nok (error); - - MonoGCHandle nullable_gchandle = 0; - guint8 *nval = (guint8*)mono_object_handle_pin_unbox (nullable, &nullable_gchandle); - mono_nullable_init_from_handle (nval, value, nklass); - - isref = FALSE; - value_gchandle = nullable_gchandle; - v = (gchar*)nval; - } - else { - isref = !m_class_is_valuetype (gclass->container_class); - if (!isref && !MONO_HANDLE_IS_NULL (value)) { - v = (char*)mono_object_handle_pin_unbox (value, &value_gchandle); - }; - } + isref = !m_class_is_valuetype (gclass->container_class); + if (!isref && !MONO_HANDLE_IS_NULL (value)) + v = (char*)mono_object_handle_pin_unbox (value, &value_gchandle); break; } default: @@ -3403,11 +3428,10 @@ ves_icall_RuntimeMethodInfo_GetGenericArguments (MonoReflectionMethodHandle ref_ MonoObjectHandle ves_icall_InternalInvoke (MonoReflectionMethodHandle method_handle, MonoObjectHandle this_arg_handle, - MonoSpanOfObjects *params_span, MonoExceptionHandleOut exception_out, MonoError *error) + gpointer *params_byref, MonoExceptionHandleOut exception_out, MonoError *error) { MonoReflectionMethod* const method = MONO_HANDLE_RAW (method_handle); MonoObject* const this_arg = MONO_HANDLE_RAW (this_arg_handle); - g_assert (params_span != NULL); /* * Invoke from reflection is supposed to always be a virtual call (the API @@ -3416,7 +3440,6 @@ ves_icall_InternalInvoke (MonoReflectionMethodHandle method_handle, MonoObjectHa */ MonoMethod *m = method->method; MonoMethodSignature* const sig = mono_method_signature_internal (m); - int pcount = 0; void *obj = this_arg; MonoObject *result = NULL; MonoArray *arr = NULL; @@ -3447,11 +3470,11 @@ ves_icall_InternalInvoke (MonoReflectionMethodHandle method_handle, MonoObjectHa /* Array constructor */ if (m_class_get_rank (m->klass) && !strcmp (m->name, ".ctor")) { - pcount = mono_span_length (params_span); - uintptr_t * const lengths = g_newa (uintptr_t, pcount); + int pcount = sig->param_count; + uintptr_t *lengths = g_newa (uintptr_t, pcount); /* Note: the synthetized array .ctors have int32 as argument type */ for (int i = 0; i < pcount; ++i) - lengths [i] = *(int32_t*) ((char*)mono_span_get (params_span, MonoObject*, i) + sizeof (MonoObject)); + lengths [i] = *(int32_t*) params_byref [i]; if (m_class_get_rank (m->klass) == 1 && sig->param_count == 2 && m_class_get_rank (m_class_get_element_class (m->klass))) { /* This is a ctor for jagged arrays. MS creates an array of arrays. */ @@ -3477,11 +3500,11 @@ ves_icall_InternalInvoke (MonoReflectionMethodHandle method_handle, MonoObjectHa } else { g_assert (pcount == (m_class_get_rank (m->klass) * 2)); /* The arguments are lower-bound-length pairs */ - intptr_t * const lower_bounds = (intptr_t *)g_alloca (sizeof (intptr_t) * pcount); + intptr_t *lower_bounds = (intptr_t *)g_alloca (sizeof (intptr_t) * pcount); for (int i = 0; i < pcount / 2; ++i) { - lower_bounds [i] = *(int32_t*) ((char*)mono_span_get (params_span, MonoObject*, (i * 2)) + sizeof (MonoObject)); - lengths [i] = *(int32_t*) ((char*)mono_span_get (params_span, MonoObject*, (i * 2) + 1) + sizeof (MonoObject)); + lower_bounds [i] = *(int32_t*) params_byref [i * 2]; + lengths [i] = *(int32_t*) params_byref [i * 2 + 1]; } arr = mono_array_new_full_checked (m->klass, lengths, lower_bounds, error); @@ -3489,7 +3512,9 @@ ves_icall_InternalInvoke (MonoReflectionMethodHandle method_handle, MonoObjectHa goto exit; } } - result = mono_runtime_invoke_span_checked (m, obj, params_span, error); + + result = mono_runtime_try_invoke_byrefs (m, obj, params_byref, NULL, error); + goto exit; return_null: result = NULL; @@ -6157,6 +6182,29 @@ ves_icall_System_RuntimeType_CreateInstanceInternal (MonoQCallTypeHandle type_ha return mono_object_new_handle (klass, error); } +/* Only used for value types */ +void +ves_icall_System_RuntimeType_AllocateValueType (MonoQCallTypeHandle type_handle, MonoObjectHandle value_h, MonoObjectHandleOnStack res, MonoError *error) +{ + MonoType *type = type_handle.type; + MonoClass *klass = mono_class_from_mono_type_internal (type); + + mono_class_init_checked (klass, error); + goto_if_nok (error, error_ret); + + MonoObject *obj_res = mono_object_new_checked (klass, error); + goto_if_nok (error, error_ret); + + MonoObject *value = MONO_HANDLE_RAW (value_h); + if (value) + mono_value_copy_internal (mono_object_unbox_internal (obj_res), mono_object_unbox_internal (value), klass); + + HANDLE_ON_STACK_SET (res, obj_res); + return; +error_ret: + HANDLE_ON_STACK_SET (res, NULL); +} + MonoReflectionMethodHandle ves_icall_RuntimeMethodInfo_get_base_method (MonoReflectionMethodHandle m, MonoBoolean definition, MonoError *error) { diff --git a/src/mono/mono/metadata/marshal-lightweight.c b/src/mono/mono/metadata/marshal-lightweight.c index 964fd84823a6c..072ddf5e176a3 100644 --- a/src/mono/mono/metadata/marshal-lightweight.c +++ b/src/mono/mono/metadata/marshal-lightweight.c @@ -289,7 +289,6 @@ emit_invoke_call (MonoMethodBuilder *mb, MonoMethod *method, gboolean virtual_, gboolean need_direct_wrapper) { int i; - int *tmp_nullable_locals; gboolean void_ret = FALSE; gboolean string_ctor = method && method->string_ctor; @@ -308,8 +307,6 @@ emit_invoke_call (MonoMethodBuilder *mb, MonoMethod *method, } } - tmp_nullable_locals = g_new0 (int, sig->param_count); - for (i = 0; i < sig->param_count; i++) { MonoType *t = sig->params [i]; int type; @@ -322,16 +319,6 @@ emit_invoke_call (MonoMethodBuilder *mb, MonoMethod *method, if (m_type_is_byref (t)) { mono_mb_emit_byte (mb, CEE_LDIND_I); - /* A Nullable type don't have a boxed form, it's either null or a boxed T. - * So to make this work we unbox it to a local variablee and push a reference to that. - */ - if (t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type_internal (t))) { - tmp_nullable_locals [i] = mono_mb_add_local (mb, m_class_get_byval_arg (mono_class_from_mono_type_internal (t))); - - mono_mb_emit_op (mb, CEE_UNBOX_ANY, mono_class_from_mono_type_internal (t)); - mono_mb_emit_stloc (mb, tmp_nullable_locals [i]); - mono_mb_emit_ldloc_addr (mb, tmp_nullable_locals [i]); - } continue; } @@ -384,13 +371,7 @@ emit_invoke_call (MonoMethodBuilder *mb, MonoMethod *method, } mono_mb_emit_no_nullcheck (mb); mono_mb_emit_byte (mb, CEE_LDIND_I); - if (mono_class_is_nullable (mono_class_from_mono_type_internal (sig->params [i]))) { - /* Need to convert a boxed vtype to an mp to a Nullable struct */ - mono_mb_emit_op (mb, CEE_UNBOX, mono_class_from_mono_type_internal (sig->params [i])); - mono_mb_emit_op (mb, CEE_LDOBJ, mono_class_from_mono_type_internal (sig->params [i])); - } else { - mono_mb_emit_op (mb, CEE_LDOBJ, mono_class_from_mono_type_internal (sig->params [i])); - } + mono_mb_emit_op (mb, CEE_LDOBJ, mono_class_from_mono_type_internal (sig->params [i])); break; default: g_assert_not_reached (); @@ -408,16 +389,9 @@ emit_invoke_call (MonoMethodBuilder *mb, MonoMethod *method, if (m_type_is_byref (sig->ret)) { /* perform indirect load and return by value */ - int pos; - mono_mb_emit_byte (mb, CEE_DUP); - pos = mono_mb_emit_branch (mb, CEE_BRTRUE); - mono_mb_emit_exception_full (mb, "Mono", "NullByRefReturnException", NULL); - mono_mb_patch_branch (mb, pos); - guint8 ldind_op; MonoType* ret_byval = m_class_get_byval_arg (mono_class_from_mono_type_internal (sig->ret)); g_assert (!m_type_is_byref (ret_byval)); - // TODO: Handle null references ldind_op = mono_type_to_ldind (ret_byval); /* taken from similar code in mini-generic-sharing.c * we need to use mono_mb_emit_op to add method data when loading @@ -470,28 +444,6 @@ emit_invoke_call (MonoMethodBuilder *mb, MonoMethod *method, if (!void_ret) mono_mb_emit_stloc (mb, loc_res); - - /* Convert back nullable-byref arguments */ - for (i = 0; i < sig->param_count; i++) { - MonoType *t = sig->params [i]; - - /* - * Box the result and put it back into the array, the caller will have - * to obtain it from there. - */ - if (m_type_is_byref (t) && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type_internal (t))) { - mono_mb_emit_ldarg (mb, 1); - mono_mb_emit_icon (mb, TARGET_SIZEOF_VOID_P * i); - mono_mb_emit_byte (mb, CEE_ADD); - - mono_mb_emit_ldloc (mb, tmp_nullable_locals [i]); - mono_mb_emit_op (mb, CEE_BOX, mono_class_from_mono_type_internal (t)); - - mono_mb_emit_byte (mb, CEE_STIND_REF); - } - } - - g_free (tmp_nullable_locals); } static void diff --git a/src/mono/mono/metadata/object-internals.h b/src/mono/mono/metadata/object-internals.h index 7e32a0a905cca..3967256d5bcbb 100644 --- a/src/mono/mono/metadata/object-internals.h +++ b/src/mono/mono/metadata/object-internals.h @@ -1879,12 +1879,8 @@ void mono_runtime_invoke_handle_void (MonoMethod *method, MonoObjectHandle obj, void **params, MonoError* error); MonoObject* -mono_runtime_try_invoke_array (MonoMethod *method, void *obj, MonoArray *params, - MonoObject **exc, MonoError *error); - -MonoObject* -mono_runtime_invoke_span_checked (MonoMethod *method, void *obj, MonoSpanOfObjects *params, - MonoError *error); +mono_runtime_try_invoke_byrefs (MonoMethod *method, void *obj, gpointer *params_byref, + MonoObject **exc, MonoError *error); void* mono_compile_method_checked (MonoMethod *method, MonoError *error); diff --git a/src/mono/mono/metadata/object.c b/src/mono/mono/metadata/object.c index fde5f8ed8476f..6e8e933bce635 100644 --- a/src/mono/mono/metadata/object.c +++ b/src/mono/mono/metadata/object.c @@ -2460,16 +2460,59 @@ mono_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject ** MonoObject *res; MONO_ENTER_GC_UNSAFE; ERROR_DECL (error); + gboolean has_byref_nullables = FALSE; + void **params_copy = NULL; + void **params_arg; + + MonoMethodSignature *sig = mono_method_signature_internal (method); + for (int i = 0; i < sig->param_count; i++) { + MonoType *t = sig->params [i]; + if (t->type == MONO_TYPE_GENERICINST && t->data.generic_class->container_class == mono_defaults.generic_nullable_class) { + MonoClass *klass = mono_class_from_mono_type_internal (t); + MonoObject *boxed_vt = (MonoObject*)params [i]; + gpointer unboxed_vt = mono_object_unbox_internal (boxed_vt); + gpointer nullable_vt = g_alloca (mono_class_value_size (klass, NULL)); + + mono_nullable_init_unboxed (nullable_vt, unboxed_vt, klass); + if (!params_copy) { + params_copy = g_alloca (sig->param_count * sizeof (void*)); + memcpy (params_copy, params, sig->param_count * sizeof (void*)); + } + params_copy [i] = nullable_vt; + if (m_type_is_byref (t)) + has_byref_nullables = TRUE; + } + } + + if (params_copy != NULL) + params_arg = params_copy; + else + params_arg = params; + if (exc) { - res = mono_runtime_try_invoke (method, obj, params, exc, error); + res = mono_runtime_try_invoke (method, obj, params_arg, exc, error); if (*exc == NULL && !is_ok(error)) { *exc = (MonoObject*) mono_error_convert_to_exception (error); } else mono_error_cleanup (error); } else { - res = mono_runtime_invoke_checked (method, obj, params, error); + res = mono_runtime_invoke_checked (method, obj, params_arg, error); mono_error_raise_exception_deprecated (error); /* OK to throw, external only without a good alternative */ } + + if (has_byref_nullables) { + // The params_args will contain the ref to the modified nullable. We need + // to return it as boxed vt or NULL + for (int i = 0; i < sig->param_count; i++) { + MonoType *t = sig->params [i]; + if (t->type == MONO_TYPE_GENERICINST && m_type_is_byref (t) && t->data.generic_class->container_class == mono_defaults.generic_nullable_class) { + MonoClass *klass = mono_class_from_mono_type_internal (t); + gpointer nullable_vt = params_arg [i]; + params [i] = mono_nullable_box (nullable_vt, klass, error); + } + } + } + MONO_EXIT_GC_UNSAFE; return res; } @@ -4554,114 +4597,192 @@ mono_runtime_try_exec_main (MonoMethod *method, MonoArray *args, MonoObject **ex return do_try_exec_main (method, args, exc); } -/** invoke_span_extract_argument: - * @params: span of object arguments to the method. - * @i: the index of the argument to extract. - * @t: ith type from the method signature. - * @has_byref_nullables: outarg - TRUE if method expects a byref nullable argument - * @error: set on error. - * - * Given an array of method arguments, return the ith one using the corresponding type - * to perform necessary unboxing. If method expects a ref nullable argument, writes TRUE to @has_byref_nullables. - * - * On failure sets @error and returns NULL. - */ +static MonoObject* +mono_boxed_intptr_to_pointer (MonoObject *boxed_intptr, MonoType *ret_type, MonoError *error) +{ + MonoClass *pointer_class; + void *box_args [2]; + MonoObject *box_exc; + + /* + * The runtime-invoke wrapper returns a boxed IntPtr, need to + * convert it to a Pointer object. + */ + pointer_class = mono_class_get_pointer_class (); + + MONO_STATIC_POINTER_INIT (MonoMethod, box_method) + box_method = mono_class_get_method_from_name_checked (pointer_class, "Box", -1, 0, error); + mono_error_assert_ok (error); + MONO_STATIC_POINTER_INIT_END (MonoMethod, box_method) + + if (boxed_intptr) { + g_assert (boxed_intptr->vtable->klass == mono_defaults.int_class); + box_args [0] = ((MonoIntPtr*)boxed_intptr)->m_value; + } else { + box_args [0] = NULL; + } + if (m_type_is_byref (ret_type)) { + // byref is already unboxed by the invoke code + MonoType *tmpret = mono_metadata_type_dup (NULL, ret_type); + tmpret->byref__ = FALSE; + MonoReflectionTypeHandle type_h = mono_type_get_object_handle (tmpret, error); + box_args [1] = MONO_HANDLE_RAW (type_h); + mono_metadata_free_type (tmpret); + } else { + MonoReflectionTypeHandle type_h = mono_type_get_object_handle (ret_type, error); + box_args [1] = MONO_HANDLE_RAW (type_h); + } + return_val_if_nok (error, NULL); + + MonoObject *res = mono_runtime_try_invoke (box_method, NULL, box_args, &box_exc, error); + g_assert (box_exc == NULL); + mono_error_assert_ok (error); + + return res; +} + +static gpointer +extract_this_ptr (MonoMethod *method, gpointer this_ptr, MonoObject **res, MonoError *error) +{ + gpointer new_this_ptr = this_ptr; + if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) { + MonoObject *newobj; + if (!this_ptr) { + newobj = mono_object_new_checked (method->klass, error); + MONO_HANDLE_PIN (newobj); + return_val_if_nok (error, NULL); + if (m_class_is_valuetype (method->klass)) + new_this_ptr = mono_object_unbox_internal (newobj); + else + new_this_ptr = newobj; + *res = newobj; + } else if (m_class_is_valuetype (method->klass)) { + newobj = mono_value_box_checked (method->klass, this_ptr, error); + MONO_HANDLE_PIN (newobj); + return_val_if_nok (error, NULL); + *res = newobj; + } else { + *res = (MonoObject*)this_ptr; + } + + } else { + if (mono_class_is_nullable (method->klass)) { + if (method->flags & METHOD_ATTRIBUTE_STATIC) { + new_this_ptr = NULL; + } else { + /* Convert the unboxed vtype into a Nullable structure */ + MonoObject *newobj = mono_object_new_checked (method->klass, error); + MONO_HANDLE_PIN (newobj); + + mono_nullable_init_unboxed ((guint8 *)mono_object_unbox_internal (newobj), this_ptr, method->klass); + new_this_ptr = mono_object_unbox_internal (newobj); + } + } + *res = NULL; + } + return new_this_ptr; +} + static gpointer -invoke_span_extract_argument (MonoSpanOfObjects *params_span, int i, MonoType *t, MonoObject **pa_obj, gboolean* has_byref_nullables, MonoError *error) +invoke_array_extract_argument (MonoArray *array, int i, MonoType *t, gboolean* has_byref_nullables, MonoError *error) { MonoType *t_orig = t; gpointer result = NULL; - *pa_obj = NULL; error_init (error); - again: - switch (t->type) { - case MONO_TYPE_U1: - case MONO_TYPE_I1: - case MONO_TYPE_BOOLEAN: - case MONO_TYPE_U2: - case MONO_TYPE_I2: - case MONO_TYPE_CHAR: - case MONO_TYPE_U: - case MONO_TYPE_I: - case MONO_TYPE_U4: - case MONO_TYPE_I4: - case MONO_TYPE_U8: - case MONO_TYPE_I8: - case MONO_TYPE_R4: - case MONO_TYPE_R8: - case MONO_TYPE_VALUETYPE: - if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type_internal (t_orig))) { - /* The runtime invoke wrapper needs the original boxed vtype, it does handle byref values as well. */ - *pa_obj = mono_span_get (params_span, MonoObject*, i); - result = *pa_obj; - if (m_type_is_byref (t)) - *has_byref_nullables = TRUE; - } else { - /* MS seems to create the objects if a null is passed in */ - gboolean was_null = FALSE; - if (!mono_span_get (params_span, MonoObject*, i)) { - MonoObject *o = mono_object_new_checked (mono_class_from_mono_type_internal (t_orig), error); - return_val_if_nok (error, NULL); - mono_span_setref (params_span, i, o); - was_null = TRUE; - } - - if (m_type_is_byref (t)) { - /* - * We can't pass the unboxed vtype byref to the callee, since - * that would mean the callee would be able to modify boxed - * primitive types. So we (and MS) make a copy of the boxed - * object, pass that to the callee, and replace the original - * boxed object in the arg array with the copy. - */ - MonoObject *orig = mono_span_get (params_span, MonoObject*, i); - MonoObject *copy = mono_value_box_checked (orig->vtable->klass, mono_object_unbox_internal (orig), error); - return_val_if_nok (error, NULL); - mono_span_setref (params_span, i, copy); - } - *pa_obj = mono_span_get (params_span, MonoObject*, i); - result = mono_object_unbox_internal (*pa_obj); - if (!m_type_is_byref (t) && was_null) - mono_span_setref (params_span, i, NULL); +again: + switch (t->type) { + case MONO_TYPE_U1: + case MONO_TYPE_I1: + case MONO_TYPE_BOOLEAN: + case MONO_TYPE_U2: + case MONO_TYPE_I2: + case MONO_TYPE_CHAR: + case MONO_TYPE_U: + case MONO_TYPE_I: + case MONO_TYPE_U4: + case MONO_TYPE_I4: + case MONO_TYPE_U8: + case MONO_TYPE_I8: + case MONO_TYPE_R4: + case MONO_TYPE_R8: + case MONO_TYPE_VALUETYPE: + if (t->type == MONO_TYPE_VALUETYPE && mono_class_is_nullable (mono_class_from_mono_type_internal (t_orig))) { + // Convert from boxed_vt to pointer to nullable data + MonoClass *klass = mono_class_from_mono_type_internal (t_orig); + MonoObject *boxed_vt = mono_array_get_internal (array, MonoObject*, i); + MONO_HANDLE_PIN (boxed_vt); + gpointer unboxed_vt = mono_object_unbox_internal (boxed_vt); + MonoObject *nullable = mono_object_new_checked (klass, error); + MONO_HANDLE_PIN (nullable); + result = mono_object_unbox_internal (nullable); + mono_nullable_init_unboxed (result, unboxed_vt, klass); + if (m_type_is_byref (t)) + *has_byref_nullables = TRUE; + } else { + /* MS seems to create the objects if a null is passed in */ + gboolean was_null = FALSE; + if (!mono_array_get_internal (array, MonoObject*, i)) { + MonoObject *o = mono_object_new_checked (mono_class_from_mono_type_internal (t_orig), error); + return_val_if_nok (error, NULL); + mono_array_setref_internal (array, i, o); + was_null = TRUE; } - break; - case MONO_TYPE_STRING: - case MONO_TYPE_OBJECT: - case MONO_TYPE_CLASS: - case MONO_TYPE_ARRAY: - case MONO_TYPE_SZARRAY: if (m_type_is_byref (t)) { - result = mono_span_addr (params_span, MonoObject*, i); - // FIXME: I need to check this code path - } else { - *pa_obj = mono_span_get (params_span, MonoObject*, i); - result = *pa_obj; + /* + * We can't pass the unboxed vtype byref to the callee, since + * that would mean the callee would be able to modify boxed + * primitive types. So we (and MS) make a copy of the boxed + * object, pass that to the callee, and replace the original + * boxed object in the arg array with the copy. + */ + MonoObject *orig = mono_array_get_internal (array, MonoObject*, i); + MonoObject *copy = mono_value_box_checked (orig->vtable->klass, mono_object_unbox_internal (orig), error); + return_val_if_nok (error, NULL); + mono_array_setref_internal (array, i, copy); } - break; - case MONO_TYPE_GENERICINST: - if (m_type_is_byref (t)) - t = m_class_get_this_arg (t->data.generic_class->container_class); - else - t = m_class_get_byval_arg (t->data.generic_class->container_class); - goto again; - case MONO_TYPE_PTR: { - MonoObject *arg; - - /* The argument should be an IntPtr */ - arg = mono_span_get (params_span, MonoObject*, i); - if (arg == NULL) { - result = NULL; - } else { - g_assert (arg->vtable->klass == mono_defaults.int_class || arg->vtable->klass == mono_defaults.uint_class); - result = ((MonoIntPtr*)arg)->m_value; - } - break; + result = mono_array_get_internal (array, MonoObject*, i); + MONO_HANDLE_PIN (result); + result = mono_object_unbox_internal (result); + if (!m_type_is_byref (t) && was_null) + mono_array_set_internal (array, MonoObject*, i, NULL); } - default: - g_error ("type 0x%x not handled in mono_runtime_invoke_array", t_orig->type); + break; + case MONO_TYPE_STRING: + case MONO_TYPE_OBJECT: + case MONO_TYPE_CLASS: + case MONO_TYPE_ARRAY: + case MONO_TYPE_SZARRAY: + if (m_type_is_byref (t)) { + result = mono_array_addr_internal (array, MonoObject*, i); + } else { + result = mono_array_get_internal (array, MonoObject*, i); + MONO_HANDLE_PIN (result); } + break; + case MONO_TYPE_GENERICINST: + if (m_type_is_byref (t)) + t = m_class_get_this_arg (t->data.generic_class->container_class); + else + t = m_class_get_byval_arg (t->data.generic_class->container_class); + goto again; + case MONO_TYPE_PTR: { + MonoObject *arg; + /* The argument should be an IntPtr */ + arg = mono_array_get_internal (array, MonoObject*, i); + if (arg == NULL) { + result = NULL; + } else { + g_assert (arg->vtable->klass == mono_defaults.int_class || arg->vtable->klass == mono_defaults.uint_class); + result = ((MonoIntPtr*)arg)->m_value; + } + break; + } + default: + g_error ("type 0x%x not handled in mono_runtime_invoke_array", t_orig->type); + } return result; } + /** * mono_runtime_invoke_array: * \param method method to invoke @@ -4705,164 +4826,175 @@ mono_runtime_invoke_array (MonoMethod *method, void *obj, MonoArray *params, MonoObject *res; MONO_ENTER_GC_UNSAFE; ERROR_DECL (error); + gpointer *pa = NULL; + MonoMethodSignature *sig = mono_method_signature_internal (method); + gboolean has_byref_nullables = FALSE; + int param_count = sig->param_count; + + // This method has similar behavior as mono_runtime_try_invoke_byrefs. The only + // difference is that one receives an managed array of objects, passed over by + // the embedder, while the other one receives an array of byrefs, initialized by + // our reflection code. So the only difference lies in transforming these arguments + // to what is required by the runtime invoke wrapper. + + if (param_count) { + pa = g_newa (gpointer, param_count); + for (int i = 0; i < sig->param_count; i++) { + MonoType *t = sig->params [i]; + pa [i] = invoke_array_extract_argument (params, i, t, &has_byref_nullables, error); + goto_if_nok (error, return_error); + } + } + if (!strcmp (method->name, ".ctor") && mono_class_is_nullable (method->klass)) { + /* Need to create a boxed vtype instead */ + g_assert (!obj); + res = mono_value_box_checked (m_class_get_cast_class (method->klass), pa [0], error); + goto return_res; + } + + MonoObject *invoke_res; + obj = extract_this_ptr (method, obj, &res, error); + goto_if_nok (error, return_error); + if (exc) { - res = mono_runtime_try_invoke_array (method, obj, params, exc, error); + invoke_res = mono_runtime_try_invoke (method, obj, pa, exc, error); if (*exc) { res = NULL; mono_error_cleanup (error); - } else if (!is_ok (error)) { - *exc = (MonoObject*)mono_error_convert_to_exception (error); + goto return_res; + } else { + goto_if_nok (error, return_error); } } else { - res = mono_runtime_try_invoke_array (method, obj, params, NULL, error); + invoke_res = mono_runtime_invoke_checked (method, obj, pa, error); mono_error_raise_exception_deprecated (error); /* OK to throw, external only without a good alternative */ } + + if (!res) + res = invoke_res; + if (sig->ret->type == MONO_TYPE_PTR) { + res = mono_boxed_intptr_to_pointer (res, sig->ret, error); + goto_if_nok (error, return_error); + } + + if (has_byref_nullables) { + // The params_args will contain the ref to the modified nullable. We need + // to return it as boxed vt or NULL + for (int i = 0; i < param_count; i++) { + MonoType *t = sig->params [i]; + if (t->type == MONO_TYPE_GENERICINST && m_type_is_byref (t) && t->data.generic_class->container_class == mono_defaults.generic_nullable_class) { + MonoClass *klass = mono_class_from_mono_type_internal (t); + MonoObject *boxed_vt = mono_nullable_box (pa [i], klass, error); + goto_if_nok (error, return_error); + mono_array_setref_internal (params, i, boxed_vt); + } + } + } + + goto return_res; +return_error: + res = NULL; + if (exc) + *exc = (MonoObject*)mono_error_convert_to_exception (error); +return_res: MONO_EXIT_GC_UNSAFE; return res; } -static MonoObject* -mono_runtime_try_invoke_span (MonoMethod *method, void *obj, MonoSpanOfObjects *params_span, - MonoObject **exc, MonoError *error) +static gpointer +invoke_byrefs_extract_argument (gpointer *params_byref, int i, MonoType *t) { - error_init (error); + gpointer result = NULL; +again: + switch (t->type) { + case MONO_TYPE_U1: + case MONO_TYPE_I1: + case MONO_TYPE_BOOLEAN: + case MONO_TYPE_U2: + case MONO_TYPE_I2: + case MONO_TYPE_CHAR: + case MONO_TYPE_U: + case MONO_TYPE_I: + case MONO_TYPE_U4: + case MONO_TYPE_I4: + case MONO_TYPE_U8: + case MONO_TYPE_I8: + case MONO_TYPE_R4: + case MONO_TYPE_R8: + case MONO_TYPE_VALUETYPE: + result = params_byref [i]; + break; + case MONO_TYPE_STRING: + case MONO_TYPE_OBJECT: + case MONO_TYPE_CLASS: + case MONO_TYPE_ARRAY: + case MONO_TYPE_SZARRAY: + if (m_type_is_byref (t)) + result = params_byref [i]; + else + result = *(MonoObject**)params_byref [i]; + break; + case MONO_TYPE_GENERICINST: + if (m_type_is_byref (t)) + t = m_class_get_this_arg (t->data.generic_class->container_class); + else + t = m_class_get_byval_arg (t->data.generic_class->container_class); + goto again; + case MONO_TYPE_PTR: { + result = *(gpointer*)params_byref [i]; + break; + } + default: + g_error ("type 0x%x not handled in ves_icall_InternalInvoke", t->type); + } + + return result; +} +MonoObject* +mono_runtime_try_invoke_byrefs (MonoMethod *method, void *obj, gpointer *params_byref, + MonoObject **exc, MonoError *error) +{ MonoMethodSignature *sig = mono_method_signature_internal (method); + int params_length = sig->param_count; gpointer *pa = NULL; - MonoObject *res = NULL; - int i; - gboolean has_byref_nullables = FALSE; - int params_length = mono_span_length (params_span); + MonoObject *res; if (params_length > 0) { pa = g_newa (gpointer, params_length); - for (i = 0; i < params_length; i++) { + for (int i = 0; i < params_length; i++) { MonoType *t = sig->params [i]; - MonoObject *pa_obj; - pa [i] = invoke_span_extract_argument (params_span, i, t, &pa_obj, &has_byref_nullables, error); - if (pa_obj) - MONO_HANDLE_PIN (pa_obj); + pa [i] = invoke_byrefs_extract_argument (params_byref, i, t); goto_if_nok (error, exit_null); } } + if (!strcmp (method->name, ".ctor") && mono_class_is_nullable (method->klass)) { + /* Need to create a boxed vtype instead */ + g_assert (!obj); + res = mono_value_box_checked (m_class_get_cast_class (method->klass), pa [0], error); + goto exit; + } - if (!strcmp (method->name, ".ctor") && method->klass != mono_defaults.string_class) { - void *o = obj; - - if (mono_class_is_nullable (method->klass)) { - /* Need to create a boxed vtype instead */ - g_assert (!obj); - - if (params_length == 0) { - goto_if_nok (error, exit_null); - } else { - res = mono_value_box_checked (m_class_get_cast_class (method->klass), pa [0], error); - goto exit; - } - } - - if (!obj) { - MonoObjectHandle obj_h = mono_object_new_handle (method->klass, error); - goto_if_nok (error, exit_null); - obj = MONO_HANDLE_RAW (obj_h); - g_assert (obj); /*maybe we should raise a TLE instead?*/ - if (m_class_is_valuetype (method->klass)) - o = (MonoObject *)mono_object_unbox_internal ((MonoObject *)obj); - else - o = obj; - } else if (m_class_is_valuetype (method->klass)) { - MonoObjectHandle obj_h = mono_value_box_handle (method->klass, obj, error); - goto_if_nok (error, exit_null); - obj = MONO_HANDLE_RAW (obj_h); - } - - if (exc) { - mono_runtime_try_invoke (method, o, pa, exc, error); - } else { - mono_runtime_invoke_checked (method, o, pa, error); - } + obj = extract_this_ptr (method, obj, &res, error); + goto_if_nok (error, exit_null); - res = (MonoObject*)obj; - } else { - if (mono_class_is_nullable (method->klass)) { - if (method->flags & METHOD_ATTRIBUTE_STATIC) { - obj = NULL; - } else { - /* Convert the unboxed vtype into a Nullable structure */ - MonoObjectHandle nullable_h = mono_object_new_handle (method->klass, error); - goto_if_nok (error, exit_null); - MonoObject* nullable = MONO_HANDLE_RAW (nullable_h); - - MonoObjectHandle boxed_h = mono_value_box_handle (m_class_get_cast_class (method->klass), obj, error); - goto_if_nok (error, exit_null); - mono_nullable_init ((guint8 *)mono_object_unbox_internal (nullable), MONO_HANDLE_RAW (boxed_h), method->klass); - obj = mono_object_unbox_internal (nullable); - } - } + MonoObject *invoke_res; + if (exc) + invoke_res = mono_runtime_try_invoke (method, obj, pa, exc, error); + else + invoke_res = mono_runtime_invoke_checked (method, obj, pa, error); + goto_if_nok (error, exit_null); - /* obj must be already unboxed if needed */ - if (exc) { - res = mono_runtime_try_invoke (method, obj, pa, exc, error); - } else { - res = mono_runtime_invoke_checked (method, obj, pa, error); - } + if (!res) { + res = invoke_res; MONO_HANDLE_PIN (res); - goto_if_nok (error, exit_null); if (sig->ret->type == MONO_TYPE_PTR) { - MonoClass *pointer_class; - void *box_args [2]; - MonoObject *box_exc; - - /* - * The runtime-invoke wrapper returns a boxed IntPtr, need to - * convert it to a Pointer object. - */ - pointer_class = mono_class_get_pointer_class (); - - MONO_STATIC_POINTER_INIT (MonoMethod, box_method) - box_method = mono_class_get_method_from_name_checked (pointer_class, "Box", -1, 0, error); - mono_error_assert_ok (error); - MONO_STATIC_POINTER_INIT_END (MonoMethod, box_method) - - if (res) { - g_assert (res->vtable->klass == mono_defaults.int_class); - box_args [0] = ((MonoIntPtr*)res)->m_value; - } else { - box_args [0] = NULL; - } - if (m_type_is_byref (sig->ret)) { - // byref is already unboxed by the invoke code - MonoType *tmpret = mono_metadata_type_dup (NULL, sig->ret); - tmpret->byref__ = FALSE; - MonoReflectionTypeHandle type_h = mono_type_get_object_handle (tmpret, error); - box_args [1] = MONO_HANDLE_RAW (type_h); - mono_metadata_free_type (tmpret); - } else { - MonoReflectionTypeHandle type_h = mono_type_get_object_handle (sig->ret, error); - box_args [1] = MONO_HANDLE_RAW (type_h); - } + res = mono_boxed_intptr_to_pointer (res, sig->ret, error); goto_if_nok (error, exit_null); - - res = mono_runtime_try_invoke (box_method, NULL, box_args, &box_exc, error); - g_assert (box_exc == NULL); - mono_error_assert_ok (error); - } - - if (has_byref_nullables) { - /* - * The runtime invoke wrapper already converted byref nullables back, - * and stored them in pa, we just need to copy them back to the - * managed array. - */ - for (i = 0; i < params_length; i++) { - MonoType *t = sig->params [i]; - - if (m_type_is_byref (t) && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type_internal (t))) - mono_span_setref (params_span, i, pa [i]); - } } } + goto exit; exit_null: res = NULL; @@ -4870,99 +5002,6 @@ mono_runtime_try_invoke_span (MonoMethod *method, void *obj, MonoSpanOfObjects * return res; } -/** - * mono_runtime_invoke_array_checked: - * \param method method to invoke - * \param obj object instance - * \param params arguments to the method - * \param error set on failure. - * Invokes the method represented by \p method on the object \p obj. - * - * \p obj is the \c this pointer, it should be NULL for static - * methods, a \c MonoObject* for object instances and a pointer to - * the value type for value types. - * - * The \p params span contains the arguments to the method with the - * same convention: \c MonoObject* pointers for object instances and - * pointers to the value type otherwise. The \c _invoke_array - * variant takes a C# \c object[] as the \p params argument (\c MonoArray*): - * in this case the value types are boxed inside the - * respective reference representation. - * - * From unmanaged code you'll usually use the - * mono_runtime_invoke_checked() variant. - * - * Note that this function doesn't handle virtual methods for - * you, it will exec the exact method you pass: we still need to - * expose a function to lookup the derived class implementation - * of a virtual method (there are examples of this in the code, - * though). - * - * On failure or exception, \p error will be set. In that case, you - * can't use the \c MonoObject* result from the function. - * - * If the method returns a value type, it is boxed in an object - * reference. - */ -MonoObject* -mono_runtime_invoke_span_checked (MonoMethod *method, void *obj, MonoSpanOfObjects *params, - MonoError *error) -{ - error_init (error); - return mono_runtime_try_invoke_span (method, obj, params, NULL, error); -} - -/** - * mono_runtime_try_invoke_array: - * \param method method to invoke - * \param obj object instance - * \param params arguments to the method - * \param exc exception information. - * \param error set on failure. - * Invokes the method represented by \p method on the object \p obj. - * - * \p obj is the \c this pointer, it should be NULL for static - * methods, a \c MonoObject* for object instances and a pointer to - * the value type for value types. - * - * The \p params array contains the arguments to the method with the - * same convention: \c MonoObject* pointers for object instances and - * pointers to the value type otherwise. The \c _invoke_array - * variant takes a C# \c object[] as the params argument (\c MonoArray*): - * in this case the value types are boxed inside the - * respective reference representation. - * - * From unmanaged code you'll usually use the - * mono_runtime_invoke_checked() variant. - * - * Note that this function doesn't handle virtual methods for - * you, it will exec the exact method you pass: we still need to - * expose a function to lookup the derived class implementation - * of a virtual method (there are examples of this in the code, - * though). - * - * You can pass NULL as the \p exc argument if you don't want to catch - * exceptions, otherwise, \c *exc will be set to the exception thrown, if - * any. On other failures, \p error will be set. If an exception is - * thrown or there's an error, you can't use the \c MonoObject* result - * from the function. - * - * If the method returns a value type, it is boxed in an object - * reference. - */ -MonoObject* -mono_runtime_try_invoke_array (MonoMethod *method, void *obj, MonoArray *params, - MonoObject **exc, MonoError *error) -{ - MONO_REQ_GC_UNSAFE_MODE; - HANDLE_FUNCTION_ENTER (); - - MonoSpanOfObjects params_span = mono_span_create_from_object_array (params); - MonoObject *res = mono_runtime_try_invoke_span (method, obj, ¶ms_span, exc, error); - - HANDLE_FUNCTION_RETURN_VAL (res); -} - // FIXME these will move to header soon static MonoObjectHandle mono_object_new_by_vtable (MonoVTable *vtable, MonoError *error); diff --git a/src/mono/mono/mini/intrinsics.c b/src/mono/mono/mini/intrinsics.c index eaa0b333baa14..13be9d44131ed 100644 --- a/src/mono/mono/mini/intrinsics.c +++ b/src/mono/mono/mini/intrinsics.c @@ -718,6 +718,11 @@ emit_jit_helpers_intrinsics (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSi } } return ins; + } else if (!strcmp (cmethod->name, "DisableInline")) { + cfg->disable_inline = TRUE; + MONO_INST_NEW (cfg, ins, OP_NOP); + MONO_ADD_INS (cfg->cbb, ins); + return ins; } return NULL; diff --git a/src/mono/mono/mini/mini-amd64.c b/src/mono/mono/mini/mini-amd64.c index bfede8ad36c7f..20bacf6236cd0 100644 --- a/src/mono/mono/mini/mini-amd64.c +++ b/src/mono/mono/mini/mini-amd64.c @@ -2544,7 +2544,7 @@ mono_arch_emit_setret (MonoCompile *cfg, MonoMethod *method, MonoInst *val) typedef struct { MonoMethodSignature *sig; CallInfo *cinfo; - int nstack_args, nullable_area; + int nstack_args; } ArchDynCallInfo; static gboolean @@ -2596,7 +2596,7 @@ mono_arch_dyn_call_prepare (MonoMethodSignature *sig) { ArchDynCallInfo *info; CallInfo *cinfo; - int i, aindex; + int i; cinfo = get_call_info (NULL, sig); @@ -2622,34 +2622,6 @@ mono_arch_dyn_call_prepare (MonoMethodSignature *sig) break; } } - - for (aindex = 0; aindex < sig->param_count; aindex++) { - MonoType *t = sig->params [aindex]; - ArgInfo *ainfo = &cinfo->args [aindex + sig->hasthis]; - - if (m_type_is_byref (t)) - continue; - - switch (t->type) { - case MONO_TYPE_GENERICINST: - if (t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type_internal (t))) { - MonoClass *klass = mono_class_from_mono_type_internal (t); - int size; - - if (!(ainfo->storage == ArgValuetypeInReg || ainfo->storage == ArgOnStack)) { - /* Nullables need a temporary buffer, its stored at the end of DynCallArgs.regs after the stack args */ - size = mono_class_value_size (klass, NULL); - info->nullable_area += size; - } - } - break; - default: - break; - } - } - - info->nullable_area = ALIGN_TO (info->nullable_area, 16); - /* Align to 16 bytes */ if (info->nstack_args & 1) info->nstack_args ++; @@ -2677,7 +2649,7 @@ mono_arch_dyn_call_get_buf_size (MonoDynCallInfo *info) ArchDynCallInfo *ainfo = (ArchDynCallInfo*)info; /* Extend the 'regs' field dynamically */ - return sizeof (DynCallArgs) + (ainfo->nstack_args * sizeof (target_mgreg_t)) + ainfo->nullable_area; + return sizeof (DynCallArgs) + (ainfo->nstack_args * sizeof (target_mgreg_t)); } #define PTR_TO_GREG(ptr) ((host_mgreg_t)(ptr)) @@ -2704,8 +2676,6 @@ mono_arch_start_dyn_call (MonoDynCallInfo *info, gpointer **args, guint8 *ret, g DynCallArgs *p = (DynCallArgs*)buf; int arg_index, greg, i, pindex; MonoMethodSignature *sig = dinfo->sig; - int buffer_offset = 0; - guint8 *nullable_buffer; static int general_param_reg_to_index [MONO_MAX_IREGS]; static int float_param_reg_to_index [MONO_MAX_FREGS]; @@ -2730,9 +2700,6 @@ mono_arch_start_dyn_call (MonoDynCallInfo *info, gpointer **args, guint8 *ret, g greg = 0; pindex = 0; - /* Stored after the stack arguments */ - nullable_buffer = (guint8*)&(p->regs [PARAM_REGS + dinfo->nstack_args]); - if (sig->hasthis || dinfo->cinfo->vret_arg_index == 1) { p->regs [greg ++] = PTR_TO_GREG(*(args [arg_index ++])); if (!sig->hasthis) @@ -2820,32 +2787,11 @@ mono_arch_start_dyn_call (MonoDynCallInfo *info, gpointer **args, guint8 *ret, g } break; case MONO_TYPE_GENERICINST: - if (MONO_TYPE_IS_REFERENCE (t)) { + if (MONO_TYPE_IS_REFERENCE (t)) { p->regs [slot] = PTR_TO_GREG (*(arg)); break; - } else if (t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type_internal (t))) { - MonoClass *klass = mono_class_from_mono_type_internal (t); - guint8 *nullable_buf; - int size; - - size = mono_class_value_size (klass, NULL); - if (ainfo->storage == ArgValuetypeInReg || ainfo->storage == ArgOnStack) { - nullable_buf = g_alloca (size); - } else { - nullable_buf = nullable_buffer + buffer_offset; - buffer_offset += size; - g_assert (buffer_offset <= dinfo->nullable_area); - } - - /* The argument pointed to by arg is either a boxed vtype or null */ - mono_nullable_init (nullable_buf, (MonoObject*)arg, klass); - - arg = (gpointer*)nullable_buf; - /* Fall though */ - - } else { - /* Fall through */ } + /* Fall through */ case MONO_TYPE_VALUETYPE: { switch (ainfo->storage) { case ArgValuetypeInReg: diff --git a/src/mono/mono/mini/mini-arm.c b/src/mono/mono/mini/mini-arm.c index 323524484d05e..84b13a5d68d6a 100644 --- a/src/mono/mono/mini/mini-arm.c +++ b/src/mono/mono/mini/mini-arm.c @@ -3038,25 +3038,8 @@ mono_arch_start_dyn_call (MonoDynCallInfo *info, gpointer **args, guint8 *ret, g if (MONO_TYPE_IS_REFERENCE (t)) { p->regs [slot] = (host_mgreg_t)(gsize)*arg; break; - } else { - if (t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type_internal (t))) { - MonoClass *klass = mono_class_from_mono_type_internal (t); - guint8 *nullable_buf; - int size; - - size = mono_class_value_size (klass, NULL); - nullable_buf = g_alloca (size); - g_assert (nullable_buf); - - /* The argument pointed to by arg is either a boxed vtype or null */ - mono_nullable_init (nullable_buf, (MonoObject*)arg, klass); - - arg = (gpointer*)nullable_buf; - /* Fall though */ - } else { - /* Fall though */ - } } + /* Fall though */ case MONO_TYPE_VALUETYPE: g_assert (ainfo->storage == RegTypeStructByVal); diff --git a/src/mono/mono/mini/mini-arm64.c b/src/mono/mono/mini/mini-arm64.c index 65a6bb42e1fc7..0e2b70b5f12a9 100644 --- a/src/mono/mono/mini/mini-arm64.c +++ b/src/mono/mono/mini/mini-arm64.c @@ -1638,7 +1638,7 @@ typedef struct { CallInfo *cinfo; MonoType *rtype; MonoType **param_types; - int n_fpargs, n_fpret, nullable_area; + int n_fpargs, n_fpret; } ArchDynCallInfo; static gboolean @@ -1691,7 +1691,7 @@ mono_arch_dyn_call_prepare (MonoMethodSignature *sig) { ArchDynCallInfo *info; CallInfo *cinfo; - int i, aindex; + int i; cinfo = get_call_info (NULL, sig); @@ -1721,28 +1721,6 @@ mono_arch_dyn_call_prepare (MonoMethodSignature *sig) break; } - for (aindex = 0; aindex < sig->param_count; aindex++) { - MonoType *t = info->param_types [aindex]; - - if (m_type_is_byref (t)) - continue; - - switch (t->type) { - case MONO_TYPE_GENERICINST: - if (t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type_internal (t))) { - MonoClass *klass = mono_class_from_mono_type_internal (t); - int size; - - /* Nullables need a temporary buffer, its stored at the end of DynCallArgs.regs after the stack args */ - size = mono_class_value_size (klass, NULL); - info->nullable_area += size; - } - break; - default: - break; - } - } - return (MonoDynCallInfo*)info; } @@ -1762,7 +1740,7 @@ mono_arch_dyn_call_get_buf_size (MonoDynCallInfo *info) ArchDynCallInfo *ainfo = (ArchDynCallInfo*)info; g_assert (ainfo->cinfo->stack_usage % MONO_ARCH_FRAME_ALIGNMENT == 0); - return sizeof (DynCallArgs) + ainfo->cinfo->stack_usage + ainfo->nullable_area; + return sizeof (DynCallArgs) + ainfo->cinfo->stack_usage; } static double @@ -1789,8 +1767,6 @@ mono_arch_start_dyn_call (MonoDynCallInfo *info, gpointer **args, guint8 *ret, g int aindex, arg_index, greg, i, pindex; MonoMethodSignature *sig = dinfo->sig; CallInfo *cinfo = dinfo->cinfo; - int buffer_offset = 0; - guint8 *nullable_buffer; p->res = 0; p->ret = ret; @@ -1802,9 +1778,6 @@ mono_arch_start_dyn_call (MonoDynCallInfo *info, gpointer **args, guint8 *ret, g greg = 0; pindex = 0; - /* Stored after the stack arguments */ - nullable_buffer = (guint8*)&(p->regs [PARAM_REGS + 1 + (cinfo->stack_usage / sizeof (host_mgreg_t))]); - if (sig->hasthis) p->regs [greg ++] = (host_mgreg_t)*(args [arg_index ++]); @@ -1899,30 +1872,8 @@ mono_arch_start_dyn_call (MonoDynCallInfo *info, gpointer **args, guint8 *ret, g if (MONO_TYPE_IS_REFERENCE (t)) { p->regs [slot] = (host_mgreg_t)*arg; break; - } else { - if (t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type_internal (t))) { - MonoClass *klass = mono_class_from_mono_type_internal (t); - guint8 *nullable_buf; - int size; - - /* - * Use p->buffer as a temporary buffer since the data needs to be available after this call - * if the nullable param is passed by ref. - */ - size = mono_class_value_size (klass, NULL); - nullable_buf = nullable_buffer + buffer_offset; - buffer_offset += size; - g_assert (buffer_offset <= dinfo->nullable_area); - - /* The argument pointed to by arg is either a boxed vtype or null */ - mono_nullable_init (nullable_buf, (MonoObject*)arg, klass); - - arg = (gpointer*)nullable_buf; - /* Fall though */ - } else { - /* Fall though */ - } } + /* Fall through */ case MONO_TYPE_VALUETYPE: switch (ainfo->storage) { case ArgVtypeInIRegs: diff --git a/src/mono/mono/mini/mini-runtime.c b/src/mono/mono/mini/mini-runtime.c index f68c6a78bbd0f..c481f69adc8cd 100644 --- a/src/mono/mono/mini/mini-runtime.c +++ b/src/mono/mono/mini/mini-runtime.c @@ -3097,18 +3097,10 @@ create_runtime_invoke_info (MonoMethod *method, gpointer compiled_method, gboole #ifdef MONO_ARCH_DYN_CALL_SUPPORTED if (!mono_llvm_only && (mono_aot_only || mini_debug_options.dyn_runtime_invoke)) { gboolean supported = TRUE; - int i; if (method->string_ctor) sig = mono_marshal_get_string_ctor_signature (method); - for (i = 0; i < sig->param_count; ++i) { - MonoType *t = sig->params [i]; - - if (m_type_is_byref (t) && t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type_internal (t))) - supported = FALSE; - } - if (!info->compiled_method) supported = FALSE; @@ -3217,8 +3209,6 @@ create_runtime_invoke_info (MonoMethod *method, gpointer compiled_method, gboole return ret; } -static GENERATE_GET_CLASS_WITH_CACHE (nullbyrefreturn_ex, "Mono", "NullByRefReturnException"); - static MonoObject* mono_llvmonly_runtime_invoke (MonoMethod *method, RuntimeInvokeInfo *info, void *obj, void **params, MonoObject **exc, MonoError *error) { @@ -3271,20 +3261,6 @@ mono_llvmonly_runtime_invoke (MonoMethod *method, RuntimeInvokeInfo *info, void for (i = 0; i < sig->param_count; ++i) { MonoType *t = sig->params [i]; - if (t->type == MONO_TYPE_GENERICINST && mono_class_is_nullable (mono_class_from_mono_type_internal (t))) { - MonoClass *klass = mono_class_from_mono_type_internal (t); - guint8 *nullable_buf; - int size; - - size = mono_class_value_size (klass, NULL); - nullable_buf = g_alloca (size); - g_assert (nullable_buf); - - /* The argument pointed to by params [i] is either a boxed vtype or null */ - mono_nullable_init (nullable_buf, (MonoObject*)params [i], klass); - params [i] = nullable_buf; - } - if (!m_type_is_byref (t) && (MONO_TYPE_IS_REFERENCE (t) || t->type == MONO_TYPE_PTR)) { param_refs [i] = params [i]; params [i] = &(param_refs [i]); @@ -3302,10 +3278,9 @@ mono_llvmonly_runtime_invoke (MonoMethod *method, RuntimeInvokeInfo *info, void if (m_type_is_byref (sig->ret)) { if (*(gpointer*)retval == NULL) { - MonoClass *klass = mono_class_get_nullbyrefreturn_ex_class (); - MonoObject *ex = mono_object_new_checked (klass, error); + MonoException *ex = mono_get_exception_null_reference (); mono_error_assert_ok (error); - mono_error_set_exception_instance (error, (MonoException*)ex); + mono_error_set_exception_instance (error, ex); return NULL; } } @@ -3532,10 +3507,9 @@ mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObjec if (m_type_is_byref (sig->ret)) { if (*(gpointer*)retval == NULL) { - MonoClass *klass = mono_class_get_nullbyrefreturn_ex_class (); - MonoObject *ex = mono_object_new_checked (klass, error); + MonoException *ex = mono_get_exception_null_reference (); mono_error_assert_ok (error); - mono_error_set_exception_instance (error, (MonoException*)ex); + mono_error_set_exception_instance (error, ex); return NULL; } }