mirror of
https://github.com/VSadov/Satori.git
synced 2025-06-09 09:34:49 +09:00
Move last P/Invoke error from native Thread and delete C/C++ SafeHandle implementation (#100267)
* Delete native safehandle * Delete PInvoke last error on thread * Delete IsRealThreadPoolResetNeeded * Delete TS_TaskReset * Delete GetThreadContext * Fix build break * Delete unused resource strings * Introduce FEATURE_IJW and use it in number of places
This commit is contained in:
parent
f390af4631
commit
3f7ffddeda
24 changed files with 61 additions and 478 deletions
|
@ -25,6 +25,7 @@ terminology.
|
|||
| EE | [Execution Engine](https://docs.microsoft.com/dotnet/standard/managed-execution-process#running_code). |
|
||||
| GC | [Garbage Collector](https://github.com/dotnet/runtime/blob/main/docs/design/coreclr/botr/garbage-collection.md). |
|
||||
| IBC | Instrumented Block Counts - used as extension (`*.ibc`) for old PGO files. |
|
||||
| IJW | "It Just Works" - Codename for [C++/CLI](https://learn.microsoft.com/cpp/dotnet/dotnet-programming-with-cpp-cli-visual-cpp) managed/native interop |
|
||||
| IPC | Inter-Process Communication. |
|
||||
| IL | Intermediate Language. Equivalent to CIL, also equivalent to [MSIL](https://docs.microsoft.com/dotnet/standard/managed-execution-process#compiling-to-msil). |
|
||||
| JIT | [Just-in-Time](https://github.com/dotnet/runtime/blob/main/docs/design/coreclr/jit/ryujit-overview.md) compiler. RyuJIT is the code name for the next generation Just-in-Time(aka "JIT") for the .NET runtime. |
|
||||
|
|
|
@ -92,6 +92,7 @@ if(CLR_CMAKE_TARGET_WIN32)
|
|||
add_definitions(-DFEATURE_COMINTEROP)
|
||||
add_definitions(-DFEATURE_COMINTEROP_APARTMENT_SUPPORT)
|
||||
add_definitions(-DFEATURE_COMINTEROP_UNMANAGED_ACTIVATION)
|
||||
add_definitions(-DFEATURE_IJW) # C++/CLI managed/native interop support
|
||||
endif(CLR_CMAKE_TARGET_WIN32)
|
||||
|
||||
add_definitions(-DFEATURE_BASICFREEZE)
|
||||
|
|
|
@ -491,9 +491,6 @@ BEGIN
|
|||
IDS_EE_CLASS_TO_VARIANT_TLB_NOT_REG "Type '%1' cannot be marshalled to a Variant. Type library is not registered."
|
||||
IDS_EE_CANNOT_MAP_TO_MANAGED_VC "The specified record cannot be mapped to a managed value class."
|
||||
|
||||
IDS_EE_SAFEHANDLECLOSED "Safe handle has been closed"
|
||||
IDS_EE_SAFEHANDLECANNOTSETHANDLE "Safe handle's handle field can only be set if the safe handle is not closed and has a ref count of 1."
|
||||
|
||||
IDS_EE_SH_IN_VARIANT_NOT_SUPPORTED "SafeHandle derived types cannot be stored in Variants."
|
||||
|
||||
IDS_EE_CH_IN_VARIANT_NOT_SUPPORTED "CriticalHandle derived types cannot be stored in Variants."
|
||||
|
|
|
@ -243,9 +243,6 @@
|
|||
#define IDS_EE_METHOD_NOT_FOUND_ON_EV_PROV 0x1a24
|
||||
#define IDS_EE_BAD_COMEVENTITF_CLASS 0x1a25
|
||||
|
||||
#define IDS_EE_COREXEMAIN2_FAILED_TITLE 0x1a2b
|
||||
#define IDS_EE_COREXEMAIN2_FAILED_TEXT 0x1a2c
|
||||
|
||||
#define IDS_EE_ICUSTOMMARSHALERNOTIMPL 0x1a2e
|
||||
#define IDS_EE_GETINSTANCENOTIMPL 0x1a2f
|
||||
|
||||
|
@ -265,9 +262,6 @@
|
|||
#define IDS_EE_BADMARSHAL_RETURNSHCOMTONATIVE 0x1a3c
|
||||
#define IDS_EE_BADMARSHAL_SAFEHANDLE 0x1a3d
|
||||
|
||||
#define IDS_EE_SAFEHANDLECLOSED 0x1a3f
|
||||
#define IDS_EE_SAFEHANDLECANNOTSETHANDLE 0x1a40
|
||||
|
||||
#define IDS_EE_BADMARSHAL_ABSTRACTRETSAFEHANDLE 0x1a44
|
||||
#define IDS_EE_SH_IN_VARIANT_NOT_SUPPORTED 0x1a47
|
||||
|
||||
|
|
|
@ -358,7 +358,6 @@ set(VM_SOURCES_WKS
|
|||
reflectclasswriter.cpp
|
||||
reflectioninvocation.cpp
|
||||
runtimehandles.cpp
|
||||
safehandle.cpp
|
||||
simplerwlock.cpp
|
||||
stackingallocator.cpp
|
||||
stringliteralmap.cpp
|
||||
|
|
|
@ -1414,9 +1414,6 @@ void SystemDomain::LoadBaseSystemClasses()
|
|||
g_profControlBlock.fBaseSystemClassesLoaded = TRUE;
|
||||
#endif // PROFILING_SUPPORTED
|
||||
|
||||
// Perform any once-only SafeHandle initialization.
|
||||
SafeHandle::Init();
|
||||
|
||||
#if defined(_DEBUG)
|
||||
g_CoreLib.Check();
|
||||
g_CoreLib.CheckExtended();
|
||||
|
|
|
@ -545,9 +545,7 @@ void MethodDescCallSite::CallTargetWorker(const ARG_SLOT *pArguments, ARG_SLOT *
|
|||
if (transitionToPreemptive)
|
||||
{
|
||||
GCPreemp transitionIfILStub(transitionToPreemptive);
|
||||
DWORD* pLastError = &GetThread()->m_dwLastErrorInterp;
|
||||
CallDescrWorkerInternal(&callDescrData);
|
||||
*pLastError = GetLastError();
|
||||
}
|
||||
else
|
||||
#endif // FEATURE_INTERPRETER
|
||||
|
|
|
@ -59,7 +59,7 @@ public:
|
|||
static FCDECL1(void, Initialize, ThreadBaseObject* pThisUNSAFE);
|
||||
static FCDECL1(FC_BOOL_RET, GetIsBackground, ThreadBaseObject* pThisUNSAFE);
|
||||
static FCDECL1(INT32, GetThreadState, ThreadBaseObject* pThisUNSAFE);
|
||||
static FCDECL1(INT32, GetThreadContext, ThreadBaseObject* pThisUNSAFE);
|
||||
|
||||
#ifdef FEATURE_COMINTEROP_APARTMENT_SUPPORT
|
||||
static FCDECL1(INT32, GetApartmentState, ThreadBaseObject* pThis);
|
||||
static FCDECL2(INT32, SetApartmentState, ThreadBaseObject* pThisUNSAFE, INT32 iState);
|
||||
|
|
|
@ -188,9 +188,6 @@ DEFINE_METHOD(LICENSE_INTEROP_PROXY, SAVEKEYINCURRENTCONTEXT, SaveKeyInCurrentCo
|
|||
#endif // FEATURE_COMINTEROP
|
||||
END_ILLINK_FEATURE_SWITCH()
|
||||
|
||||
DEFINE_CLASS_U(Interop, CriticalHandle, CriticalHandle)
|
||||
DEFINE_FIELD_U(handle, CriticalHandle, m_handle)
|
||||
DEFINE_FIELD_U(_isClosed, CriticalHandle, m_isClosed)
|
||||
DEFINE_CLASS(CRITICAL_HANDLE, Interop, CriticalHandle)
|
||||
DEFINE_FIELD(CRITICAL_HANDLE, HANDLE, handle)
|
||||
DEFINE_METHOD(CRITICAL_HANDLE, RELEASE_HANDLE, ReleaseHandle, IM_RetBool)
|
||||
|
@ -731,12 +728,6 @@ DEFINE_CLASS(CALLCONV_SUPPRESSGCTRANSITION, CompilerServices, CallConvSup
|
|||
DEFINE_CLASS(CALLCONV_MEMBERFUNCTION, CompilerServices, CallConvMemberFunction)
|
||||
DEFINE_CLASS(CALLCONV_SWIFT, CompilerServices, CallConvSwift)
|
||||
|
||||
DEFINE_CLASS_U(Interop, SafeHandle, SafeHandle)
|
||||
DEFINE_FIELD_U(_ctorStackTrace, SafeHandle, m_ctorStackTrace)
|
||||
DEFINE_FIELD_U(handle, SafeHandle, m_handle)
|
||||
DEFINE_FIELD_U(_state, SafeHandle, m_state)
|
||||
DEFINE_FIELD_U(_ownsHandle, SafeHandle, m_ownsHandle)
|
||||
DEFINE_FIELD_U(_fullyInitialized, SafeHandle, m_fullyInitialized)
|
||||
DEFINE_CLASS(SAFE_HANDLE, Interop, SafeHandle)
|
||||
DEFINE_FIELD(SAFE_HANDLE, HANDLE, handle)
|
||||
DEFINE_METHOD(SAFE_HANDLE, GET_IS_INVALID, get_IsInvalid, IM_RetBool)
|
||||
|
@ -895,9 +886,6 @@ DEFINE_FIELD_U(_taggedHandle, WeakReferenceObject, m_taggedHandle)
|
|||
DEFINE_CLASS(WEAKREFERENCE, System, WeakReference)
|
||||
DEFINE_CLASS(WEAKREFERENCEGENERIC, System, WeakReference`1)
|
||||
|
||||
DEFINE_CLASS_U(Threading, WaitHandle, WaitHandleBase)
|
||||
DEFINE_FIELD_U(_waitHandle, WaitHandleBase, m_safeHandle)
|
||||
|
||||
DEFINE_CLASS(DEBUGGER, Diagnostics, Debugger)
|
||||
DEFINE_METHOD(DEBUGGER, BREAK, Break, SM_RetVoid)
|
||||
|
||||
|
|
|
@ -1631,9 +1631,9 @@ NDirectStubLinker::NDirectStubLinker(
|
|||
}
|
||||
#endif // FEATURE_COMINTEROP
|
||||
|
||||
#if defined(TARGET_X86) && defined(TARGET_WINDOWS)
|
||||
#if defined(TARGET_X86) && defined(FEATURE_IJW)
|
||||
m_dwCopyCtorChainLocalNum = (DWORD)-1;
|
||||
#endif // defined(TARGET_X86) && defined(TARGET_WINDOWS)
|
||||
#endif // defined(TARGET_X86) && defined(FEATURE_IJW)
|
||||
}
|
||||
|
||||
void NDirectStubLinker::SetCallingConvention(CorInfoCallConvExtension unmngCallConv, BOOL fIsVarArg)
|
||||
|
@ -1846,7 +1846,7 @@ DWORD NDirectStubLinker::GetReturnValueLocalNum()
|
|||
return m_dwRetValLocalNum;
|
||||
}
|
||||
|
||||
#if defined(TARGET_X86) && defined(TARGET_WINDOWS)
|
||||
#if defined(TARGET_X86) && defined(FEATURE_IJW)
|
||||
DWORD NDirectStubLinker::GetCopyCtorChainLocalNum()
|
||||
{
|
||||
STANDARD_VM_CONTRACT;
|
||||
|
@ -1861,7 +1861,7 @@ DWORD NDirectStubLinker::GetCopyCtorChainLocalNum()
|
|||
|
||||
return m_dwCopyCtorChainLocalNum;
|
||||
}
|
||||
#endif // defined(TARGET_X86) && defined(TARGET_WINDOWS)
|
||||
#endif // defined(TARGET_X86) && defined(FEATURE_IJW)
|
||||
|
||||
BOOL NDirectStubLinker::IsCleanupNeeded()
|
||||
{
|
||||
|
@ -2179,7 +2179,7 @@ void NDirectStubLinker::DoNDirect(ILCodeStream *pcsEmit, DWORD dwStubFlags, Meth
|
|||
}
|
||||
}
|
||||
|
||||
#if defined(TARGET_X86) && defined(TARGET_WINDOWS)
|
||||
#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
|
||||
|
@ -2192,7 +2192,7 @@ void NDirectStubLinker::DoNDirect(ILCodeStream *pcsEmit, DWORD dwStubFlags, Meth
|
|||
pcsEmit->EmitCALL(METHOD__COPY_CONSTRUCTOR_CHAIN__INSTALL, 2, 0);
|
||||
pcsEmit->EmitLDC((DWORD_PTR)&CopyConstructorCallStub);
|
||||
}
|
||||
#endif // defined(TARGET_X86) && defined(TARGET_WINDOWS)
|
||||
#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
|
||||
|
@ -2867,6 +2867,7 @@ static LPBYTE FollowIndirect(LPBYTE pTarget)
|
|||
}
|
||||
#endif // !TARGET_UNIX
|
||||
|
||||
#ifdef FEATURE_IJW
|
||||
BOOL HeuristicDoesThisLookLikeAGetLastErrorCall(LPBYTE pTarget)
|
||||
{
|
||||
CONTRACTL
|
||||
|
@ -2877,7 +2878,6 @@ BOOL HeuristicDoesThisLookLikeAGetLastErrorCall(LPBYTE pTarget)
|
|||
}
|
||||
CONTRACTL_END;
|
||||
|
||||
#if !defined(TARGET_UNIX)
|
||||
static LPBYTE pGetLastError = NULL;
|
||||
if (!pGetLastError)
|
||||
{
|
||||
|
@ -2912,18 +2912,10 @@ BOOL HeuristicDoesThisLookLikeAGetLastErrorCall(LPBYTE pTarget)
|
|||
// jmp [xxxx] - could be an import thunk
|
||||
return pTarget2 == pGetLastError;
|
||||
}
|
||||
#endif // !TARGET_UNIX
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
DWORD STDMETHODCALLTYPE FalseGetLastError()
|
||||
{
|
||||
WRAPPER_NO_CONTRACT;
|
||||
|
||||
return GetThread()->m_dwLastError;
|
||||
}
|
||||
|
||||
#endif // FEATURE_IJW
|
||||
|
||||
CorInfoCallConvExtension GetDefaultCallConv(BOOL bIsVarArg)
|
||||
{
|
||||
|
@ -6141,7 +6133,7 @@ PCODE GetILStubForCalli(VASigCookie *pVASigCookie, MethodDesc *pMD)
|
|||
RETURN pVASigCookie->pNDirectILStub;
|
||||
}
|
||||
|
||||
#if defined(TARGET_X86) && defined(TARGET_WINDOWS)
|
||||
#if defined(TARGET_X86) && defined(FEATURE_IJW)
|
||||
// Copy constructor support for C++/CLI
|
||||
EXTERN_C void* STDCALL CallCopyConstructorsWorker(void* esp)
|
||||
{
|
||||
|
@ -6156,6 +6148,6 @@ EXTERN_C void* STDCALL CallCopyConstructorsWorker(void* esp)
|
|||
|
||||
return pExecute(esp);
|
||||
}
|
||||
#endif // defined(TARGET_X86) && defined(TARGET_WINDOWS)
|
||||
#endif // defined(TARGET_X86) && defined(FEATURE_IJW)
|
||||
|
||||
#endif // #ifndef DACCESS_COMPILE
|
||||
|
|
|
@ -496,9 +496,9 @@ public:
|
|||
DWORD GetCleanupWorkListLocalNum();
|
||||
DWORD GetThreadLocalNum();
|
||||
DWORD GetReturnValueLocalNum();
|
||||
#if defined(TARGET_X86) && defined(TARGET_WINDOWS)
|
||||
#if defined(TARGET_X86) && defined(FEATURE_IJW)
|
||||
DWORD GetCopyCtorChainLocalNum();
|
||||
#endif // defined(TARGET_X86) && defined(TARGET_WINDOWS)
|
||||
#endif // defined(TARGET_X86) && defined(FEATURE_IJW)
|
||||
void SetCleanupNeeded();
|
||||
void SetExceptionCleanupNeeded();
|
||||
BOOL IsCleanupWorkListSetup();
|
||||
|
@ -568,9 +568,9 @@ protected:
|
|||
DWORD m_dwTargetEntryPointLocalNum;
|
||||
#endif // FEATURE_COMINTEROP
|
||||
|
||||
#if defined(TARGET_X86) && defined(TARGET_WINDOWS)
|
||||
#if defined(TARGET_X86) && defined(FEATURE_IJW)
|
||||
DWORD m_dwCopyCtorChainLocalNum;
|
||||
#endif // defined(TARGET_X86) && defined(TARGET_WINDOWS)
|
||||
#endif // defined(TARGET_X86) && defined(FEATURE_IJW)
|
||||
|
||||
BOOL m_fHasCleanupCode;
|
||||
BOOL m_fHasExceptionCleanupCode;
|
||||
|
|
|
@ -3394,7 +3394,7 @@ ILCriticalHandleMarshaler::ReturnOverride(
|
|||
return OVERRIDDEN;
|
||||
} // ILCriticalHandleMarshaler::ReturnOverride
|
||||
|
||||
#if defined(TARGET_WINDOWS)
|
||||
#if defined(FEATURE_IJW)
|
||||
MarshalerOverrideStatus ILBlittableValueClassWithCopyCtorMarshaler::ArgumentOverride(NDirectStubLinker* psl,
|
||||
BOOL byref,
|
||||
BOOL fin,
|
||||
|
@ -3520,7 +3520,7 @@ MarshalerOverrideStatus ILBlittableValueClassWithCopyCtorMarshaler::ArgumentOver
|
|||
return OVERRIDDEN;
|
||||
}
|
||||
}
|
||||
#endif // defined(TARGET_WINDOWS)
|
||||
#endif // defined(FEATURE_IJW)
|
||||
|
||||
LocalDesc ILArgIteratorMarshaler::GetNativeType()
|
||||
{
|
||||
|
|
|
@ -2923,7 +2923,7 @@ protected:
|
|||
void EmitConvertContentsNativeToCLR(ILCodeStream* pslILEmit) override;
|
||||
};
|
||||
|
||||
#if defined(TARGET_WINDOWS)
|
||||
#if defined(FEATURE_IJW)
|
||||
class ILBlittableValueClassWithCopyCtorMarshaler : public ILMarshaler
|
||||
{
|
||||
public:
|
||||
|
|
|
@ -9271,19 +9271,6 @@ void Interpreter::DoCallWork(bool virtualCall, void* thisArg, CORINFO_RESOLVED_T
|
|||
break;
|
||||
}
|
||||
|
||||
// Plus some other calls that we're going to treat "like" intrinsics...
|
||||
if (methToCall == CoreLibBinder::GetMethod(METHOD__STUBHELPERS__SET_LAST_ERROR))
|
||||
{
|
||||
// If we're interpreting a method that calls "SetLastError", it's very likely that the call(i) whose
|
||||
// error we're trying to capture was performed with MethodDescCallSite machinery that itself trashes
|
||||
// the last error. We solve this by saving the last error in a special interpreter-specific field of
|
||||
// "Thread" in that case, and essentially implement SetLastError here, taking that field as the
|
||||
// source for the last error.
|
||||
Thread* thrd = GetThread();
|
||||
thrd->m_dwLastError = thrd->m_dwLastErrorInterp;
|
||||
didIntrinsic = true;
|
||||
}
|
||||
|
||||
// TODO: The following check for hardware intrinsics is not a production-level
|
||||
// solution and may produce incorrect results.
|
||||
static ConfigDWORD s_InterpreterHWIntrinsicsIsSupportedFalse;
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include "comdelegate.h"
|
||||
#include "typestring.h"
|
||||
#include "appdomain.inl"
|
||||
#include "stubhelpers.h"
|
||||
|
||||
#ifdef FEATURE_COMINTEROP
|
||||
#include "comcallablewrapper.h"
|
||||
|
@ -283,27 +284,47 @@ extern "C" IsInCooperativeGCMode_fn QCALLTYPE MarshalNative_GetIsInCooperativeGC
|
|||
#endif
|
||||
|
||||
/************************************************************************
|
||||
* Marshal.GetLastPInvokeError
|
||||
* Support for the last PInvoke error
|
||||
*/
|
||||
static thread_local int t_lastPInvokeError;
|
||||
|
||||
FCIMPL0(int, MarshalNative::GetLastPInvokeError)
|
||||
{
|
||||
FCALL_CONTRACT;
|
||||
|
||||
return (UINT32)(GetThread()->m_dwLastError);
|
||||
return t_lastPInvokeError;
|
||||
}
|
||||
FCIMPLEND
|
||||
|
||||
/************************************************************************
|
||||
* Marshal.SetLastPInvokeError
|
||||
*/
|
||||
FCIMPL1(void, MarshalNative::SetLastPInvokeError, int error)
|
||||
{
|
||||
FCALL_CONTRACT;
|
||||
|
||||
GetThread()->m_dwLastError = (DWORD)error;
|
||||
t_lastPInvokeError = error;
|
||||
}
|
||||
FCIMPLEND
|
||||
|
||||
FCIMPL0(void, StubHelpers::SetLastError)
|
||||
{
|
||||
// Make sure this is the first thing we do after returning from the target, as almost everything can cause the last error to get trashed
|
||||
DWORD lastError = ::GetLastError();
|
||||
|
||||
FCALL_CONTRACT;
|
||||
|
||||
t_lastPInvokeError = lastError;
|
||||
}
|
||||
FCIMPLEND
|
||||
|
||||
#ifdef FEATURE_IJW
|
||||
// GetLastError override for C++/CLI
|
||||
DWORD STDMETHODCALLTYPE FalseGetLastError()
|
||||
{
|
||||
WRAPPER_NO_CONTRACT;
|
||||
|
||||
return t_lastPInvokeError;
|
||||
}
|
||||
#endif // FEATURE_IJW
|
||||
|
||||
/************************************************************************
|
||||
* Support for the GCHandle class.
|
||||
*/
|
||||
|
|
|
@ -3563,8 +3563,10 @@ void NDirectMethodDesc::InitEarlyBoundNDirectTarget()
|
|||
const void *target = GetModule()->GetInternalPInvokeTarget(GetRVA());
|
||||
_ASSERTE(target != 0);
|
||||
|
||||
#ifdef FEATURE_IJW
|
||||
if (HeuristicDoesThisLookLikeAGetLastErrorCall((LPBYTE)target))
|
||||
target = (BYTE*)FalseGetLastError;
|
||||
#endif
|
||||
|
||||
// As long as we've set the NDirect target field we don't need to backpatch the import thunk glue.
|
||||
// All NDirect calls all through the NDirect target, so if it's updated, then we won't go into
|
||||
|
|
|
@ -2383,7 +2383,7 @@ MarshalInfo::MarshalInfo(Module* pModule,
|
|||
{
|
||||
if (fNeedsCopyCtor && !IsFieldScenario()) // We don't support automatically discovering copy constructors for fields.
|
||||
{
|
||||
#if defined(TARGET_WINDOWS)
|
||||
#if defined(FEATURE_IJW)
|
||||
MethodDesc *pCopyCtor;
|
||||
MethodDesc *pDtor;
|
||||
FindCopyCtor(pModule, m_pMT, &pCopyCtor);
|
||||
|
@ -2393,10 +2393,10 @@ MarshalInfo::MarshalInfo(Module* pModule,
|
|||
m_args.mm.m_pCopyCtor = pCopyCtor;
|
||||
m_args.mm.m_pDtor = pDtor;
|
||||
m_type = MARSHAL_TYPE_BLITTABLEVALUECLASSWITHCOPYCTOR;
|
||||
#else // !defined(TARGET_WINDOWS)
|
||||
#else // !defined(FEATURE_IJW)
|
||||
m_resID = IDS_EE_BADMARSHAL_BADMANAGED;
|
||||
IfFailGoto(E_FAIL, lFail);
|
||||
#endif // defined(TARGET_WINDOWS)
|
||||
#endif // defined(FEATURE_IJW)
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -3126,9 +3126,9 @@ bool MarshalInfo::IsValueClass(MarshalType mtype)
|
|||
{
|
||||
case MARSHAL_TYPE_BLITTABLEVALUECLASS:
|
||||
case MARSHAL_TYPE_VALUECLASS:
|
||||
#if defined(TARGET_WINDOWS)
|
||||
#if defined(FEATURE_IJW)
|
||||
case MARSHAL_TYPE_BLITTABLEVALUECLASSWITHCOPYCTOR:
|
||||
#endif // defined(TARGET_WINDOWS)
|
||||
#endif // defined(FEATURE_IJW)
|
||||
return true;
|
||||
|
||||
default:
|
||||
|
@ -3612,9 +3612,9 @@ DispParamMarshaler *MarshalInfo::GenerateDispParamMarshaler()
|
|||
case MARSHAL_TYPE_BLITTABLEVALUECLASS:
|
||||
case MARSHAL_TYPE_BLITTABLEPTR:
|
||||
case MARSHAL_TYPE_LAYOUTCLASSPTR:
|
||||
#if defined(TARGET_WINDOWS)
|
||||
#if defined(FEATURE_IJW)
|
||||
case MARSHAL_TYPE_BLITTABLEVALUECLASSWITHCOPYCTOR:
|
||||
#endif // defined(TARGET_WINDOWS)
|
||||
#endif // defined(FEATURE_IJW)
|
||||
pDispParamMarshaler = new DispParamRecordMarshaler(m_pMT);
|
||||
break;
|
||||
|
||||
|
|
|
@ -80,9 +80,9 @@ DEFINE_MARSHALER_TYPE(MARSHAL_TYPE_VALUECLASS, ValueClassMa
|
|||
DEFINE_MARSHALER_TYPE(MARSHAL_TYPE_REFERENCECUSTOMMARSHALER, ReferenceCustomMarshaler)
|
||||
DEFINE_MARSHALER_TYPE(MARSHAL_TYPE_ARGITERATOR, ArgIteratorMarshaler)
|
||||
|
||||
#if defined(TARGET_WINDOWS)
|
||||
#if defined(FEATURE_IJW)
|
||||
DEFINE_MARSHALER_TYPE(MARSHAL_TYPE_BLITTABLEVALUECLASSWITHCOPYCTOR, BlittableValueClassWithCopyCtorMarshaler)
|
||||
#endif // defined(TARGET_WINDOWS)
|
||||
#endif // defined(FEATURE_IJW)
|
||||
|
||||
#ifdef FEATURE_COMINTEROP
|
||||
DEFINE_MARSHALER_TYPE(MARSHAL_TYPE_OBJECT, ObjectMarshaler)
|
||||
|
|
|
@ -1194,15 +1194,7 @@ class ReflectModuleBaseObject : public Object
|
|||
NOINLINE ReflectModuleBaseObject* GetRuntimeModuleHelper(LPVOID __me, Module *pModule, OBJECTREF keepAlive);
|
||||
#define FC_RETURN_MODULE_OBJECT(pModule, refKeepAlive) FC_INNER_RETURN(ReflectModuleBaseObject*, GetRuntimeModuleHelper(__me, pModule, refKeepAlive))
|
||||
|
||||
class SafeHandle;
|
||||
|
||||
#ifdef USE_CHECKED_OBJECTREFS
|
||||
typedef REF<SafeHandle> SAFEHANDLE;
|
||||
typedef REF<SafeHandle> SAFEHANDLEREF;
|
||||
#else // USE_CHECKED_OBJECTREFS
|
||||
typedef SafeHandle * SAFEHANDLE;
|
||||
typedef SafeHandle * SAFEHANDLEREF;
|
||||
#endif // USE_CHECKED_OBJECTREFS
|
||||
|
||||
|
||||
|
||||
|
@ -1242,19 +1234,6 @@ typedef CultureInfoBaseObject* CULTUREINFOBASEREF;
|
|||
typedef PTR_ArrayBase ARRAYBASEREF;
|
||||
#endif
|
||||
|
||||
// Note that the name must always be "" or "en-US". Other cases and nulls
|
||||
// aren't allowed (we already checked.)
|
||||
__inline bool IsCultureEnglishOrInvariant(LPCWSTR localeName)
|
||||
{
|
||||
LIMITED_METHOD_CONTRACT;
|
||||
if (localeName != NULL &&
|
||||
(localeName[0] == W('\0') ||
|
||||
u16_strcmp(localeName, W("en-US")) == 0))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
class CultureInfoBaseObject : public Object
|
||||
{
|
||||
|
@ -1866,110 +1845,6 @@ typedef BStrWrapper* BSTRWRAPPEROBJECTREF;
|
|||
|
||||
#endif // FEATURE_COMINTEROP
|
||||
|
||||
class SafeHandle : public Object
|
||||
{
|
||||
friend class CoreLibBinder;
|
||||
|
||||
private:
|
||||
// READ ME:
|
||||
// Modifying the order or fields of this object may require
|
||||
// other changes to the classlib class definition of this
|
||||
// object or special handling when loading this system class.
|
||||
#if DEBUG
|
||||
STRINGREF m_ctorStackTrace; // Debug-only stack trace captured when the SafeHandle was constructed
|
||||
#endif
|
||||
Volatile<LPVOID> m_handle;
|
||||
Volatile<INT32> m_state; // Combined ref count and closed/disposed state (for atomicity)
|
||||
Volatile<CLR_BOOL> m_ownsHandle;
|
||||
Volatile<CLR_BOOL> m_fullyInitialized; // Did constructor finish?
|
||||
|
||||
// Describe the bits in the m_state field above.
|
||||
enum StateBits
|
||||
{
|
||||
SH_State_Closed = 0x00000001,
|
||||
SH_State_Disposed = 0x00000002,
|
||||
SH_State_RefCount = 0xfffffffc,
|
||||
SH_RefCountOne = 4, // Amount to increment state field to yield a ref count increment of 1
|
||||
};
|
||||
|
||||
static WORD s_IsInvalidHandleMethodSlot;
|
||||
static WORD s_ReleaseHandleMethodSlot;
|
||||
|
||||
static void RunReleaseMethod(SafeHandle* psh);
|
||||
BOOL IsFullyInitialized() const { LIMITED_METHOD_CONTRACT; return m_fullyInitialized; }
|
||||
|
||||
public:
|
||||
static void Init();
|
||||
|
||||
// To use the SafeHandle from native, look at the SafeHandleHolder, which
|
||||
// will do the AddRef & Release for you.
|
||||
LPVOID GetHandle() const {
|
||||
LIMITED_METHOD_CONTRACT;
|
||||
_ASSERTE(((unsigned int) m_state) >= SH_RefCountOne);
|
||||
return m_handle;
|
||||
}
|
||||
|
||||
void AddRef();
|
||||
void Release(bool fDispose = false);
|
||||
void SetHandle(LPVOID handle);
|
||||
};
|
||||
|
||||
void AcquireSafeHandle(SAFEHANDLEREF* s);
|
||||
void ReleaseSafeHandle(SAFEHANDLEREF* s);
|
||||
|
||||
typedef Holder<SAFEHANDLEREF*, AcquireSafeHandle, ReleaseSafeHandle> SafeHandleHolder;
|
||||
|
||||
class CriticalHandle : public Object
|
||||
{
|
||||
friend class CoreLibBinder;
|
||||
|
||||
private:
|
||||
// READ ME:
|
||||
// Modifying the order or fields of this object may require
|
||||
// other changes to the classlib class definition of this
|
||||
// object or special handling when loading this system class.
|
||||
Volatile<LPVOID> m_handle;
|
||||
Volatile<CLR_BOOL> m_isClosed;
|
||||
|
||||
public:
|
||||
LPVOID GetHandle() const { LIMITED_METHOD_CONTRACT; return m_handle; }
|
||||
static size_t GetHandleOffset() { LIMITED_METHOD_CONTRACT; return offsetof(CriticalHandle, m_handle); }
|
||||
|
||||
void SetHandle(LPVOID handle) { LIMITED_METHOD_CONTRACT; m_handle = handle; }
|
||||
};
|
||||
|
||||
|
||||
#ifdef USE_CHECKED_OBJECTREFS
|
||||
typedef REF<CriticalHandle> CRITICALHANDLE;
|
||||
typedef REF<CriticalHandle> CRITICALHANDLEREF;
|
||||
#else // USE_CHECKED_OBJECTREFS
|
||||
typedef CriticalHandle * CRITICALHANDLE;
|
||||
typedef CriticalHandle * CRITICALHANDLEREF;
|
||||
#endif // USE_CHECKED_OBJECTREFS
|
||||
|
||||
// WaitHandleBase
|
||||
// Base class for WaitHandle
|
||||
class WaitHandleBase :public MarshalByRefObjectBaseObject
|
||||
{
|
||||
friend class CoreLibBinder;
|
||||
|
||||
public:
|
||||
__inline LPVOID GetWaitHandle() {
|
||||
LIMITED_METHOD_CONTRACT;
|
||||
SAFEHANDLEREF safeHandle = (SAFEHANDLEREF)m_safeHandle.LoadWithoutBarrier();
|
||||
return safeHandle != NULL ? safeHandle->GetHandle() : INVALID_HANDLE_VALUE;
|
||||
}
|
||||
__inline SAFEHANDLEREF GetSafeHandle() {LIMITED_METHOD_CONTRACT; return (SAFEHANDLEREF)m_safeHandle.LoadWithoutBarrier();}
|
||||
|
||||
private:
|
||||
Volatile<SafeHandle*> m_safeHandle;
|
||||
};
|
||||
|
||||
#ifdef USE_CHECKED_OBJECTREFS
|
||||
typedef REF<WaitHandleBase> WAITHANDLEREF;
|
||||
#else // USE_CHECKED_OBJECTREFS
|
||||
typedef WaitHandleBase* WAITHANDLEREF;
|
||||
#endif // USE_CHECKED_OBJECTREFS
|
||||
|
||||
// This class corresponds to System.MulticastDelegate on the managed side.
|
||||
class DelegateObject : public Object
|
||||
|
|
|
@ -1,220 +0,0 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
//
|
||||
|
||||
/*============================================================
|
||||
**
|
||||
** Class: SafeHandle
|
||||
**
|
||||
**
|
||||
** Purpose: The unmanaged implementation of the SafeHandle
|
||||
** class
|
||||
**
|
||||
===========================================================*/
|
||||
|
||||
#include "common.h"
|
||||
#include "vars.hpp"
|
||||
#include "object.h"
|
||||
#include "excep.h"
|
||||
#include "frames.h"
|
||||
#include "eecontract.h"
|
||||
#include "typestring.h"
|
||||
|
||||
WORD SafeHandle::s_IsInvalidHandleMethodSlot = MethodTable::NO_SLOT;
|
||||
WORD SafeHandle::s_ReleaseHandleMethodSlot = MethodTable::NO_SLOT;
|
||||
|
||||
void SafeHandle::Init()
|
||||
{
|
||||
CONTRACTL {
|
||||
THROWS;
|
||||
GC_TRIGGERS;
|
||||
MODE_ANY;
|
||||
} CONTRACTL_END;
|
||||
|
||||
// For reliability purposes, we need to eliminate all possible failure
|
||||
// points before making a call to a CER method. IsInvalidHandle, and
|
||||
// ReleaseHandle methods are critical calls that are already prepared (code:
|
||||
// PrepareCriticalFinalizerObject). As a performance optimization, we are
|
||||
// calling these methods through a fast macro that assumes the method slot
|
||||
// has been already cached. Since figuring out the method slot for these 2
|
||||
// methods involves calling .GetMethod which can fail, we are doing this
|
||||
// eagerly here, Otherwise we will have to do it at the time of the call,
|
||||
// and this could be at risk if .GetMethod failed.
|
||||
MethodDesc* pMD = CoreLibBinder::GetMethod(METHOD__SAFE_HANDLE__GET_IS_INVALID);
|
||||
s_IsInvalidHandleMethodSlot = pMD->GetSlot();
|
||||
|
||||
pMD = CoreLibBinder::GetMethod(METHOD__SAFE_HANDLE__RELEASE_HANDLE);
|
||||
s_ReleaseHandleMethodSlot = pMD->GetSlot();
|
||||
}
|
||||
|
||||
// These AddRef and Release methods (and supporting functions) also exist with equivalent
|
||||
// code in SafeHandle.cs. Those implementations are the primary ones used by most code
|
||||
// and exposed publicly; the implementations here are only for use by the runtime, without
|
||||
// having to call out to the managed implementations.
|
||||
|
||||
void SafeHandle::AddRef()
|
||||
{
|
||||
CONTRACTL {
|
||||
THROWS;
|
||||
GC_TRIGGERS;
|
||||
MODE_COOPERATIVE;
|
||||
INSTANCE_CHECK;
|
||||
} CONTRACTL_END;
|
||||
|
||||
// Cannot use "this" after Release, which toggles the GC mode.
|
||||
SAFEHANDLEREF sh(this);
|
||||
|
||||
_ASSERTE(sh->IsFullyInitialized());
|
||||
|
||||
// See comments in SafeHandle.cs
|
||||
|
||||
INT32 oldState, newState;
|
||||
do {
|
||||
|
||||
oldState = sh->m_state;
|
||||
|
||||
if (oldState & SH_State_Closed)
|
||||
COMPlusThrow(kObjectDisposedException, IDS_EE_SAFEHANDLECLOSED);
|
||||
|
||||
newState = oldState + SH_RefCountOne;
|
||||
|
||||
} while (InterlockedCompareExchange((LONG*)&sh->m_state, newState, oldState) != oldState);
|
||||
}
|
||||
|
||||
void SafeHandle::Release(bool fDispose)
|
||||
{
|
||||
CONTRACTL {
|
||||
THROWS;
|
||||
GC_TRIGGERS;
|
||||
MODE_COOPERATIVE;
|
||||
INSTANCE_CHECK;
|
||||
} CONTRACTL_END;
|
||||
|
||||
// Cannot use "this" after RunReleaseMethod, which toggles the GC mode.
|
||||
SAFEHANDLEREF sh(this);
|
||||
|
||||
_ASSERTE(sh->IsFullyInitialized());
|
||||
|
||||
// See comments in SafeHandle.cs
|
||||
|
||||
bool fPerformRelease = false;
|
||||
|
||||
INT32 oldState, newState;
|
||||
do {
|
||||
|
||||
oldState = sh->m_state;
|
||||
if (fDispose && (oldState & SH_State_Disposed))
|
||||
return;
|
||||
|
||||
if ((oldState & SH_State_RefCount) == 0)
|
||||
COMPlusThrow(kObjectDisposedException, IDS_EE_SAFEHANDLECLOSED);
|
||||
|
||||
fPerformRelease = ((oldState & (SH_State_RefCount | SH_State_Closed)) == SH_RefCountOne) && m_ownsHandle;
|
||||
|
||||
if (fPerformRelease)
|
||||
{
|
||||
GCPROTECT_BEGIN(sh);
|
||||
|
||||
CLR_BOOL fIsInvalid = FALSE;
|
||||
|
||||
DECLARE_ARGHOLDER_ARRAY(args, 1);
|
||||
args[ARGNUM_0] = OBJECTREF_TO_ARGHOLDER(sh);
|
||||
|
||||
PREPARE_SIMPLE_VIRTUAL_CALLSITE_USING_SLOT(s_IsInvalidHandleMethodSlot, sh);
|
||||
|
||||
CRITICAL_CALLSITE;
|
||||
CALL_MANAGED_METHOD(fIsInvalid, CLR_BOOL, args);
|
||||
|
||||
if (fIsInvalid)
|
||||
{
|
||||
fPerformRelease = false;
|
||||
}
|
||||
|
||||
GCPROTECT_END();
|
||||
}
|
||||
|
||||
newState = (oldState - SH_RefCountOne) |
|
||||
((oldState & SH_State_RefCount) == SH_RefCountOne ? SH_State_Closed : 0) |
|
||||
(fDispose ? SH_State_Disposed : 0);
|
||||
|
||||
} while (InterlockedCompareExchange((LONG*)&sh->m_state, newState, oldState) != oldState);
|
||||
|
||||
if (fPerformRelease)
|
||||
RunReleaseMethod((SafeHandle*) OBJECTREFToObject(sh));
|
||||
}
|
||||
|
||||
void SafeHandle::SetHandle(LPVOID handle)
|
||||
{
|
||||
CONTRACTL {
|
||||
THROWS;
|
||||
MODE_COOPERATIVE;
|
||||
INSTANCE_CHECK;
|
||||
} CONTRACTL_END;
|
||||
|
||||
_ASSERTE(IsFullyInitialized());
|
||||
|
||||
// The SafeHandle's handle field can only be set it if the SafeHandle isn't
|
||||
// closed or disposed and its ref count is 1.
|
||||
if (m_state != (LONG)SH_RefCountOne)
|
||||
COMPlusThrow(kObjectDisposedException, IDS_EE_SAFEHANDLECANNOTSETHANDLE);
|
||||
|
||||
m_handle = handle;
|
||||
}
|
||||
|
||||
void AcquireSafeHandle(SAFEHANDLEREF* s)
|
||||
{
|
||||
WRAPPER_NO_CONTRACT;
|
||||
GCX_COOP();
|
||||
_ASSERTE(s != NULL && *s != NULL);
|
||||
(*s)->AddRef();
|
||||
}
|
||||
|
||||
void ReleaseSafeHandle(SAFEHANDLEREF* s)
|
||||
{
|
||||
WRAPPER_NO_CONTRACT;
|
||||
GCX_COOP();
|
||||
_ASSERTE(s != NULL && *s != NULL);
|
||||
(*s)->Release(false);
|
||||
}
|
||||
|
||||
|
||||
// This could theoretically be an instance method, but we'd need to
|
||||
// somehow GC protect the this pointer or never dereference any
|
||||
// field within the object. It's a lot simpler if we simply make
|
||||
// this method static.
|
||||
void SafeHandle::RunReleaseMethod(SafeHandle* psh)
|
||||
{
|
||||
CONTRACTL {
|
||||
THROWS;
|
||||
GC_TRIGGERS;
|
||||
MODE_COOPERATIVE;
|
||||
} CONTRACTL_END;
|
||||
|
||||
SAFEHANDLEREF sh(psh);
|
||||
_ASSERTE(sh != NULL);
|
||||
_ASSERTE(sh->m_ownsHandle);
|
||||
_ASSERTE(sh->IsFullyInitialized());
|
||||
|
||||
GCPROTECT_BEGIN(sh);
|
||||
|
||||
// Save last error from P/Invoke in case the implementation of ReleaseHandle
|
||||
// trashes it (important because this ReleaseHandle could occur implicitly
|
||||
// as part of unmarshaling another P/Invoke).
|
||||
Thread *pThread = GetThread();
|
||||
DWORD dwSavedError = pThread->m_dwLastError;
|
||||
|
||||
CLR_BOOL fReleaseHandle = FALSE;
|
||||
|
||||
DECLARE_ARGHOLDER_ARRAY(args, 1);
|
||||
args[ARGNUM_0] = OBJECTREF_TO_ARGHOLDER(sh);
|
||||
|
||||
PREPARE_SIMPLE_VIRTUAL_CALLSITE_USING_SLOT(s_ReleaseHandleMethodSlot, sh);
|
||||
|
||||
CRITICAL_CALLSITE;
|
||||
CALL_MANAGED_METHOD(fReleaseHandle, CLR_BOOL, args);
|
||||
|
||||
pThread->m_dwLastError = dwSavedError;
|
||||
|
||||
GCPROTECT_END();
|
||||
}
|
|
@ -422,17 +422,6 @@ extern "C" void QCALLTYPE InterfaceMarshaler_ConvertToManaged(IUnknown** ppUnk,
|
|||
|
||||
#endif // FEATURE_COMINTEROP
|
||||
|
||||
FCIMPL0(void, StubHelpers::SetLastError)
|
||||
{
|
||||
// Make sure this is the first thing we do after returning from the target, as almost everything can cause the last error to get trashed
|
||||
DWORD lastError = ::GetLastError();
|
||||
|
||||
FCALL_CONTRACT;
|
||||
|
||||
GetThread()->m_dwLastError = lastError;
|
||||
}
|
||||
FCIMPLEND
|
||||
|
||||
FCIMPL0(void, StubHelpers::ClearLastError)
|
||||
{
|
||||
FCALL_CONTRACT;
|
||||
|
|
|
@ -7889,32 +7889,6 @@ INT32 Thread::ResetManagedThreadObjectInCoopMode(INT32 nPriority)
|
|||
return nPriority;
|
||||
}
|
||||
|
||||
BOOL Thread::IsRealThreadPoolResetNeeded()
|
||||
{
|
||||
CONTRACTL
|
||||
{
|
||||
NOTHROW;
|
||||
GC_NOTRIGGER;
|
||||
MODE_COOPERATIVE;
|
||||
}
|
||||
CONTRACTL_END;
|
||||
|
||||
if(!IsBackground())
|
||||
return TRUE;
|
||||
|
||||
THREADBASEREF pObject = (THREADBASEREF)ObjectFromHandle(m_ExposedObject);
|
||||
|
||||
if(pObject != NULL)
|
||||
{
|
||||
INT32 nPriority = pObject->GetPriority();
|
||||
|
||||
if(nPriority != ThreadNative::PRIORITY_NORMAL)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void Thread::InternalReset(BOOL fNotFinalizerThread, BOOL fThreadObjectResetNeeded, BOOL fResetAbort)
|
||||
{
|
||||
CONTRACTL {
|
||||
|
|
|
@ -638,7 +638,7 @@ public:
|
|||
TS_ReportDead = 0x00010000, // in WaitForOtherThreads()
|
||||
TS_FullyInitialized = 0x00020000, // Thread is fully initialized and we are ready to broadcast its existence to external clients
|
||||
|
||||
TS_TaskReset = 0x00040000, // The task is reset
|
||||
// unused = 0x00040000,
|
||||
|
||||
TS_SyncSuspended = 0x00080000, // Suspended via WaitSuspendEvent
|
||||
TS_DebugWillSync = 0x00100000, // Debugger will wait for this thread to sync
|
||||
|
@ -753,7 +753,7 @@ public:
|
|||
void InternalReset (BOOL fNotFinalizerThread=FALSE, BOOL fThreadObjectResetNeeded=TRUE, BOOL fResetAbort=TRUE);
|
||||
INT32 ResetManagedThreadObject(INT32 nPriority);
|
||||
INT32 ResetManagedThreadObjectInCoopMode(INT32 nPriority);
|
||||
BOOL IsRealThreadPoolResetNeeded();
|
||||
|
||||
public:
|
||||
HRESULT DetachThread(BOOL fDLLThreadDetach);
|
||||
|
||||
|
@ -2454,18 +2454,6 @@ public:
|
|||
// making m_Link public.
|
||||
SLink m_Link;
|
||||
|
||||
// For N/Direct calls with the "setLastError" bit, this field stores
|
||||
// the errorcode from that call.
|
||||
DWORD m_dwLastError;
|
||||
|
||||
#ifdef FEATURE_INTERPRETER
|
||||
// When we're interpreting IL stubs for N/Direct calls with the "setLastError" bit,
|
||||
// the interpretation will trash the last error before we get to the call to "SetLastError".
|
||||
// Therefore, we record it here immediately after the calli, and treat "SetLastError" as an
|
||||
// intrinsic that transfers the value stored here into the field above.
|
||||
DWORD m_dwLastErrorInterp;
|
||||
#endif
|
||||
|
||||
// Debugger per-thread flag for enabling notification on "manual"
|
||||
// method calls, for stepping logic
|
||||
void IncrementTraceCallCount();
|
||||
|
|
|
@ -1382,7 +1382,7 @@ Thread::UserAbort(EEPolicy::ThreadAbortTypes abortType, DWORD timeout)
|
|||
|
||||
// If a thread is Dead or Detached, abort is a NOP.
|
||||
//
|
||||
if (m_State & (TS_Dead | TS_Detached | TS_TaskReset))
|
||||
if (m_State & (TS_Dead | TS_Detached))
|
||||
{
|
||||
UnmarkThreadForAbort();
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue