Add support for large number of argumets in CCW call on Arm64 (dotnet/coreclr#20670)
authorDavid Wrighton <davidwr@microsoft.com>
Wed, 31 Oct 2018 01:05:39 +0000 (18:05 -0700)
committerGitHub <noreply@github.com>
Wed, 31 Oct 2018 01:05:39 +0000 (18:05 -0700)
* Fix CCW with large numbers of arguments on arm64
- Correctly align the stack in COMToCLRDispatchHelper
- Add tests for naturally 16 byte aligned stack growth, and non-aligned growth
* New many arguments COM test
* Add support for the IL stub ETW diagnostic event

Commit migrated from https://github.com/dotnet/coreclr/commit/e14a9ad013ad307b282def301cbf86e4252cca16

src/coreclr/src/dlls/mscorrc/mscorrc.rc
src/coreclr/src/dlls/mscorrc/resource.h
src/coreclr/src/vm/arm64/asmhelpers.asm
src/coreclr/src/vm/dllimport.cpp
src/coreclr/tests/src/Interop/COM/NETClients/Primitives/NumericTests.cs
src/coreclr/tests/src/Interop/COM/NETServer/NumericTesting.cs
src/coreclr/tests/src/Interop/COM/NativeClients/Primitives/NumericTests.cpp
src/coreclr/tests/src/Interop/COM/NativeServer/NumericTesting.h
src/coreclr/tests/src/Interop/COM/ServerContracts/Server.Contracts.cs
src/coreclr/tests/src/Interop/COM/ServerContracts/Server.Contracts.h

index 050b260..5c5c534 100644 (file)
@@ -697,7 +697,9 @@ BEGIN
     IDS_EE_CANNOTCAST_NOMARSHAL                 "The Windows Runtime Object can only be used in the threading context where it was created, because it implements INoMarshal or has MarshalingBehaviorAttribute(MarshalingType.None) set."
     IDS_EE_WINRT_WEAKREF_BAD_TYPE               "The object resolved by a native IWeakReference has an incompatible type for its managed WeakReference instance.\r\nExpected WeakReference target type: '%1'\r\nNative IWeakReference returned type: '%2'"
 #endif // FEATURE_COMINTEROP
-    
+
+    IDS_EE_INTEROP_CODE_SIZE_COMMENT        "Code size"
+
     IDS_EE_ADUNLOAD_IN_FINALIZER            "AppDomain cannot be unloaded during object finalization."
     IDS_EE_ADUNLOAD_DEFAULT                 "The default domain cannot be unloaded."
     IDS_EE_ADUNLOAD_CANT_UNWIND_THREAD      "AppDomain cannot be unloaded because the thread '%1' cannot be unwound out of it."
index 189948a..555ee4c 100644 (file)
 #define IDS_EE_INTEROP_STUB_CA_NO_ACCESS_TO_STUB_METHOD             0x2111
 #endif
 
+#define IDS_EE_INTEROP_CODE_SIZE_COMMENT        0x2112
+
 #define BFA_REFERENCE_ASSEMBLY                  0x2113
 
 #define IDS_E_FIELDACCESS                       0x2114
index 0cbc0a8..07e78cb 100644 (file)
@@ -742,12 +742,22 @@ GenericComCallStub_FirstStackAdjust     SETA GenericComCallStub_FirstStackAdjust
     cbz x0, COMToCLRDispatchHelper_RegSetup
 
     add x9, x1, #SIZEOF__ComMethodFrame
-    add x9, x9, x0, LSL #3
+
+    ; Compute number of 8 bytes slots to copy. This is done by rounding up the
+    ; dwStackSlots value to the nearest even value
+    add x0, x0, #1
+    bic x0, x0, #1
+
+    ; Compute how many slots to adjust the address to copy from. Since we
+    ; are copying 16 bytes at a time, adjust by -1 from the rounded value
+    sub x6, x0, #1
+    add x9, x9, x6, LSL #3
+
 COMToCLRDispatchHelper_StackLoop
-    ldr x8, [x9, #-8]!
-    str x8, [sp, #-8]!
-    sub x0, x0, #1
-    cbnz x0, COMToCLRDispatchHelper_StackLoop
+    ldp     x7, x8, [x9], #-16  ; post-index
+    stp     x7, x8, [sp, #-16]! ; pre-index
+    subs    x0, x0, #2
+    bne     COMToCLRDispatchHelper_StackLoop
     
 COMToCLRDispatchHelper_RegSetup
 
index 56f893a..0b20aae 100644 (file)
@@ -1142,9 +1142,176 @@ public:
         }
         LOG((LF_STUBS, LL_INFO1000, "^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n"));
 #endif // LOGGING
+
+        //
+        // Publish ETW events for IL stubs
+        //
         
+        // If the category and the event is enabled...
+        if (ETW_EVENT_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_Context, ILStubGenerated))
+        {
+            EtwOnILStubGenerated(
+                pStubMD, 
+                pbLocalSig, 
+                cbSig,
+                jitFlags,
+                &convertToHRTryCatch,
+                &cleanupTryFinally,
+                maxStack,
+                (DWORD)cbCode
+                );
+        }
+
     }
 
+    //---------------------------------------------------------------------------------------
+    // 
+    void 
+    EtwOnILStubGenerated(
+        MethodDesc *    pStubMD, 
+        PCCOR_SIGNATURE pbLocalSig, 
+        DWORD           cbSig, 
+        CORJIT_FLAGS    jitFlags,
+        ILStubEHClause * pConvertToHRTryCatchBounds,
+        ILStubEHClause * pCleanupTryFinallyBounds,
+        DWORD           maxStack, 
+        DWORD           cbCode)
+    {
+        STANDARD_VM_CONTRACT;
+
+        //
+        // Interop Method Information
+        //
+        MethodDesc *pTargetMD = m_slIL.GetTargetMD();
+        SString strNamespaceOrClassName, strMethodName, strMethodSignature;                
+        UINT64 uModuleId = 0;
+        
+        if (pTargetMD)
+        {
+            pTargetMD->GetMethodInfoWithNewSig(strNamespaceOrClassName, strMethodName, strMethodSignature);
+            uModuleId = (UINT64)pTargetMD->GetModule()->GetAddrModuleID();
+        }
+
+        //
+        // Stub Method Signature
+        //
+        SString stubNamespaceOrClassName, stubMethodName, stubMethodSignature;
+        pStubMD->GetMethodInfoWithNewSig(stubNamespaceOrClassName, stubMethodName, stubMethodSignature);
+        
+        IMDInternalImport *pStubImport = pStubMD->GetModule()->GetMDImport();
+        
+        CQuickBytes qbLocal;
+        PrettyPrintSig(pbLocalSig, (DWORD)cbSig, NULL, &qbLocal,  pStubImport, NULL);
+
+        SString strLocalSig(SString::Utf8, (LPCUTF8)qbLocal.Ptr());
+        
+        //
+        // Native Signature
+        // 
+        SString strNativeSignature(SString::Utf8);
+        if (m_dwStubFlags & NDIRECTSTUB_FL_REVERSE_INTEROP)
+        {
+            // Reverse interop. Use StubSignature
+            strNativeSignature = stubMethodSignature;                
+        }
+        else
+        {
+            // Forward interop. Use StubTarget siganture
+            PCCOR_SIGNATURE pCallTargetSig = GetStubTargetMethodSig();
+            DWORD           cCallTargetSig = GetStubTargetMethodSigLength();
+            
+            CQuickBytes qbCallTargetSig;
+            
+            PrettyPrintSig(pCallTargetSig, cCallTargetSig, "", &qbCallTargetSig,  pStubImport, NULL);
+
+            strNativeSignature.SetUTF8((LPCUTF8)qbCallTargetSig.Ptr());
+        }
+        
+        //
+        // Dump IL stub code       
+        //
+        SString strILStubCode;
+        strILStubCode.Preallocate(4096);    // Preallocate 4K bytes to avoid unnecessary growth
+
+        SString codeSizeFormat;
+        codeSizeFormat.LoadResource(CCompRC::Optional, IDS_EE_INTEROP_CODE_SIZE_COMMENT);
+        strILStubCode.AppendPrintf(W("// %s\t%d (0x%04x)\n"), codeSizeFormat.GetUnicode(), cbCode, cbCode);
+        strILStubCode.AppendPrintf(W(".maxstack %d \n"), maxStack);
+        strILStubCode.AppendPrintf(W(".locals %s\n"), strLocalSig.GetUnicode());
+        
+        m_slIL.LogILStub(jitFlags, &strILStubCode);
+
+        if (pConvertToHRTryCatchBounds->cbTryLength != 0 && pConvertToHRTryCatchBounds->cbHandlerLength != 0)
+        {
+            strILStubCode.AppendPrintf(
+                W(".try IL_%04x to IL_%04x catch handler IL_%04x to IL_%04x\n"), 
+                pConvertToHRTryCatchBounds->dwTryBeginOffset, 
+                pConvertToHRTryCatchBounds->dwTryBeginOffset + pConvertToHRTryCatchBounds->cbTryLength, 
+                pConvertToHRTryCatchBounds->dwHandlerBeginOffset, 
+                pConvertToHRTryCatchBounds->dwHandlerBeginOffset + pConvertToHRTryCatchBounds->cbHandlerLength);
+        }
+
+        if (pCleanupTryFinallyBounds->cbTryLength != 0 && pCleanupTryFinallyBounds->cbHandlerLength != 0)
+        {
+            strILStubCode.AppendPrintf(
+                W(".try IL_%04x to IL_%04x finally handler IL_%04x to IL_%04x\n"), 
+                pCleanupTryFinallyBounds->dwTryBeginOffset, 
+                pCleanupTryFinallyBounds->dwTryBeginOffset + pCleanupTryFinallyBounds->cbTryLength, 
+                pCleanupTryFinallyBounds->dwHandlerBeginOffset, 
+                pCleanupTryFinallyBounds->dwHandlerBeginOffset + pCleanupTryFinallyBounds->cbHandlerLength);
+        }
+
+        //
+        // Fire the event
+        //
+        DWORD dwFlags = 0;
+        if (m_dwStubFlags & NDIRECTSTUB_FL_REVERSE_INTEROP)
+            dwFlags |= ETW_IL_STUB_FLAGS_REVERSE_INTEROP;
+#ifdef FEATURE_COMINTEROP            
+        if (m_dwStubFlags & NDIRECTSTUB_FL_COM)
+            dwFlags |= ETW_IL_STUB_FLAGS_COM_INTEROP;
+#endif // FEATURE_COMINTEROP            
+        if (m_dwStubFlags & NDIRECTSTUB_FL_NGENEDSTUB)
+            dwFlags |= ETW_IL_STUB_FLAGS_NGENED_STUB;
+        if (m_dwStubFlags & NDIRECTSTUB_FL_DELEGATE)
+            dwFlags |= ETW_IL_STUB_FLAGS_DELEGATE;
+        if (m_dwStubFlags & NDIRECTSTUB_FL_CONVSIGASVARARG)
+            dwFlags |= ETW_IL_STUB_FLAGS_VARARG;
+        if (m_dwStubFlags & NDIRECTSTUB_FL_UNMANAGED_CALLI)
+            dwFlags |= ETW_IL_STUB_FLAGS_UNMANAGED_CALLI;
+            
+        DWORD dwToken = 0;
+        if (pTargetMD)
+            dwToken = pTargetMD->GetMemberDef();
+
+
+        //
+        // Truncate string fields. Make sure the whole event is less than 64KB
+        //
+        TruncateUnicodeString(strNamespaceOrClassName, ETW_IL_STUB_EVENT_STRING_FIELD_MAXSIZE);
+        TruncateUnicodeString(strMethodName,           ETW_IL_STUB_EVENT_STRING_FIELD_MAXSIZE);
+        TruncateUnicodeString(strMethodSignature,      ETW_IL_STUB_EVENT_STRING_FIELD_MAXSIZE);
+        TruncateUnicodeString(strNativeSignature,      ETW_IL_STUB_EVENT_STRING_FIELD_MAXSIZE);
+        TruncateUnicodeString(stubMethodSignature,     ETW_IL_STUB_EVENT_STRING_FIELD_MAXSIZE);
+        TruncateUnicodeString(strILStubCode,           ETW_IL_STUB_EVENT_CODE_STRING_FIELD_MAXSIZE);
+        
+        //
+        // Fire ETW event
+        //
+        FireEtwILStubGenerated(
+            GetClrInstanceId(),                         // ClrInstanceId
+            uModuleId,                                  // ModuleIdentifier
+            (UINT64)pStubMD,                            // StubMethodIdentifier
+            dwFlags,                                    // StubFlags                 
+            dwToken,                                    // ManagedInteropMethodToken
+            strNamespaceOrClassName.GetUnicode(),       // ManagedInteropMethodNamespace
+            strMethodName.GetUnicode(),                 // ManagedInteropMethodName
+            strMethodSignature.GetUnicode(),            // ManagedInteropMethodSignature
+            strNativeSignature.GetUnicode(),            // NativeSignature
+            stubMethodSignature.GetUnicode(),           // StubMethodSigature
+            strILStubCode.GetUnicode()                  // StubMethodILCode
+            );            
+    } // EtwOnILStubGenerated
 
 #ifdef LOGGING
     //---------------------------------------------------------------------------------------
index e184d0d..19d0574 100644 (file)
@@ -37,6 +37,7 @@ namespace NetClient
 
             this.Marshal_Float(a / 100f, b / 100f);
             this.Marshal_Double(a / 100.0, b / 100.0);
+            this.Marshal_ManyInts();
         }
 
         static private bool EqualByBound(float expected, float actual)
