-
Notifications
You must be signed in to change notification settings - Fork 4.5k
/
rwutil.h
344 lines (292 loc) · 13.4 KB
/
rwutil.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
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
//*****************************************************************************
// RWUtil.h
//
//
// Contains utility code for MD directory
//
//*****************************************************************************
#ifndef __RWUtil__h__
#define __RWUtil__h__
class UTSemReadWrite;
#define UTF8STR(wszInput, szOutput) \
do { \
if ((wszInput) == NULL) \
{ \
(szOutput) = NULL; \
} \
else \
{ \
int cbBuffer = ((int)u16_strlen(wszInput) * 3) + 1; \
(szOutput) = (char *)_alloca(cbBuffer); \
Unicode2UTF((wszInput), (szOutput), cbBuffer); \
} \
} while (0)
//*****************************************************************************
// Helper methods
//*****************************************************************************
void
Unicode2UTF(
LPCWSTR wszSrc, // The string to convert.
_Out_writes_(cbDst)
LPUTF8 szDst, // Buffer for the output UTF8 string.
int cbDst); // Size of the buffer for UTF8 string.
//*********************************************************************
// The token remap record.
//*********************************************************************
struct TOKENREC
{
mdToken m_tkFrom; // The imported token
bool m_isDuplicate; // Is record duplicate? This information is recorded during merge
bool m_isDeleted; // This information is recorded during RegMeta::ProcessFilter when we might have deleted a record
bool m_isFoundInImport; // This information is also recorded during RegMeta::ProcessFilter
mdToken m_tkTo; // The new token in the merged scope
void SetEmpty() {m_tkFrom = m_tkTo = (mdToken) -1;}
BOOL IsEmpty() {return m_tkFrom == (mdToken) -1;}
};
//*********************************************************************
//
// This structure keeps track on token remap for an imported scope. This map is initially sorted by from
// tokens. It can then become sorted by To tokens. This usually happen during PreSave remap lookup. Thus
// we assert if we try to look up or sort by From token.
//
//*********************************************************************
class MDTOKENMAP : public CDynArray<TOKENREC>
{
public:
enum SortKind{
Unsorted = 0,
SortByFromToken = 1,
SortByToToken = 2,
Indexed = 3, // Indexed by table/rid. Implies that strings are sorted by "From".
};
MDTOKENMAP()
: m_pNextMap(NULL),
m_pMap(NULL),
m_iCountTotal(0),
m_iCountSorted(0),
m_sortKind(SortByFromToken),
m_iCountIndexed(0)
#if defined(_DEBUG)
,m_pImport(0)
#endif
{ }
~MDTOKENMAP();
HRESULT Init(IUnknown *pImport);
// find a token in the tokenmap.
bool Find(mdToken tkFrom, TOKENREC **ppRec);
// remap a token. We assert if we don't find the tkFind in the table
HRESULT Remap(mdToken tkFrom, mdToken *ptkTo);
// Insert a record. This function will keep the inserted record in a sorted sequence
HRESULT InsertNotFound(mdToken tkFrom, bool fDuplicate, mdToken tkTo, TOKENREC **ppRec);
// This function will just append the record to the end of the list
HRESULT AppendRecord(
mdToken tkFrom,
bool fDuplicate,
mdToken tkTo,
TOKENREC **ppRec);
// This is a safe remap. *tpkTo will be tkFind if we cannot find tkFind in the lookup table.
mdToken SafeRemap(mdToken tkFrom); // [IN] the token value to find
bool FindWithToToken(
mdToken tkFind, // [IN] the token value to find
int *piPosition); // [OUT] return the first from-token that has the matching to-token
FORCEINLINE void SortTokensByFromToken()
{
_ASSERTE(m_sortKind == SortByFromToken || m_sortKind == Indexed);
// Only sort if there are unsorted records.
if (m_iCountSorted < m_iCountTotal)
{
SortRangeFromToken(m_iCountIndexed, m_iCountIndexed+m_iCountTotal - 1);
m_iCountSorted = m_iCountTotal;
}
} // void MDTOKENMAP::SortTokensByFromToken()
HRESULT EmptyMap();
void SortTokensByToToken();
MDTOKENMAP *m_pNextMap;
IMapToken *m_pMap;
private:
FORCEINLINE int CompareFromToken( // -1, 0, or 1
int iLeft, // First item to compare.
int iRight) // Second item to compare.
{
if ( Get(iLeft)->m_tkFrom < Get(iRight)->m_tkFrom )
return -1;
if ( Get(iLeft)->m_tkFrom == Get(iRight)->m_tkFrom )
return 0;
return 1;
}
FORCEINLINE int CompareToToken( // -1, 0, or 1
int iLeft, // First item to compare.
int iRight) // Second item to compare.
{
if ( Get(iLeft)->m_tkTo < Get(iRight)->m_tkTo )
return -1;
if ( Get(iLeft)->m_tkTo == Get(iRight)->m_tkTo )
return 0;
return 1;
}
FORCEINLINE void Swap(
int iFirst,
int iSecond)
{
if ( iFirst == iSecond ) return;
memcpy( &m_buf, Get(iFirst), sizeof(TOKENREC) );
memcpy( Get(iFirst), Get(iSecond),sizeof(TOKENREC) );
memcpy( Get(iSecond), &m_buf, sizeof(TOKENREC) );
}
void SortRangeFromToken(int iLeft, int iRight);
void SortRangeToToken(int iLeft, int iRight);
TOKENREC m_buf;
ULONG m_iCountTotal; // total entry in the map
ULONG m_iCountSorted; // number of entries that are sorted
SortKind m_sortKind;
ULONG m_TableOffset[TBL_COUNT+1]; // Start of each table in map.
ULONG m_iCountIndexed; // number of entries that are indexed.
#if defined(_DEBUG)
IMetaDataImport *m_pImport; // For data validation.
#endif
};
//*********************************************************************
//
// This CMapToken class implemented the IMapToken. It is used in RegMeta for
// filter process. This class can track all of the tokens are mapped. It also
// supplies a Find function.
//
//*********************************************************************
class CMapToken : public IMapToken
{
friend class RegMeta;
public:
STDMETHODIMP QueryInterface(REFIID riid, PVOID *pp);
STDMETHODIMP_(ULONG) AddRef();
STDMETHODIMP_(ULONG) Release();
STDMETHODIMP Map(mdToken tkImp, mdToken tkEmit);
bool Find(mdToken tkFrom, TOKENREC **pRecTo);
CMapToken();
virtual ~CMapToken();
MDTOKENMAP *m_pTKMap;
private:
LONG m_cRef;
bool m_isSorted;
};
typedef CDynArray<mdToken> TOKENMAP;
//*********************************************************************
//
// This class records all sorts of token movement during optimization phase.
// This including Ref to Def optimization. This also includes token movement
// due to sorting or eleminating the pointer tables.
//
//*********************************************************************
class TokenRemapManager
{
public:
//*********************************************************************
//
// This function is called when a TypeRef is resolved to a TypeDef.
//
//*********************************************************************
FORCEINLINE void RecordTypeRefToTypeDefOptimization(
mdToken tkFrom,
mdToken tkTo)
{
_ASSERTE( TypeFromToken(tkFrom) == mdtTypeRef );
_ASSERTE( TypeFromToken(tkTo) == mdtTypeDef );
m_TypeRefToTypeDefMap[RidFromToken(tkFrom)] = tkTo;
} // RecordTypeRefToTypeDefOptimization
//*********************************************************************
//
// This function is called when a MemberRef is resolved to a MethodDef or FieldDef.
//
//*********************************************************************
FORCEINLINE void RecordMemberRefToMemberDefOptimization(
mdToken tkFrom,
mdToken tkTo)
{
_ASSERTE( TypeFromToken(tkFrom) == mdtMemberRef );
_ASSERTE( TypeFromToken(tkTo) == mdtMethodDef || TypeFromToken(tkTo) == mdtFieldDef);
m_MemberRefToMemberDefMap[RidFromToken(tkFrom)] = tkTo;
} // RecordMemberRefToMemberDefOptimization
//*********************************************************************
//
// This function is called when the token kind does not change but token
// is moved. For example, when we sort CustomAttribute table or when we optimize
// away MethodPtr table. These operation will not change the token type.
//
//*********************************************************************
FORCEINLINE HRESULT RecordTokenMovement(
mdToken tkFrom,
mdToken tkTo)
{
TOKENREC *pTokenRec;
_ASSERTE( TypeFromToken(tkFrom) == TypeFromToken(tkTo) );
return m_TKMap.AppendRecord( tkFrom, false, tkTo, &pTokenRec );
} // RecordTokenMovement
bool ResolveRefToDef(
mdToken tkRef, // [IN] ref token
mdToken *ptkDef); // [OUT] def token that it resolves to. If it does not resolve to a def
FORCEINLINE TOKENMAP *GetTypeRefToTypeDefMap() { return &m_TypeRefToTypeDefMap; }
FORCEINLINE TOKENMAP *GetMemberRefToMemberDefMap() { return &m_MemberRefToMemberDefMap; }
FORCEINLINE MDTOKENMAP *GetTokenMovementMap() { return &m_TKMap; }
~TokenRemapManager();
HRESULT ClearAndEnsureCapacity(ULONG cTypeRef, ULONG cMemberRef);
private:
MDTOKENMAP m_TKMap;
TOKENMAP m_TypeRefToTypeDefMap;
TOKENMAP m_MemberRefToMemberDefMap;
}; // class TokenRemapManager
// value that can be set by SetOption APIs
struct OptionValue
{
CorCheckDuplicatesFor m_DupCheck; // Bit Map for checking duplicates during emit.
CorRefToDefCheck m_RefToDefCheck; // Bit Map for specifying whether to do a ref to def optimization.
CorNotificationForTokenMovement m_NotifyRemap; // Bit Map for token remap notification.
ULONG m_UpdateMode; // (CorSetENC) Specifies whether ENC or Extension mode is on.
CorErrorIfEmitOutOfOrder m_ErrorIfEmitOutOfOrder; // Do not generate pointer tables
CorThreadSafetyOptions m_ThreadSafetyOptions; // specify if thread safety is turn on or not.
CorImportOptions m_ImportOption; // import options such as to skip over deleted items or not
CorLinkerOptions m_LinkerOption; // Linker option. Currently only used in UnmarkAll
BOOL m_GenerateTCEAdapters; // Do not generate the TCE adapters for COM CPC.
LPSTR m_RuntimeVersion; // CLR Version stamp
MetadataVersion m_MetadataVersion; // Version of the metadata to emit
MergeFlags m_MergeOptions; // Options to pass to the merger
UINT32 m_InitialSize; // Initial size of MetaData with values: code:CorMetaDataInitialSize.
CorLocalRefPreservation m_LocalRefPreservation; // Preserve module-local refs instead of optimizing them to defs
}; // struct OptionValue
//*********************************************************************
//
// Helper class to ensure calling UTSemReadWrite correctly.
// The destructor will call the correct UnlockRead or UnlockWrite depends what lock it is holding.
// User should use macro defined in below instead of calling functions on this class directly.
// They are LOCKREAD(), LOCKWRITE(), and CONVERT_READ_TO_WRITE_LOCK.
//
//*********************************************************************
class CMDSemReadWrite
{
public:
CMDSemReadWrite(UTSemReadWrite *pSem);
~CMDSemReadWrite();
HRESULT LockRead();
HRESULT LockWrite();
void UnlockWrite();
HRESULT ConvertReadLockToWriteLock();
private:
bool m_fLockedForRead;
bool m_fLockedForWrite;
UTSemReadWrite *m_pSem;
};
#define LOCKREADIFFAILRET() CMDSemReadWrite cSem(m_pSemReadWrite);\
IfFailRet(cSem.LockRead());
#define LOCKWRITEIFFAILRET() CMDSemReadWrite cSem(m_pSemReadWrite);\
IfFailRet(cSem.LockWrite());
#define LOCKREADNORET() CMDSemReadWrite cSem(m_pSemReadWrite);\
hr = cSem.LockRead();
#define LOCKWRITENORET() CMDSemReadWrite cSem(m_pSemReadWrite);\
hr = cSem.LockWrite();
#define LOCKREAD() CMDSemReadWrite cSem(m_pSemReadWrite);\
IfFailGo(cSem.LockRead());
#define LOCKWRITE() CMDSemReadWrite cSem(m_pSemReadWrite);\
IfFailGo(cSem.LockWrite());
#define UNLOCKWRITE() cSem.UnlockWrite();
#define CONVERT_READ_TO_WRITE_LOCK() IfFailGo(cSem.ConvertReadLockToWriteLock());
#endif // __RWUtil__h__