Rollback https://github.com/dotnet/coreclr/pull/17639 (#17671)
authorAtsushi Kanamori <AtsushiKan@users.noreply.github.com>
Thu, 19 Apr 2018 19:23:43 +0000 (12:23 -0700)
committerGitHub <noreply@github.com>
Thu, 19 Apr 2018 19:23:43 +0000 (12:23 -0700)
src/dlls/mscorrc/mscorrc.rc
src/dlls/mscorrc/resource.h
src/mscorlib/Resources/Strings.resx
src/mscorlib/src/System/Reflection/RuntimeMethodInfo.cs
src/vm/invokeutil.cpp
src/vm/invokeutil.h
src/vm/reflectioninvocation.cpp

index 42c0be4..61f5c9a 100644 (file)
@@ -1538,7 +1538,6 @@ BEGIN
 
     IDS_EE_TORNSTATE                        "Unexpected change made to file '%1'."
 
-    IDS_INVOKE_NULLREF_RETURNED             "The target method returned a null reference."
 END
 
 // These strings are generated from within the EE for streams
index 49f1d0e..b8e1b2b 100644 (file)
 #define IDS_EE_NDIRECT_LOADLIB_MAC                 0x263f
 #define IDS_EE_NDIRECT_GETPROCADDRESS_UNIX         0x2640
 #define IDS_EE_ERROR_COM                           0x2641
-
-#define IDS_INVOKE_NULLREF_RETURNED             0x2642
index 29ebb33..8ec81b9 100644 (file)
   <data name="NotSupported_ByRefLikeArray" xml:space="preserve">
     <value>Cannot create arrays of ByRef-like values.</value>
   </data>
-  <data name="NotSupported_ByRefToByRefLikeReturn" xml:space="preserve">
-    <value>ByRef to ByRefLike return values not supported in reflection invocation.</value>
+  <data name="NotSupported_ByRefReturn" xml:space="preserve">
+    <value>ByRef return value not supported in reflection invocation.</value>
   </data>
   <data name="NotSupported_CallToVarArg" xml:space="preserve">
     <value>Vararg calling convention not supported.</value>
index 692bfa3..1c23f16 100644 (file)
@@ -41,7 +41,7 @@ namespace System.Reflection
                     //
                     // first take care of all the NO_INVOKE cases. 
                     if (ContainsGenericParameters ||
-                         (ReturnType.IsByRef && ReturnType.GetElementType().IsByRefLike) ||
+                         ReturnType.IsByRef ||
                          (declaringType != null && declaringType.ContainsGenericParameters) ||
                          ((CallingConvention & CallingConventions.VarArgs) == CallingConventions.VarArgs))
                     {
@@ -444,10 +444,10 @@ namespace System.Reflection
             {
                 throw new MemberAccessException();
             }
-            // ByRef to ByRefLike returns are not allowed in reflection
-            else if (ReturnType.IsByRef && ReturnType.GetElementType().IsByRefLike)
+            // ByRef return are not allowed in reflection
+            else if (ReturnType.IsByRef)
             {
-                throw new NotSupportedException(SR.NotSupported_ByRefToByRefLikeReturn);
+                throw new NotSupportedException(SR.NotSupported_ByRefReturn);
             }
 
             throw new TargetException();
index 3672cc2..170b0da 100644 (file)
@@ -649,14 +649,9 @@ void InvokeUtil::ValidField(TypeHandle th, OBJECTREF* value)
         COMPlusThrow(kArgumentException,W("Arg_ObjObj"));
 }
 
