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
|
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license 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);
// determines whether the delegate needs to be wrapped
static BOOL NeedsSecureDelegate(MethodDesc* pCreatorMethod, AppDomain *pCreatorDomain, 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_
#ifdef FEATURE_COMINTEROP
static void DoUnmanagedCodeAccessCheck(MethodDesc* pMeth);
#endif // FEATURE_COMINTEROP
static MethodDesc * __fastcall GetMethodDesc(OBJECTREF obj);
static OBJECTREF GetTargetObject(OBJECTREF obj);
static BOOL IsTrueMulticastDelegate(OBJECTREF delegate);
#ifdef FEATURE_CORECLR
static BOOL IsMethodAllowedToSinkReversePInvoke(MethodDesc *pMD);
#endif
private:
#ifdef FEATURE_CORECLR
static BOOL IsFullTrustDelegate(DELEGATEREF pDelegate);
#endif
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);
static BOOL ValidateSecurityTransparency(MethodDesc *pFtn, MethodTable *pdlgMT); // enforce the transparency rules
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 DistributeEventReliably(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
{
enum {
REGMASK = 0x8000,
OFSMASK = 0x7fff,
SENTINEL = 0xffff,
};
#if defined(_TARGET_AMD64_) && !defined(UNIX_AMD64_ABI)
union {
UINT16 srcofs;
CorElementType argtype; // AMD64: shuffle array is just types
};
#else
// Special values:
// -1 - indicates end of shuffle array: stacksizedelta
// == difference in stack size between virtual and static sigs.
// high bit - indicates a register argument: mask it off and
// the result is an offset into ArgumentRegisters.
UINT16 srcofs;
union {
UINT16 dstofs; //if srcofs != SENTINEL
UINT16 stacksizedelta; //if dstofs == SENTINEL
};
#endif // _TARGET_AMD64_
};
#include <poppack.h>
void __stdcall DoDelegateInvokeForHostCheck(Object* pDelegate);
#endif // _COMDELEGATE_H_
|