@@ -189,5 +190,15 @@ namespace NetClient
             this.server.Add_Double_Out(a, b, out c);
             Assert.IsTrue(EqualByBound(expected, c));
         }
+
+        private void Marshal_ManyInts()
+        {
+            var expected = 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11;
+            Console.WriteLine($"{expected.GetType().Name} 11 test invariant: 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 = {expected}");
+            Assert.IsTrue(expected == this.server.Add_ManyInts11(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11));
+            expected = 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12;
+            Console.WriteLine($"{expected.GetType().Name} 12 test invariant: 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 = {expected}");
+            Assert.IsTrue(expected == this.server.Add_ManyInts12(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12));
+        }
     }
 }
index c6b1163..4ed713d 100644 (file)
@@ -190,4 +190,14 @@ public class NumericTesting : Server.Contract.INumericTesting
     {
         c = a + b;
     }
+
+    public int Add_ManyInts11(int i1, int i2, int i3, int i4, int i5, int i6, int i7, int i8, int i9, int i10, int i11)
+    {
+        return i1 + i2 + i3 + i4 + i5 + i6 + i7 + i8 + i9 + i10 + i11;
+    }
+
+    public int Add_ManyInts12(int i1, int i2, int i3, int i4, int i5, int i6, int i7, int i8, int i9, int i10, int i11, int i12)
+    {
+        return i1 + i2 + i3 + i4 + i5 + i6 + i7 + i8 + i9 + i10 + i11 + i12;
+    }
 }
