diff --git a/docs/design/datacontracts/RuntimeTypeSystem.md b/docs/design/datacontracts/RuntimeTypeSystem.md index 3e6fefa0790735..c79f441080c15c 100644 --- a/docs/design/datacontracts/RuntimeTypeSystem.md +++ b/docs/design/datacontracts/RuntimeTypeSystem.md @@ -23,6 +23,7 @@ internal enum CorElementType // Values defined in ECMA-335 - II.23.1.16 Element types used in signatures // + Internal = 0x21, // Indicates that the next pointer sized number of bytes is the address of a TypeHandle. Signatures that contain the Internal CorElementType cannot exist in metadata that is saved into a serialized format. + CModInternal = 0x22, // Indicates that the next byte specifies if the modifier is required and the next pointer sized number of bytes after that is the address of a TypeHandle. Signatures that contain the CModInternal CorElementType cannot exist in metadata that is saved into a seralized format. } ``` 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 88e07e8d388ced..57e606a138cda2 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 @@ -360,6 +360,11 @@ 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/ildasm/dasm.cpp b/src/coreclr/ildasm/dasm.cpp index f94a5846672d96..f514e90cca65e6 100644 --- a/src/coreclr/ildasm/dasm.cpp +++ b/src/coreclr/ildasm/dasm.cpp @@ -2088,6 +2088,9 @@ BYTE* PrettyPrintCABlobValue(PCCOR_SIGNATURE &typePtr, #ifdef LOGGING case ELEMENT_TYPE_INTERNAL : + case ELEMENT_TYPE_CMOD_INTERNAL : + typePtr += 1; + Reiterate = TRUE; #endif // LOGGING return NULL; diff --git a/src/coreclr/inc/corhdr.h b/src/coreclr/inc/corhdr.h index c12c1cfdd4f710..b0e257a8469b24 100644 --- a/src/coreclr/inc/corhdr.h +++ b/src/coreclr/inc/corhdr.h @@ -911,9 +911,10 @@ typedef enum CorElementType // This is for signatures generated internally (which will not be persisted in any way). ELEMENT_TYPE_INTERNAL = 0x21, // INTERNAL + ELEMENT_TYPE_CMOD_INTERNAL = 0x22, // CMOD_INTERNAL // Note that this is the max of base type excluding modifiers - ELEMENT_TYPE_MAX = 0x22, // first invalid element type + ELEMENT_TYPE_MAX = 0x23, // first invalid element type ELEMENT_TYPE_MODIFIER = 0x40, 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/cortypeinfo.h b/src/coreclr/inc/cortypeinfo.h index 87d960301b64b3..d051c352127dda 100644 --- a/src/coreclr/inc/cortypeinfo.h +++ b/src/coreclr/inc/cortypeinfo.h @@ -54,3 +54,4 @@ TYPEINFO(ELEMENT_TYPE_MVAR, NULL, NULL, TARGET_POINTER_SI TYPEINFO(ELEMENT_TYPE_CMOD_REQD, NULL, NULL, 0, TYPE_GC_NONE, false, false, false, false, false) // 0x1f TYPEINFO(ELEMENT_TYPE_CMOD_OPT, NULL, NULL, 0, TYPE_GC_NONE, false, false, false, false, false) // 0x20 TYPEINFO(ELEMENT_TYPE_INTERNAL, NULL, NULL, 0, TYPE_GC_OTHER, false, false, false, false, false) // 0x21 +TYPEINFO(ELEMENT_TYPE_CMOD_INTERNAL,NULL, NULL, 0, TYPE_GC_NONE, false, false, false, false, false) // 0x22 diff --git a/src/coreclr/inc/formattype.cpp b/src/coreclr/inc/formattype.cpp index 64d401ffb4d618..af30955047acb1 100644 --- a/src/coreclr/inc/formattype.cpp +++ b/src/coreclr/inc/formattype.cpp @@ -694,6 +694,44 @@ PCCOR_SIGNATURE PrettyPrintType( appendStr(out, sz); break; } + case ELEMENT_TYPE_CMOD_INTERNAL : + { + // ELEMENT_TYPE_CMOD_INTERNAL + bool required = *typePtr++ != 0; + _ASSERTE(sizeof(TypeHandle) == sizeof(void *)); + TypeHandle typeHandle; + typePtr += CorSigUncompressPointer(typePtr, (void **)&typeHandle); + + MethodTable *pMT = NULL; + if (typeHandle.IsTypeDesc()) + { + pMT = typeHandle.AsTypeDesc()->GetMethodTable(); + if (pMT) + { + PrettyPrintClass(out, pMT->GetCl(), pMT->GetMDImport()); + + // It could be a "native version" of the managed type used in interop + if (typeHandle.AsTypeDesc()->IsNativeValueType()) + appendStr(out, "_NativeValueType"); + } + else + appendStr(out, "(null)"); + } + else + { + pMT = typeHandle.AsMethodTable(); + if (pMT) + PrettyPrintClass(out, pMT->GetCl(), pMT->GetMDImport()); + else + appendStr(out, "(null)"); + } + + const char fmt[] = " mod%s(/* MT: %p */)"; + char sz[Max64BitHexString + ARRAY_SIZE(fmt) + ARRAY_SIZE("req")]; + sprintf_s(sz, ARRAY_SIZE(sz), fmt, required ? "req" : "opt", pMT); + appendStr(out, sz); + break; + } #endif 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/inc/sigparser.h b/src/coreclr/inc/sigparser.h index 4446a37e372b52..6aad0669d94ed7 100644 --- a/src/coreclr/inc/sigparser.h +++ b/src/coreclr/inc/sigparser.h @@ -582,19 +582,32 @@ class SigParser return hr; while ((ELEMENT_TYPE_CMOD_REQD == bElementType) || - (ELEMENT_TYPE_CMOD_OPT == bElementType)) + (ELEMENT_TYPE_CMOD_OPT == bElementType) || + (ELEMENT_TYPE_CMOD_INTERNAL == bElementType)) { sigTemp.SkipBytes(1); + if (ELEMENT_TYPE_CMOD_INTERNAL == bElementType) + { + void * pMT; + // If this custom modifier is required or optional + uint8_t required; + if (FAILED(hr = sigTemp.GetByte(&required))) + return hr; + + if (FAILED(hr = sigTemp.GetPointer(&pMT))) + return hr; + } + else + { + mdToken token; - mdToken token; - - hr = sigTemp.GetToken(&token); + hr = sigTemp.GetToken(&token); - if (FAILED(hr)) - return hr; + if (FAILED(hr)) + return hr; + } - hr = sigTemp.PeekByte(&bElementType); - if (FAILED(hr)) + if (FAILED(hr = sigTemp.PeekByte(&bElementType))) return hr; } @@ -643,19 +656,31 @@ class SigParser while (ELEMENT_TYPE_CMOD_REQD == bElementType || ELEMENT_TYPE_CMOD_OPT == bElementType || ELEMENT_TYPE_MODIFIER == bElementType || - ELEMENT_TYPE_PINNED == bElementType) + ELEMENT_TYPE_PINNED == bElementType || + ELEMENT_TYPE_CMOD_INTERNAL == bElementType) { sigTemp.SkipBytes(1); + if (ELEMENT_TYPE_CMOD_INTERNAL == bElementType) + { + void * pMT; + uint8_t required; + if (FAILED(hr = sigTemp.GetByte(&required))) + return hr; + + if (FAILED(hr = sigTemp.GetPointer(&pMT))) + return hr; + } + else + { + mdToken token; - mdToken token; - - hr = sigTemp.GetToken(&token); + hr = sigTemp.GetToken(&token); - if (FAILED(hr)) - return hr; + if (FAILED(hr)) + return hr; + } - hr = sigTemp.PeekByte(&bElementType); - if (FAILED(hr)) + if (FAILED(hr = sigTemp.PeekByte(&bElementType))) return hr; } 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 ad8622e109cdd6..5ff9a2e94d0e4f 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 f687f9139f5981..33f03ac420fffc 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -16599,6 +16599,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/utilcode/prettyprintsig.cpp b/src/coreclr/utilcode/prettyprintsig.cpp index 59f6e88c26df85..31f6a93c4a194b 100644 --- a/src/coreclr/utilcode/prettyprintsig.cpp +++ b/src/coreclr/utilcode/prettyprintsig.cpp @@ -674,6 +674,18 @@ static HRESULT PrettyPrintTypeA( sprintf_s(tempBuffer, 64, "pMT: %p", pMT); IfFailGo(appendStrA(out, tempBuffer)); break; + + case ELEMENT_TYPE_CMOD_INTERNAL: + { + bool required = *typePtr++ != 0; + void* pMT; + memcpy(&pMT, &typePtr, sizeof(pMT)); + typePtr += sizeof(pMT); + CHAR tempBuffer[64]; + sprintf_s(tempBuffer, 64, "pMT: %p", pMT); + IfFailGo(appendStrA(out, tempBuffer)); + break; + } case ELEMENT_TYPE_VALUETYPE: str = "value class "; diff --git a/src/coreclr/vm/callconvbuilder.cpp b/src/coreclr/vm/callconvbuilder.cpp index d68ac7f023ec3d..aafc371782cbdd 100644 --- a/src/coreclr/vm/callconvbuilder.cpp +++ b/src/coreclr/vm/callconvbuilder.cpp @@ -358,25 +358,49 @@ HRESULT CallConv::TryGetUnmanagedCallingConventionFromModOpt( _ASSERTE(pWalk <= pSig + cSig); CallConvBuilder& callConvBuilder = *builder; - while ((pWalk < (pSig + cSig)) && ((*pWalk == ELEMENT_TYPE_CMOD_OPT) || (*pWalk == ELEMENT_TYPE_CMOD_REQD))) + while ((pWalk < (pSig + cSig)) && ((*pWalk == ELEMENT_TYPE_CMOD_OPT) || (*pWalk == ELEMENT_TYPE_CMOD_REQD) || (*pWalk == ELEMENT_TYPE_CMOD_INTERNAL))) { - BOOL fIsOptional = (*pWalk == ELEMENT_TYPE_CMOD_OPT); - - pWalk++; - if (pWalk + CorSigUncompressedDataSize(pWalk) > pSig + cSig) + CORINFO_MODULE_HANDLE tokenLookupModule = pModule; + mdToken tk; + LPCSTR typeNamespace; + LPCSTR typeName; + if (*pWalk == ELEMENT_TYPE_CMOD_INTERNAL) { - *errorResID = BFA_BAD_SIGNATURE; - return COR_E_BADIMAGEFORMAT; // Bad formatting + // Skip internal modifiers + pWalk++; + if (pWalk + 1 + sizeof(void*) > pSig + cSig) + { + *errorResID = BFA_BAD_SIGNATURE; + return COR_E_BADIMAGEFORMAT; // Bad formatting + } + + BOOL required = *pWalk++ != 0; + void* pType; + pWalk += CorSigUncompressPointer(pWalk, &pType); + TypeHandle type = TypeHandle::FromPtr(pType); + + if (!required) + continue; + + tokenLookupModule = GetScopeHandle(type.GetModule()); + tk = type.GetCl(); } + else + { + BOOL fIsOptional = (*pWalk == ELEMENT_TYPE_CMOD_OPT); - mdToken tk; - pWalk += CorSigUncompressToken(pWalk, &tk); + pWalk++; + if (pWalk + CorSigUncompressedDataSize(pWalk) > pSig + cSig) + { + *errorResID = BFA_BAD_SIGNATURE; + return COR_E_BADIMAGEFORMAT; // Bad formatting + } - if (!fIsOptional) - continue; + pWalk += CorSigUncompressToken(pWalk, &tk); - LPCSTR typeNamespace; - LPCSTR typeName; + if (!fIsOptional) + continue; + } // Check for CallConv types specified in modopt if (FAILED(GetNameOfTypeRefOrDef(pModule, tk, &typeNamespace, &typeName))) 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..c4b9c9feb61798 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) @@ -407,8 +407,9 @@ class ILStubState : public StubState SigBuilder sigBuilder; { + // Convert to a module independent signature SigPointer sigPtr(pStubMD->GetSig()); - sigPtr.ConvertToInternalSignature(pStubMD->GetModule(), NULL, &sigBuilder); + sigPtr.ConvertToInternalSignature(pStubMD->GetModule(), NULL, &sigBuilder, /* bSkipCustomModifier */ FALSE); } // @@ -464,6 +465,26 @@ class ILStubState : public StubState cbTempModuleIndependentSigLength); } + void ConvertMethodDescSigToModuleIndependentSig(MethodDesc* pStubMD) + { + SigBuilder sigBuilder; + _ASSERTE(pStubMD->IsNoMetadata()); + SigPointer sigPtr(pStubMD->GetSig()); + sigPtr.ConvertToInternalSignature(pStubMD->GetModule(), NULL, &sigBuilder, /* bSkipCustomModifier */ FALSE); + + // + // 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 +820,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 +1650,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 +1862,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 +2091,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 +2174,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 +2405,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 +3447,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 +3569,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 +3758,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 +3794,6 @@ static void CreateNDirectStubWorker(StubState* pss, argOffset, dwStubFlags, pMD, - nativeStackSize, fStubNeedsCOM, nativeArgIndex DEBUG_ARG(pSigDesc->m_pDebugName) @@ -4078,8 +4053,9 @@ 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 that influence behavior, so don't skip them SigBuilder sigBuilder; - sigPtr.ConvertToInternalSignature(pParams->m_pModule, pParams->m_pTypeContext, &sigBuilder, /* bSkipCustomModifier = */ FALSE); + sigPtr.ConvertToInternalSignature(pParams->m_pModule, pParams->m_pTypeContext, &sigBuilder, /* bSkipCustomModifier */ FALSE); DWORD cbSig; PVOID pSig = sigBuilder.GetSignature(&cbSig); @@ -6113,21 +6089,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/gdbjit.h b/src/coreclr/vm/gdbjit.h index d0adbc9cee8c53..8a73ce52ba821b 100644 --- a/src/coreclr/vm/gdbjit.h +++ b/src/coreclr/vm/gdbjit.h @@ -74,6 +74,7 @@ static constexpr const int CorElementTypeToDWEncoding[] = /* ELEMENT_TYPE_CMOD_REQD */ DW_ATE_address, /* ELEMENT_TYPE_CMOD_OPT */ DW_ATE_address, /* ELEMENT_TYPE_INTERNAL */ DW_ATE_address, +/* ELEMENT_TYPE_CMOD_INTERNAL */DW_ATE_address, /* ELEMENT_TYPE_MAX */ DW_ATE_address, }; 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..e7e59cc82bca6a 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, 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/ilstubcache.cpp b/src/coreclr/vm/ilstubcache.cpp index cf97371eee30e0..e16ddbc0f3b2c7 100644 --- a/src/coreclr/vm/ilstubcache.cpp +++ b/src/coreclr/vm/ilstubcache.cpp @@ -55,7 +55,7 @@ void CreateModuleIndependentSignature(LoaderHeap* pCreationHeap, SigPointer sigPtr(pSig, cbSig); SigBuilder sigBuilder; - sigPtr.ConvertToInternalSignature(pSigModule, pTypeContext, &sigBuilder); + sigPtr.ConvertToInternalSignature(pSigModule, pTypeContext, &sigBuilder, /* bSkipCustomModifier */ FALSE); DWORD cbNewSig; PVOID pConvertedSig = sigBuilder.GetSignature(&cbNewSig); diff --git a/src/coreclr/vm/ilstubresolver.cpp b/src/coreclr/vm/ilstubresolver.cpp index 980d62032a4c9d..7e2786baa9d82c 100644 --- a/src/coreclr/vm/ilstubresolver.cpp +++ b/src/coreclr/vm/ilstubresolver.cpp @@ -546,4 +546,4 @@ void ILStubResolver::StubGenFailed(ILStubResolver* pResolver) } pResolver->ClearCompileTimeState(ILNotYetGenerated); -} +} \ No newline at end of file diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index 9c76cf0e7b08b0..d205c413bc7586 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -391,6 +391,7 @@ CorInfoType CEEInfo::asCorInfoType(CorElementType eeType, CORINFO_TYPE_UNDEF, // CMOD_REQD CORINFO_TYPE_UNDEF, // CMOD_OPT CORINFO_TYPE_UNDEF, // INTERNAL + CORINFO_TYPE_UNDEF, // CMOD_INTERNAL }; _ASSERTE(sizeof(map) == ELEMENT_TYPE_MAX); @@ -3743,18 +3744,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 +7635,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)) @@ -9427,7 +9438,6 @@ CORINFO_ARG_LIST_HANDLE CEEInfo::getArgNext(CORINFO_ARG_LIST_HANDLE args) /*********************************************************************/ - CorInfoTypeWithMod CEEInfo::getArgType ( CORINFO_SIG_INFO* sig, CORINFO_ARG_LIST_HANDLE args, @@ -9458,12 +9468,18 @@ CorInfoTypeWithMod CEEInfo::getArgType ( IfFailThrow(ptr.PeekElemType(&eType)); } + Module* pModule = GetModule(sig->scope); + + if (ptr.HasCustomModifier(pModule, "Microsoft.VisualC.NeedsCopyConstructorModifier", ELEMENT_TYPE_CMOD_REQD) || + ptr.HasCustomModifier(pModule, "System.Runtime.CompilerServices.IsCopyConstructed", ELEMENT_TYPE_CMOD_REQD)) + { + 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 +9517,15 @@ CorInfoTypeWithMod CEEInfo::getArgType ( classMustBeLoadedBeforeCodeIsRun(CORINFO_CLASS_HANDLE(thPtr.AsPtr())); } } + FALLTHROUGH; + + case ELEMENT_TYPE_BYREF: + IfFailThrow(ptr.GetElemType(NULL)); + if (ptr.HasCustomModifier(pModule, "Microsoft.VisualC.NeedsCopyConstructorModifier", ELEMENT_TYPE_CMOD_REQD) || + ptr.HasCustomModifier(pModule, "System.Runtime.CompilerServices.IsCopyConstructed", ELEMENT_TYPE_CMOD_REQD)) + { + result = CorInfoTypeWithMod((int)result | CORINFO_TYPE_MOD_COPY_WITH_HELPER); + } break; case ELEMENT_TYPE_VOID: @@ -9953,6 +9978,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/methodtable.h b/src/coreclr/vm/methodtable.h index 79334cb03201fd..eab30fba86d019 100644 --- a/src/coreclr/vm/methodtable.h +++ b/src/coreclr/vm/methodtable.h @@ -737,6 +737,7 @@ SystemVClassificationType CorInfoType2UnixAmd64Classification(CorElementType eeT SystemVClassificationTypeUnknown, // ELEMENT_TYPE_CMOD_REQD SystemVClassificationTypeUnknown, // ELEMENT_TYPE_CMOD_OPT SystemVClassificationTypeUnknown, // ELEMENT_TYPE_INTERNAL + SystemVClassificationTypeUnknown, // ELEMENT_TYPE_CMOD_INTERNAL }; _ASSERTE(sizeof(toSystemVAmd64ClassificationTypeMap) == ELEMENT_TYPE_MAX); diff --git a/src/coreclr/vm/mlinfo.cpp b/src/coreclr/vm/mlinfo.cpp index 8131e4fd3053a4..40ccb2eeaff134 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. //========================================================================== @@ -1117,6 +779,7 @@ namespace // Skip modreqs and modopts in the signature. case ELEMENT_TYPE_CMOD_OPT: case ELEMENT_TYPE_CMOD_REQD: + case ELEMENT_TYPE_CMOD_INTERNAL: { if(FAILED(sig.GetElemType(NULL))) { @@ -1251,7 +914,8 @@ MarshalInfo::MarshalInfo(Module* pModule, CorNativeType nativeType = NATIVE_TYPE_DEFAULT; Assembly *pAssembly = pModule->GetAssembly(); - BOOL fNeedsCopyCtor = FALSE; + Module* pCopyCtorModule = NULL; + mdToken pCopyCtorModifier = mdTokenNil; m_BestFit = BestFit; m_ThrowOnUnmappableChar = ThrowOnUnmappableChar; m_ms = ms; @@ -1378,11 +1042,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, &pCopyCtorModule, &pCopyCtorModifier) || + sigtmp.HasCustomModifier(pModule, "System.Runtime.CompilerServices.IsCopyConstructed", ELEMENT_TYPE_CMOD_REQD, &pCopyCtorModule, &pCopyCtorModifier) ) { mtype = ELEMENT_TYPE_VALUETYPE; - fNeedsCopyCtor = TRUE; m_byref = FALSE; } } @@ -1411,8 +1074,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, &pCopyCtorModule, &pCopyCtorModifier) || + sigtmp.HasCustomModifier(pModule, "System.Runtime.CompilerServices.IsCopyConstructed", ELEMENT_TYPE_CMOD_REQD, &pCopyCtorModule, &pCopyCtorModifier) ) { mtype = mtype2; @@ -1420,7 +1083,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 +2043,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(pCopyCtorModule, 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 +2469,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 +2496,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/runtimehandles.cpp b/src/coreclr/vm/runtimehandles.cpp index 33171f08e13546..da9d57deebff98 100644 --- a/src/coreclr/vm/runtimehandles.cpp +++ b/src/coreclr/vm/runtimehandles.cpp @@ -1855,13 +1855,24 @@ FCIMPL3(Object *, SignatureNative::GetCustomModifiersAtOffset, { cMods ++; } + + IfFailThrow(sp.GetToken(NULL)); + } + else if (cmodType == ELEMENT_TYPE_CMOD_INTERNAL) + { + BYTE required; + IfFailThrow(sp.GetByte(&required)); + if (fRequired == (required != 0)) + { + cMods ++; + } + + IfFailThrow(sp.GetPointer(NULL)); } else if (cmodType != ELEMENT_TYPE_SENTINEL) { break; } - - IfFailThrow(sp.GetToken(NULL)); } // Reset sp and populate the arrays for the required and optional custom @@ -1879,18 +1890,35 @@ FCIMPL3(Object *, SignatureNative::GetCustomModifiersAtOffset, IfFailThrow(sp.GetByte(&data)); cmodType = (CorElementType)data; - mdToken token; - IfFailThrow(sp.GetToken(&token)); + if (cmodType == ELEMENT_TYPE_CMOD_INTERNAL) + { + BYTE required; + IfFailThrow(sp.GetByte(&required)); + + TypeHandle th; + IfFailThrow(sp.GetPointer((void**)&th)); - if (cmodType == cmodTypeExpected) + if (fRequired == (required != 0)) + { + OBJECTREF refType = th.GetManagedClassObject(); + gc.retVal->SetAt(--cMods, refType); + } + } + else { - TypeHandle th = ClassLoader::LoadTypeDefOrRefOrSpecThrowing(pModule, token, - &typeContext, - ClassLoader::ThrowIfNotFound, - ClassLoader::FailIfUninstDefOrRef); + mdToken token; + IfFailThrow(sp.GetToken(&token)); - OBJECTREF refType = th.GetManagedClassObject(); - gc.retVal->SetAt(--cMods, refType); + if (cmodType == cmodTypeExpected) + { + TypeHandle th = ClassLoader::LoadTypeDefOrRefOrSpecThrowing(pModule, token, + &typeContext, + ClassLoader::ThrowIfNotFound, + ClassLoader::FailIfUninstDefOrRef); + + OBJECTREF refType = th.GetManagedClassObject(); + gc.retVal->SetAt(--cMods, refType); + } } } } diff --git a/src/coreclr/vm/siginfo.cpp b/src/coreclr/vm/siginfo.cpp index facb809cd4841a..f110b75286c66c 100644 --- a/src/coreclr/vm/siginfo.cpp +++ b/src/coreclr/vm/siginfo.cpp @@ -126,6 +126,7 @@ DEFINEELEMENTTYPEINFO(ELEMENT_TYPE_MVAR, -1, TYPE_GC DEFINEELEMENTTYPEINFO(ELEMENT_TYPE_CMOD_REQD, -1, TYPE_GC_NONE, 1) DEFINEELEMENTTYPEINFO(ELEMENT_TYPE_CMOD_OPT, -1, TYPE_GC_NONE, 1) DEFINEELEMENTTYPEINFO(ELEMENT_TYPE_INTERNAL, -1, TYPE_GC_NONE, 0) +DEFINEELEMENTTYPEINFO(ELEMENT_TYPE_CMOD_INTERNAL, -1, TYPE_GC_NONE, 0) }; unsigned GetSizeForCorElementType(CorElementType etyp) @@ -152,8 +153,9 @@ 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 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 (bSkipCustomModifier) { // GetElemType eats sentinel and custom modifiers @@ -180,6 +182,17 @@ void SigPointer::ConvertToInternalExactlyOne(Module* pSigModule, SigTypeContext return; } + if (typ == ELEMENT_TYPE_CMOD_REQD || typ == ELEMENT_TYPE_CMOD_OPT) + { + mdToken tk; + IfFailThrowBF(GetToken(&tk), BFA_BAD_COMPLUS_SIG, pSigModule); + TypeHandle th = ClassLoader::LoadTypeDefOrRefThrowing(pSigModule, tk); + pSigBuilder->AppendElementType(ELEMENT_TYPE_CMOD_INTERNAL); + pSigBuilder->AppendByte(typ == ELEMENT_TYPE_CMOD_REQD); // "is required" byte + pSigBuilder->AppendPointer(th.AsPtr()); + return ConvertToInternalExactlyOne(pSigModule, pTypeContext, pSigBuilder, bSkipCustomModifier); + } + if (pTypeContext != NULL) { uint32_t varNum; @@ -272,6 +285,29 @@ void SigPointer::ConvertToInternalExactlyOne(Module* pSigModule, SigTypeContext } break; + case ELEMENT_TYPE_CMOD_INTERNAL: + { + uint8_t required; + IfFailThrowBF(GetByte(&required), BFA_BAD_COMPLUS_SIG, pSigModule); + pSigBuilder->AppendByte(required); + + // this check is not functional in DAC and provides no security against a malicious dump + // the DAC is prepared to receive an invalid type handle +#ifndef DACCESS_COMPILE + if (pSigModule->IsSigInIL(m_ptr)) + THROW_BAD_FORMAT(BFA_BAD_COMPLUS_SIG, pSigModule); +#endif + + TypeHandle hType; + + IfFailThrowBF(GetPointer((void**)&hType), BFA_BAD_COMPLUS_SIG, pSigModule); + + pSigBuilder->AppendPointer(hType.AsPtr()); + + ConvertToInternalExactlyOne(pSigModule, pTypeContext, pSigBuilder, bSkipCustomModifier); + } + break; + case ELEMENT_TYPE_INTERNAL: { // this check is not functional in DAC and provides no security against a malicious dump @@ -306,20 +342,6 @@ void SigPointer::ConvertToInternalExactlyOne(Module* pSigModule, SigTypeContext } } break; - - // Note: the following is only for correctly computing IL stub hash for modifiers in order to support C++ scenarios - case ELEMENT_TYPE_CMOD_OPT: - case ELEMENT_TYPE_CMOD_REQD: - { - 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()); - - ConvertToInternalExactlyOne(pSigModule, pTypeContext, pSigBuilder, bSkipCustomModifier); - } - break; } } } @@ -937,6 +959,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 +2323,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, Module** pModifierScope, mdToken* pModifierType) const { CONTRACTL { @@ -2310,14 +2351,41 @@ BOOL SigPointer::HasCustomModifier(Module *pModule, LPCSTR szModName, CorElement etyp = (CorElementType)data; - while (etyp == ELEMENT_TYPE_CMOD_OPT || etyp == ELEMENT_TYPE_CMOD_REQD) { - + while (etyp == ELEMENT_TYPE_CMOD_OPT || etyp == ELEMENT_TYPE_CMOD_REQD || etyp == ELEMENT_TYPE_CMOD_INTERNAL) { + Module* lookupModule = pModule; mdToken tk; - if (FAILED(sp.GetToken(&tk))) - return FALSE; - if (etyp == cmodtype && IsTypeRefOrDef(szModName, pModule, tk)) + if (etyp == ELEMENT_TYPE_CMOD_INTERNAL) + { + uint8_t required; + if (FAILED(sp.GetByte(&required))) + return FALSE; + + void* typeHandle; + if (FAILED(sp.GetPointer(&typeHandle))) + return FALSE; + + TypeHandle type = TypeHandle::FromPtr(typeHandle); + tk = type.GetCl(); + lookupModule = type.GetModule(); + etyp = required ? ELEMENT_TYPE_CMOD_REQD : ELEMENT_TYPE_CMOD_OPT; + } + else { + if (FAILED(sp.GetToken(&tk))) + return FALSE; + } + + if (etyp == cmodtype && IsTypeRefOrDef(szModName, lookupModule, tk)) + { + if (pModifierScope != nullptr) + { + *pModifierScope = lookupModule; + } + if (pModifierType != nullptr) + { + *pModifierType = tk; + } return(TRUE); } @@ -3607,6 +3675,7 @@ BOOL CompareTypeTokens(mdToken tk1, mdToken tk2, ModuleBase *pModule1, ModuleBas static void ConsumeCustomModifiers(PCCOR_SIGNATURE& pSig, PCCOR_SIGNATURE pEndSig) { mdToken tk; + void* ptr; CorElementType type; PCCOR_SIGNATURE pSigTmp = pSig; @@ -3617,6 +3686,15 @@ static void ConsumeCustomModifiers(PCCOR_SIGNATURE& pSig, PCCOR_SIGNATURE pEndSi switch (type) { + case ELEMENT_TYPE_CMOD_INTERNAL: + if (pSigTmp + 1 > pEndSig) + { + IfFailThrow(META_E_BAD_SIGNATURE); + } + pSigTmp++; // Skip the required bit + IfFailThrow(CorSigUncompressPointer_EndPtr(pSigTmp, pEndSig, &ptr)); + pSig = pSigTmp; + break; case ELEMENT_TYPE_CMOD_REQD: case ELEMENT_TYPE_CMOD_OPT: IfFailThrow(CorSigUncompressToken_EndPtr(pSigTmp, pEndSig, &tk)); @@ -3828,6 +3906,71 @@ MetaSig::CompareElementType( } } + if (Type1 == ELEMENT_TYPE_CMOD_INTERNAL || Type2 == ELEMENT_TYPE_CMOD_INTERNAL) + { + bool internalRequired; + TypeHandle hInternal; + CorElementType eOtherType; + ModuleBase * pOtherModule; + + // One type is already loaded, collect all the necessary information to identify the other type. + if (Type1 == ELEMENT_TYPE_CMOD_INTERNAL) + { + if (pSig1 + 1 > pEndSig1) + { + IfFailThrow(META_E_BAD_SIGNATURE); + } + internalRequired = *pSig1++; + IfFailThrow(CorSigUncompressPointer_EndPtr(pSig1, pEndSig1, (void**)&hInternal)); + + eOtherType = Type2; + pOtherModule = pModule2; + } + else + { + if (pSig2 + 1 > pEndSig2) + { + IfFailThrow(META_E_BAD_SIGNATURE); + } + internalRequired = *pSig2++; + IfFailThrow(CorSigUncompressPointer_EndPtr(pSig2, pEndSig2, (void **)&hInternal)); + + eOtherType = Type1; + pOtherModule = pModule1; + } + + if (internalRequired && (eOtherType != ELEMENT_TYPE_CMOD_REQD)) + { + return FALSE; + } + else if (!internalRequired && (eOtherType != ELEMENT_TYPE_CMOD_OPT)) + { + return FALSE; + } + + mdToken tkOther; + if (Type1 == ELEMENT_TYPE_CMOD_INTERNAL) + { + IfFailThrow(CorSigUncompressToken_EndPtr(pSig2, pEndSig2, &tkOther)); + } + else + { + IfFailThrow(CorSigUncompressToken_EndPtr(pSig1, pEndSig1, &tkOther)); + } + + TypeHandle hOtherType = ClassLoader::LoadTypeDefOrRefThrowing( + pOtherModule, + tkOther, + ClassLoader::ReturnNullIfNotFound, + ClassLoader::FailIfUninstDefOrRef); + + if (hInternal != hOtherType) + { + return FALSE; + } + goto redo; + + } return FALSE; // types must be the same } @@ -4144,6 +4287,39 @@ MetaSig::CompareElementType( return (hType1 == hType2); } + case ELEMENT_TYPE_CMOD_INTERNAL: + { + uint8_t required1, required2; + + if (pSig1 + 1 > pEndSig1) + { + IfFailThrow(META_E_BAD_SIGNATURE); + } + required1 = *pSig1++; + + if (pSig2 + 1 > pEndSig2) + { + IfFailThrow(META_E_BAD_SIGNATURE); + } + required2 = *pSig2++; + + if (required1 != required2) + { + return FALSE; + } + + TypeHandle hType1, hType2; + + IfFailThrow(CorSigUncompressPointer_EndPtr(pSig1, pEndSig1, (void **)&hType1)); + IfFailThrow(CorSigUncompressPointer_EndPtr(pSig2, pEndSig2, (void **)&hType2)); + + if (hType1 != hType2) + { + return FALSE; + } + + goto redo; + } } // switch // Unreachable UNREACHABLE(); diff --git a/src/coreclr/vm/siginfo.hpp b/src/coreclr/vm/siginfo.hpp index fab9a79260d2d1..5715eee63662f6 100644 --- a/src/coreclr/vm/siginfo.hpp +++ b/src/coreclr/vm/siginfo.hpp @@ -49,6 +49,8 @@ unsigned GetSizeForCorElementType(CorElementType etyp); class SigBuilder; class ArgDestination; +class TokenLookupMap; +class DynamicResolver; typedef const struct HardCodedMetaSig *LPHARDCODEDMETASIG; @@ -277,7 +279,7 @@ 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, Module** pModifierScope = NULL, 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..17602750ab2edc 100644 --- a/src/coreclr/vm/stubgen.cpp +++ b/src/coreclr/vm/stubgen.cpp @@ -1938,7 +1938,13 @@ DWORD StubSigBuilder::Append(LocalDesc* pLoc) } CONTRACTL_END; - EnsureEnoughQuickBytes(pLoc->cbType + sizeof(TypeHandle)); + // Ensure we have enough bytes for the provided signature, + // the handle for ELEMENT_TYPE_INTERNAL, + // and the byte and handle for ELEMENT_TYPE_CMOD_INTERNAL + const size_t InternalPayloadSize = sizeof(TypeHandle); + const size_t CModInternalPayloadSize = sizeof(BYTE) + sizeof(TypeHandle); + EnsureEnoughQuickBytes(pLoc->cbType + InternalPayloadSize + CModInternalPayloadSize); + BYTE* pbSigStart = m_pbSigCursor; memcpyNoGCRefs(m_pbSigCursor, pLoc->ElementType, pLoc->cbType); m_pbSigCursor += pLoc->cbType; @@ -1958,6 +1964,23 @@ DWORD StubSigBuilder::Append(LocalDesc* pLoc) m_pbSigCursor += sizeof(TypeHandle); m_cbSig += sizeof(TypeHandle); break; + + case ELEMENT_TYPE_CMOD_INTERNAL: + { + // Nove later elements in the signature to make room for the CMOD_INTERNAL payload + memmove(pbSigStart + i + 1 + CModInternalPayloadSize, pbSigStart + i + 1, pLoc->cbType - i - 1); + _ASSERTE(pbSigStart[i] == ELEMENT_TYPE_CMOD_INTERNAL); + BYTE* pbSigInternalPayload = pbSigStart + i + 1; + + // Write the "required" byte + *pbSigInternalPayload++ = pLoc->InternalModifierRequired ? 1 : 0; + + // Write the modifier + SET_UNALIGNED_PTR(pbSigInternalPayload, (UINT_PTR)pLoc->InternalModifierToken.AsPtr()); + m_pbSigCursor += CModInternalPayloadSize; + m_cbSig += CModInternalPayloadSize; + break; + } case ELEMENT_TYPE_FNPTR: { @@ -2083,9 +2106,27 @@ void FunctionSigBuilder::SetReturnType(LocalDesc* pLoc) { case ELEMENT_TYPE_INTERNAL: m_qbReturnSig.ReSizeThrows(m_qbReturnSig.Size() + sizeof(TypeHandle)); - SET_UNALIGNED_PTR((BYTE *)m_qbReturnSig.Ptr() + m_qbReturnSig.Size() - + sizeof(TypeHandle), (UINT_PTR)pLoc->InternalToken.AsPtr()); + SET_UNALIGNED_PTR((BYTE *)m_qbReturnSig.Ptr() + m_qbReturnSig.Size() - sizeof(TypeHandle), (UINT_PTR)pLoc->InternalToken.AsPtr()); break; + case ELEMENT_TYPE_CMOD_INTERNAL: + { + // Nove later elements in the signature to make room for the CMOD_INTERNAL payload + const size_t CModInternalPayloadSize = sizeof(BYTE) + sizeof(TypeHandle); + m_qbReturnSig.ReSizeThrows(m_qbReturnSig.Size() + CModInternalPayloadSize); + BYTE* pbSigStart = (BYTE*)m_qbReturnSig.Ptr(); + memmove(pbSigStart + i + 1 + CModInternalPayloadSize, pbSigStart + i + 1, pLoc->cbType - i); + _ASSERTE(pbSigStart[i] == ELEMENT_TYPE_CMOD_INTERNAL); + BYTE* pbSigInternalPayload = pbSigStart + i + 1; + + // Write the "required" byte + *pbSigInternalPayload++ = pLoc->InternalModifierRequired ? 1 : 0; + + // Write the modifier + SET_UNALIGNED_PTR(pbSigInternalPayload, (UINT_PTR)pLoc->InternalModifierToken.AsPtr()); + break; + } + case ELEMENT_TYPE_FNPTR: { SigPointer ptr(pLoc->pSig); @@ -2608,69 +2649,90 @@ void ILStubLinker::TransformArgForJIT(LocalDesc *pLoc) // 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: + bool again; + BYTE* elementType = pLoc->ElementType; + do + { + again = false; + switch (*elementType) { - // 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. + *elementType = ELEMENT_TYPE_PTR; + break; + } - case ELEMENT_TYPE_INTERNAL: - { - // JIT will handle structures - if (pLoc->InternalToken.IsValueType()) + case ELEMENT_TYPE_INTERNAL: { - _ASSERTE(pLoc->InternalToken.IsNativeValueType() || !pLoc->InternalToken.GetMethodTable()->ContainsGCPointers()); + // JIT will handle structures + if (pLoc->InternalToken.IsValueType()) + { + _ASSERTE(pLoc->InternalToken.IsNativeValueType() || !pLoc->InternalToken.GetMethodTable()->ContainsGCPointers()); + break; + } + FALLTHROUGH; + } + + case ELEMENT_TYPE_CMOD_REQD: + case ELEMENT_TYPE_CMOD_OPT: + { + _ASSERTE("Custom modifiers should be represented in a LocalDesc as ELEMENT_TYPE_CMOD_INTERNAL. Use AddModifier to add custom modifiers."); + FALLTHROUGH; + } + case ELEMENT_TYPE_CMOD_INTERNAL: + { + again = true; break; } - FALLTHROUGH; - } - // ref types -> ELEMENT_TYPE_I - default: - { - pLoc->ElementType[0] = ELEMENT_TYPE_I; - pLoc->cbType = 1; - break; + // ref types -> ELEMENT_TYPE_I + default: + { + pLoc->ElementType[0] = ELEMENT_TYPE_I; + pLoc->cbType = 1; + return; + } } + elementType++; + _ASSERTE(elementType - pLoc->ElementType <= (ptrdiff_t)pLoc->cbType); } + while(again); } Module *ILStubLinker::GetStubSigModule() diff --git a/src/coreclr/vm/stubgen.h b/src/coreclr/vm/stubgen.h index 968e5f9b48291f..3e5427fece5753 100644 --- a/src/coreclr/vm/stubgen.h +++ b/src/coreclr/vm/stubgen.h @@ -39,6 +39,10 @@ struct LocalDesc size_t cbType; TypeHandle InternalToken; // only valid with ELEMENT_TYPE_INTERNAL + // only valid with ELEMENT_TYPE_CMOD_INTERNAL + bool InternalModifierRequired; + TypeHandle InternalModifierToken; + // used only for E_T_FNPTR and E_T_ARRAY PCCOR_SIGNATURE pSig; union @@ -96,6 +100,14 @@ struct LocalDesc ChangeType(ELEMENT_TYPE_PTR); } + void AddModifier(bool required, TypeHandle thModifier) + { + _ASSERTE_MSG(InternalModifierToken.IsNull(), "Only one custom modifier is supported per element signature"); + ChangeType(ELEMENT_TYPE_CMOD_INTERNAL); + InternalModifierRequired = required; + InternalModifierToken = thModifier; + } + void ChangeType(CorElementType elemType) { LIMITED_METHOD_CONTRACT; @@ -267,7 +279,6 @@ class FunctionSigBuilder : protected StubSigBuilder #else // _DEBUG #define TOKEN_LOOKUP_MAP_SIZE (64*sizeof(void*)) #endif // _DEBUG - //--------------------------------------------------------------------------------------- // class TokenLookupMap diff --git a/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem.cs b/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem.cs index 5a87fe72f1535a..4cd535f9dd1394 100644 --- a/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem.cs +++ b/src/native/managed/cdacreader/src/Contracts/RuntimeTypeSystem.cs @@ -52,6 +52,7 @@ internal enum CorElementType CModReqd = 0x1f, CModOpt = 0x20, Internal = 0x21, + CModInternal = 0x22, Sentinel = 0x41, } diff --git a/src/native/managed/cdacreader/src/Legacy/SigFormat.cs b/src/native/managed/cdacreader/src/Legacy/SigFormat.cs index 4ce7832a7bd01b..288857f2d574f4 100644 --- a/src/native/managed/cdacreader/src/Legacy/SigFormat.cs +++ b/src/native/managed/cdacreader/src/Legacy/SigFormat.cs @@ -301,6 +301,11 @@ private static unsafe void AddTypeString(Target target, _ = signature.ReadTypeHandle(); break; + case CorElementType.CModInternal: + _ = signature.ReadByte(); + _ = signature.ReadBytes(target.PointerSize); + break; + default: stringBuilder.Append("**UNKNOWN TYPE**"); return; 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"));