From c6c46423e916735213940f7fdf19b1fad62fb602 Mon Sep 17 00:00:00 2001 From: David Wrighton Date: Tue, 30 Oct 2018 18:05:39 -0700 Subject: [PATCH] Add support for large number of argumets in CCW call on Arm64 (dotnet/coreclr#20670) * 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 | 4 +- src/coreclr/src/dlls/mscorrc/resource.h | 2 + src/coreclr/src/vm/arm64/asmhelpers.asm | 20 ++- src/coreclr/src/vm/dllimport.cpp | 167 +++++++++++++++++++++ .../COM/NETClients/Primitives/NumericTests.cs | 11 ++ .../src/Interop/COM/NETServer/NumericTesting.cs | 10 ++ .../COM/NativeClients/Primitives/NumericTests.cpp | 20 +++ .../src/Interop/COM/NativeServer/NumericTesting.h | 37 +++++ .../COM/ServerContracts/Server.Contracts.cs | 3 + .../Interop/COM/ServerContracts/Server.Contracts.h | 27 ++++ 10 files changed, 295 insertions(+), 6 deletions(-) diff --git a/src/coreclr/src/dlls/mscorrc/mscorrc.rc b/src/coreclr/src/dlls/mscorrc/mscorrc.rc index 050b260..5c5c534 100644 --- a/src/coreclr/src/dlls/mscorrc/mscorrc.rc +++ b/src/coreclr/src/dlls/mscorrc/mscorrc.rc @@ -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." diff --git a/src/coreclr/src/dlls/mscorrc/resource.h b/src/coreclr/src/dlls/mscorrc/resource.h index 189948a..555ee4c 100644 --- a/src/coreclr/src/dlls/mscorrc/resource.h +++ b/src/coreclr/src/dlls/mscorrc/resource.h @@ -611,6 +611,8 @@ #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 diff --git a/src/coreclr/src/vm/arm64/asmhelpers.asm b/src/coreclr/src/vm/arm64/asmhelpers.asm index 0cbc0a8..07e78cb 100644 --- a/src/coreclr/src/vm/arm64/asmhelpers.asm +++ b/src/coreclr/src/vm/arm64/asmhelpers.asm @@ -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 diff --git a/src/coreclr/src/vm/dllimport.cpp b/src/coreclr/src/vm/dllimport.cpp index 56f893a..0b20aae 100644 --- a/src/coreclr/src/vm/dllimport.cpp +++ b/src/coreclr/src/vm/dllimport.cpp @@ -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 //--------------------------------------------------------------------------------------- diff --git a/src/coreclr/tests/src/Interop/COM/NETClients/Primitives/NumericTests.cs b/src/coreclr/tests/src/Interop/COM/NETClients/Primitives/NumericTests.cs index e184d0d..19d0574 100644 --- a/src/coreclr/tests/src/Interop/COM/NETClients/Primitives/NumericTests.cs +++ b/src/coreclr/tests/src/Interop/COM/NETClients/Primitives/NumericTests.cs @@ -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)); + } } } diff --git a/src/coreclr/tests/src/Interop/COM/NETServer/NumericTesting.cs b/src/coreclr/tests/src/Interop/COM/NETServer/NumericTesting.cs index c6b1163..4ed713d 100644 --- a/src/coreclr/tests/src/Interop/COM/NETServer/NumericTesting.cs +++ b/src/coreclr/tests/src/Interop/COM/NETServer/NumericTesting.cs @@ -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 diff --git a/src/coreclr/tests/src/Interop/COM/NativeClients/Primitives/NumericTests.cpp b/src/coreclr/tests/src/Interop/COM/NativeClients/Primitives/NumericTests.cpp index 3d1a624..4afebb3 100644 --- a/src/coreclr/tests/src/Interop/COM/NativeClients/Primitives/NumericTests.cpp +++ b/src/coreclr/tests/src/Interop/COM/NativeClients/Primitives/NumericTests.cpp @@ -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); } diff --git a/src/coreclr/tests/src/Interop/COM/NativeServer/NumericTesting.h b/src/coreclr/tests/src/Interop/COM/NativeServer/NumericTesting.h index a6e76ec..aa703be 100644 --- a/src/coreclr/tests/src/Interop/COM/NativeServer/NumericTesting.h +++ b/src/coreclr/tests/src/Interop/COM/NativeServer/NumericTesting.h @@ -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, diff --git a/src/coreclr/tests/src/Interop/COM/ServerContracts/Server.Contracts.cs b/src/coreclr/tests/src/Interop/COM/ServerContracts/Server.Contracts.cs index 0aa247f..cc003ed 100644 --- a/src/coreclr/tests/src/Interop/COM/ServerContracts/Server.Contracts.cs +++ b/src/coreclr/tests/src/Interop/COM/ServerContracts/Server.Contracts.cs @@ -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)] diff --git a/src/coreclr/tests/src/Interop/COM/ServerContracts/Server.Contracts.h b/src/coreclr/tests/src/Interop/COM/ServerContracts/Server.Contracts.h index 9723106..a15f39f 100644 --- a/src/coreclr/tests/src/Interop/COM/ServerContracts/Server.Contracts.h +++ b/src/coreclr/tests/src/Interop/COM/ServerContracts/Server.Contracts.h @@ -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")) -- 2.7.4