summaryrefslogtreecommitdiff
path: root/src/vm/comtoclrcall.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/vm/comtoclrcall.h')
-rw-r--r--src/vm/comtoclrcall.h482
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__