diff options
Diffstat (limited to 'src/vm/comtoclrcall.h')
-rw-r--r-- | src/vm/comtoclrcall.h | 482 |
1 files changed, 482 insertions, 0 deletions
diff --git a/src/vm/comtoclrcall.h b/src/vm/comtoclrcall.h new file mode 100644 index 0000000000..145aaadbd7 --- /dev/null +++ b/src/vm/comtoclrcall.h @@ -0,0 +1,482 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. +// +// File: COMtoCLRCall.h +// + +// + + +#ifndef __COMTOCLRCALL_H__ +#define __COMTOCLRCALL_H__ + +#ifndef FEATURE_COMINTEROP +#error FEATURE_COMINTEROP is required for this file +#endif // FEATURE_COMINTEROP + +#include "util.hpp" +#include "spinlock.h" + +enum ComCallFlags +{ + enum_IsVirtual = 0x0001, // If true the method is virtual on the managed side + enum_IsFieldCall = 0x0002, // is field call + enum_IsGetter = 0x0004, // is field call getter + enum_NativeInfoInitialized = 0x0008, // Has the native info been initialized + enum_NativeR4Retval = 0x0010, // Native ret val is an R4 + enum_NativeR8Retval = 0x0020, // Native ret val is an R8 + enum_NativeHResultRetVal = 0x0040, // Native ret val is an HRESULT + enum_NativeBoolRetVal = 0x0080, // Native ret val is 0 in the case of failure + enum_NativeVoidRetVal = 0x0100, // Native ret val is void + enum_IsEarlyBoundUnsafe = 0x0200, // Is unsafe to be called early-bound + enum_HasMarshalError = 0x0400, // The signature is not marshalable and m_StackBytes is a guess + enum_IsDelegateInvoke = 0x0800, // The method is an 'Invoke' on a delegate + enum_NeedsSecurityCheck = 0x1000, // Security check is needed at every invocation + enum_IsWinRTCall = 0x2000, // The method is declared on a WinRT interface/delegate + enum_IsWinRTCtor = 0x4000, // The method is a WinRT constructor + enum_IsWinRTStatic = 0x8000, // The method is a WinRT static + enum_IsWinRTRedirected = 0x10000, // The method is declared on a redirected WinRT interface +}; + + +//======================================================================= +// class com call +//======================================================================= + +#if !defined(DACCESS_COMPILE) +class ComCall +{ +public: + // Encapsulate a SpinLockHolder, so that clients of our lock don't have to know + // the details of our implementation. + class LockHolder : public SpinLockHolder + { + public: + LockHolder() + : SpinLockHolder(ComCall::s_plock) + { + WRAPPER_NO_CONTRACT; + } + }; + + + //--------------------------------------------------------- + // One-time init + //--------------------------------------------------------- + static void Init(); + + // + static void PopulateComCallMethodDesc(ComCallMethodDesc *pCMD, DWORD *pdwStubFlags); + + // helper to create a generic stub for com calls + static Stub* CreateGenericComCallStub(BOOL isFieldAccess); + + //--------------------------------------------------------- + // Either creates or retrieves from the cache, a stub to + // invoke com to com+ + // Each call refcounts the returned stub. + // This routines throws an exception rather than returning + // NULL. + //--------------------------------------------------------- + static PCODE GetComCallMethodStub(ComCallMethodDesc *pMD); + + // pCallMD is either interface or class method - the one returned by + // code:ComCallMethodDesc.GetCallMethodDesc on the ComCallMethodDesc + // that owns the stub; pFD is the target field + static MethodDesc* GetILStubMethodDesc(MethodDesc *pCallMD, DWORD dwStubFlags); + static MethodDesc* GetILStubMethodDesc(FieldDesc *pFD, DWORD dwStubFlags); + + static MethodDesc *GetCtorForWinRTFactoryMethod(MethodTable *pClsMT, MethodDesc *pMD); + static MethodDesc *GetStaticForWinRTFactoryMethod(MethodTable *pClsMT, MethodDesc *pMD); + +private: + ComCall() {LIMITED_METHOD_CONTRACT;}; // prevent "new"'s on this class + + static SpinLock* s_plock; +}; +#endif // DACCESS_COMPILE + +//----------------------------------------------------------------------- +// Operations specific to ComCall methods. This is not a code:MethodDesc. +//----------------------------------------------------------------------- + +class ComCallMethodDesc +{ + friend void InvokeStub(ComCallMethodDesc *pCMD, PCODE pManagedTarget, OBJECTREF orThis, ComMethodFrame *pFrame, Thread *pThread, UINT64* pRetValOut); + +public: + // init method + void InitMethod(MethodDesc *pMD, MethodDesc *pInterfaceMD, BOOL fRedirectedInterface = FALSE); + + // init field + void InitField(FieldDesc* pField, BOOL isGetter); + + // is field call + BOOL IsFieldCall() + { + LIMITED_METHOD_CONTRACT; + return (m_flags & enum_IsFieldCall); + } + + BOOL IsEarlyBoundUnsafe() + { + LIMITED_METHOD_CONTRACT; + return (m_flags & enum_IsEarlyBoundUnsafe); + } + + BOOL NeedsSecurityCheck() + { + LIMITED_METHOD_CONTRACT; + return (m_flags & enum_NeedsSecurityCheck); + } + + BOOL IsMethodCall() + { + WRAPPER_NO_CONTRACT; + return !IsFieldCall(); + } + + // is field getter + BOOL IsFieldGetter() + { + CONTRACT (BOOL) + { + NOTHROW; + GC_NOTRIGGER; + MODE_ANY; + SO_TOLERANT; + PRECONDITION(IsFieldCall()); + } + CONTRACT_END; + + RETURN (m_flags & enum_IsGetter); + } + + // is a virtual method + BOOL IsVirtual() + { + CONTRACT (BOOL) + { + NOTHROW; + GC_NOTRIGGER; + MODE_ANY; + SO_TOLERANT; + PRECONDITION(IsMethodCall()); + } + CONTRACT_END; + + RETURN (m_flags & enum_IsVirtual); + } + + BOOL IsNativeR4RetVal() + { + LIMITED_METHOD_CONTRACT; + return m_flags & enum_NativeR4Retval; + } + + BOOL IsNativeR8RetVal() + { + LIMITED_METHOD_CONTRACT; + return m_flags & enum_NativeR8Retval; + } + + BOOL IsNativeFloatingPointRetVal() + { + LIMITED_METHOD_CONTRACT; + return m_flags & (enum_NativeR4Retval | enum_NativeR8Retval); + } + + BOOL IsNativeHResultRetVal() + { + LIMITED_METHOD_CONTRACT; + return m_flags & enum_NativeHResultRetVal; + } + + BOOL IsNativeBoolRetVal() + { + LIMITED_METHOD_CONTRACT; + return m_flags & enum_NativeBoolRetVal; + } + + BOOL IsNativeVoidRetVal() + { + LIMITED_METHOD_CONTRACT; + return m_flags & enum_NativeVoidRetVal; + } + + BOOL HasMarshalError() + { + LIMITED_METHOD_CONTRACT; + return m_flags & enum_HasMarshalError; + } + + BOOL IsDelegateInvoke() + { + LIMITED_METHOD_CONTRACT; + return m_flags & enum_IsDelegateInvoke; + } + + BOOL IsWinRTCall() + { + LIMITED_METHOD_CONTRACT; + return m_flags & enum_IsWinRTCall; + } + + BOOL IsWinRTCtor() + { + LIMITED_METHOD_CONTRACT; + return m_flags & enum_IsWinRTCtor; + } + + BOOL IsWinRTStatic() + { + LIMITED_METHOD_CONTRACT; + return m_flags & enum_IsWinRTStatic; + } + + BOOL IsWinRTRedirectedMethod() + { + LIMITED_METHOD_CONTRACT; + return m_flags & enum_IsWinRTRedirected; + } + + BOOL IsNativeInfoInitialized() + { + LIMITED_METHOD_CONTRACT; + return m_flags & enum_NativeInfoInitialized; + } + + DWORD GetFlags() + { + LIMITED_METHOD_CONTRACT; + return m_flags; + } + + // get method desc + MethodDesc* GetMethodDesc() + { + CONTRACT (MethodDesc*) + { + NOTHROW; + GC_NOTRIGGER; + MODE_ANY; + SO_TOLERANT; + PRECONDITION(!IsFieldCall()); + PRECONDITION(CheckPointer(m_pMD)); + POSTCONDITION(CheckPointer(RETVAL, NULL_OK)); + } + CONTRACT_END; + + RETURN m_pMD; + } + + // get interface method desc + MethodDesc* GetInterfaceMethodDesc() + { + CONTRACT (MethodDesc *) + { + NOTHROW; + GC_NOTRIGGER; + MODE_ANY; + SO_TOLERANT; + PRECONDITION(!IsFieldCall()); + POSTCONDITION(CheckPointer(RETVAL, NULL_OK)); + SUPPORTS_DAC; + } + CONTRACT_END; + + RETURN m_pInterfaceMD; + } + + // get interface method desc if non-NULL, class method desc otherwise + MethodDesc* GetCallMethodDesc() + { + WRAPPER_NO_CONTRACT; + + MethodDesc *pMD = GetInterfaceMethodDesc(); + if (pMD == NULL) + pMD = GetMethodDesc(); + _ASSERTE(pMD != NULL); + + return pMD; + } + + // get field desc + FieldDesc* GetFieldDesc() + { + CONTRACT (FieldDesc*) + { + NOTHROW; + GC_NOTRIGGER; + MODE_ANY; + SO_TOLERANT; + PRECONDITION(IsFieldCall()); + PRECONDITION(CheckPointer(m_pFD)); + POSTCONDITION(CheckPointer(RETVAL, NULL_OK)); + } + CONTRACT_END; + + RETURN m_pFD; + } + + // get module + Module* GetModule(); + + PCODE *GetAddrOfILStubField() + { + LIMITED_METHOD_CONTRACT; + return &m_pILStub; + } + + PCODE GetILStub() + { + LIMITED_METHOD_CONTRACT; + return m_pILStub; + } + + // get slot number for the method + unsigned GetSlot() + { + CONTRACT (unsigned) + { + NOTHROW; + GC_NOTRIGGER; + MODE_ANY; + SO_TOLERANT; + PRECONDITION(IsMethodCall()); + PRECONDITION(CheckPointer(m_pMD)); + } + CONTRACT_END; + + RETURN m_pMD->GetSlot(); + } + + // get num stack bytes to pop + UINT16 GetNumStackBytes() + { + CONTRACTL + { + NOTHROW; + GC_NOTRIGGER; + MODE_ANY; + SO_TOLERANT; + PRECONDITION(m_flags & enum_NativeInfoInitialized); + SUPPORTS_DAC; + } + CONTRACTL_END; + + return m_StackBytes; + } + + static DWORD GetOffsetOfReturnThunk() + { + LIMITED_METHOD_CONTRACT; + return -COMMETHOD_PREPAD; + } + + static DWORD GetOffsetOfMethodDesc() + { + LIMITED_METHOD_CONTRACT; + return ((DWORD) offsetof(class ComCallMethodDesc, m_pMD)); + } + + //get call sig + PCCOR_SIGNATURE GetSig(DWORD *pcbSigSize = NULL) + { + CONTRACT (PCCOR_SIGNATURE) + { + NOTHROW; + GC_NOTRIGGER; + MODE_ANY; + SO_TOLERANT; + PRECONDITION(IsMethodCall()); + PRECONDITION(CheckPointer(m_pMD)); + } + CONTRACT_END; + + PCCOR_SIGNATURE pSig; + DWORD cbSigSize; + + m_pMD->GetSig(&pSig, &cbSigSize); + + if (pcbSigSize != NULL) + { + *pcbSigSize = cbSigSize; + } + + RETURN pSig; + } + + // Discard all the resources owned by this ComCallMethodDesc. + void Destruct() + { + CONTRACTL + { + NOTHROW; + GC_TRIGGERS; + MODE_ANY; + } + CONTRACTL_END; + +#ifdef _TARGET_X86_ + if (m_pwStubStackSlotOffsets != NULL) + delete [] m_pwStubStackSlotOffsets; +#endif // _TARGET_X86_ + } + + static void ReleaseComCallMethodDesc(ComCallMethodDesc *pCMD) + { + WRAPPER_NO_CONTRACT; + pCMD->Destruct(); + } + + PCODE CreateCOMToCLRStub(DWORD dwStubFlags, MethodDesc **ppStubMD); + void InitRuntimeNativeInfo(MethodDesc *pStubMD); + +private: + // Initialize the member's native type information (size of native stack, native retval flags, etc). + void InitNativeInfo(); + + // see ComCallFlags enum above + DWORD m_flags; + union + { + struct + { + MethodDesc* m_pMD; + PTR_MethodDesc m_pInterfaceMD; + }; + FieldDesc* m_pFD; + }; + + PCODE m_pILStub; // IL stub for COM to CLR call, invokes GetCallMethodDesc() + + // Platform specific data needed for efficient IL stub invocation: +#ifdef _TARGET_X86_ + union + { + struct + { + // Index of the stack slot that gets stuffed into EDX when calling the stub. + UINT16 m_wSourceSlotEDX; + + // Number of stack slots expected by the IL stub. + UINT16 m_wStubStackSlotCount; + }; + // Combination of m_wSourceSlotEDX and m_wStubStackSlotCount for atomic updates. + UINT32 m_dwSlotInfo; + }; + + // This is an array of m_wStubStackSlotCount numbers where each element is the offset + // on the source stack where the particular stub stack slot should be copied from. + UINT16 *m_pwStubStackSlotOffsets; +#endif // _TARGET_X86_ + + // Number of stack bytes pushed by the unmanaged caller. + UINT16 m_StackBytes; +}; + +typedef Holder<ComCallMethodDesc *, DoNothing<ComCallMethodDesc *>, ComCallMethodDesc::ReleaseComCallMethodDesc> ComCallMethodDescHolder; + +#endif // __COMTOCLRCALL_H__ |