\ No newline at end of file
index 3d1a624..4afebb3 100644 (file)
@@ -196,6 +196,25 @@ namespace
         THROW_IF_FAILED(numericTesting->Add_Double_Out(a, b, &c));
         THROW_FAIL_IF_FALSE(EqualByBound(expected, c));
     }
+
+    void MarshalManyInts(_In_ INumericTesting *numericTesting)
+    {
+        HRESULT hr;
+
+        int expected = 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11;
+        ::printf("Many ints 11 test invariant: 1 + 2 + 3 + 4... + 11 = %d\n", expected);
+
+        int result = 0;
+        THROW_IF_FAILED(numericTesting->Add_ManyInts11(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, &result));
+        THROW_FAIL_IF_FALSE(result == expected);
+
+        expected = 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12;
+        ::printf("Many ints 12 test invariant: 1 + 2 + 3 + 4... + 11 + 12= %d\n", expected);
+
+        result = 0;
+        THROW_IF_FAILED(numericTesting->Add_ManyInts12(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, &result));
+        THROW_FAIL_IF_FALSE(result == expected);
+    }
 }
 
 void Run_NumericTests()
@@ -224,4 +243,5 @@ void Run_NumericTests()
     MarshalULong(numericTesting, (uint64_t)a, (uint64_t)b);
     MarshalFloat(numericTesting, (float)a / 100.f, (float)b / 100.f);
     MarshalDouble(numericTesting, (double)a / 100.0, (double)b / 100.0);
