diff options
Diffstat (limited to 'src/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/CallConverterThunk.cs')
-rw-r--r-- | src/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/CallConverterThunk.cs | 36 |
1 files changed, 33 insertions, 3 deletions
diff --git a/src/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/CallConverterThunk.cs b/src/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/CallConverterThunk.cs index b9b8a9cff..f0f8256c7 100644 --- a/src/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/CallConverterThunk.cs +++ b/src/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/CallConverterThunk.cs @@ -1114,11 +1114,12 @@ namespace Internal.Runtime.TypeLoader #endif } } - else if (conversionParams._conversionInfo.IsAnyDynamicInvokerThunk && thRetType.IsValueType()) + else if (conversionParams._conversionInfo.IsAnyDynamicInvokerThunk && + (thRetType.IsValueType() || thRetType.IsPointerType() || returnType == CorElementType.ELEMENT_TYPE_BYREF)) { Debug.Assert(returnValueToCopy != null); - if (conversionParams._calleeArgs.GetReturnType(out thDummy, out dummyBool) == CorElementType.ELEMENT_TYPE_VOID) + if (returnType == CorElementType.ELEMENT_TYPE_VOID) { // Invokers returning void need to return a null object returnValueToCopy = null; @@ -1128,8 +1129,37 @@ namespace Internal.Runtime.TypeLoader if (!conversionParams._callerArgs.HasRetBuffArg() && conversionParams._calleeArgs.HasRetBuffArg()) returnValueToCopy = (void*)(new IntPtr(*((void**)returnValueToCopy)) + IntPtr.Size); + if (returnType == CorElementType.ELEMENT_TYPE_BYREF) + { + // If this is a byref return, we're going to dereference the result + returnValueToCopy = *(void**)returnValueToCopy; + } + + RuntimeTypeHandle returnTypeRuntimeTypeHandle = thRetType.GetRuntimeTypeHandle(); + // Need to box value type before returning it - object returnValue = RuntimeAugments.Box(thRetType.GetRuntimeTypeHandle(), new IntPtr(returnValueToCopy)); + object returnValue; + if (returnType == CorElementType.ELEMENT_TYPE_BYREF && returnValueToCopy == null) + { + // This is a byref return and dereferencing it would result in a NullReferenceException. + // Set the return value to a sentinel that InvokeUtils will recognize. + // Can't throw from here or we would wrap this in a TargetInvocationException. + returnValue = InvokeUtils.NullByRefValueSentinel; + } + else if (RuntimeAugments.IsUnmanagedPointerType(returnTypeRuntimeTypeHandle)) + { + returnValue = System.Reflection.Pointer.Box(*(void**)returnValueToCopy, Type.GetTypeFromHandle(returnTypeRuntimeTypeHandle)); + } + else if (RuntimeAugments.IsValueType(returnTypeRuntimeTypeHandle)) + { + returnValue = RuntimeAugments.Box(returnTypeRuntimeTypeHandle, new IntPtr(returnValueToCopy)); + } + else + { + // byref return of a reference type + Debug.Assert(returnType == CorElementType.ELEMENT_TYPE_BYREF); + returnValue = Unsafe.As<byte, object>(ref *(byte*)returnValueToCopy); + } CallConversionParameters.s_pinnedGCHandles._returnObjectHandle.Target = returnValue; pinnedResultObject = CallConversionParameters.s_pinnedGCHandles._returnObjectHandle.GetRawTargetAddress(); returnValueToCopy = (void*)&pinnedResultObject; |