-//
-// CreateObjectAfterInvoke
-// This routine will create the specified object from the value returned by the Invoke target. 
-//
-// This does not handle the ELEMENT_TYPE_VALUETYPE case. The caller must preallocate the box object and
-// copy the value type into it afterward.
-//
-OBJECTREF InvokeUtil::CreateObjectAfterInvoke(TypeHandle th, void * pValue) {
+// InternalCreateObject
+// This routine will create the specified object from the value
+OBJECTREF InvokeUtil::CreateObject(TypeHandle th, void * pValue) {
     CONTRACTL {
         THROWS;
         GC_TRIGGERS;
@@ -671,9 +666,6 @@ OBJECTREF InvokeUtil::CreateObjectAfterInvoke(TypeHandle th, void * pValue) {
     MethodTable *pMT = NULL;
     OBJECTREF obj = NULL;
 
-    // WARNING: pValue can be an inner reference into a managed object and it is not protected from GC. You must do nothing that
-    // triggers a GC until the all the data it points to has been captured in a GC-protected location.
-
     // Handle the non-table types
     switch (type) {
     case ELEMENT_TYPE_VOID:
@@ -690,8 +682,12 @@ OBJECTREF InvokeUtil::CreateObjectAfterInvoke(TypeHandle th, void * pValue) {
         goto PrimitiveType;
 
     case ELEMENT_TYPE_VALUETYPE:
-        _ASSERTE(!"You cannot use this function for arbitrary value types. You must preallocate a box object and copy the value in yourself.");
+    {
+        _ASSERTE(!th.IsTypeDesc());
+        pMT = th.AsMethodTable();
+        obj = pMT->Box(pValue);
         break;
+    }
 
     case ELEMENT_TYPE_CLASS:        // Class
     case ELEMENT_TYPE_SZARRAY:      // Single Dim, Zero
@@ -722,17 +718,14 @@ OBJECTREF InvokeUtil::CreateObjectAfterInvoke(TypeHandle th, void * pValue) {
         {
             // Don't use MethodTable::Box here for perf reasons
             PREFIX_ASSUME(pMT != NULL);
-            DWORD size = pMT->GetNumInstanceFieldBytes();
-
-            UINT64 capturedValue;
-            memcpyNoGCRefs(&capturedValue, pValue, size); // Must capture the primitive value before we allocate the boxed object which can trigger a GC.
-
-            INDEBUG(pValue = (LPVOID)0xcccccccc); // We're about to allocate a GC object - can no longer trust pValue
             obj = AllocateObject(pMT);
-            memcpyNoGCRefs(obj->UnBox(), &capturedValue, size);
+            DWORD size = pMT->GetNumInstanceFieldBytes();
+            memcpyNoGCRefs(obj->UnBox(), pValue, size);
         }
         break;
     
+    case ELEMENT_TYPE_BYREF:
+        COMPlusThrow(kNotSupportedException, W("NotSupported_ByRefReturn"));
     case ELEMENT_TYPE_END:
     default:
         _ASSERTE(!"Unknown Type");
index 79ded1d..80db622 100644 (file)
@@ -105,7 +105,7 @@ public:
     // Given a type, this routine will convert an return value representing that
     //  type into an ObjectReference.  If the type is a primitive, the 
     //  value is wrapped in one of the Value classes.
-    static OBJECTREF CreateObjectAfterInvoke(TypeHandle th, void * pValue);
+    static OBJECTREF CreateObject(TypeHandle th, void * pValue);
 
     // This is a special purpose Exception creation function.  It
     //  creates the TargetInvocationExeption placing the passed
index 2cc86e5..d4f5a99 100644 (file)
@@ -1092,28 +1092,12 @@ FCIMPL5(Object*, RuntimeMethodHandle::InvokeMethod,
     // if we have the magic Value Class return, we need to allocate that class
     // and place a pointer to it on the stack.
 
-    BOOL hasRefReturnAndNeedsBoxing = FALSE; // Indicates that the method has a BYREF return type and the target type needs to be copied into a preallocated boxed object.
-
     TypeHandle retTH = gc.pSig->GetReturnTypeHandle();
-    TypeHandle refReturnTargetTH;  // Valid only if retType == ELEMENT_TYPE_BYREF. Caches the TypeHandle of the byref target.
     BOOL fHasRetBuffArg = argit.HasRetBuffArg();
     CorElementType retType = retTH.GetInternalCorElementType();
     if (retType == ELEMENT_TYPE_VALUETYPE || fHasRetBuffArg) {
         gc.retVal = retTH.GetMethodTable()->Allocate();
     }
-    else if (retType == ELEMENT_TYPE_BYREF)
-    {
-        refReturnTargetTH = retTH.AsTypeDesc()->GetTypeParam();
-        CorElementType refReturnTargetType = refReturnTargetTH.GetInternalCorElementType();
-
-        // If the target of the byref is a general valuetype (i.e. not one of the primitives), we need to preallocate a boxed object
-        // to hold the managed return value.
-        if (refReturnTargetType == ELEMENT_TYPE_VALUETYPE)
-        {
-            hasRefReturnAndNeedsBoxing = TRUE;
-            gc.retVal = refReturnTargetTH.GetMethodTable()->Allocate();
-        }
-    }
 
     // Copy "this" pointer
     if (!pMeth->IsStatic()) {
@@ -1339,23 +1323,13 @@ FCIMPL5(Object*, RuntimeMethodHandle::InvokeMethod,
         gc.retVal = Nullable::NormalizeBox(gc.retVal);
     }
     else
-    if (retType == ELEMENT_TYPE_VALUETYPE || hasRefReturnAndNeedsBoxing)
+    if (retType == ELEMENT_TYPE_VALUETYPE)
     {
         _ASSERTE(gc.retVal != NULL);
 
-        if (hasRefReturnAndNeedsBoxing)
-        {
-            // Method has BYREF return and the target type is one that needs boxing. We need to copy into the boxed object we have allocated for this purpose.
-            LPVOID pReturnedReference = *(LPVOID*)&callDescrData.returnValue;
-            if (pReturnedReference == NULL)
-            {
-                COMPlusThrow(kNullReferenceException, IDS_INVOKE_NULLREF_RETURNED);
-            }
-            CopyValueClass(gc.retVal->GetData(), pReturnedReference, gc.retVal->GetMethodTable(), gc.retVal->GetAppDomain());
-        }
         // if the structure is returned by value, then we need to copy in the boxed object
         // we have allocated for this purpose.
-        else if (!fHasRetBuffArg) 
+        if (!fHasRetBuffArg) 
         {
             CopyValueClass(gc.retVal->GetData(), &callDescrData.returnValue, gc.retVal->GetMethodTable(), gc.retVal->GetAppDomain());
         }
@@ -1370,20 +1344,9 @@ FCIMPL5(Object*, RuntimeMethodHandle::InvokeMethod,
             // If the return type is a Nullable<T> box it into the correct form
         gc.retVal = Nullable::NormalizeBox(gc.retVal);
     }
-    else if (retType == ELEMENT_TYPE_BYREF)
-    {
-        // WARNING: pReturnedReference is an unprotected inner reference so we must not trigger a GC until the referenced value has been safely captured.
-        LPVOID pReturnedReference = *(LPVOID*)&callDescrData.returnValue;
-        if (pReturnedReference == NULL)
-        {
-            COMPlusThrow(kNullReferenceException, IDS_INVOKE_NULLREF_RETURNED);
-        }
-
-        gc.retVal = InvokeUtil::CreateObjectAfterInvoke(refReturnTargetTH, pReturnedReference);
-    }
     else 
     {
-        gc.retVal = InvokeUtil::CreateObjectAfterInvoke(retTH, &callDescrData.returnValue);
+        gc.retVal = InvokeUtil::CreateObject(retTH, &callDescrData.returnValue);
     }
 
     while (byRefToNullables != NULL) {