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 e155b109886d08..4389d9507a4c41 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,6 +344,12 @@ 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 4d04557565c3ca..9f2528b1a82314 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/StubHelpers.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/StubHelpers.cs @@ -1315,75 +1315,6 @@ 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 b7229ff35f3f66..fde019934f5f3e 100644 --- a/src/coreclr/inc/corinfo.h +++ b/src/coreclr/inc/corinfo.h @@ -644,6 +644,7 @@ 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) { @@ -3325,6 +3326,8 @@ 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 d652f262ab8fdd..96068326c34704 100644 --- a/src/coreclr/inc/icorjitinfoimpl_generated.h +++ b/src/coreclr/inc/icorjitinfoimpl_generated.h @@ -742,6 +742,9 @@ 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 4af8e1a80522e5..fc1917037043ba 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 = { /* f43f9022-8795-4791-ba55-c450d76cfeb9 */ - 0xf43f9022, - 0x8795, - 0x4791, - {0xba, 0x55, 0xc4, 0x50, 0xd7, 0x6c, 0xfe, 0xb9} +constexpr GUID JITEEVersionIdentifier = { /* 62865a69-7c84-4ba5-8636-a7dec55c05a7 */ + 0x62865a69, + 0x7c84, + 0x4ba5, + {0x86, 0x36, 0xa7, 0xde, 0xc5, 0x5c, 0x05, 0xa7} }; ////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/coreclr/jit/ICorJitInfo_names_generated.h b/src/coreclr/jit/ICorJitInfo_names_generated.h index 4779f13a029b84..2d3865018d1de4 100644 --- a/src/coreclr/jit/ICorJitInfo_names_generated.h +++ b/src/coreclr/jit/ICorJitInfo_names_generated.h @@ -180,5 +180,6 @@ 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 4db7f026f9d774..0ee637a957cf39 100644 --- a/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp +++ b/src/coreclr/jit/ICorJitInfo_wrapper_generated.hpp @@ -1742,6 +1742,15 @@ 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 d94d1f7e107565..7d2c2eceebce1d 100644 --- a/src/coreclr/jit/compiler.cpp +++ b/src/coreclr/jit/compiler.cpp @@ -1989,6 +1989,10 @@ 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 b748f3b81138a3..1315a57a139a5e 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -5703,6 +5703,36 @@ 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 aaf67c59530b08..2dd4afa9c4d2fd 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -16604,6 +16604,7 @@ 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 0baa5ad289c246..06802181eea226 100644 --- a/src/coreclr/jit/gschecks.cpp +++ b/src/coreclr/jit/gschecks.cpp @@ -516,13 +516,59 @@ void Compiler::gsParamsToShadows() continue; } - GenTree* src = gtNewLclvNode(lclNum, varDsc->TypeGet()); - src->gtFlags |= GTF_DONT_CSE; - GenTree* store = gtNewStoreLclVarNode(shadowVarNum, src); +#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; - fgEnsureFirstBBisScratch(); - compCurBB = fgFirstBB; // Needed by some morphing - (void)fgNewStmtAtBeg(fgFirstBB, fgMorphTree(store)); + GenTree* store = gtNewStoreLclVarNode(shadowVarNum, src); + + 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 5b1003c0b82263..780d0989783653 100644 --- a/src/coreclr/jit/lclvars.cpp +++ b/src/coreclr/jit/lclvars.cpp @@ -653,6 +653,19 @@ 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 77776a903d4fa8..f8bc8002414917 100644 --- a/src/coreclr/jit/lower.cpp +++ b/src/coreclr/jit/lower.cpp @@ -1994,9 +1994,148 @@ 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 bff33917f28da1..c5c771167025e4 100644 --- a/src/coreclr/jit/lower.h +++ b/src/coreclr/jit/lower.h @@ -183,6 +183,10 @@ 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 5f908f3c2d179d..06141640ef53cb 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs @@ -4464,5 +4464,10 @@ 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 94a45a5c574552..76b08b42458b38 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl_generated.cs @@ -2605,10 +2605,25 @@ 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) * 176); + void** callbacks = (void**)Marshal.AllocCoTaskMem(sizeof(IntPtr) * 177); callbacks[0] = (delegate* unmanaged)&_isIntrinsic; callbacks[1] = (delegate* unmanaged)&_notifyMethodInfoUsage; @@ -2786,6 +2801,7 @@ 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 902fa1159ed534..4be84d0c316f82 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoTypes.cs @@ -783,6 +783,7 @@ 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 a7ca75b0d7becc..e776aa2796259f 100644 --- a/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt +++ b/src/coreclr/tools/Common/JitInterface/ThunkGenerator/ThunkInput.txt @@ -340,3 +340,4 @@ 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 f1ddd133406729..c56fe139318630 100644 --- a/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h +++ b/src/coreclr/tools/aot/jitinterface/jitinterface_generated.h @@ -187,6 +187,7 @@ 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); }; @@ -1919,4 +1920,13 @@ 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 bb2c78da308549..e00f86d1b64587 100644 --- a/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h +++ b/src/coreclr/tools/superpmi/superpmi-shared/lwmlist.h @@ -131,6 +131,7 @@ 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 4c56364d865396..d1078fe8d356ca 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,6 +7212,33 @@ 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 0b2e84d37811e7..4625ad44aab37d 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,6 +898,10 @@ 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 @@ -1189,6 +1193,7 @@ 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 368b2cbaec47d2..b3fab2e939dae8 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-collector/icorjitinfo.cpp @@ -2028,3 +2028,11 @@ 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 2702c0a409bcfc..638f6649613fa5 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-counter/icorjitinfo_generated.cpp @@ -1437,3 +1437,10 @@ 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 f2e6f5cbd9962e..c285ef2c3c6ca9 100644 --- a/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp +++ b/src/coreclr/tools/superpmi/superpmi-shim-simple/icorjitinfo_generated.cpp @@ -1261,3 +1261,9 @@ 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 153ba61212305e..64c52f61705ae5 100644 --- a/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp +++ b/src/coreclr/tools/superpmi/superpmi/icorjitinfo.cpp @@ -1864,3 +1864,10 @@ 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 ea78d259cd73e9..b73ad90126df93 100644 --- a/src/coreclr/vm/corelib.h +++ b/src/coreclr/vm/corelib.h @@ -635,6 +635,7 @@ 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) @@ -1049,21 +1050,6 @@ 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 d6ebd11a59c37b..285e06ee2a1318 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, UINT nativeStackOffset) = 0; + virtual void MarshalArgument(MarshalInfo* pInfo, int argOffset) = 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, UINT nativeStackOffset) + void MarshalArgument(MarshalInfo* pInfo, int argOffset) { CONTRACTL { @@ -297,7 +297,7 @@ class ILStubState : public StubState } CONTRACTL_END; - pInfo->GenerateArgumentIL(&m_slIL, argOffset, nativeStackOffset, SF_IsForwardStub(m_dwStubFlags)); + pInfo->GenerateArgumentIL(&m_slIL, argOffset, 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); + sigPtr.ConvertToInternalSignature(pStubMD->GetModule(), NULL, &sigBuilder, GetTokenLookupMap()); } // @@ -464,6 +464,25 @@ 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; @@ -799,8 +818,17 @@ 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; @@ -1620,10 +1648,6 @@ 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) @@ -1836,23 +1860,6 @@ 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; @@ -2082,10 +2089,6 @@ 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; @@ -2169,21 +2172,6 @@ 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 @@ -2415,7 +2403,7 @@ class DispatchStubState : public StubState // For CLR-to-COM late-bound/eventing CONTRACTL_END; } - void MarshalArgument(MarshalInfo* pInfo, int argOffset, UINT nativeStackOffset) + void MarshalArgument(MarshalInfo* pInfo, int argOffset) { CONTRACTL { @@ -3457,7 +3445,6 @@ static MarshalInfo::MarshalType DoMarshalReturnValue(MetaSig& msig, int argOffset, DWORD dwStubFlags, MethodDesc *pMD, - UINT& nativeStackOffset, bool& fStubNeedsCOM, int nativeArgIndex DEBUG_ARG(LPCUTF8 pDebugName) @@ -3580,19 +3567,6 @@ 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 @@ -3782,7 +3756,7 @@ static void CreateNDirectStubWorker(StubState* pss, MarshalInfo &info = pParamMarshalInfo[argidx - 1]; - pss->MarshalArgument(&info, argOffset, GetStackOffsetFromStackSize(nativeStackSize, fThisCall)); + pss->MarshalArgument(&info, argOffset); nativeStackSize += info.GetNativeArgSize(); fStubNeedsCOM |= info.MarshalerRequiresCOM(); @@ -3818,7 +3792,6 @@ static void CreateNDirectStubWorker(StubState* pss, argOffset, dwStubFlags, pMD, - nativeStackSize, fStubNeedsCOM, nativeArgIndex DEBUG_ARG(pSigDesc->m_pDebugName) @@ -4023,6 +3996,7 @@ namespace DWORD m_StubFlags; INT32 m_iLCIDArg; + INT32 m_tokenMapHash; INT32 m_nParams; BYTE m_rgbSigAndParamData[1]; // (dwParamAttr, cbNativeType) // length: number of parameters @@ -4078,8 +4052,11 @@ 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, /* bSkipCustomModifier = */ FALSE); + sigPtr.ConvertToInternalSignature(pParams->m_pModule, pParams->m_pTypeContext, &sigBuilder, &tokenLookupMap); DWORD cbSig; PVOID pSig = sigBuilder.GetSignature(&cbSig); @@ -4114,6 +4091,7 @@ 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; @@ -6113,21 +6091,415 @@ PCODE GetILStubForCalli(VASigCookie *pVASigCookie, MethodDesc *pMD) RETURN pVASigCookie->pNDirectILStub; } -#if defined(TARGET_X86) && defined(FEATURE_IJW) -// Copy constructor support for C++/CLI -EXTERN_C void* STDCALL CallCopyConstructorsWorker(void* esp) +namespace { - STATIC_CONTRACT_THROWS; - STATIC_CONTRACT_GC_TRIGGERS; - STATIC_CONTRACT_MODE_PREEMPTIVE; // we've already switched to preemptive + //------------------------------------------------------------------------------------- + // 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; + } + } + } + } + } + } + } + } + - using ExecuteCallback = void*(STDMETHODCALLTYPE*)(void*); + // + // Next try the old syntax: global .__dtor + // + IfFailThrow(pInternalImport->EnumGlobalFunctionsInit(&hEnumMethod)); - MethodDesc* pMD = CoreLibBinder::GetMethod(METHOD__COPY_CONSTRUCTOR_CHAIN__EXECUTE_CURRENT_COPIES_AND_GET_TARGET); - ExecuteCallback pExecute = (ExecuteCallback)pMD->GetMultiCallableAddrOfCode(); + 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 (!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); + + // Store the token lookup map + ilResolver->SetTokenLookupMap(sl.GetTokenLookupMap()); + ilResolver->SetJitFlags(CORJIT_FLAGS(CORJIT_FLAGS::CORJIT_FLAG_IL_STUB)); + + *ppResolver = (DynamicResolver*)ilResolver; + *ppHeader = pILHeader; + } - return pExecute(esp); + ilResolver.SuppressRelease(); + return true; } -#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 f5e2c058fb1a1c..2fdd426391a1c8 100644 --- a/src/coreclr/vm/dllimport.h +++ b/src/coreclr/vm/dllimport.h @@ -488,9 +488,6 @@ 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(); @@ -560,10 +557,6 @@ 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; @@ -599,6 +592,7 @@ 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 07f6e8b955d038..801de37407386a 100644 --- a/src/coreclr/vm/i386/asmhelpers.asm +++ b/src/coreclr/vm/i386/asmhelpers.asm @@ -40,7 +40,6 @@ EXTERN _NDirectImportWorker@4:PROC EXTERN _VarargPInvokeStubWorker@12:PROC EXTERN _GenericPInvokeCalliStubWorker@12:PROC -EXTERN _CallCopyConstructorsWorker@4:PROC EXTERN _PreStubWorker@8:PROC EXTERN _TheUMEntryPrestubWorker@4:PROC @@ -1006,29 +1005,6 @@ 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 75d979076bd3a9..ab3a8b4539d143 100644 --- a/src/coreclr/vm/ilmarshalers.cpp +++ b/src/coreclr/vm/ilmarshalers.cpp @@ -2644,8 +2644,7 @@ MarshalerOverrideStatus ILHandleRefMarshaler::ArgumentOverride(NDirectStubLinker BOOL fManagedToNative, OverrideProcArgs* pargs, UINT* pResID, - UINT argidx, - UINT nativeStackOffset) + UINT argidx) { CONTRACTL { @@ -2737,8 +2736,7 @@ MarshalerOverrideStatus ILSafeHandleMarshaler::ArgumentOverride(NDirectStubLinke BOOL fManagedToNative, OverrideProcArgs* pargs, UINT* pResID, - UINT argidx, - UINT nativeStackOffset) + UINT argidx) { CONTRACTL { @@ -3095,8 +3093,7 @@ MarshalerOverrideStatus ILCriticalHandleMarshaler::ArgumentOverride(NDirectStubL BOOL fManagedToNative, OverrideProcArgs* pargs, UINT* pResID, - UINT argidx, - UINT nativeStackOffset) + UINT argidx) { CONTRACTL { @@ -3402,8 +3399,7 @@ MarshalerOverrideStatus ILBlittableValueClassWithCopyCtorMarshaler::ArgumentOver BOOL fManagedToNative, OverrideProcArgs* pargs, UINT* pResID, - UINT argidx, - UINT nativeStackOffset) + UINT argidx) { CONTRACTL { @@ -3424,75 +3420,40 @@ MarshalerOverrideStatus ILBlittableValueClassWithCopyCtorMarshaler::ArgumentOver if (fManagedToNative) { - // 1) create new native value type local - // 2) run new->CopyCtor(old) - // 3) run old->Dtor() - +#ifdef TARGET_X86 LocalDesc locDesc(pargs->mm.m_pMT); + pslIL->SetStubTargetArgType(&locDesc); // native type is the value type + locDesc.MakeByRef(); + + locDesc.MakePinned(); - DWORD dwNewValueTypeLocal; + DWORD dwPinnedArgLocal; // Step 1 - dwNewValueTypeLocal = pslIL->NewLocal(locDesc); + dwPinnedArgLocal = pslIL->NewLocal(locDesc); - // 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); - } + pslIL->EmitLDARG(argidx); + pslIL->EmitSTLOC(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))); - } + pslILDispatch->EmitLDARG(argidx); + pslILDispatch->EmitLDOBJ(pslIL->GetToken(pargs->mm.m_pMT)); +#else + LocalDesc locDesc(pargs->mm.m_pMT); - 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))); - } + locDesc.MakeByRef(); + locDesc.MakePinned(); - pslIL->EmitLDLOCA(psl->GetCopyCtorChainLocalNum()); - pslIL->EmitLDLOCA(ctorCookie); - pslIL->EmitCALL(METHOD__COPY_CONSTRUCTOR_CHAIN__ADD, 2, 0); + DWORD dwPinnedArgLocal; -#else - pslIL->SetStubTargetArgType(ELEMENT_TYPE_I); // native type is a pointer - EmitLoadNativeLocalAddrForByRefDispatch(pslILDispatch, dwNewValueTypeLocal); + // Step 1 + dwPinnedArgLocal = pslIL->NewLocal(locDesc); + + pslIL->EmitLDARG(argidx); + pslIL->EmitSTLOC(dwPinnedArgLocal); + + pslIL->SetStubTargetArgType(ELEMENT_TYPE_U); // native type is a pointer + pslILDispatch->EmitLDLOC(dwPinnedArgLocal); + pslILDispatch->EmitCONV_U(); #endif return OVERRIDDEN; @@ -3504,10 +3465,9 @@ 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 11c3983fc65491..ca84692561b038 100644 --- a/src/coreclr/vm/ilmarshalers.h +++ b/src/coreclr/vm/ilmarshalers.h @@ -1490,8 +1490,7 @@ class ILMarshaler BOOL fManagedToNative, OverrideProcArgs* pargs, UINT* pResID, - UINT argidx, - UINT nativeStackOffset) + UINT argidx) { LIMITED_METHOD_CONTRACT; return HANDLEASNORMAL; @@ -2207,8 +2206,7 @@ class ILHandleRefMarshaler : public ILMarshaler BOOL fManagedToNative, OverrideProcArgs* pargs, UINT* pResID, - UINT argidx, - UINT nativeStackOffset); + UINT argidx); static MarshalerOverrideStatus ReturnOverride(NDirectStubLinker* psl, BOOL fManagedToNative, @@ -2248,8 +2246,7 @@ class ILSafeHandleMarshaler : public ILMarshaler BOOL fManagedToNative, OverrideProcArgs* pargs, UINT* pResID, - UINT argidx, - UINT nativeStackOffset); + UINT argidx); static MarshalerOverrideStatus ReturnOverride(NDirectStubLinker *psl, BOOL fManagedToNative, @@ -2292,8 +2289,7 @@ class ILCriticalHandleMarshaler : public ILMarshaler BOOL fManagedToNative, OverrideProcArgs* pargs, UINT* pResID, - UINT argidx, - UINT nativeStackOffset); + UINT argidx); static MarshalerOverrideStatus ReturnOverride(NDirectStubLinker *psl, BOOL fManagedToNative, @@ -2952,8 +2948,7 @@ class ILBlittableValueClassWithCopyCtorMarshaler : public ILMarshaler BOOL fManagedToNative, OverrideProcArgs* pargs, UINT* pResID, - UINT argidx, - UINT nativeStackOffset); + UINT argidx); }; diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index edabdbc3d4373c..505b35c4552afb 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -3743,18 +3743,8 @@ uint32_t CEEInfo::getClassAttribsInternal (CORINFO_CLASS_HANDLE clsHnd) if (pMT->IsByRefLike()) ret |= CORINFO_FLG_BYREF_LIKE; - // 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)) - { + if (pClass->IsUnsafeValueClass()) ret |= CORINFO_FLG_UNSAFE_VALUECLASS; - } } if (pClass->HasExplicitFieldOffsetLayout() && pClass->HasOverlaidField()) ret |= CORINFO_FLG_OVERLAPPING_FIELDS; @@ -7644,6 +7634,26 @@ 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)) @@ -9428,6 +9438,32 @@ 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, @@ -9458,12 +9494,17 @@ 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(); @@ -9501,6 +9542,14 @@ 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: @@ -9953,6 +10002,40 @@ 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 0f0b5cd898aa3b..5aadd2c49f6e92 100644 --- a/src/coreclr/vm/metasig.h +++ b/src/coreclr/vm/metasig.h @@ -589,9 +589,6 @@ 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 8131e4fd3053a4..53edc30eec3d8b 100644 --- a/src/coreclr/vm/mlinfo.cpp +++ b/src/coreclr/vm/mlinfo.cpp @@ -46,344 +46,6 @@ #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. //========================================================================== @@ -1251,7 +913,7 @@ MarshalInfo::MarshalInfo(Module* pModule, CorNativeType nativeType = NATIVE_TYPE_DEFAULT; Assembly *pAssembly = pModule->GetAssembly(); - BOOL fNeedsCopyCtor = FALSE; + mdToken pCopyCtorModifier = mdTokenNil; m_BestFit = BestFit; m_ThrowOnUnmappableChar = ThrowOnUnmappableChar; m_ms = ms; @@ -1378,11 +1040,10 @@ MarshalInfo::MarshalInfo(Module* pModule, // Skip ET_BYREF IfFailGoto(sigtmp.GetByte(NULL), lFail); - if (sigtmp.HasCustomModifier(pModule, "Microsoft.VisualC.NeedsCopyConstructorModifier", ELEMENT_TYPE_CMOD_REQD) || - sigtmp.HasCustomModifier(pModule, "System.Runtime.CompilerServices.IsCopyConstructed", ELEMENT_TYPE_CMOD_REQD) ) + if (sigtmp.HasCustomModifier(pModule, "Microsoft.VisualC.NeedsCopyConstructorModifier", ELEMENT_TYPE_CMOD_REQD, &pCopyCtorModifier) || + sigtmp.HasCustomModifier(pModule, "System.Runtime.CompilerServices.IsCopyConstructed", ELEMENT_TYPE_CMOD_REQD, &pCopyCtorModifier) ) { mtype = ELEMENT_TYPE_VALUETYPE; - fNeedsCopyCtor = TRUE; m_byref = FALSE; } } @@ -1411,8 +1072,8 @@ MarshalInfo::MarshalInfo(Module* pModule, if (!th.IsEnum()) { // Check for Copy Constructor Modifier - if (sigtmp.HasCustomModifier(pModule, "Microsoft.VisualC.NeedsCopyConstructorModifier", ELEMENT_TYPE_CMOD_REQD) || - sigtmp.HasCustomModifier(pModule, "System.Runtime.CompilerServices.IsCopyConstructed", ELEMENT_TYPE_CMOD_REQD) ) + if (sigtmp.HasCustomModifier(pModule, "Microsoft.VisualC.NeedsCopyConstructorModifier", ELEMENT_TYPE_CMOD_REQD, &pCopyCtorModifier) || + sigtmp.HasCustomModifier(pModule, "System.Runtime.CompilerServices.IsCopyConstructed", ELEMENT_TYPE_CMOD_REQD, &pCopyCtorModifier) ) { mtype = mtype2; @@ -1420,7 +1081,6 @@ 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; } } @@ -2381,17 +2041,11 @@ MarshalInfo::MarshalInfo(Module* pModule, } else { - if (fNeedsCopyCtor && !IsFieldScenario()) // We don't support automatically discovering copy constructors for fields. + if (pCopyCtorModifier != mdTokenNil && !IsFieldScenario()) // We don't support automatically discovering copy constructors for fields. { #if defined(FEATURE_IJW) - MethodDesc *pCopyCtor; - MethodDesc *pDtor; - FindCopyCtor(pModule, m_pMT, &pCopyCtor); - FindDtor(pModule, m_pMT, &pDtor); - + m_args.mm.m_pSigMod = ClassLoader::LoadTypeDefOrRefThrowing(pModule, pCopyCtorModifier).AsMethodTable(); 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; @@ -2813,7 +2467,6 @@ 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 @@ -2841,8 +2494,7 @@ void MarshalInfo::GenerateArgumentIL(NDirectStubLinker* psl, fMngToNative, &m_args, &resID, - m_paramidx + argOffset, - nativeStackOffset); + m_paramidx + argOffset); if (amostat == OVERRIDDEN) diff --git a/src/coreclr/vm/mlinfo.h b/src/coreclr/vm/mlinfo.h index 93a0f554d30af4..795427ef4b9a45 100644 --- a/src/coreclr/vm/mlinfo.h +++ b/src/coreclr/vm/mlinfo.h @@ -87,9 +87,8 @@ struct OverrideProcArgs struct { + MethodTable* m_pSigMod; MethodTable* m_pMT; - MethodDesc* m_pCopyCtor; - MethodDesc* m_pDtor; } mm; struct @@ -113,8 +112,7 @@ typedef MarshalerOverrideStatus (*OVERRIDEPROC)(NDirectStubLinker* psl, BOOL fManagedToNative, OverrideProcArgs* pargs, UINT* pResID, - UINT argidx, - UINT nativeStackOffset); + UINT argidx); typedef MarshalerOverrideStatus (*RETURNOVERRIDEPROC)(NDirectStubLinker* psl, BOOL fManagedToNative, @@ -356,7 +354,6 @@ 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 facb809cd4841a..f1adff6d4f3adb 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, BOOL bSkipCustomModifier) +void SigPointer::ConvertToInternalExactlyOne(Module* pSigModule, SigTypeContext *pTypeContext, SigBuilder * pSigBuilder, TokenLookupMap* pTokenLookupMap) { CONTRACTL { @@ -152,9 +152,10 @@ void SigPointer::ConvertToInternalExactlyOne(Module* pSigModule, SigTypeContext CorElementType typ = ELEMENT_TYPE_END; - // Check whether we need to skip custom modifier - // Only preserve custom modifier when calculating IL stub hash blob - if (bSkipCustomModifier) + // 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) { // GetElemType eats sentinel and custom modifiers IfFailThrowBF(GetElemType(&typ), BFA_BAD_COMPLUS_SIG, pSigModule); @@ -230,16 +231,16 @@ void SigPointer::ConvertToInternalExactlyOne(Module* pSigModule, SigTypeContext case ELEMENT_TYPE_PTR: case ELEMENT_TYPE_PINNED: case ELEMENT_TYPE_SZARRAY: - ConvertToInternalExactlyOne(pSigModule, pTypeContext, pSigBuilder, bSkipCustomModifier); + ConvertToInternalExactlyOne(pSigModule, pTypeContext, pSigBuilder, pTokenLookupMap); break; case ELEMENT_TYPE_FNPTR: - ConvertToInternalSignature(pSigModule, pTypeContext, pSigBuilder, bSkipCustomModifier); + ConvertToInternalSignature(pSigModule, pTypeContext, pSigBuilder, pTokenLookupMap); break; case ELEMENT_TYPE_ARRAY: { - ConvertToInternalExactlyOne(pSigModule, pTypeContext, pSigBuilder, bSkipCustomModifier); + ConvertToInternalExactlyOne(pSigModule, pTypeContext, pSigBuilder, pTokenLookupMap); uint32_t rank = 0; // Get rank IfFailThrowBF(GetData(&rank), BFA_BAD_COMPLUS_SIG, pSigModule); @@ -302,7 +303,7 @@ void SigPointer::ConvertToInternalExactlyOne(Module* pSigModule, SigTypeContext while (argCnt--) { - ConvertToInternalExactlyOne(pSigModule, pTypeContext, pSigBuilder, bSkipCustomModifier); + ConvertToInternalExactlyOne(pSigModule, pTypeContext, pSigBuilder, pTokenLookupMap); } } break; @@ -311,20 +312,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->AppendElementType(ELEMENT_TYPE_INTERNAL); - pSigBuilder->AppendPointer(th.AsPtr()); + pSigBuilder->AppendToken(pTokenLookupMap->GetToken(th)); - ConvertToInternalExactlyOne(pSigModule, pTypeContext, pSigBuilder, bSkipCustomModifier); + ConvertToInternalExactlyOne(pSigModule, pTypeContext, pSigBuilder, pTokenLookupMap); } break; } } } -void SigPointer::ConvertToInternalSignature(Module* pSigModule, SigTypeContext *pTypeContext, SigBuilder * pSigBuilder, BOOL bSkipCustomModifier) +void SigPointer::ConvertToInternalSignature(Module* pSigModule, SigTypeContext *pTypeContext, SigBuilder * pSigBuilder, TokenLookupMap* pTokenLookupMap) { CONTRACTL { @@ -361,7 +362,7 @@ void SigPointer::ConvertToInternalSignature(Module* pSigModule, SigTypeContext * // Skip args. while (cArgs) { - ConvertToInternalExactlyOne(pSigModule, pTypeContext, pSigBuilder, bSkipCustomModifier); + ConvertToInternalExactlyOne(pSigModule, pTypeContext, pSigBuilder, pTokenLookupMap); cArgs--; } } @@ -937,6 +938,25 @@ 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 { @@ -2282,7 +2302,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) const +BOOL SigPointer::HasCustomModifier(Module *pModule, LPCSTR szModName, CorElementType cmodtype, mdToken* pModifierType) const { CONTRACTL { @@ -2318,6 +2338,54 @@ 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 fab9a79260d2d1..935d6ccd7fe109 100644 --- a/src/coreclr/vm/siginfo.hpp +++ b/src/coreclr/vm/siginfo.hpp @@ -49,6 +49,7 @@ unsigned GetSizeForCorElementType(CorElementType etyp); class SigBuilder; class ArgDestination; +class TokenLookupMap; typedef const struct HardCodedMetaSig *LPHARDCODEDMETASIG; @@ -125,8 +126,8 @@ class SigPointer : public SigParser //========================================================================= - void ConvertToInternalExactlyOne(Module* pSigModule, SigTypeContext *pTypeContext, SigBuilder * pSigBuilder, BOOL bSkipCustomModifier = TRUE); - void ConvertToInternalSignature(Module* pSigModule, SigTypeContext *pTypeContext, SigBuilder * pSigBuilder, BOOL bSkipCustomModifier = TRUE); + void ConvertToInternalExactlyOne(Module* pSigModule, SigTypeContext *pTypeContext, SigBuilder * pSigBuilder, TokenLookupMap* pTokenMap = nullptr); + void ConvertToInternalSignature(Module* pSigModule, SigTypeContext *pTypeContext, SigBuilder * pSigBuilder, TokenLookupMap* pTokenMap = nullptr); //========================================================================= @@ -277,7 +278,8 @@ class SigPointer : public SigParser //------------------------------------------------------------------------ // Tests for the existence of a custom modifier //------------------------------------------------------------------------ - BOOL HasCustomModifier(Module *pModule, LPCSTR szModName, CorElementType cmodtype) const; + BOOL HasCustomModifier(Module *pModule, LPCSTR szModName, CorElementType cmodtype, mdToken* pModifierType = NULL) const; + BOOL HasCustomModifier(DynamicResolver *pResolver, LPCSTR szModName, CorElementType cmodtype, mdToken* pModifierType = NULL) 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 283b6d3fa2d883..4164da672a1c64 100644 --- a/src/coreclr/vm/stubgen.cpp +++ b/src/coreclr/vm/stubgen.cpp @@ -2601,78 +2601,101 @@ CorCallingConvention ILStubLinker::GetStubTargetCallingConv() return m_nativeFnSigBuilder.GetCallingConv(); } -void ILStubLinker::TransformArgForJIT(LocalDesc *pLoc) +namespace { - 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: + 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]) { - // no transformation needed - break; - } + // 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; + } - 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. - pLoc->ElementType[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. + sig[0] = ELEMENT_TYPE_PTR; + break; + } - case ELEMENT_TYPE_INTERNAL: - { - // JIT will handle structures - if (pLoc->InternalToken.IsValueType()) + case ELEMENT_TYPE_CMOD_OPT: + case ELEMENT_TYPE_CMOD_REQD: { - _ASSERTE(pLoc->InternalToken.IsNativeValueType() || !pLoc->InternalToken.GetMethodTable()->ContainsGCPointers()); + // 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; break; } - FALLTHROUGH; - } - // ref types -> ELEMENT_TYPE_I - default: - { - pLoc->ElementType[0] = ELEMENT_TYPE_I; - pLoc->cbType = 1; - break; + 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; + } } } } +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 968e5f9b48291f..00cc8c21d53e1b 100644 --- a/src/coreclr/vm/stubgen.h +++ b/src/coreclr/vm/stubgen.h @@ -96,6 +96,19 @@ 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; @@ -270,7 +283,7 @@ class FunctionSigBuilder : protected StubSigBuilder //--------------------------------------------------------------------------------------- // -class TokenLookupMap +class TokenLookupMap final { public: TokenLookupMap() @@ -477,7 +490,52 @@ class TokenLookupMap return token; } -protected: + // 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: mdToken GetMemberRefWorker(MemberRefEntry** entry) { CONTRACTL diff --git a/src/tests/Interop/IJW/CopyConstructorMarshaler/CopyConstructorMarshaler.cs b/src/tests/Interop/IJW/CopyConstructorMarshaler/CopyConstructorMarshaler.cs index b59dcb74dd521d..757b35cfb07a9b 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 have an additional copy on every P/Invoke from the "native" parameter to the actual location on the stack. + // On x86, we will copy in the IL stub to the final arg slot. int platformExtra = 0; if (RuntimeInformation.ProcessArchitecture == Architecture.X86) { platformExtra = 1; } - - // 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)); + + // PInvoke will copy once. Once from the managed to native parameter. + Assert.Equal(1 + platformExtra, (int)testMethod.Invoke(testInstance, null)); testMethod = testType.GetMethod("ReversePInvokeNumCopies"); - // 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)); + // 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)); testMethod = testType.GetMethod("PInvokeNumCopiesDerivedType"); - // 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)); + // PInvoke will copy once from the managed to native parameter. + Assert.Equal(1 + platformExtra, (int)testMethod.Invoke(testInstance, null)); testMethod = testType.GetMethod("ReversePInvokeNumCopiesDerivedType"); - // 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)); + // 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)); } catch (Exception ex) { @@ -62,7 +62,6 @@ 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"); @@ -74,7 +73,6 @@ 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 57ec4d9632426d..9601a835bb79ac 100644 --- a/src/tests/Interop/PInvoke/Miscellaneous/CopyCtor/CopyCtorTest.cs +++ b/src/tests/Interop/PInvoke/Miscellaneous/CopyCtor/CopyCtorTest.cs @@ -25,11 +25,7 @@ public static unsafe int StructWithCtorTest(StructWithCtor* ptrStruct, ref Struc return 2; } - int expectedCallCount = 2; - if (RuntimeInformation.ProcessArchitecture == Architecture.X86) - { - expectedCallCount = 4; - } + int expectedCallCount = RuntimeInformation.ProcessArchitecture == Architecture.X86 ? 2 : 0; if (StructWithCtor.CopyCtorCallCount != expectedCallCount) { @@ -48,6 +44,7 @@ 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"));