summaryrefslogtreecommitdiff
path: root/src/vm/comdelegate.h
blob: 1bfe8ac987a1414fedbc2eaf724b3105ff763cdf (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
// 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: COMDelegate.h
// 
// This module contains the native methods for the Delegate class.
// 


#ifndef _COMDELEGATE_H_
#define _COMDELEGATE_H_

class Stub;
class ShuffleThunkCache;

#include "cgensys.h"
#include "dllimportcallback.h"
#include "stubcache.h"

typedef ArgBasedStubCache MulticastStubCache;

VOID GenerateShuffleArray(MethodDesc* pInvoke, MethodDesc *pTargetMeth, struct ShuffleEntry * pShuffleEntryArray, size_t nEntries);


// This class represents the native methods for the Delegate class
class COMDelegate
{
private:
    // friend VOID CPUSTUBLINKER::EmitMulticastInvoke(...);
    // friend VOID CPUSTUBLINKER::EmitShuffleThunk(...);
    friend class CPUSTUBLINKER;
    friend class DelegateInvokeStubManager;
    friend class SecureDelegateFrame;
    friend BOOL MulticastFrame::TraceFrame(Thread *thread, BOOL fromPatch, 
                                TraceDestination *trace, REGDISPLAY *regs);

    static MulticastStubCache* m_pSecureDelegateStubCache;
    static MulticastStubCache* m_pMulticastStubCache;

    static CrstStatic   s_DelegateToFPtrHashCrst;   // Lock for the following hash.
    static PtrHashMap*  s_pDelegateToFPtrHash;      // Hash table containing the Delegate->FPtr pairs
                                                    // passed out to unmanaged code.
public:
    static ShuffleThunkCache *m_pShuffleThunkCache;

    //REVIEW: reconcile initialization, one init?
    // One time init.
    static void Init();

    static FCDECL3(void, DelegateConstruct, Object* refThis, Object* target, PCODE method);

    static FCDECL1(Object*, InternalAlloc, ReflectClassBaseObject* target);
    static FCDECL1(Object*, InternalAllocLike, Object* pThis);
    static FCDECL2(FC_BOOL_RET, InternalEqualTypes, Object* pThis, Object *pThat);
    
    static FCDECL3(PCODE, AdjustTarget, Object* refThis, Object* target, PCODE method);
    static FCDECL2(PCODE, GetCallStub, Object* refThis, PCODE method);

    static FCDECL5(FC_BOOL_RET, BindToMethodName, Object* refThisUNSAFE, Object* targetUNSAFE, ReflectClassBaseObject *pMethodTypeUNSAFE, StringObject* methodNameUNSAFE, int flags);

    static FCDECL5(FC_BOOL_RET, BindToMethodInfo, Object* refThisUNSAFE, Object* targetUNSAFE, ReflectMethodObject *method, ReflectClassBaseObject *pMethodTypeUNSAFE, int flags);

    // This gets the MethodInfo for a delegate, creating it if necessary
    static FCDECL1(ReflectMethodObject*, FindMethodHandle, Object* refThis);
    static FCDECL2(FC_BOOL_RET, InternalEqualMethodHandles, Object *refLeftIn, Object *refRightIn);

    // Get the invoke method for the delegate. Used to transition delegates to multicast delegates.
    static FCDECL1(PCODE, GetMulticastInvoke, Object* refThis);
    static FCDECL1(MethodDesc*, GetInvokeMethod, Object* refThis);
    static PCODE GetSecureInvoke(MethodDesc* pMD);
    // determines where the delegate needs to be wrapped for non-security reason
    static BOOL NeedsWrapperDelegate(MethodDesc* pTargetMD);
    // on entry delegate points to the delegate to wrap
    static DELEGATEREF CreateSecureDelegate(DELEGATEREF delegate, MethodDesc* pCreatorMethod, MethodDesc* pTargetMD);

    // Marshals a delegate to a unmanaged callback.
    static LPVOID ConvertToCallback(OBJECTREF pDelegate);
    
    // Marshals a managed method to an unmanaged callback , provided the method is static and uses only 
    // blittable parameter types.
    static PCODE ConvertToCallback(MethodDesc* pMD);

    // Marshals an unmanaged callback to Delegate
    static OBJECTREF ConvertToDelegate(LPVOID pCallback, MethodTable* pMT);

#ifdef FEATURE_COMINTEROP
    // Marshals a WinRT delegate interface pointer to a managed Delegate
    static OBJECTREF ConvertWinRTInterfaceToDelegate(IUnknown *pUnk, MethodTable* pMT);

    static ComPlusCallInfo * PopulateComPlusCallInfo(MethodTable * pDelMT);
#endif // FEATURE_COMINTEROP

    // Checks whether two delegates wrapping function pointers have the same unmanaged target
    static FCDECL2(FC_BOOL_RET, CompareUnmanagedFunctionPtrs, Object *refDelegate1UNSAFE, Object *refDelegate2UNSAFE);

    static PCODE GetStubForILStub(EEImplMethodDesc* pDelegateMD, MethodDesc** ppStubMD, DWORD dwStubFlags);
    static MethodDesc* GetILStubMethodDesc(EEImplMethodDesc* pDelegateMD, DWORD dwStubFlags);

    static void ValidateDelegatePInvoke(MethodDesc* pMD);

    static void RemoveEntryFromFPtrHash(UPTR key);
    
    // Decides if pcls derives from Delegate.
    static BOOL IsDelegate(MethodTable *pMT);

    // Decides if this is a secure delegate
    static BOOL IsSecureDelegate(DELEGATEREF dRef);
   
    // Get the cpu stub for a delegate invoke.
    static PCODE GetInvokeMethodStub(EEImplMethodDesc* pMD);

    // get the one single delegate invoke stub
    static PCODE TheDelegateInvokeStub();

#ifdef _TARGET_X86_
#ifdef MDA_SUPPORTED
    static Stub *GenerateStubForMDA(MethodDesc *pInvokeMD, MethodDesc *pStubMD, LPVOID pNativeTarget, Stub *pInnerStub);
#endif // MDA_SUPPORTED
    static Stub *GenerateStubForHost(MethodDesc *pInvokeMD, MethodDesc *pStubMD, LPVOID pNativeTarget, Stub *pInnerStub);
#endif // _TARGET_X86_

    static MethodDesc * __fastcall GetMethodDesc(OBJECTREF obj);
    static OBJECTREF GetTargetObject(OBJECTREF obj);

    static BOOL IsTrueMulticastDelegate(OBJECTREF delegate);

private:
    static Stub* SetupShuffleThunk(MethodTable * pDelMT, MethodDesc *pTargetMeth);

public:
    static MethodDesc* FindDelegateInvokeMethod(MethodTable *pMT);
    static BOOL IsDelegateInvokeMethod(MethodDesc *pMD);

    static BOOL IsMethodDescCompatible(TypeHandle   thFirstArg,
                                       TypeHandle   thExactMethodType,
                                       MethodDesc  *pTargetMethod,
                                       TypeHandle   thDelegate,
                                       MethodDesc  *pInvokeMethod,
                                       int          flags,
                                       BOOL        *pfIsOpenDelegate);
    static MethodDesc* GetDelegateCtor(TypeHandle delegateType, MethodDesc *pTargetMethod, DelegateCtorArgs *pCtorData);
    //@GENERICSVER: new (suitable for generics)
    // Method to do static validation of delegate .ctor
    static BOOL ValidateCtor(TypeHandle objHnd, TypeHandle ftnParentHnd, MethodDesc *pFtn, TypeHandle dlgtHnd, BOOL *pfIsOpenDelegate);

private:
    static BOOL ValidateBeginInvoke(DelegateEEClass* pClass);   // make certain the BeginInvoke method is consistant with the Invoke Method
    static BOOL ValidateEndInvoke(DelegateEEClass* pClass);     // make certain the EndInvoke method is consistant with the Invoke Method

    static void BindToMethod(DELEGATEREF   *pRefThis,
                             OBJECTREF     *pRefFirstArg,
                             MethodDesc    *pTargetMethod,
                             MethodTable   *pExactMethodType,
                             BOOL           fIsOpenDelegate,
                             BOOL           fCheckSecurity);
};

// These flags effect the way BindToMethodInfo and BindToMethodName are allowed to bind a delegate to a target method. Their
// values must be kept in sync with the definition in bcl\system\delegate.cs.
enum DelegateBindingFlags
{
    DBF_StaticMethodOnly    =   0x00000001, // Can only bind to static target methods
    DBF_InstanceMethodOnly  =   0x00000002, // Can only bind to instance (including virtual) methods
    DBF_OpenDelegateOnly    =   0x00000004, // Only allow the creation of delegates open over the 1st argument
    DBF_ClosedDelegateOnly  =   0x00000008, // Only allow the creation of delegates closed over the 1st argument
    DBF_NeverCloseOverNull  =   0x00000010, // A null target will never been considered as a possible null 1st argument
    DBF_CaselessMatching    =   0x00000020, // Use case insensitive lookup for methods matched by name
    DBF_SkipSecurityChecks  =   0x00000040, // Skip security checks (visibility, link demand etc.)
    DBF_RelaxedSignature    =   0x00000080, // Allow relaxed signature matching (co/contra variance)
};

void DistributeEvent(OBJECTREF *pDelegate,
                     OBJECTREF *pDomain);

void DistributeUnhandledExceptionReliably(OBJECTREF *pDelegate,
                                          OBJECTREF *pDomain,
                                          OBJECTREF *pThrowable,
                                          BOOL       isTerminating);

// Want no unused bits in ShuffleEntry since unused bits can make
// equivalent ShuffleEntry arrays look unequivalent and deoptimize our
// hashing.
#include <pshpack1.h>

// To handle a call to a static delegate, we create an array of ShuffleEntry
// structures. Each entry instructs the shuffler to move a chunk of bytes.
// The size of the chunk is StackElemSize (typically a DWORD): long arguments
// have to be expressed as multiple ShuffleEntry's.
//
// The ShuffleEntry array serves two purposes:
//
//  1. A platform-indepedent blueprint for creating the platform-specific
//     shuffle thunk.
//  2. A hash key for finding the shared shuffle thunk for a particular
//     signature.
struct ShuffleEntry
{
    // Offset masks and special value
    enum {
        REGMASK      = 0x8000, // Register offset bit
        FPREGMASK    = 0x4000, // Floating point register bit
        FPSINGLEMASK = 0x2000, // Single precising floating point register
        OFSMASK      = 0x7fff, // Mask to get stack offset
        OFSREGMASK   = 0x1fff, // Mask to get register index
        SENTINEL     = 0xffff, // Indicates end of shuffle array
    };

#if defined(_TARGET_AMD64_) && !defined(UNIX_AMD64_ABI)
    union {
        UINT16          srcofs;
        CorElementType  argtype;    // AMD64: shuffle array is just types
    };
#else

    UINT16    srcofs;

    union {
        UINT16    dstofs;           //if srcofs != SENTINEL
        UINT16    stacksizedelta;   //if dstofs == SENTINEL, difference in stack size between virtual and static sigs
    };
#endif // _TARGET_AMD64_
};


#include <poppack.h>

#endif  // _COMDELEGATE_H_