+    MarshalManyInts(numericTesting);
 }
index a6e76ec..aa703be 100644 (file)
@@ -246,6 +246,43 @@ public:
         return S_OK;
     }
 
+    DEF_FUNC(Add_ManyInts11)(
+        /*[in]*/ int i1,
+        /*[in]*/ int i2,
+        /*[in]*/ int i3,
+        /*[in]*/ int i4,
+        /*[in]*/ int i5,
+        /*[in]*/ int i6,
+        /*[in]*/ int i7,
+        /*[in]*/ int i8,
+        /*[in]*/ int i9,
+        /*[in]*/ int i10,
+        /*[in]*/ int i11,
+        /*[out]*/ int * result )
+    {
+        *result = i1 + i2 + i3 + i4 + i5 + i6 + i7 + i8 + i9 + i10 + i11;
+        return S_OK;
+    }
+
+    DEF_FUNC(Add_ManyInts12)(
+        /*[in]*/ int i1,
+        /*[in]*/ int i2,
+        /*[in]*/ int i3,
+        /*[in]*/ int i4,
+        /*[in]*/ int i5,
+        /*[in]*/ int i6,
+        /*[in]*/ int i7,
+        /*[in]*/ int i8,
+        /*[in]*/ int i9,
+        /*[in]*/ int i10,
+        /*[in]*/ int i11,
+        /*[in]*/ int i12,
+        /*[out]*/ int * result )
+    {
+        *result = i1 + i2 + i3 + i4 + i5 + i6 + i7 + i8 + i9 + i10 + i11 + i12;
+        return S_OK;
+    }
+
 public: // IUnknown
     STDMETHOD(QueryInterface)(
         /* [in] */ REFIID riid,
index 0aa247f..cc003ed 100644 (file)
@@ -44,6 +44,9 @@ namespace Server.Contract
         void Add_ULong_Out(ulong a, ulong b, out ulong c);
         void Add_Float_Out(float a, float b, out float c);
         void Add_Double_Out(double a, double b, out double c);
+
+        int Add_ManyInts11(int i1, int i2, int i3, int i4, int i5, int i6, int i7, int i8, int i9, int i10, int i11);
+        int Add_ManyInts12(int i1, int i2, int i3, int i4, int i5, int i6, int i7, int i8, int i9, int i10, int i11, int i12);
     }
 
     [ComVisible(true)]
