diff --git a/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.CoreCLR.cs index 4389d9507a4c4..e155b109886d0 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Runtime/CompilerServices/RuntimeHelpers.CoreCLR.cs @@ -344,12 +344,6 @@ internal static int EnumCompareTo(T x, T y) where T : struct, Enum return x.CompareTo(y); } - - // The body of this function will be created by the EE for the specific type. - // See getILIntrinsicImplementation for how this happens. - [Intrinsic] - internal static extern unsafe void CopyConstruct(T* dest, T* src) where T : unmanaged; - internal static ref byte GetRawData(this object obj) => ref Unsafe.As(obj).Data; diff --git a/src/coreclr/System.Private.CoreLib/src/System/StubHelpers.cs b/src/coreclr/System.Private.CoreLib/src/System/StubHelpers.cs index 9f2528b1a8231..4d04557565c3c 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/StubHelpers.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/StubHelpers.cs @@ -1315,6 +1315,75 @@ public IntPtr AddRef() } } // class CleanupWorkListElement + internal unsafe struct CopyConstructorCookie + { + private void* m_source; + + private nuint m_destinationOffset; + + public delegate* m_copyConstructor; + + public delegate* m_destructor; + + public CopyConstructorCookie* m_next; + + [StackTraceHidden] + public void ExecuteCopy(void* destinationBase) + { + if (m_copyConstructor != null) + { + m_copyConstructor((byte*)destinationBase + m_destinationOffset, m_source); + } + + if (m_destructor != null) + { + m_destructor(m_source); + } + } + } + + internal unsafe struct CopyConstructorChain + { + public void* m_realTarget; + public CopyConstructorCookie* m_head; + + public void Add(CopyConstructorCookie* cookie) + { + cookie->m_next = m_head; + m_head = cookie; + } + + [ThreadStatic] + private static CopyConstructorChain s_copyConstructorChain; + + public void Install(void* realTarget) + { + m_realTarget = realTarget; + s_copyConstructorChain = this; + } + + [StackTraceHidden] + private void ExecuteCopies(void* destinationBase) + { + for (CopyConstructorCookie* current = m_head; current != null; current = current->m_next) + { + current->ExecuteCopy(destinationBase); + } + } + + [UnmanagedCallersOnly] + [StackTraceHidden] + public static void* ExecuteCurrentCopiesAndGetTarget(void* destinationBase) + { + void* target = s_copyConstructorChain.m_realTarget; + s_copyConstructorChain.ExecuteCopies(destinationBase); + // Reset this instance to ensure we don't accidentally execute the copies again. + // All of the pointers point to the stack, so we don't need to free any memory. + s_copyConstructorChain = default; + return target; + } + } + internal static partial class StubHelpers { [MethodImpl(MethodImplOptions.InternalCall)] diff --git a/src/coreclr/inc/corinfo.h b/src/coreclr/inc/corinfo.h index fde019934f5f3..b7229ff35f3f6 100644 --- a/src/coreclr/inc/corinfo.h +++ b/src/coreclr/inc/corinfo.h @@ -644,7 +644,6 @@ enum CorInfoTypeWithMod { CORINFO_TYPE_MASK = 0x3F, // lower 6 bits are type mask CORINFO_TYPE_MOD_PINNED = 0x40, // can be applied to CLASS, or BYREF to indicate pinned - CORINFO_TYPE_MOD_COPY_WITH_HELPER = 0x80 // can be applied to VALUECLASS to indicate 'needs helper to copy' }; inline CorInfoType strip(CorInfoTypeWithMod val) { @@ -3326,8 +3325,6 @@ class ICorDynamicInfo : public ICorStaticInfo // but for tailcalls, the contract is that JIT leaves the indirection cell in // a register during tailcall. virtual void updateEntryPointForTailCall(CORINFO_CONST_LOOKUP* entryPoint) = 0; - - virtual CORINFO_METHOD_HANDLE getSpecialCopyHelper(CORINFO_CLASS_HANDLE type) = 0; }; /**********************************************************************************/ diff --git a/src/coreclr/inc/icorjitinfoimpl_generated.h b/src/coreclr/inc/icorjitinfoimpl_generated.h index 96068326c3470..d652f262ab8fd 100644 --- a/src/coreclr/inc/icorjitinfoimpl_generated.h +++ b/src/coreclr/inc/icorjitinfoimpl_generated.h @@ -742,9 +742,6 @@ uint32_t getJitFlags( CORJIT_FLAGS* flags, uint32_t sizeInBytes) override; -CORINFO_METHOD_HANDLE getSpecialCopyHelper( - CORINFO_CLASS_HANDLE type) override; - /**********************************************************************************/ // clang-format on /**********************************************************************************/ diff --git a/src/coreclr/inc/jiteeversionguid.h b/src/coreclr/inc/jiteeversionguid.h index fc1917037043b..4af8e1a80522e 100644 --- a/src/coreclr/inc/jiteeversionguid.h +++ b/src/coreclr/inc/jiteeversionguid.h @@ -43,11 +43,11 @@ typedef const GUID *LPCGUID; #define GUID_DEFINED #endif // !GUID_DEFINED -constexpr GUID JITEEVersionIdentifier = { /* 62865a69-7c84-4ba5-8636-a7dec55c05a7 */ - 0x62865a69, - 0x7c84, - 0x4ba5, - {0x86, 0x36, 0xa7, 0xde, 0xc5, 0x5c, 0x05, 0xa7} +constexpr GUID JITEEVersionIdentifier = { /* f43f9022-8795-4791-ba55-c450d76cfeb9 */ + 0xf43f9022, + 0x8795, + 0x4791, + {0xba, 0x55, 0xc4, 0x50, 0xd7, 0x6c, 0xfe, 0xb9} }; ////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/coreclr/jit/ICorJitInfo_names_generated.h b/src/coreclr/jit/ICorJitInfo_names_generated.h index 2d3865018d1de..4779f13a029b8 100644 --- a/src/coreclr/jit/ICorJitInfo_names_generated.h +++ b/src/coreclr/jit/ICorJitInfo_names_generated.h @@ -180,6 +180,5 @@ DEF_CLR_API(recordRelocation) DEF_CLR_API(getRelocTypeHint) DEF_CLR_API(getExpectedTargetArchitecture) DEF_CLR_API(getJitFlags) -DEF_CLR_API(getSpecialCopyHelper) #undef DEF_CLR_API diff --git a/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp b/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp index 0ee637a957cf3..4db7f026f9d77 100644 --- a/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp +++ b/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp @@ -1742,15 +1742,6 @@ uint32_t WrapICorJitInfo::getJitFlags( return temp; } -CORINFO_METHOD_HANDLE WrapICorJitInfo::getSpecialCopyHelper( - CORINFO_CLASS_HANDLE type) -{ - API_ENTER(getSpecialCopyHelper); - CORINFO_METHOD_HANDLE temp = wrapHnd->getSpecialCopyHelper(type); - API_LEAVE(getSpecialCopyHelper); - return temp; -} - /**********************************************************************************/ // clang-format on /**********************************************************************************/ diff --git a/src/coreclr/jit/compiler.cpp b/src/coreclr/jit/compiler.cpp index 7d2c2eceebce1..d94d1f7e10756 100644 --- a/src/coreclr/jit/compiler.cpp +++ b/src/coreclr/jit/compiler.cpp @@ -1989,10 +1989,6 @@ void Compiler::compInit(ArenaAllocator* pAlloc, m_fpStructLoweringCache = nullptr; #endif -#if defined(TARGET_X86) && defined(FEATURE_IJW) - m_specialCopyArgs = nullptr; -#endif - // check that HelperCallProperties are initialized assert(s_helperCallProperties.IsPure(CORINFO_HELP_GET_GCSTATIC_BASE)); diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index 1315a57a139a5..b748f3b81138a 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -5703,36 +5703,6 @@ class Compiler const CORINFO_SWIFT_LOWERING* GetSwiftLowering(CORINFO_CLASS_HANDLE clsHnd); #endif -#if defined(TARGET_X86) && defined(FEATURE_IJW) - bool* m_specialCopyArgs; - bool recordArgRequiresSpecialCopy(unsigned argNum) - { - if (argNum >= info.compArgsCount) - { - return false; - } - - if (m_specialCopyArgs == nullptr) - { - m_specialCopyArgs = new (getAllocator()) bool[info.compArgsCount]; - memset(m_specialCopyArgs, 0, info.compArgsCount * sizeof(bool)); - } - - m_specialCopyArgs[argNum] = true; - return true; - } - - bool argRequiresSpecialCopy(unsigned argNum) - { - return argNum < info.compArgsCount && m_specialCopyArgs != nullptr && m_specialCopyArgs[argNum]; - } - - bool compHasSpecialCopyArgs() - { - return m_specialCopyArgs != nullptr; - } -#endif - void optRecordLoopMemoryDependence(GenTree* tree, BasicBlock* block, ValueNum memoryVN); void optCopyLoopMemoryDependence(GenTree* fromTree, GenTree* toTree); diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index f8a00303308ea..bcab097e35f2b 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -16599,7 +16599,6 @@ GenTree* Compiler::gtNewTempStore( valTyp = lvaGetRealType(val->AsLclVar()->GetLclNum()); val->gtType = valTyp; } - var_types dstTyp = varDsc->TypeGet(); /* If the variable's lvType is not yet set then set it here */ diff --git a/src/coreclr/jit/gschecks.cpp b/src/coreclr/jit/gschecks.cpp index 06802181eea22..0baa5ad289c24 100644 --- a/src/coreclr/jit/gschecks.cpp +++ b/src/coreclr/jit/gschecks.cpp @@ -516,59 +516,13 @@ void Compiler::gsParamsToShadows() continue; } -#if defined(TARGET_X86) && defined(FEATURE_IJW) - if (lclNum < info.compArgsCount && argRequiresSpecialCopy(lclNum) && (varDsc->TypeGet() == TYP_STRUCT)) - { - JITDUMP("arg%02u requires special copy, using special copy helper to copy to shadow var V%02u\n", lclNum, - shadowVarNum); - CORINFO_METHOD_HANDLE copyHelper = - info.compCompHnd->getSpecialCopyHelper(varDsc->GetLayout()->GetClassHandle()); - GenTreeCall* call = gtNewCallNode(CT_USER_FUNC, copyHelper, TYP_VOID); - - GenTree* src = gtNewLclVarAddrNode(lclNum); - GenTree* dst = gtNewLclVarAddrNode(shadowVarNum); - - call->gtArgs.PushBack(this, NewCallArg::Primitive(dst)); - call->gtArgs.PushBack(this, NewCallArg::Primitive(src)); - - fgEnsureFirstBBisScratch(); - compCurBB = fgFirstBB; // Needed by some morphing - if (opts.IsReversePInvoke()) - { - JITDUMP( - "Inserting special copy helper call at the end of the first block after Reverse P/Invoke transition\n"); - -#ifdef DEBUG - // assert that we don't have any uses of the local variable in the first block - // before we insert the shadow copy statement. - for (Statement* const stmt : fgFirstBB->Statements()) - { - assert(!gtHasRef(stmt->GetRootNode(), lclNum)); - } -#endif - // If we are in a reverse P/Invoke, then we need to insert - // the call at the end of the first block as we need to do the GC transition - // before we can call the helper. - (void)fgNewStmtAtEnd(fgFirstBB, fgMorphTree(call)); - } - else - { - JITDUMP("Inserting special copy helper call at the beginning of the first block\n"); - (void)fgNewStmtAtBeg(fgFirstBB, fgMorphTree(call)); - } - } - else -#endif // TARGET_X86 && FEATURE_IJW - { - GenTree* src = gtNewLclvNode(lclNum, varDsc->TypeGet()); - src->gtFlags |= GTF_DONT_CSE; + GenTree* src = gtNewLclvNode(lclNum, varDsc->TypeGet()); + src->gtFlags |= GTF_DONT_CSE; + GenTree* store = gtNewStoreLclVarNode(shadowVarNum, src); - GenTree* store = gtNewStoreLclVarNode(shadowVarNum, src); - - fgEnsureFirstBBisScratch(); - compCurBB = fgFirstBB; // Needed by some morphing - (void)fgNewStmtAtBeg(fgFirstBB, fgMorphTree(store)); - } + fgEnsureFirstBBisScratch(); + compCurBB = fgFirstBB; // Needed by some morphing + (void)fgNewStmtAtBeg(fgFirstBB, fgMorphTree(store)); } compCurBB = nullptr; diff --git a/src/coreclr/jit/lclvars.cpp b/src/coreclr/jit/lclvars.cpp index 780d098978365..5b1003c0b8226 100644 --- a/src/coreclr/jit/lclvars.cpp +++ b/src/coreclr/jit/lclvars.cpp @@ -653,19 +653,6 @@ void Compiler::lvaInitUserArgs(InitVarDscInfo* varDscInfo, unsigned skipArgs, un CorInfoTypeWithMod corInfoType = info.compCompHnd->getArgType(&info.compMethodInfo->args, argLst, &typeHnd); varDsc->lvIsParam = 1; -#if defined(TARGET_X86) && defined(FEATURE_IJW) - if ((corInfoType & CORINFO_TYPE_MOD_COPY_WITH_HELPER) != 0) - { - CorInfoType typeWithoutMod = strip(corInfoType); - if (typeWithoutMod == CORINFO_TYPE_VALUECLASS || typeWithoutMod == CORINFO_TYPE_PTR || - typeWithoutMod == CORINFO_TYPE_BYREF) - { - JITDUMP("Marking user arg%02u as requiring special copy semantics\n", i); - recordArgRequiresSpecialCopy(i); - } - } -#endif // TARGET_X86 && FEATURE_IJW - lvaInitVarDsc(varDsc, varDscInfo->varNum, strip(corInfoType), typeHnd, argLst, &info.compMethodInfo->args); if (strip(corInfoType) == CORINFO_TYPE_CLASS) diff --git a/src/coreclr/jit/lower.cpp b/src/coreclr/jit/lower.cpp index f8bc800241491..77776a903d4fa 100644 --- a/src/coreclr/jit/lower.cpp +++ b/src/coreclr/jit/lower.cpp @@ -1994,148 +1994,9 @@ void Lowering::LowerArgsForCall(GenTreeCall* call) LowerArg(call, &arg, true); } -#if defined(TARGET_X86) && defined(FEATURE_IJW) - LowerSpecialCopyArgs(call); -#endif // defined(TARGET_X86) && defined(FEATURE_IJW) - LegalizeArgPlacement(call); } -#if defined(TARGET_X86) && defined(FEATURE_IJW) -//------------------------------------------------------------------------ -// LowerSpecialCopyArgs: Lower special copy arguments for P/Invoke IL stubs -// -// Arguments: -// call - the call node -// -// Notes: -// This method is used for P/Invoke IL stubs on x86 to handle arguments with special copy semantics. -// In particular, this method implements copy-constructor semantics for managed-to-unmanaged IL stubs -// for C++/CLI. In this case, the managed argument is passed by (managed or unmanaged) pointer in the -// P/Invoke signature with a speial modreq, but is passed to the unmanaged function by value. -// The value passed to the unmanaged function must be created through a copy-constructor call copying from -// the original source argument. -// We assume that the IL stub will be generated such that the following holds true: -// - If an argument to the IL stub has the special modreq, then its corresponding argument to the -// unmanaged function will be passed as the same argument index. Therefore, we can introduce the copy call -// from the original source argument to the argument slot in the unmanaged call. -void Lowering::LowerSpecialCopyArgs(GenTreeCall* call) -{ - // We only need to use the special copy helper on P/Invoke IL stubs - // for the unmanaged call. - if (comp->opts.jitFlags->IsSet(JitFlags::JIT_FLAG_IL_STUB) && comp->compMethodRequiresPInvokeFrame() && - call->IsUnmanaged() && comp->compHasSpecialCopyArgs()) - { - // Unmanaged calling conventions on Windows x86 are passed in reverse order - // of managed args, so we need to count down the number of args. - // If the call is thiscall, we need to account for the this parameter, - // which will be first in the list. - // The this parameter is always passed in registers, so we can ignore it. - unsigned argIndex = call->gtArgs.CountUserArgs() - 1; - assert(call->gtArgs.CountUserArgs() == comp->info.compILargsCount); - for (CallArg& arg : call->gtArgs.Args()) - { - if (!arg.IsUserArg()) - { - continue; - } - - if (call->GetUnmanagedCallConv() == CorInfoCallConvExtension::Thiscall && - argIndex == call->gtArgs.CountUserArgs() - 1) - { - assert(arg.GetNode()->OperIs(GT_PUTARG_REG)); - continue; - } - - unsigned paramLclNum = comp->compMapILargNum(argIndex); - assert(paramLclNum < comp->info.compArgsCount); - - // check if parameter at the same index as the IL argument is marked as requiring special copy, assuming - // that it is being passed 1:1 to the pinvoke - if (comp->argRequiresSpecialCopy(paramLclNum) && (arg.GetSignatureType() == TYP_STRUCT)) - { - assert(arg.GetNode()->OperIs(GT_PUTARG_STK)); - InsertSpecialCopyArg(arg.GetNode()->AsPutArgStk(), arg.GetSignatureClassHandle(), paramLclNum); - } - - argIndex--; - } - } -} - -//------------------------------------------------------------------------ -// InsertSpecialCopyArg: Insert a call to the special copy helper to copy from the (possibly value pointed-to by) local -// lclnum to the argument slot represented by putArgStk -// -// Arguments: -// putArgStk - the PutArgStk node representing the stack slot of the argument -// argType - the struct type of the argument -// lclNum - the local to use as the source for the special copy helper -// -// Notes: -// This method assumes that lclNum is either a by-ref to a struct of type argType -// or a struct of type argType. -// We use this to preserve special copy semantics for interop calls where we pass in a byref to a struct into a -// P/Invoke with a special modreq and the native function expects to recieve the struct by value with the argument -// being passed in having been created by the special copy helper. -// -void Lowering::InsertSpecialCopyArg(GenTreePutArgStk* putArgStk, CORINFO_CLASS_HANDLE argType, unsigned lclNum) -{ - assert(putArgStk != nullptr); - GenTree* dest = comp->gtNewPhysRegNode(REG_SPBASE, TYP_I_IMPL); - - GenTree* src; - var_types lclType = comp->lvaGetRealType(lclNum); - - if (lclType == TYP_BYREF || lclType == TYP_I_IMPL) - { - src = comp->gtNewLclVarNode(lclNum, lclType); - } - else - { - assert(lclType == TYP_STRUCT); - src = comp->gtNewLclAddrNode(lclNum, 0, TYP_I_IMPL); - } - - GenTree* destPlaceholder = comp->gtNewZeroConNode(dest->TypeGet()); - GenTree* srcPlaceholder = comp->gtNewZeroConNode(src->TypeGet()); - - GenTreeCall* call = - comp->gtNewCallNode(CT_USER_FUNC, comp->info.compCompHnd->getSpecialCopyHelper(argType), TYP_VOID); - - call->gtArgs.PushBack(comp, NewCallArg::Primitive(destPlaceholder)); - call->gtArgs.PushBack(comp, NewCallArg::Primitive(srcPlaceholder)); - - comp->fgMorphArgs(call); - - LIR::Range callRange = LIR::SeqTree(comp, call); - GenTree* callRangeStart = callRange.FirstNode(); - GenTree* callRangeEnd = callRange.LastNode(); - - BlockRange().InsertAfter(putArgStk, std::move(callRange)); - BlockRange().InsertAfter(putArgStk, dest); - BlockRange().InsertAfter(putArgStk, src); - - LIR::Use destUse; - LIR::Use srcUse; - BlockRange().TryGetUse(destPlaceholder, &destUse); - BlockRange().TryGetUse(srcPlaceholder, &srcUse); - destUse.ReplaceWith(dest); - srcUse.ReplaceWith(src); - destPlaceholder->SetUnusedValue(); - srcPlaceholder->SetUnusedValue(); - - LowerRange(callRangeStart, callRangeEnd); - - // Finally move all GT_PUTARG_* nodes - // Re-use the existing logic for CFG call args here - MoveCFGCallArgs(call); - - BlockRange().Remove(destPlaceholder); - BlockRange().Remove(srcPlaceholder); -} -#endif // defined(TARGET_X86) && defined(FEATURE_IJW) - //------------------------------------------------------------------------ // LegalizeArgPlacement: Move arg placement nodes (PUTARG_*) into a legal // ordering after they have been created. diff --git a/src/coreclr/jit/lower.h b/src/coreclr/jit/lower.h index c5c771167025e..bff33917f28da 100644 --- a/src/coreclr/jit/lower.h +++ b/src/coreclr/jit/lower.h @@ -183,10 +183,6 @@ class Lowering final : public Phase GenTree* LowerVirtualStubCall(GenTreeCall* call); void LowerArgsForCall(GenTreeCall* call); void ReplaceArgWithPutArgOrBitcast(GenTree** ppChild, GenTree* newNode); -#if defined(TARGET_X86) && defined(FEATURE_IJW) - void LowerSpecialCopyArgs(GenTreeCall* call); - void InsertSpecialCopyArg(GenTreePutArgStk* putArgStk, CORINFO_CLASS_HANDLE argType, unsigned lclNum); -#endif // defined(TARGET_X86) && defined(FEATURE_IJW) GenTree* NewPutArg(GenTreeCall* call, GenTree* arg, CallArg* callArg, var_types type); void LowerArg(GenTreeCall* call, CallArg* callArg, bool late); #if defined(TARGET_ARMARCH) || defined(TARGET_LOONGARCH64) || defined(TARGET_RISCV64) diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs index 06141640ef53c..5f908f3c2d179 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs @@ -4464,10 +4464,5 @@ private static bool TryReadRvaFieldData(FieldDesc field, byte* buffer, int buffe } return false; } - - private CORINFO_METHOD_STRUCT_* getSpecialCopyHelper(CORINFO_CLASS_STRUCT_* type) - { - throw new NotImplementedException("getSpecialCopyHelper"); - } } } diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs index 76b08b42458b3..94a45a5c57455 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs @@ -2605,25 +2605,10 @@ private static uint _getJitFlags(IntPtr thisHandle, IntPtr* ppException, CORJIT_ } } - [UnmanagedCallersOnly] - private static CORINFO_METHOD_STRUCT_* _getSpecialCopyHelper(IntPtr thisHandle, IntPtr* ppException, CORINFO_CLASS_STRUCT_* type) - { - var _this = GetThis(thisHandle); - try - { - return _this.getSpecialCopyHelper(type); - } - catch (Exception ex) - { - *ppException = _this.AllocException(ex); - return default; - } - } - private static IntPtr GetUnmanagedCallbacks() { - void** callbacks = (void**)Marshal.AllocCoTaskMem(sizeof(IntPtr) * 177); + void** callbacks = (void**)Marshal.AllocCoTaskMem(sizeof(IntPtr) * 176); callbacks[0] = (delegate* unmanaged)&_isIntrinsic; callbacks[1] = (delegate* unmanaged)&_notifyMethodInfoUsage; @@ -2801,7 +2786,6 @@ private static IntPtr GetUnmanagedCallbacks() callbacks[173] = (delegate* unmanaged)&_getRelocTypeHint; callbacks[174] = (delegate* unmanaged)&_getExpectedTargetArchitecture; callbacks[175] = (delegate* unmanaged)&_getJitFlags; - callbacks[176] = (delegate* unmanaged)&_getSpecialCopyHelper; return (IntPtr)callbacks; } diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs b/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs index 4be84d0c316f8..902fa1159ed53 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs @@ -783,7 +783,6 @@ public enum CorInfoTypeWithMod { CORINFO_TYPE_MASK = 0x3F, // lower 6 bits are type mask CORINFO_TYPE_MOD_PINNED = 0x40, // can be applied to CLASS, or BYREF to indicate pinned - CORINFO_TYPE_MOD_COPY_WITH_HELPER = 0x80, // can be applied to VALUECLASS to indicate 'needs helper to copy' }; public struct CORINFO_HELPER_ARG diff --git a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt index e776aa2796259..a7ca75b0d7bec 100644 --- a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt +++ b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt @@ -340,4 +340,3 @@ FUNCTIONS uint16_t getRelocTypeHint(void* target) uint32_t getExpectedTargetArchitecture() uint32_t getJitFlags(CORJIT_FLAGS* flags, uint32_t sizeInBytes) - CORINFO_METHOD_HANDLE getSpecialCopyHelper(CORINFO_CLASS_HANDLE type) = 0; diff --git a/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h b/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h index c56fe13931863..f1ddd13340672 100644 --- a/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h +++ b/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h @@ -187,7 +187,6 @@ struct JitInterfaceCallbacks uint16_t (* getRelocTypeHint)(void * thisHandle, CorInfoExceptionClass** ppException, void* target); uint32_t (* getExpectedTargetArchitecture)(void * thisHandle, CorInfoExceptionClass** ppException); uint32_t (* getJitFlags)(void * thisHandle, CorInfoExceptionClass** ppException, CORJIT_FLAGS* flags, uint32_t sizeInBytes); - CORINFO_METHOD_HANDLE (* getSpecialCopyHelper)(void * thisHandle, CorInfoExceptionClass** ppException, CORINFO_CLASS_HANDLE type); }; @@ -1920,13 +1919,4 @@ class JitInterfaceWrapper : public ICorJitInfo if (pException != nullptr) throw pException; return temp; } - - virtual CORINFO_METHOD_HANDLE getSpecialCopyHelper( - CORINFO_CLASS_HANDLE type) -{ - CorInfoExceptionClass* pException = nullptr; - CORINFO_METHOD_HANDLE temp = _callbacks->getSpecialCopyHelper(_thisHandle, &pException, type); - if (pException != nullptr) throw pException; - return temp; -} }; diff --git a/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h b/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h index e00f86d1b6458..bb2c78da30854 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h @@ -131,7 +131,6 @@ LWM(GetSwiftLowering, DWORDLONG, Agnostic_GetSwiftLowering) LWM(GetFpStructLowering, DWORDLONG, Agnostic_GetFpStructLowering) LWM(GetTailCallHelpers, Agnostic_GetTailCallHelpers, Agnostic_CORINFO_TAILCALL_HELPERS) LWM(UpdateEntryPointForTailCall, Agnostic_CORINFO_CONST_LOOKUP, Agnostic_CORINFO_CONST_LOOKUP) -LWM(GetSpecialCopyHelper, DWORDLONG, DWORDLONG) LWM(GetThreadTLSIndex, DWORD, DLD) LWM(GetTokenTypeAsHandle, GetTokenTypeAsHandleValue, DWORDLONG) LWM(GetTypeForBox, DWORDLONG, DWORDLONG) diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp index d1078fe8d356c..4c56364d86539 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.cpp @@ -3718,7 +3718,7 @@ void MethodContext::recGetThreadLocalStaticBlocksInfo(CORINFO_THREAD_STATIC_BLOC void MethodContext::dmpGetThreadLocalStaticBlocksInfo(DWORD key, const Agnostic_GetThreadLocalStaticBlocksInfo& value) { printf("GetThreadLocalStaticBlocksInfo key %u, tlsIndex-%s, " - ", tlsGetAddrFtnPtr-%016" PRIX64 ", tlsIndexObject - %016" PRIX64 + ", tlsGetAddrFtnPtr-%016" PRIX64 ", tlsIndexObject - %016" PRIX64 ", threadVarsSection - %016" PRIX64 ", offsetOfThreadLocalStoragePointer-%u" ", offsetOfMaxThreadStaticBlocks-%u" @@ -7212,33 +7212,6 @@ const WCHAR* MethodContext::repGetStringConfigValue(const WCHAR* name) return value; } -void MethodContext::recGetSpecialCopyHelper(CORINFO_CLASS_HANDLE type, CORINFO_METHOD_HANDLE helper) -{ - if (GetSpecialCopyHelper == nullptr) - GetSpecialCopyHelper = new LightWeightMap(); - - DWORDLONG key; - ZeroMemory(&key, sizeof(key)); // Zero key including any struct padding - key = CastHandle(type); - - DWORDLONG value = CastHandle(helper); - GetSpecialCopyHelper->Add(key, value); - DEBUG_REC(dmpGetSpecialCopyHelper(key, value)); -} - -void MethodContext::dmpGetSpecialCopyHelper(DWORDLONG key, DWORDLONG value) -{ - printf("getSpecialCopyHelper key %016" PRIX64 ", value %016" PRIX64 "", key, value); -} - -CORINFO_METHOD_HANDLE MethodContext::repGetSpecialCopyHelper(CORINFO_CLASS_HANDLE type) -{ - DWORDLONG key = CastHandle(type); - DWORDLONG value = LookupByKeyOrMiss(GetSpecialCopyHelper, key, ": key %016" PRIX64 "", key); - DEBUG_REP(dmpGetSpecialCopyHelper(key, value)); - return (CORINFO_METHOD_HANDLE)value; -} - void MethodContext::dmpSigInstHandleMap(DWORD key, DWORDLONG value) { printf("SigInstHandleMap key %u, value %016" PRIX64 "", key, value); diff --git a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h index 4625ad44aab37..0b2e84d37811e 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/methodcontext.h @@ -589,7 +589,7 @@ class MethodContext void recGetIsClassInitedFlagAddress(CORINFO_CLASS_HANDLE cls, CORINFO_CONST_LOOKUP* addr, int* offset, bool result); void dmpGetIsClassInitedFlagAddress(DWORDLONG key, const Agnostic_GetIsClassInitedFlagAddress& value); bool repGetIsClassInitedFlagAddress(CORINFO_CLASS_HANDLE cls, CORINFO_CONST_LOOKUP* addr, int* offset); - + void recGetStaticBaseAddress(CORINFO_CLASS_HANDLE cls, bool isGc, CORINFO_CONST_LOOKUP* addr, bool result); void dmpGetStaticBaseAddress(DLD key, const Agnostic_GetStaticBaseAddress& value); bool repGetStaticBaseAddress(CORINFO_CLASS_HANDLE cls, bool isGc, CORINFO_CONST_LOOKUP* addr); @@ -898,10 +898,6 @@ class MethodContext void dmpGetStringConfigValue(DWORD nameIndex, DWORD result); const WCHAR* repGetStringConfigValue(const WCHAR* name); - void recGetSpecialCopyHelper(CORINFO_CLASS_HANDLE type, CORINFO_METHOD_HANDLE helper); - void dmpGetSpecialCopyHelper(DWORDLONG key, DWORDLONG value); - CORINFO_METHOD_HANDLE repGetSpecialCopyHelper(CORINFO_CLASS_HANDLE type); - void dmpSigInstHandleMap(DWORD key, DWORDLONG value); struct Environment @@ -1193,7 +1189,6 @@ enum mcPackets Packet_GetTypeForBoxOnStack = 221, Packet_GetTypeDefinition = 222, Packet_GetFpStructLowering = 223, - Packet_GetSpecialCopyHelper = 224, }; void SetDebugDumpVariables(); diff --git a/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp index b3fab2e939dae..368b2cbaec47d 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp @@ -2028,11 +2028,3 @@ bool interceptor_ICJI::notifyInstructionSetUsage(CORINFO_InstructionSet instruct { return original_ICorJitInfo->notifyInstructionSetUsage(instructionSet, supported); } - -CORINFO_METHOD_HANDLE interceptor_ICJI::getSpecialCopyHelper(CORINFO_CLASS_HANDLE type) -{ - mc->cr->AddCall("getSpecialCopyHelper"); - CORINFO_METHOD_HANDLE temp = original_ICorJitInfo->getSpecialCopyHelper(type); - mc->recGetSpecialCopyHelper(type, temp); - return temp; -} diff --git a/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp b/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp index 638f6649613fa..2702c0a409bcf 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp @@ -1437,10 +1437,3 @@ uint32_t interceptor_ICJI::getJitFlags( return original_ICorJitInfo->getJitFlags(flags, sizeInBytes); } -CORINFO_METHOD_HANDLE interceptor_ICJI::getSpecialCopyHelper( - CORINFO_CLASS_HANDLE type) -{ - mcs->AddCall("getSpecialCopyHelper"); - return original_ICorJitInfo->getSpecialCopyHelper(type); -} - diff --git a/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp b/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp index c285ef2c3c6ca..f2e6f5cbd9962 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp @@ -1261,9 +1261,3 @@ uint32_t interceptor_ICJI::getJitFlags( return original_ICorJitInfo->getJitFlags(flags, sizeInBytes); } -CORINFO_METHOD_HANDLE interceptor_ICJI::getSpecialCopyHelper( - CORINFO_CLASS_HANDLE type) -{ - return original_ICorJitInfo->getSpecialCopyHelper(type); -} - diff --git a/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp b/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp index 64c52f61705ae..153ba61212305 100644 --- a/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp +++ b/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp @@ -1864,10 +1864,3 @@ uint32_t MyICJI::getExpectedTargetArchitecture() DWORD result = jitInstance->mc->repGetExpectedTargetArchitecture(); return result; } - -CORINFO_METHOD_HANDLE MyICJI::getSpecialCopyHelper(CORINFO_CLASS_HANDLE type) -{ - jitInstance->mc->cr->AddCall("getSpecialCopyHelper"); - CORINFO_METHOD_HANDLE result = jitInstance->mc->repGetSpecialCopyHelper(type); - return result; -} diff --git a/src/coreclr/vm/corelib.h b/src/coreclr/vm/corelib.h index b73ad90126df9..ea78d259cd73e 100644 --- a/src/coreclr/vm/corelib.h +++ b/src/coreclr/vm/corelib.h @@ -635,7 +635,6 @@ DEFINE_METHOD(RUNTIME_HELPERS, ENUM_COMPARE_TO, EnumCompareTo, NoSig DEFINE_METHOD(RUNTIME_HELPERS, ALLOC_TAILCALL_ARG_BUFFER, AllocTailCallArgBuffer, SM_Int_IntPtr_RetIntPtr) DEFINE_METHOD(RUNTIME_HELPERS, GET_TAILCALL_INFO, GetTailCallInfo, NoSig) DEFINE_METHOD(RUNTIME_HELPERS, DISPATCH_TAILCALLS, DispatchTailCalls, NoSig) -DEFINE_METHOD(RUNTIME_HELPERS, COPY_CONSTRUCT, CopyConstruct, NoSig) DEFINE_CLASS(SPAN_HELPERS, System, SpanHelpers) DEFINE_METHOD(SPAN_HELPERS, MEMSET, Fill, SM_RefByte_Byte_UIntPtr_RetVoid) @@ -1050,6 +1049,21 @@ DEFINE_METHOD(HANDLE_MARSHALER, CONVERT_SAFEHANDLE_TO_NATIVE,ConvertSaf DEFINE_METHOD(HANDLE_MARSHALER, THROW_SAFEHANDLE_FIELD_CHANGED, ThrowSafeHandleFieldChanged, SM_RetVoid) DEFINE_METHOD(HANDLE_MARSHALER, THROW_CRITICALHANDLE_FIELD_CHANGED, ThrowCriticalHandleFieldChanged, SM_RetVoid) +#ifdef TARGET_WINDOWS +#ifdef TARGET_X86 +DEFINE_CLASS(COPY_CONSTRUCTOR_CHAIN, StubHelpers, CopyConstructorChain) +DEFINE_METHOD(COPY_CONSTRUCTOR_CHAIN, EXECUTE_CURRENT_COPIES_AND_GET_TARGET, ExecuteCurrentCopiesAndGetTarget, SM_PtrVoid_RetPtrVoid) +DEFINE_METHOD(COPY_CONSTRUCTOR_CHAIN, INSTALL, Install, IM_PtrVoid_RetVoid) +DEFINE_METHOD(COPY_CONSTRUCTOR_CHAIN, ADD, Add, IM_PtrCopyConstructorCookie_RetVoid) + +DEFINE_CLASS(COPY_CONSTRUCTOR_COOKIE, StubHelpers, CopyConstructorCookie) +DEFINE_FIELD(COPY_CONSTRUCTOR_COOKIE, SOURCE, m_source) +DEFINE_FIELD(COPY_CONSTRUCTOR_COOKIE, DESTINATION_OFFSET, m_destinationOffset) +DEFINE_FIELD(COPY_CONSTRUCTOR_COOKIE, COPY_CONSTRUCTOR, m_copyConstructor) +DEFINE_FIELD(COPY_CONSTRUCTOR_COOKIE, DESTRUCTOR, m_destructor) +#endif // TARGET_X86 +#endif // TARGET_WINDOWS + DEFINE_CLASS(COMVARIANT, Marshalling, ComVariant) DEFINE_CLASS(SZARRAYHELPER, System, SZArrayHelper) diff --git a/src/coreclr/vm/dllimport.cpp b/src/coreclr/vm/dllimport.cpp index 285e06ee2a131..d6ebd11a59c37 100644 --- a/src/coreclr/vm/dllimport.cpp +++ b/src/coreclr/vm/dllimport.cpp @@ -211,7 +211,7 @@ class StubState virtual void SetLastError(BOOL fSetLastError) = 0; virtual void BeginEmit(DWORD dwStubFlags) = 0; virtual void MarshalReturn(MarshalInfo* pInfo, int argOffset) = 0; - virtual void MarshalArgument(MarshalInfo* pInfo, int argOffset) = 0; + virtual void MarshalArgument(MarshalInfo* pInfo, int argOffset, UINT nativeStackOffset) = 0; virtual void MarshalLCID(int argIdx) = 0; virtual void MarshalField(MarshalInfo* pInfo, UINT32 managedOffset, UINT32 nativeOffset, FieldDesc* pFieldDesc) = 0; @@ -288,7 +288,7 @@ class ILStubState : public StubState SF_IsHRESULTSwapping(m_dwStubFlags)); } - void MarshalArgument(MarshalInfo* pInfo, int argOffset) + void MarshalArgument(MarshalInfo* pInfo, int argOffset, UINT nativeStackOffset) { CONTRACTL { @@ -297,7 +297,7 @@ class ILStubState : public StubState } CONTRACTL_END; - pInfo->GenerateArgumentIL(&m_slIL, argOffset, SF_IsForwardStub(m_dwStubFlags)); + pInfo->GenerateArgumentIL(&m_slIL, argOffset, nativeStackOffset, SF_IsForwardStub(m_dwStubFlags)); } void MarshalField(MarshalInfo* pInfo, UINT32 managedOffset, UINT32 nativeOffset, FieldDesc* pFieldDesc) @@ -408,7 +408,7 @@ class ILStubState : public StubState { SigPointer sigPtr(pStubMD->GetSig()); - sigPtr.ConvertToInternalSignature(pStubMD->GetModule(), NULL, &sigBuilder, GetTokenLookupMap()); + sigPtr.ConvertToInternalSignature(pStubMD->GetModule(), NULL, &sigBuilder); } // @@ -464,25 +464,6 @@ class ILStubState : public StubState cbTempModuleIndependentSigLength); } - void ConvertMethodDescSigToModuleIndependentSig(MethodDesc* pStubMD) - { - SigBuilder sigBuilder; - SigPointer sigPtr(pStubMD->GetSig()); - sigPtr.ConvertToInternalSignature(pStubMD->GetModule(), NULL, &sigBuilder, GetTokenLookupMap()); - - // - // make a domain-local copy of the sig so that this state can outlive the - // compile time state. - // - DWORD cbNewSig = sigBuilder.GetSignatureLength(); - PVOID pNewSigBuffer = sigBuilder.GetSignature(&cbNewSig); - PCCOR_SIGNATURE pNewSig = (PCCOR_SIGNATURE)(void *)pStubMD->GetLoaderAllocator()->GetHighFrequencyHeap()->AllocMem(S_SIZE_T(cbNewSig)); - - memcpyNoGCRefs((void *)pNewSig, pNewSigBuffer, cbNewSig); - - pStubMD->AsDynamicMethodDesc()->SetStoredMethodSig(pNewSig, cbNewSig); - } - void EmitInvokeTarget(MethodDesc *pStubMD) { STANDARD_VM_CONTRACT; @@ -818,17 +799,8 @@ class ILStubState : public StubState if (SF_IsReverseStub(m_dwStubFlags)) { - // If we're in a Reverse stub, the target signature we've built - // is the signature of the stub, and the current signature of the stub - // is the target signature. We need to swap them. SwapStubSignatures(pStubMD); } - else - { - // If we're not in a Reverse stub, the signatures are correct, - // but we need to convert the signature into a module-independent form. - ConvertMethodDescSigToModuleIndependentSig(pStubMD); - } ILCodeLabel* pTryBeginLabel = nullptr; ILCodeLabel* pTryEndAndCatchBeginLabel = nullptr; @@ -1648,6 +1620,10 @@ NDirectStubLinker::NDirectStubLinker( m_pcsSetup->EmitSTLOC(m_dwTargetInterfacePointerLocalNum); } #endif // FEATURE_COMINTEROP + +#if defined(TARGET_X86) && defined(FEATURE_IJW) + m_dwCopyCtorChainLocalNum = (DWORD)-1; +#endif // defined(TARGET_X86) && defined(FEATURE_IJW) } void NDirectStubLinker::SetCallingConvention(CorInfoCallConvExtension unmngCallConv, BOOL fIsVarArg) @@ -1860,6 +1836,23 @@ DWORD NDirectStubLinker::GetReturnValueLocalNum() return m_dwRetValLocalNum; } +#if defined(TARGET_X86) && defined(FEATURE_IJW) +DWORD NDirectStubLinker::GetCopyCtorChainLocalNum() +{ + STANDARD_VM_CONTRACT; + + if (m_dwCopyCtorChainLocalNum == (DWORD)-1) + { + // The local is created and initialized lazily when first asked. + m_dwCopyCtorChainLocalNum = NewLocal(CoreLibBinder::GetClass(CLASS__COPY_CONSTRUCTOR_CHAIN)); + m_pcsSetup->EmitLDLOCA(m_dwCopyCtorChainLocalNum); + m_pcsSetup->EmitINITOBJ(m_pcsSetup->GetToken(CoreLibBinder::GetClass(CLASS__COPY_CONSTRUCTOR_CHAIN))); + } + + return m_dwCopyCtorChainLocalNum; +} +#endif // defined(TARGET_X86) && defined(FEATURE_IJW) + BOOL NDirectStubLinker::IsCleanupNeeded() { LIMITED_METHOD_CONTRACT; @@ -2089,6 +2082,10 @@ void NDirectStubLinker::End(DWORD dwStubFlags) } } +#if defined(TARGET_X86) && defined(TARGET_WINDOWS) +EXTERN_C void STDCALL CopyConstructorCallStub(void); +#endif // defined(TARGET_X86) && defined(TARGET_WINDOWS) + void NDirectStubLinker::DoNDirect(ILCodeStream *pcsEmit, DWORD dwStubFlags, MethodDesc * pStubMD) { STANDARD_VM_CONTRACT; @@ -2172,6 +2169,21 @@ void NDirectStubLinker::DoNDirect(ILCodeStream *pcsEmit, DWORD dwStubFlags, Meth } } +#if defined(TARGET_X86) && defined(FEATURE_IJW) + if (m_dwCopyCtorChainLocalNum != (DWORD)-1) + { + // If we have a copy constructor chain local, we need to call the copy constructor stub + // to ensure that the chain is called correctly. + // Let's install the stub chain here and redirect the call to the stub. + DWORD targetLoc = NewLocal(ELEMENT_TYPE_I); + pcsEmit->EmitSTLOC(targetLoc); + pcsEmit->EmitLDLOCA(m_dwCopyCtorChainLocalNum); + pcsEmit->EmitLDLOC(targetLoc); + pcsEmit->EmitCALL(METHOD__COPY_CONSTRUCTOR_CHAIN__INSTALL, 2, 0); + pcsEmit->EmitLDC((DWORD_PTR)&CopyConstructorCallStub); + } +#endif // defined(TARGET_X86) && defined(FEATURE_IJW) + // For managed-to-native calls, the rest of the work is done by the JIT. It will // erect InlinedCallFrame, flip GC mode, and use the specified calling convention // to call the target. For native-to-managed calls, this is an ordinary managed @@ -2403,7 +2415,7 @@ class DispatchStubState : public StubState // For CLR-to-COM late-bound/eventing CONTRACTL_END; } - void MarshalArgument(MarshalInfo* pInfo, int argOffset) + void MarshalArgument(MarshalInfo* pInfo, int argOffset, UINT nativeStackOffset) { CONTRACTL { @@ -3445,6 +3457,7 @@ static MarshalInfo::MarshalType DoMarshalReturnValue(MetaSig& msig, int argOffset, DWORD dwStubFlags, MethodDesc *pMD, + UINT& nativeStackOffset, bool& fStubNeedsCOM, int nativeArgIndex DEBUG_ARG(LPCUTF8 pDebugName) @@ -3567,6 +3580,19 @@ static MarshalInfo::MarshalType DoMarshalReturnValue(MetaSig& msig, return marshalType; } +static inline UINT GetStackOffsetFromStackSize(UINT stackSize, bool fThisCall) +{ + LIMITED_METHOD_CONTRACT; +#ifdef TARGET_X86 + if (fThisCall) + { + // -1 means that the argument is not on the stack + return (stackSize >= TARGET_POINTER_SIZE ? (stackSize - TARGET_POINTER_SIZE) : (UINT)-1); + } +#endif // TARGET_X86 + return stackSize; +} + //--------------------------------------------------------- // Creates a new stub for a N/Direct call. Return refcount is 1. // Note that this function may now throw if it fails to create @@ -3756,7 +3782,7 @@ static void CreateNDirectStubWorker(StubState* pss, MarshalInfo &info = pParamMarshalInfo[argidx - 1]; - pss->MarshalArgument(&info, argOffset); + pss->MarshalArgument(&info, argOffset, GetStackOffsetFromStackSize(nativeStackSize, fThisCall)); nativeStackSize += info.GetNativeArgSize(); fStubNeedsCOM |= info.MarshalerRequiresCOM(); @@ -3792,6 +3818,7 @@ static void CreateNDirectStubWorker(StubState* pss, argOffset, dwStubFlags, pMD, + nativeStackSize, fStubNeedsCOM, nativeArgIndex DEBUG_ARG(pSigDesc->m_pDebugName) @@ -3996,7 +4023,6 @@ namespace DWORD m_StubFlags; INT32 m_iLCIDArg; - INT32 m_tokenMapHash; INT32 m_nParams; BYTE m_rgbSigAndParamData[1]; // (dwParamAttr, cbNativeType) // length: number of parameters @@ -4052,11 +4078,8 @@ namespace // note that ConvertToInternalSignature also resolves generics so different instantiations will get different // hash blobs for methods that have generic parameters in their signature - // The signature may have custom modifiers, so provide a token lookup map to resolve them. - // We'll include a hash of the token lookup map in the hash blob. - TokenLookupMap tokenLookupMap; SigBuilder sigBuilder; - sigPtr.ConvertToInternalSignature(pParams->m_pModule, pParams->m_pTypeContext, &sigBuilder, &tokenLookupMap); + sigPtr.ConvertToInternalSignature(pParams->m_pModule, pParams->m_pTypeContext, &sigBuilder, /* bSkipCustomModifier = */ FALSE); DWORD cbSig; PVOID pSig = sigBuilder.GetSignature(&cbSig); @@ -4091,7 +4114,6 @@ namespace pBlob->m_nlFlags = static_cast(pParams->m_nlFlags & ~nlfNoMangle); // this flag does not affect the stub pBlob->m_iLCIDArg = pParams->m_iLCIDArg; - pBlob->m_tokenMapHash = tokenLookupMap.GetHashValue(); pBlob->m_StubFlags = pParams->m_dwStubFlags; pBlob->m_nParams = pParams->m_nParamTokens; @@ -6091,415 +6113,21 @@ PCODE GetILStubForCalli(VASigCookie *pVASigCookie, MethodDesc *pMD) RETURN pVASigCookie->pNDirectILStub; } -namespace -{ - //------------------------------------------------------------------------------------- - // Return the copy ctor for a VC class (if any exists) - //------------------------------------------------------------------------------------- - void FindCopyConstructor(Module *pModule, MethodTable *pMT, MethodDesc **pMDOut) - { - CONTRACTL - { - THROWS; - GC_TRIGGERS; // CompareTypeTokens may trigger GC - MODE_ANY; - } - CONTRACTL_END; - - *pMDOut = NULL; - - HRESULT hr; - mdMethodDef tk; - mdTypeDef cl = pMT->GetCl(); - TypeHandle th = TypeHandle(pMT); - SigTypeContext typeContext(th); - - IMDInternalImport *pInternalImport = pModule->GetMDImport(); - MDEnumHolder hEnumMethod(pInternalImport); - - // - // First try for the new syntax: - // - IfFailThrow(pInternalImport->EnumInit(mdtMethodDef, cl, &hEnumMethod)); - - while (pInternalImport->EnumNext(&hEnumMethod, &tk)) - { - _ASSERTE(TypeFromToken(tk) == mdtMethodDef); - DWORD dwMemberAttrs; - IfFailThrow(pInternalImport->GetMethodDefProps(tk, &dwMemberAttrs)); - - if (IsMdSpecialName(dwMemberAttrs)) - { - ULONG cSig; - PCCOR_SIGNATURE pSig; - LPCSTR pName; - IfFailThrow(pInternalImport->GetNameAndSigOfMethodDef(tk, &pSig, &cSig, &pName)); - - const char *pBaseName = ""; - int ncBaseName = (int)strlen(pBaseName); - int nc = (int)strlen(pName); - if (nc >= ncBaseName && 0 == strcmp(pName + nc - ncBaseName, pBaseName)) - { - MetaSig msig(pSig, cSig, pModule, &typeContext); - - // Looking for the prototype void (Ptr VC, Ptr VC); - if (msig.NumFixedArgs() == 2) - { - if (msig.GetReturnType() == ELEMENT_TYPE_VOID) - { - if (msig.NextArg() == ELEMENT_TYPE_PTR) - { - SigPointer sp1 = msig.GetArgProps(); - IfFailThrow(sp1.GetElemType(NULL)); - CorElementType eType; - IfFailThrow(sp1.GetElemType(&eType)); - if (eType == ELEMENT_TYPE_VALUETYPE) - { - mdToken tk1; - IfFailThrow(sp1.GetToken(&tk1)); - hr = CompareTypeTokensNT(tk1, cl, pModule, pModule); - if (FAILED(hr)) - { - pInternalImport->EnumClose(&hEnumMethod); - ThrowHR(hr); - } - - if (hr == S_OK) - { - if (msig.NextArg() == ELEMENT_TYPE_PTR) - { - SigPointer sp2 = msig.GetArgProps(); - IfFailThrow(sp2.GetElemType(NULL)); - IfFailThrow(sp2.GetElemType(&eType)); - if (eType == ELEMENT_TYPE_VALUETYPE) - { - mdToken tk2; - IfFailThrow(sp2.GetToken(&tk2)); - - hr = (tk2 == tk1) ? S_OK : CompareTypeTokensNT(tk2, cl, pModule, pModule); - if (hr == S_OK) - { - *pMDOut = pModule->LookupMethodDef(tk); - return; - } - } - } - } - } - } - } - } - } - } - } - - // - // Next try the old syntax: global .__ctor - // - IfFailThrow(pInternalImport->EnumGlobalFunctionsInit(&hEnumMethod)); - - while (pInternalImport->EnumNext(&hEnumMethod, &tk)) - { - _ASSERTE(TypeFromToken(tk) == mdtMethodDef); - DWORD dwMemberAttrs; - IfFailThrow(pInternalImport->GetMethodDefProps(tk, &dwMemberAttrs)); - - if (IsMdSpecialName(dwMemberAttrs)) - { - ULONG cSig; - PCCOR_SIGNATURE pSig; - LPCSTR pName; - IfFailThrow(pInternalImport->GetNameAndSigOfMethodDef(tk, &pSig, &cSig, &pName)); - - const char *pBaseName = ".__ctor"; - int ncBaseName = (int)strlen(pBaseName); - int nc = (int)strlen(pName); - if (nc >= ncBaseName && 0 == strcmp(pName + nc - ncBaseName, pBaseName)) - { - - MetaSig msig(pSig, cSig, pModule, &typeContext); - - // Looking for the prototype Ptr VC __ctor(Ptr VC, ByRef VC); - if (msig.NumFixedArgs() == 2) - { - if (msig.GetReturnType() == ELEMENT_TYPE_PTR) - { - SigPointer spret = msig.GetReturnProps(); - IfFailThrow(spret.GetElemType(NULL)); - CorElementType eType; - IfFailThrow(spret.GetElemType(&eType)); - if (eType == ELEMENT_TYPE_VALUETYPE) - { - mdToken tk0; - IfFailThrow(spret.GetToken(&tk0)); - hr = CompareTypeTokensNT(tk0, cl, pModule, pModule); - if (FAILED(hr)) - { - pInternalImport->EnumClose(&hEnumMethod); - ThrowHR(hr); - } - - if (hr == S_OK) - { - if (msig.NextArg() == ELEMENT_TYPE_PTR) - { - SigPointer sp1 = msig.GetArgProps(); - IfFailThrow(sp1.GetElemType(NULL)); - IfFailThrow(sp1.GetElemType(&eType)); - if (eType == ELEMENT_TYPE_VALUETYPE) - { - mdToken tk1; - IfFailThrow(sp1.GetToken(&tk1)); - hr = (tk1 == tk0) ? S_OK : CompareTypeTokensNT(tk1, cl, pModule, pModule); - if (FAILED(hr)) - { - pInternalImport->EnumClose(&hEnumMethod); - ThrowHR(hr); - } - - if (hr == S_OK) - { - if (msig.NextArg() == ELEMENT_TYPE_PTR && - msig.GetArgProps().HasCustomModifier(pModule, "Microsoft.VisualC.IsCXXReferenceModifier", ELEMENT_TYPE_CMOD_OPT)) - { - SigPointer sp2 = msig.GetArgProps(); - IfFailThrow(sp2.GetElemType(NULL)); - IfFailThrow(sp2.GetElemType(&eType)); - if (eType == ELEMENT_TYPE_VALUETYPE) - { - mdToken tk2; - IfFailThrow(sp2.GetToken(&tk2)); - - hr = (tk2 == tk0) ? S_OK : CompareTypeTokensNT(tk2, cl, pModule, pModule); - if (hr == S_OK) - { - *pMDOut = pModule->LookupMethodDef(tk); - return; - } - } - } - } - } - } - } - } - } - } - } - } - } - } - - - //------------------------------------------------------------------------------------- - // Return the destructor for a VC class (if any exists) - //------------------------------------------------------------------------------------- - void FindDestructor(Module *pModule, MethodTable *pMT, MethodDesc **pMDOut) - { - CONTRACTL - { - THROWS; - GC_TRIGGERS; // CompareTypeTokens may trigger GC - MODE_ANY; - } - CONTRACTL_END; - - *pMDOut = NULL; - - HRESULT hr; - mdMethodDef tk; - mdTypeDef cl = pMT->GetCl(); - TypeHandle th = TypeHandle(pMT); - SigTypeContext typeContext(th); - - IMDInternalImport *pInternalImport = pModule->GetMDImport(); - MDEnumHolder hEnumMethod(pInternalImport); - - // - // First try for the new syntax: - // - IfFailThrow(pInternalImport->EnumInit(mdtMethodDef, cl, &hEnumMethod)); - - while (pInternalImport->EnumNext(&hEnumMethod, &tk)) - { - _ASSERTE(TypeFromToken(tk) == mdtMethodDef); - DWORD dwMemberAttrs; - IfFailThrow(pInternalImport->GetMethodDefProps(tk, &dwMemberAttrs)); - - if (IsMdSpecialName(dwMemberAttrs)) - { - ULONG cSig; - PCCOR_SIGNATURE pSig; - LPCSTR pName; - IfFailThrow(pInternalImport->GetNameAndSigOfMethodDef(tk, &pSig, &cSig, &pName)); - - const char *pBaseName = ""; - int ncBaseName = (int)strlen(pBaseName); - int nc = (int)strlen(pName); - if (nc >= ncBaseName && 0 == strcmp(pName + nc - ncBaseName, pBaseName)) - { - MetaSig msig(pSig, cSig, pModule, &typeContext); - - // Looking for the prototype void (Ptr VC); - if (msig.NumFixedArgs() == 1) - { - if (msig.GetReturnType() == ELEMENT_TYPE_VOID) - { - if (msig.NextArg() == ELEMENT_TYPE_PTR) - { - SigPointer sp1 = msig.GetArgProps(); - IfFailThrow(sp1.GetElemType(NULL)); - CorElementType eType; - IfFailThrow(sp1.GetElemType(&eType)); - if (eType == ELEMENT_TYPE_VALUETYPE) - { - mdToken tk1; - IfFailThrow(sp1.GetToken(&tk1)); - - hr = CompareTypeTokensNT(tk1, cl, pModule, pModule); - IfFailThrow(hr); - - if (hr == S_OK) - { - *pMDOut = pModule->LookupMethodDef(tk); - return; - } - } - } - } - } - } - } - } - - - // - // Next try the old syntax: global .__dtor - // - IfFailThrow(pInternalImport->EnumGlobalFunctionsInit(&hEnumMethod)); - - while (pInternalImport->EnumNext(&hEnumMethod, &tk)) - { - _ASSERTE(TypeFromToken(tk) == mdtMethodDef); - ULONG cSig; - PCCOR_SIGNATURE pSig; - LPCSTR pName; - IfFailThrow(pInternalImport->GetNameAndSigOfMethodDef(tk, &pSig, &cSig, &pName)); - - const char *pBaseName = ".__dtor"; - int ncBaseName = (int)strlen(pBaseName); - int nc = (int)strlen(pName); - if (nc >= ncBaseName && 0 == strcmp(pName + nc - ncBaseName, pBaseName)) - { - MetaSig msig(pSig, cSig, pModule, &typeContext); - - // Looking for the prototype void __dtor(Ptr VC); - if (msig.NumFixedArgs() == 1) - { - if (msig.GetReturnType() == ELEMENT_TYPE_VOID) - { - if (msig.NextArg() == ELEMENT_TYPE_PTR) - { - SigPointer sp1 = msig.GetArgProps(); - IfFailThrow(sp1.GetElemType(NULL)); - CorElementType eType; - IfFailThrow(sp1.GetElemType(&eType)); - if (eType == ELEMENT_TYPE_VALUETYPE) - { - mdToken tk1; - IfFailThrow(sp1.GetToken(&tk1)); - hr = CompareTypeTokensNT(tk1, cl, pModule, pModule); - if (FAILED(hr)) - { - pInternalImport->EnumClose(&hEnumMethod); - ThrowHR(hr); - } - - if (hr == S_OK) - { - *pMDOut = pModule->LookupMethodDef(tk); - return; - } - } - } - } - } - } - } - } -} - -bool GenerateCopyConstructorHelper(MethodDesc* ftn, TypeHandle type, DynamicResolver** ppResolver, COR_ILMETHOD_DECODER** ppHeader, CORINFO_METHOD_INFO* methInfo) +#if defined(TARGET_X86) && defined(FEATURE_IJW) +// Copy constructor support for C++/CLI +EXTERN_C void* STDCALL CallCopyConstructorsWorker(void* esp) { - if (!type.IsValueType()) - return false; - - MethodTable * pMT = type.AsMethodTable(); - - MethodDesc* pCopyCtor = nullptr; - FindCopyConstructor(pMT->GetModule(), pMT, &pCopyCtor); - - MethodDesc* pDestructor = nullptr; - FindDestructor(pMT->GetModule(), pMT, &pDestructor); - - NewHolder ilResolver = new ILStubResolver(); - ilResolver->SetStubMethodDesc(ftn); - - SigTypeContext genericContext; - SigTypeContext::InitTypeContext(ftn, &genericContext); - - ILStubLinker sl( - ftn->GetModule(), - ftn->GetSignature(), - &genericContext, - ftn, - ILSTUB_LINKER_FLAG_NONE); - - ILCodeStream* pCode = sl.NewCodeStream(ILStubLinker::kDispatch); - - pCode->EmitLDARG(0); - pCode->EmitLDARG(1); - if (pCopyCtor != nullptr) - { - pCode->EmitCALL(pCode->GetToken(pCopyCtor), 2, 0); - } - else - { - pCode->EmitLDC(type.GetSize()); - pCode->EmitCPBLK(); - } - - if (pDestructor != nullptr) - { - pCode->EmitLDARG(1); - pCode->EmitCALL(pCode->GetToken(pDestructor), 1, 0); - } - - pCode->EmitRET(); - - // Generate all IL associated data for JIT - { - UINT maxStack; - size_t cbCode = sl.Link(&maxStack); - DWORD cbSig = sl.GetLocalSigSize(); - - COR_ILMETHOD_DECODER* pILHeader = ilResolver->AllocGeneratedIL(cbCode, cbSig, maxStack); - BYTE* pbBuffer = (BYTE*)pILHeader->Code; - BYTE* pbLocalSig = (BYTE*)pILHeader->LocalVarSig; - _ASSERTE(cbSig == pILHeader->cbLocalVarSig); - sl.GenerateCode(pbBuffer, cbCode); - sl.GetLocalSig(pbLocalSig, cbSig); + STATIC_CONTRACT_THROWS; + STATIC_CONTRACT_GC_TRIGGERS; + STATIC_CONTRACT_MODE_PREEMPTIVE; // we've already switched to preemptive - // Store the token lookup map - ilResolver->SetTokenLookupMap(sl.GetTokenLookupMap()); - ilResolver->SetJitFlags(CORJIT_FLAGS(CORJIT_FLAGS::CORJIT_FLAG_IL_STUB)); + using ExecuteCallback = void*(STDMETHODCALLTYPE*)(void*); - *ppResolver = (DynamicResolver*)ilResolver; - *ppHeader = pILHeader; - } + MethodDesc* pMD = CoreLibBinder::GetMethod(METHOD__COPY_CONSTRUCTOR_CHAIN__EXECUTE_CURRENT_COPIES_AND_GET_TARGET); + ExecuteCallback pExecute = (ExecuteCallback)pMD->GetMultiCallableAddrOfCode(); - ilResolver.SuppressRelease(); - return true; + return pExecute(esp); } +#endif // defined(TARGET_X86) && defined(FEATURE_IJW) #endif // #ifndef DACCESS_COMPILE diff --git a/src/coreclr/vm/dllimport.h b/src/coreclr/vm/dllimport.h index 2fdd426391a1c..f5e2c058fb1a1 100644 --- a/src/coreclr/vm/dllimport.h +++ b/src/coreclr/vm/dllimport.h @@ -488,6 +488,9 @@ class NDirectStubLinker : public ILStubLinker DWORD GetCleanupWorkListLocalNum(); DWORD GetThreadLocalNum(); DWORD GetReturnValueLocalNum(); +#if defined(TARGET_X86) && defined(FEATURE_IJW) + DWORD GetCopyCtorChainLocalNum(); +#endif // defined(TARGET_X86) && defined(FEATURE_IJW) void SetCleanupNeeded(); void SetExceptionCleanupNeeded(); BOOL IsCleanupWorkListSetup(); @@ -557,6 +560,10 @@ class NDirectStubLinker : public ILStubLinker DWORD m_dwTargetEntryPointLocalNum; #endif // FEATURE_COMINTEROP +#if defined(TARGET_X86) && defined(FEATURE_IJW) + DWORD m_dwCopyCtorChainLocalNum; +#endif // defined(TARGET_X86) && defined(FEATURE_IJW) + BOOL m_fHasCleanupCode; BOOL m_fHasExceptionCleanupCode; BOOL m_fCleanupWorkListIsSetup; @@ -592,7 +599,6 @@ HRESULT FindPredefinedILStubMethod(MethodDesc *pTargetMD, DWORD dwStubFlags, Met #ifndef DACCESS_COMPILE void MarshalStructViaILStub(MethodDesc* pStubMD, void* pManagedData, void* pNativeData, StructMarshalStubs::MarshalOperation operation, void** ppCleanupWorkList = nullptr); void MarshalStructViaILStubCode(PCODE pStubCode, void* pManagedData, void* pNativeData, StructMarshalStubs::MarshalOperation operation, void** ppCleanupWorkList = nullptr); -bool GenerateCopyConstructorHelper(MethodDesc* ftn, TypeHandle type, DynamicResolver** ppResolver, COR_ILMETHOD_DECODER** ppHeader, CORINFO_METHOD_INFO* methInfo); #endif // DACCESS_COMPILE // diff --git a/src/coreclr/vm/i386/asmhelpers.asm b/src/coreclr/vm/i386/asmhelpers.asm index 801de37407386..07f6e8b955d03 100644 --- a/src/coreclr/vm/i386/asmhelpers.asm +++ b/src/coreclr/vm/i386/asmhelpers.asm @@ -40,6 +40,7 @@ EXTERN _NDirectImportWorker@4:PROC EXTERN _VarargPInvokeStubWorker@12:PROC EXTERN _GenericPInvokeCalliStubWorker@12:PROC +EXTERN _CallCopyConstructorsWorker@4:PROC EXTERN _PreStubWorker@8:PROC EXTERN _TheUMEntryPrestubWorker@4:PROC @@ -1005,6 +1006,29 @@ GoCallCalliWorker: _GenericPInvokeCalliHelper@0 endp +;========================================================================== +; This is small stub whose purpose is to record current stack pointer and +; call CallCopyConstructorsWorker to invoke copy constructors and destructors +; as appropriate. This stub operates on arguments already pushed to the +; stack by JITted IL stub and must not create a new frame, i.e. it must tail +; call to the target for it to see the arguments that copy ctors have been +; called on. +; +_CopyConstructorCallStub@0 proc public + ; there may be an argument in ecx - save it + push ecx + + ; push pointer to arguments + lea edx, [esp + 8] + push edx + + call _CallCopyConstructorsWorker@4 + + ; restore ecx and tail call to the target + pop ecx + jmp eax +_CopyConstructorCallStub@0 endp + ifdef FEATURE_COMINTEROP ;========================================================================== diff --git a/src/coreclr/vm/ilmarshalers.cpp b/src/coreclr/vm/ilmarshalers.cpp index ab3a8b4539d14..75d979076bd3a 100644 --- a/src/coreclr/vm/ilmarshalers.cpp +++ b/src/coreclr/vm/ilmarshalers.cpp @@ -2644,7 +2644,8 @@ MarshalerOverrideStatus ILHandleRefMarshaler::ArgumentOverride(NDirectStubLinker BOOL fManagedToNative, OverrideProcArgs* pargs, UINT* pResID, - UINT argidx) + UINT argidx, + UINT nativeStackOffset) { CONTRACTL { @@ -2736,7 +2737,8 @@ MarshalerOverrideStatus ILSafeHandleMarshaler::ArgumentOverride(NDirectStubLinke BOOL fManagedToNative, OverrideProcArgs* pargs, UINT* pResID, - UINT argidx) + UINT argidx, + UINT nativeStackOffset) { CONTRACTL { @@ -3093,7 +3095,8 @@ MarshalerOverrideStatus ILCriticalHandleMarshaler::ArgumentOverride(NDirectStubL BOOL fManagedToNative, OverrideProcArgs* pargs, UINT* pResID, - UINT argidx) + UINT argidx, + UINT nativeStackOffset) { CONTRACTL { @@ -3399,7 +3402,8 @@ MarshalerOverrideStatus ILBlittableValueClassWithCopyCtorMarshaler::ArgumentOver BOOL fManagedToNative, OverrideProcArgs* pargs, UINT* pResID, - UINT argidx) + UINT argidx, + UINT nativeStackOffset) { CONTRACTL { @@ -3420,40 +3424,75 @@ MarshalerOverrideStatus ILBlittableValueClassWithCopyCtorMarshaler::ArgumentOver if (fManagedToNative) { -#ifdef TARGET_X86 - LocalDesc locDesc(pargs->mm.m_pMT); - pslIL->SetStubTargetArgType(&locDesc); // native type is the value type - locDesc.MakeByRef(); + // 1) create new native value type local + // 2) run new->CopyCtor(old) + // 3) run old->Dtor() - locDesc.MakePinned(); + LocalDesc locDesc(pargs->mm.m_pMT); - DWORD dwPinnedArgLocal; + DWORD dwNewValueTypeLocal; // Step 1 - dwPinnedArgLocal = pslIL->NewLocal(locDesc); - - pslIL->EmitLDARG(argidx); - pslIL->EmitSTLOC(dwPinnedArgLocal); - - pslILDispatch->EmitLDARG(argidx); - pslILDispatch->EmitLDOBJ(pslIL->GetToken(pargs->mm.m_pMT)); -#else - LocalDesc locDesc(pargs->mm.m_pMT); + dwNewValueTypeLocal = pslIL->NewLocal(locDesc); - locDesc.MakeByRef(); - locDesc.MakePinned(); + // Step 2 + if (pargs->mm.m_pCopyCtor) + { + // Managed copy constructor has signature of CopyCtor(T* new, T old); + pslIL->EmitLDLOCA(dwNewValueTypeLocal); + pslIL->EmitLDARG(argidx); + pslIL->EmitCALL(pslIL->GetToken(pargs->mm.m_pCopyCtor), 2, 0); + } + else + { + pslIL->EmitLDARG(argidx); + pslIL->EmitLDOBJ(pslIL->GetToken(pargs->mm.m_pMT)); + pslIL->EmitSTLOC(dwNewValueTypeLocal); + } - DWORD dwPinnedArgLocal; + // Step 3 + if (pargs->mm.m_pDtor) + { + // Managed destructor has signature of Destructor(T old); + pslIL->EmitLDARG(argidx); + pslIL->EmitCALL(pslIL->GetToken(pargs->mm.m_pDtor), 1, 0); + } +#ifdef TARGET_X86 + pslIL->SetStubTargetArgType(&locDesc); // native type is the value type + pslILDispatch->EmitLDLOC(dwNewValueTypeLocal); // we load the local directly + + // Record this argument's stack slot in the copy constructor chain so we can correctly invoke the copy constructor. + DWORD ctorCookie = pslIL->NewLocal(CoreLibBinder::GetClass(CLASS__COPY_CONSTRUCTOR_COOKIE)); + pslIL->EmitLDLOCA(ctorCookie); + pslIL->EmitINITOBJ(pslIL->GetToken(CoreLibBinder::GetClass(CLASS__COPY_CONSTRUCTOR_COOKIE))); + pslIL->EmitLDLOCA(ctorCookie); + pslIL->EmitLDLOCA(dwNewValueTypeLocal); + pslIL->EmitSTFLD(pslIL->GetToken(CoreLibBinder::GetField(FIELD__COPY_CONSTRUCTOR_COOKIE__SOURCE))); + pslIL->EmitLDLOCA(ctorCookie); + pslIL->EmitLDC(nativeStackOffset); + pslIL->EmitSTFLD(pslIL->GetToken(CoreLibBinder::GetField(FIELD__COPY_CONSTRUCTOR_COOKIE__DESTINATION_OFFSET))); + + if (pargs->mm.m_pCopyCtor) + { + pslIL->EmitLDLOCA(ctorCookie); + pslIL->EmitLDFTN(pslIL->GetToken(pargs->mm.m_pCopyCtor)); + pslIL->EmitSTFLD(pslIL->GetToken(CoreLibBinder::GetField(FIELD__COPY_CONSTRUCTOR_COOKIE__COPY_CONSTRUCTOR))); + } - // Step 1 - dwPinnedArgLocal = pslIL->NewLocal(locDesc); + if (pargs->mm.m_pDtor) + { + pslIL->EmitLDLOCA(ctorCookie); + pslIL->EmitLDFTN(pslIL->GetToken(pargs->mm.m_pDtor)); + pslIL->EmitSTFLD(pslIL->GetToken(CoreLibBinder::GetField(FIELD__COPY_CONSTRUCTOR_COOKIE__DESTRUCTOR))); + } - pslIL->EmitLDARG(argidx); - pslIL->EmitSTLOC(dwPinnedArgLocal); + pslIL->EmitLDLOCA(psl->GetCopyCtorChainLocalNum()); + pslIL->EmitLDLOCA(ctorCookie); + pslIL->EmitCALL(METHOD__COPY_CONSTRUCTOR_CHAIN__ADD, 2, 0); - pslIL->SetStubTargetArgType(ELEMENT_TYPE_U); // native type is a pointer - pslILDispatch->EmitLDLOC(dwPinnedArgLocal); - pslILDispatch->EmitCONV_U(); +#else + pslIL->SetStubTargetArgType(ELEMENT_TYPE_I); // native type is a pointer + EmitLoadNativeLocalAddrForByRefDispatch(pslILDispatch, dwNewValueTypeLocal); #endif return OVERRIDDEN; @@ -3465,9 +3504,10 @@ MarshalerOverrideStatus ILBlittableValueClassWithCopyCtorMarshaler::ArgumentOver // but on other platforms it comes by-reference #ifdef TARGET_X86 LocalDesc locDesc(pargs->mm.m_pMT); - locDesc.AddModifier(true, pslIL->GetToken(pargs->mm.m_pSigMod)); pslIL->SetStubTargetArgType(&locDesc); + DWORD dwNewValueTypeLocal; + dwNewValueTypeLocal = pslIL->NewLocal(locDesc); pslILDispatch->EmitLDARGA(argidx); #else LocalDesc locDesc(pargs->mm.m_pMT); diff --git a/src/coreclr/vm/ilmarshalers.h b/src/coreclr/vm/ilmarshalers.h index ca84692561b03..11c3983fc6549 100644 --- a/src/coreclr/vm/ilmarshalers.h +++ b/src/coreclr/vm/ilmarshalers.h @@ -1490,7 +1490,8 @@ class ILMarshaler BOOL fManagedToNative, OverrideProcArgs* pargs, UINT* pResID, - UINT argidx) + UINT argidx, + UINT nativeStackOffset) { LIMITED_METHOD_CONTRACT; return HANDLEASNORMAL; @@ -2206,7 +2207,8 @@ class ILHandleRefMarshaler : public ILMarshaler BOOL fManagedToNative, OverrideProcArgs* pargs, UINT* pResID, - UINT argidx); + UINT argidx, + UINT nativeStackOffset); static MarshalerOverrideStatus ReturnOverride(NDirectStubLinker* psl, BOOL fManagedToNative, @@ -2246,7 +2248,8 @@ class ILSafeHandleMarshaler : public ILMarshaler BOOL fManagedToNative, OverrideProcArgs* pargs, UINT* pResID, - UINT argidx); + UINT argidx, + UINT nativeStackOffset); static MarshalerOverrideStatus ReturnOverride(NDirectStubLinker *psl, BOOL fManagedToNative, @@ -2289,7 +2292,8 @@ class ILCriticalHandleMarshaler : public ILMarshaler BOOL fManagedToNative, OverrideProcArgs* pargs, UINT* pResID, - UINT argidx); + UINT argidx, + UINT nativeStackOffset); static MarshalerOverrideStatus ReturnOverride(NDirectStubLinker *psl, BOOL fManagedToNative, @@ -2948,7 +2952,8 @@ class ILBlittableValueClassWithCopyCtorMarshaler : public ILMarshaler BOOL fManagedToNative, OverrideProcArgs* pargs, UINT* pResID, - UINT argidx); + UINT argidx, + UINT nativeStackOffset); }; diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index 505b35c4552af..edabdbc3d4373 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -3743,8 +3743,18 @@ uint32_t CEEInfo::getClassAttribsInternal (CORINFO_CLASS_HANDLE clsHnd) if (pMT->IsByRefLike()) ret |= CORINFO_FLG_BYREF_LIKE; - if (pClass->IsUnsafeValueClass()) + // In Reverse P/Invoke stubs, we are generating the code + // and we are not generating the code patterns that the GS checks + // are meant to catch. + // As a result, we can skip setting this flag. + // We do this as the GS checks (emitted when this flag is set) + // can break C++/CLI's copy-constructor semantics by missing copies. + if (pClass->IsUnsafeValueClass() + && !(m_pMethodBeingCompiled->IsILStub() + && dac_cast(m_pMethodBeingCompiled)->GetILStubType() == DynamicMethodDesc::StubNativeToCLRInterop)) + { ret |= CORINFO_FLG_UNSAFE_VALUECLASS; + } } if (pClass->HasExplicitFieldOffsetLayout() && pClass->HasOverlaidField()) ret |= CORINFO_FLG_OVERLAPPING_FIELDS; @@ -7634,26 +7644,6 @@ static void getMethodInfoHelper( SigPointer localSig = pResolver->GetLocalSig(); localSig.GetSignature(&pLocalSig, &cbLocalSig); } - else if (ftn->GetMemberDef() == CoreLibBinder::GetMethod(METHOD__RUNTIME_HELPERS__COPY_CONSTRUCT)->GetMemberDef()) - { - _ASSERTE(ftn->HasMethodInstantiation()); - Instantiation inst = ftn->GetMethodInstantiation(); - - _ASSERTE(inst.GetNumArgs() == 1); - TypeHandle type = inst[0]; - - if (!GenerateCopyConstructorHelper(ftn, type, &cxt.TransientResolver, &cxt.Header, methInfo)) - { - ThrowHR(COR_E_BADIMAGEFORMAT); - } - - scopeHnd = cxt.CreateScopeHandle(); - - _ASSERTE(cxt.Header != NULL); - getMethodInfoILMethodHeaderHelper(cxt.Header, methInfo); - pLocalSig = cxt.Header->LocalVarSig; - cbLocalSig = cxt.Header->cbLocalVarSig; - } else { if (!ftn->TryGenerateUnsafeAccessor(&cxt.TransientResolver, &cxt.Header)) @@ -9438,32 +9428,6 @@ CORINFO_ARG_LIST_HANDLE CEEInfo::getArgNext(CORINFO_ARG_LIST_HANDLE args) /*********************************************************************/ -namespace -{ - bool HasCopyConstructorModifier(SigPointer sig, CORINFO_MODULE_HANDLE scope) - { - if (IsDynamicScope(scope)) - { - DynamicResolver* pResolver = GetDynamicResolver(scope); - if (sig.HasCustomModifier(pResolver, "Microsoft.VisualC.NeedsCopyConstructorModifier", ELEMENT_TYPE_CMOD_REQD) || - sig.HasCustomModifier(pResolver, "System.Runtime.CompilerServices.IsCopyConstructed", ELEMENT_TYPE_CMOD_REQD)) - { - return true; - } - } - else - { - Module* pModule = GetModule(scope); - if (sig.HasCustomModifier(pModule, "Microsoft.VisualC.NeedsCopyConstructorModifier", ELEMENT_TYPE_CMOD_REQD) || - sig.HasCustomModifier(pModule, "System.Runtime.CompilerServices.IsCopyConstructed", ELEMENT_TYPE_CMOD_REQD)) - { - return true; - } - } - return false; - } -} - CorInfoTypeWithMod CEEInfo::getArgType ( CORINFO_SIG_INFO* sig, CORINFO_ARG_LIST_HANDLE args, @@ -9494,17 +9458,12 @@ CorInfoTypeWithMod CEEInfo::getArgType ( IfFailThrow(ptr.PeekElemType(&eType)); } - Module* pModule = GetModule(sig->scope); - - if (HasCopyConstructorModifier(ptr, sig->scope)) - { - result = CorInfoTypeWithMod((int)result | CORINFO_TYPE_MOD_COPY_WITH_HELPER); - } - // Now read off the "real" element type after taking any instantiations into consideration SigTypeContext typeContext; GetTypeContext(&sig->sigInst,&typeContext); + Module* pModule = GetModule(sig->scope); + CorElementType type = ptr.PeekElemTypeClosed(pModule, &typeContext); TypeHandle typeHnd = TypeHandle(); @@ -9542,14 +9501,6 @@ CorInfoTypeWithMod CEEInfo::getArgType ( classMustBeLoadedBeforeCodeIsRun(CORINFO_CLASS_HANDLE(thPtr.AsPtr())); } } - FALLTHROUGH; - - case ELEMENT_TYPE_BYREF: - IfFailThrow(ptr.GetElemType(NULL)); - if (HasCopyConstructorModifier(ptr, sig->scope)) - { - result = CorInfoTypeWithMod((int)result | CORINFO_TYPE_MOD_COPY_WITH_HELPER); - } break; case ELEMENT_TYPE_VOID: @@ -10002,40 +9953,6 @@ void CEEInfo::getAddressOfPInvokeTarget(CORINFO_METHOD_HANDLE method, EE_TO_JIT_TRANSITION(); } -CORINFO_METHOD_HANDLE CEEInfo::getSpecialCopyHelper(CORINFO_CLASS_HANDLE type) -{ - CONTRACTL { - THROWS; - GC_TRIGGERS; - MODE_PREEMPTIVE; - } CONTRACTL_END; - - CORINFO_METHOD_HANDLE result = NULL; - - JIT_TO_EE_TRANSITION(); - - TypeHandle th = TypeHandle(type); - - _ASSERTE(th.IsValueType()); - - MethodDesc* pHelperMD = CoreLibBinder::GetMethod(METHOD__RUNTIME_HELPERS__COPY_CONSTRUCT); - - pHelperMD = MethodDesc::FindOrCreateAssociatedMethodDesc( - pHelperMD, - pHelperMD->GetMethodTable(), - FALSE, - Instantiation(&th, 1), - FALSE, - FALSE); - - pHelperMD->CheckRestore(); - result = (CORINFO_METHOD_HANDLE)pHelperMD; - - EE_TO_JIT_TRANSITION(); - - return result; -} - /*********************************************************************/ CORINFO_JUST_MY_CODE_HANDLE CEEInfo::getJustMyCodeHandle( CORINFO_METHOD_HANDLE method, diff --git a/src/coreclr/vm/metasig.h b/src/coreclr/vm/metasig.h index 5aadd2c49f6e9..0f0b5cd898aa3 100644 --- a/src/coreclr/vm/metasig.h +++ b/src/coreclr/vm/metasig.h @@ -589,6 +589,9 @@ DEFINE_METASIG_T(SM(RefCleanupWorkListElement_Obj_RetVoid, r(C(CLEANUP_WORK_LIST DEFINE_METASIG(SM(PtrVoid_RetPtrVoid, P(v), P(v))) DEFINE_METASIG(SM(PtrVoid_PtrVoid_PtrVoid_RetVoid, P(v) P(v) P(v), v)) DEFINE_METASIG(IM(PtrVoid_RetVoid, P(v), v)) +#if defined(TARGET_X86) && defined(TARGET_WINDOWS) +DEFINE_METASIG_T(IM(PtrCopyConstructorCookie_RetVoid, P(g(COPY_CONSTRUCTOR_COOKIE)), v)) +#endif // defined(TARGET_X86) && defined(TARGET_WINDOWS) #ifdef FEATURE_ICASTABLE diff --git a/src/coreclr/vm/mlinfo.cpp b/src/coreclr/vm/mlinfo.cpp index 53edc30eec3d8..8131e4fd3053a 100644 --- a/src/coreclr/vm/mlinfo.cpp +++ b/src/coreclr/vm/mlinfo.cpp @@ -46,6 +46,344 @@ #define INITIAL_NUM_CMINFO_HASHTABLE_BUCKETS 32 #define DEBUG_CONTEXT_STR_LEN 2000 +namespace +{ + //------------------------------------------------------------------------------------- + // Return the copy ctor for a VC class (if any exists) + //------------------------------------------------------------------------------------- + void FindCopyCtor(Module *pModule, MethodTable *pMT, MethodDesc **pMDOut) + { + CONTRACTL + { + THROWS; + GC_TRIGGERS; // CompareTypeTokens may trigger GC + MODE_ANY; + } + CONTRACTL_END; + + *pMDOut = NULL; + + HRESULT hr; + mdMethodDef tk; + mdTypeDef cl = pMT->GetCl(); + TypeHandle th = TypeHandle(pMT); + SigTypeContext typeContext(th); + + IMDInternalImport *pInternalImport = pModule->GetMDImport(); + MDEnumHolder hEnumMethod(pInternalImport); + + // + // First try for the new syntax: + // + IfFailThrow(pInternalImport->EnumInit(mdtMethodDef, cl, &hEnumMethod)); + + while (pInternalImport->EnumNext(&hEnumMethod, &tk)) + { + _ASSERTE(TypeFromToken(tk) == mdtMethodDef); + DWORD dwMemberAttrs; + IfFailThrow(pInternalImport->GetMethodDefProps(tk, &dwMemberAttrs)); + + if (IsMdSpecialName(dwMemberAttrs)) + { + ULONG cSig; + PCCOR_SIGNATURE pSig; + LPCSTR pName; + IfFailThrow(pInternalImport->GetNameAndSigOfMethodDef(tk, &pSig, &cSig, &pName)); + + const char *pBaseName = ""; + int ncBaseName = (int)strlen(pBaseName); + int nc = (int)strlen(pName); + if (nc >= ncBaseName && 0 == strcmp(pName + nc - ncBaseName, pBaseName)) + { + MetaSig msig(pSig, cSig, pModule, &typeContext); + + // Looking for the prototype void (Ptr VC, Ptr VC); + if (msig.NumFixedArgs() == 2) + { + if (msig.GetReturnType() == ELEMENT_TYPE_VOID) + { + if (msig.NextArg() == ELEMENT_TYPE_PTR) + { + SigPointer sp1 = msig.GetArgProps(); + IfFailThrow(sp1.GetElemType(NULL)); + CorElementType eType; + IfFailThrow(sp1.GetElemType(&eType)); + if (eType == ELEMENT_TYPE_VALUETYPE) + { + mdToken tk1; + IfFailThrow(sp1.GetToken(&tk1)); + hr = CompareTypeTokensNT(tk1, cl, pModule, pModule); + if (FAILED(hr)) + { + pInternalImport->EnumClose(&hEnumMethod); + ThrowHR(hr); + } + + if (hr == S_OK) + { + if (msig.NextArg() == ELEMENT_TYPE_PTR) + { + SigPointer sp2 = msig.GetArgProps(); + IfFailThrow(sp2.GetElemType(NULL)); + IfFailThrow(sp2.GetElemType(&eType)); + if (eType == ELEMENT_TYPE_VALUETYPE) + { + mdToken tk2; + IfFailThrow(sp2.GetToken(&tk2)); + + hr = (tk2 == tk1) ? S_OK : CompareTypeTokensNT(tk2, cl, pModule, pModule); + if (hr == S_OK) + { + *pMDOut = pModule->LookupMethodDef(tk); + return; + } + } + } + } + } + } + } + } + } + } + } + + // + // Next try the old syntax: global .__ctor + // + IfFailThrow(pInternalImport->EnumGlobalFunctionsInit(&hEnumMethod)); + + while (pInternalImport->EnumNext(&hEnumMethod, &tk)) + { + _ASSERTE(TypeFromToken(tk) == mdtMethodDef); + DWORD dwMemberAttrs; + IfFailThrow(pInternalImport->GetMethodDefProps(tk, &dwMemberAttrs)); + + if (IsMdSpecialName(dwMemberAttrs)) + { + ULONG cSig; + PCCOR_SIGNATURE pSig; + LPCSTR pName; + IfFailThrow(pInternalImport->GetNameAndSigOfMethodDef(tk, &pSig, &cSig, &pName)); + + const char *pBaseName = ".__ctor"; + int ncBaseName = (int)strlen(pBaseName); + int nc = (int)strlen(pName); + if (nc >= ncBaseName && 0 == strcmp(pName + nc - ncBaseName, pBaseName)) + { + + MetaSig msig(pSig, cSig, pModule, &typeContext); + + // Looking for the prototype Ptr VC __ctor(Ptr VC, ByRef VC); + if (msig.NumFixedArgs() == 2) + { + if (msig.GetReturnType() == ELEMENT_TYPE_PTR) + { + SigPointer spret = msig.GetReturnProps(); + IfFailThrow(spret.GetElemType(NULL)); + CorElementType eType; + IfFailThrow(spret.GetElemType(&eType)); + if (eType == ELEMENT_TYPE_VALUETYPE) + { + mdToken tk0; + IfFailThrow(spret.GetToken(&tk0)); + hr = CompareTypeTokensNT(tk0, cl, pModule, pModule); + if (FAILED(hr)) + { + pInternalImport->EnumClose(&hEnumMethod); + ThrowHR(hr); + } + + if (hr == S_OK) + { + if (msig.NextArg() == ELEMENT_TYPE_PTR) + { + SigPointer sp1 = msig.GetArgProps(); + IfFailThrow(sp1.GetElemType(NULL)); + IfFailThrow(sp1.GetElemType(&eType)); + if (eType == ELEMENT_TYPE_VALUETYPE) + { + mdToken tk1; + IfFailThrow(sp1.GetToken(&tk1)); + hr = (tk1 == tk0) ? S_OK : CompareTypeTokensNT(tk1, cl, pModule, pModule); + if (FAILED(hr)) + { + pInternalImport->EnumClose(&hEnumMethod); + ThrowHR(hr); + } + + if (hr == S_OK) + { + if (msig.NextArg() == ELEMENT_TYPE_PTR && + msig.GetArgProps().HasCustomModifier(pModule, "Microsoft.VisualC.IsCXXReferenceModifier", ELEMENT_TYPE_CMOD_OPT)) + { + SigPointer sp2 = msig.GetArgProps(); + IfFailThrow(sp2.GetElemType(NULL)); + IfFailThrow(sp2.GetElemType(&eType)); + if (eType == ELEMENT_TYPE_VALUETYPE) + { + mdToken tk2; + IfFailThrow(sp2.GetToken(&tk2)); + + hr = (tk2 == tk0) ? S_OK : CompareTypeTokensNT(tk2, cl, pModule, pModule); + if (hr == S_OK) + { + *pMDOut = pModule->LookupMethodDef(tk); + return; + } + } + } + } + } + } + } + } + } + } + } + } + } + } + + + //------------------------------------------------------------------------------------- + // Return the destructor for a VC class (if any exists) + //------------------------------------------------------------------------------------- + void FindDtor(Module *pModule, MethodTable *pMT, MethodDesc **pMDOut) + { + CONTRACTL + { + THROWS; + GC_TRIGGERS; // CompareTypeTokens may trigger GC + MODE_ANY; + } + CONTRACTL_END; + + *pMDOut = NULL; + + HRESULT hr; + mdMethodDef tk; + mdTypeDef cl = pMT->GetCl(); + TypeHandle th = TypeHandle(pMT); + SigTypeContext typeContext(th); + + IMDInternalImport *pInternalImport = pModule->GetMDImport(); + MDEnumHolder hEnumMethod(pInternalImport); + + // + // First try for the new syntax: + // + IfFailThrow(pInternalImport->EnumInit(mdtMethodDef, cl, &hEnumMethod)); + + while (pInternalImport->EnumNext(&hEnumMethod, &tk)) + { + _ASSERTE(TypeFromToken(tk) == mdtMethodDef); + DWORD dwMemberAttrs; + IfFailThrow(pInternalImport->GetMethodDefProps(tk, &dwMemberAttrs)); + + if (IsMdSpecialName(dwMemberAttrs)) + { + ULONG cSig; + PCCOR_SIGNATURE pSig; + LPCSTR pName; + IfFailThrow(pInternalImport->GetNameAndSigOfMethodDef(tk, &pSig, &cSig, &pName)); + + const char *pBaseName = ""; + int ncBaseName = (int)strlen(pBaseName); + int nc = (int)strlen(pName); + if (nc >= ncBaseName && 0 == strcmp(pName + nc - ncBaseName, pBaseName)) + { + MetaSig msig(pSig, cSig, pModule, &typeContext); + + // Looking for the prototype void (Ptr VC); + if (msig.NumFixedArgs() == 1) + { + if (msig.GetReturnType() == ELEMENT_TYPE_VOID) + { + if (msig.NextArg() == ELEMENT_TYPE_PTR) + { + SigPointer sp1 = msig.GetArgProps(); + IfFailThrow(sp1.GetElemType(NULL)); + CorElementType eType; + IfFailThrow(sp1.GetElemType(&eType)); + if (eType == ELEMENT_TYPE_VALUETYPE) + { + mdToken tk1; + IfFailThrow(sp1.GetToken(&tk1)); + + hr = CompareTypeTokensNT(tk1, cl, pModule, pModule); + IfFailThrow(hr); + + if (hr == S_OK) + { + *pMDOut = pModule->LookupMethodDef(tk); + return; + } + } + } + } + } + } + } + } + + + // + // Next try the old syntax: global .__dtor + // + IfFailThrow(pInternalImport->EnumGlobalFunctionsInit(&hEnumMethod)); + + while (pInternalImport->EnumNext(&hEnumMethod, &tk)) + { + _ASSERTE(TypeFromToken(tk) == mdtMethodDef); + ULONG cSig; + PCCOR_SIGNATURE pSig; + LPCSTR pName; + IfFailThrow(pInternalImport->GetNameAndSigOfMethodDef(tk, &pSig, &cSig, &pName)); + + const char *pBaseName = ".__dtor"; + int ncBaseName = (int)strlen(pBaseName); + int nc = (int)strlen(pName); + if (nc >= ncBaseName && 0 == strcmp(pName + nc - ncBaseName, pBaseName)) + { + MetaSig msig(pSig, cSig, pModule, &typeContext); + + // Looking for the prototype void __dtor(Ptr VC); + if (msig.NumFixedArgs() == 1) + { + if (msig.GetReturnType() == ELEMENT_TYPE_VOID) + { + if (msig.NextArg() == ELEMENT_TYPE_PTR) + { + SigPointer sp1 = msig.GetArgProps(); + IfFailThrow(sp1.GetElemType(NULL)); + CorElementType eType; + IfFailThrow(sp1.GetElemType(&eType)); + if (eType == ELEMENT_TYPE_VALUETYPE) + { + mdToken tk1; + IfFailThrow(sp1.GetToken(&tk1)); + hr = CompareTypeTokensNT(tk1, cl, pModule, pModule); + if (FAILED(hr)) + { + pInternalImport->EnumClose(&hEnumMethod); + ThrowHR(hr); + } + + if (hr == S_OK) + { + *pMDOut = pModule->LookupMethodDef(tk); + return; + } + } + } + } + } + } + } + } +} + //========================================================================== // Set's up the custom marshaler information. //========================================================================== @@ -913,7 +1251,7 @@ MarshalInfo::MarshalInfo(Module* pModule, CorNativeType nativeType = NATIVE_TYPE_DEFAULT; Assembly *pAssembly = pModule->GetAssembly(); - mdToken pCopyCtorModifier = mdTokenNil; + BOOL fNeedsCopyCtor = FALSE; m_BestFit = BestFit; m_ThrowOnUnmappableChar = ThrowOnUnmappableChar; m_ms = ms; @@ -1040,10 +1378,11 @@ MarshalInfo::MarshalInfo(Module* pModule, // Skip ET_BYREF IfFailGoto(sigtmp.GetByte(NULL), lFail); - if (sigtmp.HasCustomModifier(pModule, "Microsoft.VisualC.NeedsCopyConstructorModifier", ELEMENT_TYPE_CMOD_REQD, &pCopyCtorModifier) || - sigtmp.HasCustomModifier(pModule, "System.Runtime.CompilerServices.IsCopyConstructed", ELEMENT_TYPE_CMOD_REQD, &pCopyCtorModifier) ) + if (sigtmp.HasCustomModifier(pModule, "Microsoft.VisualC.NeedsCopyConstructorModifier", ELEMENT_TYPE_CMOD_REQD) || + sigtmp.HasCustomModifier(pModule, "System.Runtime.CompilerServices.IsCopyConstructed", ELEMENT_TYPE_CMOD_REQD) ) { mtype = ELEMENT_TYPE_VALUETYPE; + fNeedsCopyCtor = TRUE; m_byref = FALSE; } } @@ -1072,8 +1411,8 @@ MarshalInfo::MarshalInfo(Module* pModule, if (!th.IsEnum()) { // Check for Copy Constructor Modifier - if (sigtmp.HasCustomModifier(pModule, "Microsoft.VisualC.NeedsCopyConstructorModifier", ELEMENT_TYPE_CMOD_REQD, &pCopyCtorModifier) || - sigtmp.HasCustomModifier(pModule, "System.Runtime.CompilerServices.IsCopyConstructed", ELEMENT_TYPE_CMOD_REQD, &pCopyCtorModifier) ) + if (sigtmp.HasCustomModifier(pModule, "Microsoft.VisualC.NeedsCopyConstructorModifier", ELEMENT_TYPE_CMOD_REQD) || + sigtmp.HasCustomModifier(pModule, "System.Runtime.CompilerServices.IsCopyConstructed", ELEMENT_TYPE_CMOD_REQD) ) { mtype = mtype2; @@ -1081,6 +1420,7 @@ MarshalInfo::MarshalInfo(Module* pModule, // of this method we are pretending that the parameter is a value type passed by-value. IfFailGoto(sig.GetElemType(NULL), lFail); + fNeedsCopyCtor = TRUE; m_byref = FALSE; } } @@ -2041,11 +2381,17 @@ MarshalInfo::MarshalInfo(Module* pModule, } else { - if (pCopyCtorModifier != mdTokenNil && !IsFieldScenario()) // We don't support automatically discovering copy constructors for fields. + if (fNeedsCopyCtor && !IsFieldScenario()) // We don't support automatically discovering copy constructors for fields. { #if defined(FEATURE_IJW) - m_args.mm.m_pSigMod = ClassLoader::LoadTypeDefOrRefThrowing(pModule, pCopyCtorModifier).AsMethodTable(); + MethodDesc *pCopyCtor; + MethodDesc *pDtor; + FindCopyCtor(pModule, m_pMT, &pCopyCtor); + FindDtor(pModule, m_pMT, &pDtor); + m_args.mm.m_pMT = m_pMT; + m_args.mm.m_pCopyCtor = pCopyCtor; + m_args.mm.m_pDtor = pDtor; m_type = MARSHAL_TYPE_BLITTABLEVALUECLASSWITHCOPYCTOR; #else // !defined(FEATURE_IJW) m_resID = IDS_EE_BADMARSHAL_BADMANAGED; @@ -2467,6 +2813,7 @@ namespace void MarshalInfo::GenerateArgumentIL(NDirectStubLinker* psl, int argOffset, // the argument's index is m_paramidx + argOffset + UINT nativeStackOffset, // offset of the argument on the native stack BOOL fMngToNative) { CONTRACTL @@ -2494,7 +2841,8 @@ void MarshalInfo::GenerateArgumentIL(NDirectStubLinker* psl, fMngToNative, &m_args, &resID, - m_paramidx + argOffset); + m_paramidx + argOffset, + nativeStackOffset); if (amostat == OVERRIDDEN) diff --git a/src/coreclr/vm/mlinfo.h b/src/coreclr/vm/mlinfo.h index 795427ef4b9a4..93a0f554d30af 100644 --- a/src/coreclr/vm/mlinfo.h +++ b/src/coreclr/vm/mlinfo.h @@ -87,8 +87,9 @@ struct OverrideProcArgs struct { - MethodTable* m_pSigMod; MethodTable* m_pMT; + MethodDesc* m_pCopyCtor; + MethodDesc* m_pDtor; } mm; struct @@ -112,7 +113,8 @@ typedef MarshalerOverrideStatus (*OVERRIDEPROC)(NDirectStubLinker* psl, BOOL fManagedToNative, OverrideProcArgs* pargs, UINT* pResID, - UINT argidx); + UINT argidx, + UINT nativeStackOffset); typedef MarshalerOverrideStatus (*RETURNOVERRIDEPROC)(NDirectStubLinker* psl, BOOL fManagedToNative, @@ -354,6 +356,7 @@ class MarshalInfo void GenerateArgumentIL(NDirectStubLinker* psl, int argOffset, // the argument's index is m_paramidx + argOffset + UINT nativeStackOffset, // offset of the argument on the native stack BOOL fMngToNative); void GenerateReturnIL(NDirectStubLinker* psl, diff --git a/src/coreclr/vm/siginfo.cpp b/src/coreclr/vm/siginfo.cpp index f1adff6d4f3ad..facb809cd4841 100644 --- a/src/coreclr/vm/siginfo.cpp +++ b/src/coreclr/vm/siginfo.cpp @@ -137,7 +137,7 @@ unsigned GetSizeForCorElementType(CorElementType etyp) #ifndef DACCESS_COMPILE -void SigPointer::ConvertToInternalExactlyOne(Module* pSigModule, SigTypeContext *pTypeContext, SigBuilder * pSigBuilder, TokenLookupMap* pTokenLookupMap) +void SigPointer::ConvertToInternalExactlyOne(Module* pSigModule, SigTypeContext *pTypeContext, SigBuilder * pSigBuilder, BOOL bSkipCustomModifier) { CONTRACTL { @@ -152,10 +152,9 @@ void SigPointer::ConvertToInternalExactlyOne(Module* pSigModule, SigTypeContext CorElementType typ = ELEMENT_TYPE_END; - // If we don't have a token lookup map, skip custom modifiers. - // We can't accurately represent them in the internal signature unless we can - // resolve tokens through a token lookup map. - if (pTokenLookupMap == nullptr) + // Check whether we need to skip custom modifier + // Only preserve custom modifier when calculating IL stub hash blob + if (bSkipCustomModifier) { // GetElemType eats sentinel and custom modifiers IfFailThrowBF(GetElemType(&typ), BFA_BAD_COMPLUS_SIG, pSigModule); @@ -231,16 +230,16 @@ void SigPointer::ConvertToInternalExactlyOne(Module* pSigModule, SigTypeContext case ELEMENT_TYPE_PTR: case ELEMENT_TYPE_PINNED: case ELEMENT_TYPE_SZARRAY: - ConvertToInternalExactlyOne(pSigModule, pTypeContext, pSigBuilder, pTokenLookupMap); + ConvertToInternalExactlyOne(pSigModule, pTypeContext, pSigBuilder, bSkipCustomModifier); break; case ELEMENT_TYPE_FNPTR: - ConvertToInternalSignature(pSigModule, pTypeContext, pSigBuilder, pTokenLookupMap); + ConvertToInternalSignature(pSigModule, pTypeContext, pSigBuilder, bSkipCustomModifier); break; case ELEMENT_TYPE_ARRAY: { - ConvertToInternalExactlyOne(pSigModule, pTypeContext, pSigBuilder, pTokenLookupMap); + ConvertToInternalExactlyOne(pSigModule, pTypeContext, pSigBuilder, bSkipCustomModifier); uint32_t rank = 0; // Get rank IfFailThrowBF(GetData(&rank), BFA_BAD_COMPLUS_SIG, pSigModule); @@ -303,7 +302,7 @@ void SigPointer::ConvertToInternalExactlyOne(Module* pSigModule, SigTypeContext while (argCnt--) { - ConvertToInternalExactlyOne(pSigModule, pTypeContext, pSigBuilder, pTokenLookupMap); + ConvertToInternalExactlyOne(pSigModule, pTypeContext, pSigBuilder, bSkipCustomModifier); } } break; @@ -312,20 +311,20 @@ void SigPointer::ConvertToInternalExactlyOne(Module* pSigModule, SigTypeContext case ELEMENT_TYPE_CMOD_OPT: case ELEMENT_TYPE_CMOD_REQD: { - _ASSERTE_MSG(pTokenLookupMap != nullptr, "A token lookup map must be provided for custom modifiers"); mdToken tk; IfFailThrowBF(GetToken(&tk), BFA_BAD_COMPLUS_SIG, pSigModule); TypeHandle th = ClassLoader::LoadTypeDefOrRefThrowing(pSigModule, tk); - pSigBuilder->AppendToken(pTokenLookupMap->GetToken(th)); + pSigBuilder->AppendElementType(ELEMENT_TYPE_INTERNAL); + pSigBuilder->AppendPointer(th.AsPtr()); - ConvertToInternalExactlyOne(pSigModule, pTypeContext, pSigBuilder, pTokenLookupMap); + ConvertToInternalExactlyOne(pSigModule, pTypeContext, pSigBuilder, bSkipCustomModifier); } break; } } } -void SigPointer::ConvertToInternalSignature(Module* pSigModule, SigTypeContext *pTypeContext, SigBuilder * pSigBuilder, TokenLookupMap* pTokenLookupMap) +void SigPointer::ConvertToInternalSignature(Module* pSigModule, SigTypeContext *pTypeContext, SigBuilder * pSigBuilder, BOOL bSkipCustomModifier) { CONTRACTL { @@ -362,7 +361,7 @@ void SigPointer::ConvertToInternalSignature(Module* pSigModule, SigTypeContext * // Skip args. while (cArgs) { - ConvertToInternalExactlyOne(pSigModule, pTypeContext, pSigBuilder, pTokenLookupMap); + ConvertToInternalExactlyOne(pSigModule, pTypeContext, pSigBuilder, bSkipCustomModifier); cArgs--; } } @@ -938,25 +937,6 @@ IsTypeRefOrDef( return(true); } // IsTypeRefOrDef -BOOL IsTypeRefOrDef( - LPCSTR szClassName, - DynamicResolver * pResolver, - mdToken token) -{ - STANDARD_VM_CONTRACT; - - ResolvedToken resolved; - pResolver->ResolveToken(token, &resolved); - - if (resolved.TypeHandle.IsNull()) - return false; - - DefineFullyQualifiedNameForClassOnStack(); - LPCUTF8 fullyQualifiedName = GetFullyQualifiedNameForClass(resolved.TypeHandle.GetMethodTable()); - - return (strcmp(szClassName, fullyQualifiedName) == 0); -} - TypeHandle SigPointer::GetTypeHandleNT(Module* pModule, const SigTypeContext *pTypeContext) const { @@ -2302,7 +2282,7 @@ BOOL SigPointer::IsClassHelper(Module* pModule, LPCUTF8 szClassName, const SigTy //------------------------------------------------------------------------ // Tests for the existence of a custom modifier //------------------------------------------------------------------------ -BOOL SigPointer::HasCustomModifier(Module *pModule, LPCSTR szModName, CorElementType cmodtype, mdToken* pModifierType) const +BOOL SigPointer::HasCustomModifier(Module *pModule, LPCSTR szModName, CorElementType cmodtype) const { CONTRACTL { @@ -2338,54 +2318,6 @@ BOOL SigPointer::HasCustomModifier(Module *pModule, LPCSTR szModName, CorElement if (etyp == cmodtype && IsTypeRefOrDef(szModName, pModule, tk)) { - if (pModifierType != nullptr) - { - *pModifierType = tk; - } - return(TRUE); - } - - if (FAILED(sp.GetByte(&data))) - return FALSE; - - etyp = (CorElementType)data; - - - } - return(FALSE); -} - -BOOL SigPointer::HasCustomModifier(DynamicResolver *pResolver, LPCSTR szModName, CorElementType cmodtype, mdToken* pModifierType) const -{ - STANDARD_VM_CONTRACT; - - BAD_FORMAT_NOTHROW_ASSERT(cmodtype == ELEMENT_TYPE_CMOD_OPT || cmodtype == ELEMENT_TYPE_CMOD_REQD); - - SigPointer sp = *this; - CorElementType etyp; - if (sp.AtSentinel()) - sp.m_ptr++; - - BYTE data; - - if (FAILED(sp.GetByte(&data))) - return FALSE; - - etyp = (CorElementType)data; - - - while (etyp == ELEMENT_TYPE_CMOD_OPT || etyp == ELEMENT_TYPE_CMOD_REQD) { - - mdToken tk; - if (FAILED(sp.GetToken(&tk))) - return FALSE; - - if (etyp == cmodtype && IsTypeRefOrDef(szModName, pResolver, tk)) - { - if (pModifierType != nullptr) - { - *pModifierType = tk; - } return(TRUE); } diff --git a/src/coreclr/vm/siginfo.hpp b/src/coreclr/vm/siginfo.hpp index 935d6ccd7fe10..fab9a79260d2d 100644 --- a/src/coreclr/vm/siginfo.hpp +++ b/src/coreclr/vm/siginfo.hpp @@ -49,7 +49,6 @@ unsigned GetSizeForCorElementType(CorElementType etyp); class SigBuilder; class ArgDestination; -class TokenLookupMap; typedef const struct HardCodedMetaSig *LPHARDCODEDMETASIG; @@ -126,8 +125,8 @@ class SigPointer : public SigParser //========================================================================= - void ConvertToInternalExactlyOne(Module* pSigModule, SigTypeContext *pTypeContext, SigBuilder * pSigBuilder, TokenLookupMap* pTokenMap = nullptr); - void ConvertToInternalSignature(Module* pSigModule, SigTypeContext *pTypeContext, SigBuilder * pSigBuilder, TokenLookupMap* pTokenMap = nullptr); + void ConvertToInternalExactlyOne(Module* pSigModule, SigTypeContext *pTypeContext, SigBuilder * pSigBuilder, BOOL bSkipCustomModifier = TRUE); + void ConvertToInternalSignature(Module* pSigModule, SigTypeContext *pTypeContext, SigBuilder * pSigBuilder, BOOL bSkipCustomModifier = TRUE); //========================================================================= @@ -278,8 +277,7 @@ class SigPointer : public SigParser //------------------------------------------------------------------------ // Tests for the existence of a custom modifier //------------------------------------------------------------------------ - BOOL HasCustomModifier(Module *pModule, LPCSTR szModName, CorElementType cmodtype, mdToken* pModifierType = NULL) const; - BOOL HasCustomModifier(DynamicResolver *pResolver, LPCSTR szModName, CorElementType cmodtype, mdToken* pModifierType = NULL) const; + BOOL HasCustomModifier(Module *pModule, LPCSTR szModName, CorElementType cmodtype) const; //------------------------------------------------------------------------ // Tests for ELEMENT_TYPE_CLASS or ELEMENT_TYPE_VALUETYPE followed by a TypeDef, diff --git a/src/coreclr/vm/stubgen.cpp b/src/coreclr/vm/stubgen.cpp index 4164da672a1c6..283b6d3fa2d88 100644 --- a/src/coreclr/vm/stubgen.cpp +++ b/src/coreclr/vm/stubgen.cpp @@ -2601,101 +2601,78 @@ CorCallingConvention ILStubLinker::GetStubTargetCallingConv() return m_nativeFnSigBuilder.GetCallingConv(); } -namespace +void ILStubLinker::TransformArgForJIT(LocalDesc *pLoc) { - void TransformArgSignatureForJIT(BYTE sig[], size_t* cbSig, TypeHandle internalToken) - { - STANDARD_VM_CONTRACT; - _ASSERTE(*cbSig > 0); - // Turn everything into blittable primitives. The reason this method is needed are - // byrefs which are OK only when they ref stack data or are pinned. This condition - // cannot be verified by code:NDirect.MarshalingRequired so we explicitly get rid - // of them here. - switch (sig[0]) + STANDARD_VM_CONTRACT; + // Turn everything into blittable primitives. The reason this method is needed are + // byrefs which are OK only when they ref stack data or are pinned. This condition + // cannot be verified by code:NDirect.MarshalingRequired so we explicitly get rid + // of them here. + switch (pLoc->ElementType[0]) + { + // primitives + case ELEMENT_TYPE_VOID: + case ELEMENT_TYPE_BOOLEAN: + case ELEMENT_TYPE_CHAR: + case ELEMENT_TYPE_I1: + case ELEMENT_TYPE_U1: + case ELEMENT_TYPE_I2: + case ELEMENT_TYPE_U2: + case ELEMENT_TYPE_I4: + case ELEMENT_TYPE_U4: + case ELEMENT_TYPE_I8: + case ELEMENT_TYPE_U8: + case ELEMENT_TYPE_R4: + case ELEMENT_TYPE_R8: + case ELEMENT_TYPE_I: + case ELEMENT_TYPE_U: { - // primitives - case ELEMENT_TYPE_VOID: - case ELEMENT_TYPE_BOOLEAN: - case ELEMENT_TYPE_CHAR: - case ELEMENT_TYPE_I1: - case ELEMENT_TYPE_U1: - case ELEMENT_TYPE_I2: - case ELEMENT_TYPE_U2: - case ELEMENT_TYPE_I4: - case ELEMENT_TYPE_U4: - case ELEMENT_TYPE_I8: - case ELEMENT_TYPE_U8: - case ELEMENT_TYPE_R4: - case ELEMENT_TYPE_R8: - case ELEMENT_TYPE_I: - case ELEMENT_TYPE_U: - { - // no transformation needed - break; - } + // no transformation needed + break; + } - case ELEMENT_TYPE_VALUETYPE: - { - _ASSERTE(!"Should have been replaced by a native value type!"); - break; - } + case ELEMENT_TYPE_VALUETYPE: + { + _ASSERTE(!"Should have been replaced by a native value type!"); + break; + } - case ELEMENT_TYPE_PTR: - { - // Don't transform pointer types to ELEMENT_TYPE_I. The JIT can handle the correct type information, - // and it's required for some cases (such as SwiftError*). - break; - } + case ELEMENT_TYPE_PTR: + { + // Don't transform pointer types to ELEMENT_TYPE_I. The JIT can handle the correct type information, + // and it's required for some cases (such as SwiftError*). + break; + } - case ELEMENT_TYPE_BYREF: - { - // Transform ELEMENT_TYPE_BYREF to ELEMENT_TYPE_PTR to retain the pointed-to type information - // while making the type blittable. - sig[0] = ELEMENT_TYPE_PTR; - break; - } + case ELEMENT_TYPE_BYREF: + { + // Transform ELEMENT_TYPE_BYREF to ELEMENT_TYPE_PTR to retain the pointed-to type information + // while making the type blittable. + pLoc->ElementType[0] = ELEMENT_TYPE_PTR; + break; + } - case ELEMENT_TYPE_CMOD_OPT: - case ELEMENT_TYPE_CMOD_REQD: + case ELEMENT_TYPE_INTERNAL: + { + // JIT will handle structures + if (pLoc->InternalToken.IsValueType()) { - // Keep the custom modifier, - // but scan the rest of the signature after the modifier token. - - size_t cbModOpt = CorSigUncompressedDataSize(&sig[1]); - size_t cbRemainingSig = *cbSig - 1 - cbModOpt; - TransformArgSignatureForJIT(&sig[1 + cbModOpt], &cbRemainingSig, internalToken); - *cbSig = 1 + cbModOpt + cbRemainingSig; + _ASSERTE(pLoc->InternalToken.IsNativeValueType() || !pLoc->InternalToken.GetMethodTable()->ContainsGCPointers()); break; } + FALLTHROUGH; + } - case ELEMENT_TYPE_INTERNAL: - { - // JIT will handle structures - if (internalToken.IsValueType()) - { - _ASSERTE(internalToken.IsNativeValueType() || !internalToken.GetMethodTable()->ContainsGCPointers()); - break; - } - FALLTHROUGH; - } - - // ref types -> ELEMENT_TYPE_I - default: - { - sig[0] = ELEMENT_TYPE_I; - *cbSig = 1; - break; - } + // ref types -> ELEMENT_TYPE_I + default: + { + pLoc->ElementType[0] = ELEMENT_TYPE_I; + pLoc->cbType = 1; + break; } } } -void ILStubLinker::TransformArgForJIT(LocalDesc *pLoc) -{ - STANDARD_VM_CONTRACT; - return TransformArgSignatureForJIT(pLoc->ElementType, &pLoc->cbType, pLoc->InternalToken); -} - Module *ILStubLinker::GetStubSigModule() { LIMITED_METHOD_CONTRACT; diff --git a/src/coreclr/vm/stubgen.h b/src/coreclr/vm/stubgen.h index 00cc8c21d53e1..968e5f9b48291 100644 --- a/src/coreclr/vm/stubgen.h +++ b/src/coreclr/vm/stubgen.h @@ -96,19 +96,6 @@ struct LocalDesc ChangeType(ELEMENT_TYPE_PTR); } - void AddModifier(bool required, mdToken token) - { - LIMITED_METHOD_CONTRACT; - BYTE compressed[4]; - ULONG cbCompressed; - cbCompressed = CorSigCompressToken(token, compressed); - _ASSERTE(cbCompressed + cbType + 1 <= MAX_LOCALDESC_ELEMENTS); - memmove(&ElementType[cbCompressed], ElementType, cbType); - memmove(&ElementType, compressed, cbCompressed); - cbType += cbCompressed; - ChangeType(required ? ELEMENT_TYPE_CMOD_REQD : ELEMENT_TYPE_CMOD_OPT); - } - void ChangeType(CorElementType elemType) { LIMITED_METHOD_CONTRACT; @@ -283,7 +270,7 @@ class FunctionSigBuilder : protected StubSigBuilder //--------------------------------------------------------------------------------------- // -class TokenLookupMap final +class TokenLookupMap { public: TokenLookupMap() @@ -490,52 +477,7 @@ class TokenLookupMap final return token; } - // Generate a hash value of the token lookup map - int GetHashValue() - { - int hash = 0; - - for (size_t i = 0; i < m_nextAvailableRid; i++) - { - // Hash in the pointer values - // for the simple token map - hash = _rotl(hash, 1) + (int)((size_t*)m_qbEntries.Ptr())[i]; - } - - for (COUNT_T i = 0; i < m_signatures.GetCount(); i++) - { - // Hash the signatures for the signature tokens - CQuickBytesSpecifySize<16>& sigData = m_signatures[i]; - PCCOR_SIGNATURE pSig = (PCCOR_SIGNATURE)sigData.Ptr(); - DWORD cbSig = static_cast(sigData.Size()); - for (DWORD j = 0; j < cbSig; j++) - { - hash = _rotl(hash, 1) + pSig[j]; - } - } - - for (COUNT_T i = 0; i < m_memberRefs.GetCount(); i++) - { - // Hash the member ref entries - MemberRefEntry& entry = m_memberRefs[i]; - hash = _rotl(hash, 1) + entry.Type; - hash = _rotl(hash, 1) + entry.ClassSignatureToken; - hash = _rotl(hash, 1) + (int)(size_t)entry.Entry.Method; - } - - for (COUNT_T i = 0; i < m_methodSpecs.GetCount(); i++) - { - // Hash the method spec entries - MethodSpecEntry& entry = m_methodSpecs[i]; - hash = _rotl(hash, 1) + entry.ClassSignatureToken; - hash = _rotl(hash, 1) + entry.MethodSignatureToken; - hash = _rotl(hash, 1) + (int)(size_t)entry.Method; - } - - return hash; - } - -private: +protected: mdToken GetMemberRefWorker(MemberRefEntry** entry) { CONTRACTL diff --git a/src/tests/Interop/IJW/CopyConstructorMarshaler/CopyConstructorMarshaler.cs b/src/tests/Interop/IJW/CopyConstructorMarshaler/CopyConstructorMarshaler.cs index 757b35cfb07a9..b59dcb74dd521 100644 --- a/src/tests/Interop/IJW/CopyConstructorMarshaler/CopyConstructorMarshaler.cs +++ b/src/tests/Interop/IJW/CopyConstructorMarshaler/CopyConstructorMarshaler.cs @@ -26,32 +26,32 @@ public static int TestEntryPoint() object testInstance = Activator.CreateInstance(testType); MethodInfo testMethod = testType.GetMethod("PInvokeNumCopies"); - // On x86, we will copy in the IL stub to the final arg slot. + // On x86, we have an additional copy on every P/Invoke from the "native" parameter to the actual location on the stack. int platformExtra = 0; if (RuntimeInformation.ProcessArchitecture == Architecture.X86) { platformExtra = 1; } - - // PInvoke will copy once. Once from the managed to native parameter. - Assert.Equal(1 + platformExtra, (int)testMethod.Invoke(testInstance, null)); + + // PInvoke will copy twice. Once from argument to parameter, and once from the managed to native parameter. + Assert.Equal(2 + platformExtra, (int)testMethod.Invoke(testInstance, null)); testMethod = testType.GetMethod("ReversePInvokeNumCopies"); - // Reverse PInvoke will copy 2 times. One from the same path as the PInvoke, - // and one from the reverse P/Invoke call. - Assert.Equal(2 + platformExtra, (int)testMethod.Invoke(testInstance, null)); + // Reverse PInvoke will copy 3 times. Two are from the same paths as the PInvoke, + // and the third is from the reverse P/Invoke call. + Assert.Equal(3 + platformExtra, (int)testMethod.Invoke(testInstance, null)); testMethod = testType.GetMethod("PInvokeNumCopiesDerivedType"); - // PInvoke will copy once from the managed to native parameter. - Assert.Equal(1 + platformExtra, (int)testMethod.Invoke(testInstance, null)); + // PInvoke will copy twice. Once from argument to parameter, and once from the managed to native parameter. + Assert.Equal(2 + platformExtra, (int)testMethod.Invoke(testInstance, null)); testMethod = testType.GetMethod("ReversePInvokeNumCopiesDerivedType"); - // Reverse PInvoke will copy 2 times. One from the same path as the PInvoke, - // and one from the reverse P/Invoke call. - Assert.Equal(2 + platformExtra, (int)testMethod.Invoke(testInstance, null)); + // Reverse PInvoke will copy 3 times. Two are from the same paths as the PInvoke, + // and the third is from the reverse P/Invoke call. + Assert.Equal(3 + platformExtra, (int)testMethod.Invoke(testInstance, null)); } catch (Exception ex) { @@ -62,6 +62,7 @@ public static int TestEntryPoint() } [Fact] + [SkipOnCoreClr("JitStress can introduce extra copies that won't happen in production scenarios.", RuntimeTestModes.JitStress)] public static void CopyConstructorsInArgumentStackSlots() { Assembly ijwNativeDll = Assembly.Load("IjwCopyConstructorMarshaler"); @@ -73,6 +74,7 @@ public static void CopyConstructorsInArgumentStackSlots() } [Fact] + [SkipOnCoreClr("JitStress can introduce extra copies that won't happen in production scenarios.", RuntimeTestModes.JitStress)] public static void CopyConstructorsInArgumentStackSlotsWithUnsafeValueType() { Assembly ijwNativeDll = Assembly.Load("IjwCopyConstructorMarshaler"); diff --git a/src/tests/Interop/PInvoke/Miscellaneous/CopyCtor/CopyCtorTest.cs b/src/tests/Interop/PInvoke/Miscellaneous/CopyCtor/CopyCtorTest.cs index 9601a835bb79a..57ec4d9632426 100644 --- a/src/tests/Interop/PInvoke/Miscellaneous/CopyCtor/CopyCtorTest.cs +++ b/src/tests/Interop/PInvoke/Miscellaneous/CopyCtor/CopyCtorTest.cs @@ -25,7 +25,11 @@ public static unsafe int StructWithCtorTest(StructWithCtor* ptrStruct, ref Struc return 2; } - int expectedCallCount = RuntimeInformation.ProcessArchitecture == Architecture.X86 ? 2 : 0; + int expectedCallCount = 2; + if (RuntimeInformation.ProcessArchitecture == Architecture.X86) + { + expectedCallCount = 4; + } if (StructWithCtor.CopyCtorCallCount != expectedCallCount) { @@ -44,7 +48,6 @@ public static unsafe int StructWithCtorTest(StructWithCtor* ptrStruct, ref Struc [ConditionalFact(typeof(TestLibrary.PlatformDetection), nameof(TestLibrary.PlatformDetection.IsWindows))] [SkipOnMono("Not supported on Mono")] [ActiveIssue("https://github.com/dotnet/runtimelab/issues/155", typeof(TestLibrary.Utilities), nameof(TestLibrary.Utilities.IsNativeAot))] - [SkipOnCoreClr("JitStress can introduce extra copies", RuntimeTestModes.JitStress)] public static unsafe void ValidateCopyConstructorAndDestructorCalled() { CopyCtorUtil.TestDelegate del = (CopyCtorUtil.TestDelegate)Delegate.CreateDelegate(typeof(CopyCtorUtil.TestDelegate), typeof(CopyCtor).GetMethod("StructWithCtorTest"));