This repository has been archived by the owner on Jan 23, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2.7k
/
comdelegate.h
276 lines (221 loc) · 11.3 KB
/
comdelegate.h
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
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
// 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
#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>
class ShuffleThunkCache : public StubCacheBase
{
public:
ShuffleThunkCache(LoaderHeap* heap) : StubCacheBase(heap)
{
}
private:
//---------------------------------------------------------
// Compile a static delegate shufflethunk. Always returns
// STANDALONE since we don't interpret these things.
//---------------------------------------------------------
virtual void CompileStub(const BYTE *pRawStub,
StubLinker *pstublinker)
{
STANDARD_VM_CONTRACT;
((CPUSTUBLINKER*)pstublinker)->EmitShuffleThunk((ShuffleEntry*)pRawStub);
}
//---------------------------------------------------------
// Tells the StubCacheBase the length of a ShuffleEntryArray.
//---------------------------------------------------------
virtual UINT Length(const BYTE *pRawStub)
{
LIMITED_METHOD_CONTRACT;
ShuffleEntry *pse = (ShuffleEntry*)pRawStub;
while (pse->srcofs != ShuffleEntry::SENTINEL)
{
pse++;
}
return sizeof(ShuffleEntry) * (UINT)(1 + (pse - (ShuffleEntry*)pRawStub));
}
virtual void AddStub(const BYTE* pRawStub, Stub* pNewStub)
{
CONTRACTL
{
THROWS;
GC_NOTRIGGER;
MODE_ANY;
}
CONTRACTL_END;
#ifndef CROSSGEN_COMPILE
DelegateInvokeStubManager::g_pManager->AddStub(pNewStub);
#endif
}
};
#endif // _COMDELEGATE_H_