index 9723106..a15f39f 100644 (file)
@@ -148,6 +148,33 @@ INumericTesting : IUnknown
         /*[in]*/ double a,
         /*[in]*/ double b,
         /*[out]*/ double * c ) = 0;
+      virtual HRESULT STDMETHODCALLTYPE Add_ManyInts11 (
+        /*[in]*/ int i1,
+        /*[in]*/ int i2,
+        /*[in]*/ int i3,
+        /*[in]*/ int i4,
+        /*[in]*/ int i5,
+        /*[in]*/ int i6,
+        /*[in]*/ int i7,
+        /*[in]*/ int i8,
+        /*[in]*/ int i9,
+        /*[in]*/ int i10,
+        /*[in]*/ int i11,
+        /*[out]*/ int * result ) = 0;
+      virtual HRESULT STDMETHODCALLTYPE Add_ManyInts12 (
+        /*[in]*/ int i1,
+        /*[in]*/ int i2,
+        /*[in]*/ int i3,
+        /*[in]*/ int i4,
+        /*[in]*/ int i5,
+        /*[in]*/ int i6,
+        /*[in]*/ int i7,
+        /*[in]*/ int i8,
+        /*[in]*/ int i9,
+        /*[in]*/ int i10,
+        /*[in]*/ int i11,
+        /*[in]*/ int i12,
+        /*[out]*/ int * result ) = 0;
 };
 
 struct __declspec(uuid("7731cb31-e063-4cc8-bcd2-d151d6bc8f43"))