1// Licensed to the .NET Foundation under one or more agreements.
2// The .NET Foundation licenses this file to you under the MIT license.
3// See the LICENSE file in the project root for more information.
4//
5// File: RegMeta_IMetaDataImport.cpp
6//
7
8//
9// Some methods of code:RegMeta class which implement public API interfaces:
10// * code:IMetaDataEmit
11// * code:IMetaDataEmit2
12//
13// ======================================================================================
14
15#include "stdafx.h"
16#include "regmeta.h"
17#include "metadata.h"
18#include "corerror.h"
19#include "mdutil.h"
20#include "rwutil.h"
21#include "mdlog.h"
22#include "importhelper.h"
23#include "filtermanager.h"
24#include "mdperf.h"
25#include "switches.h"
26#include "posterror.h"
27#include "stgio.h"
28#include "sstring.h"
29
30#include <metamodelrw.h>
31
32#define DEFINE_CUSTOM_NODUPCHECK 1
33#define DEFINE_CUSTOM_DUPCHECK 2
34#define SET_CUSTOM 3
35
36#if defined(_DEBUG) && defined(_TRACE_REMAPS)
37#define LOGGING
38#endif
39#include <log.h>
40
41#ifdef _MSC_VER
42#pragma warning(disable: 4102)
43#endif
44
45#ifdef FEATURE_METADATA_EMIT
46
47//*****************************************************************************
48// Set module properties on a scope.
49//*****************************************************************************
50STDMETHODIMP RegMeta::SetModuleProps( // S_OK or error.
51 LPCWSTR szName) // [IN] If not NULL, the name to set.
52{
53 HRESULT hr = S_OK;
54
55 BEGIN_ENTRYPOINT_NOTHROW;
56
57 ModuleRec *pModule; // The module record to modify.
58
59 LOG((LOGMD, "RegMeta::SetModuleProps(%S)\n", MDSTR(szName)));
60
61
62 START_MD_PERF()
63 LOCKWRITE();
64
65 IfFailGo(m_pStgdb->m_MiniMd.PreUpdate());
66
67 IfFailGo(m_pStgdb->m_MiniMd.GetModuleRecord(1, &pModule));
68 if (szName != NULL)
69 {
70 LPCWSTR szFile = NULL;
71 size_t cchFile;
72
73 SplitPathInterior(szName, NULL, 0, NULL, 0, &szFile, &cchFile, NULL, 0);
74 IfFailGo(m_pStgdb->m_MiniMd.PutStringW(TBL_Module, ModuleRec::COL_Name, pModule, szFile));
75 }
76
77 IfFailGo(UpdateENCLog(TokenFromRid(1, mdtModule)));
78
79ErrExit:
80
81 STOP_MD_PERF(SetModuleProps);
82 END_ENTRYPOINT_NOTHROW;
83
84 return hr;
85} // STDMETHODIMP RegMeta::SetModuleProps()
86
87//*****************************************************************************
88// Saves a scope to a file of a given name.
89//*****************************************************************************
90STDMETHODIMP RegMeta::Save( // S_OK or error.
91 LPCWSTR szFile, // [IN] The filename to save to.
92 DWORD dwSaveFlags) // [IN] Flags for the save.
93{
94 HRESULT hr=S_OK;
95
96 BEGIN_ENTRYPOINT_NOTHROW;
97
98 LOG((LOGMD, "RegMeta::Save(%S, 0x%08x)\n", MDSTR(szFile), dwSaveFlags));
99 START_MD_PERF()
100 LOCKWRITE();
101
102 // Check reserved param..
103 if (dwSaveFlags != 0)
104 IfFailGo (E_INVALIDARG);
105 IfFailGo(PreSave());
106 IfFailGo(m_pStgdb->Save(szFile, dwSaveFlags));
107
108 // Reset m_bSaveOptimized, this is to handle the incremental and ENC
109 // scenerios where one may do multiple saves.
110 _ASSERTE(m_bSaveOptimized && !m_pStgdb->m_MiniMd.IsPreSaveDone());
111 m_bSaveOptimized = false;
112
113#if defined(_DEBUG)
114 if (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_MD_RegMetaDump))
115 {
116 int DumpMD_impl(RegMeta *pMD);
117 DumpMD_impl(this);
118 }
119#endif // _DEBUG
120
121ErrExit:
122
123 STOP_MD_PERF(Save);
124 END_ENTRYPOINT_NOTHROW;
125
126 return hr;
127} // STDMETHODIMP RegMeta::Save()
128
129//*****************************************************************************
130// Saves a scope to a stream.
131//*****************************************************************************
132STDMETHODIMP RegMeta::SaveToStream( // S_OK or error.
133 IStream *pIStream, // [IN] A writable stream to save to.
134 DWORD dwSaveFlags) // [IN] Flags for the save.
135{
136 HRESULT hr=S_OK;
137
138 BEGIN_ENTRYPOINT_NOTHROW;
139
140 LOCKWRITE();
141
142 LOG((LOGMD, "RegMeta::SaveToStream(0x%08x, 0x%08x)\n", pIStream, dwSaveFlags));
143 START_MD_PERF()
144
145 IfFailGo(m_pStgdb->m_MiniMd.PreUpdate());
146
147 hr = _SaveToStream(pIStream, dwSaveFlags);
148
149 STOP_MD_PERF(SaveToStream);
150
151#if defined(_DEBUG)
152 if (CLRConfig::GetConfigValue(CLRConfig::INTERNAL_MD_RegMetaDump))
153 {
154 int DumpMD_impl(RegMeta *pMD);
155 DumpMD_impl(this);
156 }
157#endif // _DEBUG
158
159ErrExit:
160
161 END_ENTRYPOINT_NOTHROW;
162
163 return hr;
164} // STDMETHODIMP RegMeta::SaveToStream()
165
166//*****************************************************************************
167// Saves a scope to a stream.
168//*****************************************************************************
169HRESULT RegMeta::_SaveToStream( // S_OK or error.
170 IStream *pIStream, // [IN] A writable stream to save to.
171 DWORD dwSaveFlags) // [IN] Flags for the save.
172{
173 HRESULT hr=S_OK;
174
175 IfFailGo(PreSave());
176 IfFailGo( m_pStgdb->SaveToStream(pIStream, m_ReorderingOptions, m_pCorProfileData) );
177
178 // Reset m_bSaveOptimized, this is to handle the incremental and ENC
179 // scenerios where one may do multiple saves.
180 _ASSERTE(m_bSaveOptimized && !m_pStgdb->m_MiniMd.IsPreSaveDone());
181 m_bSaveOptimized = false;
182
183ErrExit:
184
185 return hr;
186} // STDMETHODIMP RegMeta::_SaveToStream()
187
188//*****************************************************************************
189// Saves a copy of the scope into the memory buffer provided. The buffer size
190// must be at least as large as the GetSaveSize value.
191//*****************************************************************************
192STDMETHODIMP RegMeta::SaveToMemory( // S_OK or error.
193 void *pbData, // [OUT] Location to write data.
194 ULONG cbData) // [IN] Max size of data buffer.
195{
196 HRESULT hr;
197
198 BEGIN_ENTRYPOINT_NOTHROW;
199
200 IStream *pStream = 0; // Working pointer for save.
201
202 LOG((LOGMD, "MD RegMeta::SaveToMemory(0x%08x, 0x%08x)\n",
203 pbData, cbData));
204 START_MD_PERF();
205
206#ifdef _DEBUG
207 ULONG cbActual; // Size of the real data.
208 IfFailGo(GetSaveSize(cssAccurate, &cbActual));
209 _ASSERTE(cbData >= cbActual);
210#endif
211
212 { // cannot lock before the debug statement. Because GetSaveSize is also a public API which will take the Write lock.
213 LOCKWRITE();
214 IfFailGo(m_pStgdb->m_MiniMd.PreUpdate());
215 // Create a stream interface on top of the user's data buffer, then simply
216 // call the save to stream method.
217 IfFailGo(CInMemoryStream::CreateStreamOnMemory(pbData, cbData, &pStream));
218 IfFailGo(_SaveToStream(pStream, 0));
219 }
220ErrExit:
221 if (pStream)
222 pStream->Release();
223 STOP_MD_PERF(SaveToMemory);
224 END_ENTRYPOINT_NOTHROW;
225
226 return (hr);
227} // STDMETHODIMP RegMeta::SaveToMemory()
228
229//*****************************************************************************
230// As the Stgdb object to get the save size for the scope.
231//*****************************************************************************
232STDMETHODIMP RegMeta::GetSaveSize( // S_OK or error.
233 CorSaveSize fSave, // [IN] cssAccurate or cssQuick.
234 DWORD *pdwSaveSize) // [OUT] Put the size here.
235{
236 HRESULT hr=S_OK;
237
238 BEGIN_ENTRYPOINT_NOTHROW;
239
240 FilterTable *ft = NULL;
241
242 LOG((LOGMD, "RegMeta::GetSaveSize(0x%08x, 0x%08x)\n", fSave, pdwSaveSize));
243 START_MD_PERF();
244 LOCKWRITE();
245
246 ft = m_pStgdb->m_MiniMd.GetFilterTable();
247 IfNullGo(ft);
248
249 if (m_pStgdb->m_MiniMd.m_UserStringHeap.GetUnalignedSize() == 0)
250 {
251 if (!IsENCDelta(m_pStgdb->m_MiniMd.m_OptionValue.m_UpdateMode) &&
252 !m_pStgdb->m_MiniMd.IsMinimalDelta())
253 {
254 BYTE rgData[] = {' ', 0, 0};
255 UINT32 nIndex;
256 IfFailGo(m_pStgdb->m_MiniMd.PutUserString(
257 MetaData::DataBlob(rgData, sizeof(rgData)),
258 &nIndex));
259 // Make sure this user string is marked
260 if (ft->Count() != 0)
261 {
262 IfFailGo( m_pFilterManager->MarkNewUserString(TokenFromRid(nIndex, mdtString)));
263 }
264 }
265 }
266
267
268 if (ft->Count() != 0)
269 {
270 int iCount;
271
272 // There is filter table. Linker is using /opt:ref.
273 // Make sure that we are marking the AssemblyDef token!
274 iCount = m_pStgdb->m_MiniMd.getCountAssemblys();
275 _ASSERTE(iCount <= 1);
276
277 if (iCount)
278 {
279 IfFailGo(m_pFilterManager->Mark(TokenFromRid(iCount, mdtAssembly)));
280 }
281 }
282
283 IfFailGo(PreSave());
284
285 hr = m_pStgdb->GetSaveSize(fSave, (UINT32 *)pdwSaveSize, m_ReorderingOptions, m_pCorProfileData);
286
287ErrExit:
288 STOP_MD_PERF(GetSaveSize);
289
290 END_ENTRYPOINT_NOTHROW;
291
292 return hr;
293} // RegMeta::GetSaveSize
294
295#ifdef FEATURE_METADATA_EMIT_ALL
296
297//*****************************************************************************
298// Unmark everything in this module
299//
300// Implements public API code:IMetaDataFilter::UnmarkAll.
301//*****************************************************************************
302HRESULT RegMeta::UnmarkAll()
303{
304 HRESULT hr = S_OK;
305
306 BEGIN_ENTRYPOINT_NOTHROW;
307 int i;
308 int iCount;
309 TypeDefRec *pRec;
310 ULONG ulEncloser;
311 NestedClassRec *pNestedClass;
312 CustomAttributeRec *pCARec;
313 mdToken tkParent;
314 int iStart, iEnd;
315
316 LOG((LOGMD, "RegMeta::UnmarkAll\n"));
317
318 START_MD_PERF();
319 LOCKWRITE();
320
321#if 0
322 // We cannot enable this check. Because our tests are depending on this.. Sigh..
323 if (m_pFilterManager != NULL)
324 {
325 // UnmarkAll has been called before
326 IfFailGo( META_E_HAS_UNMARKALL );
327 }
328#endif // 0
329
330 // calculate the TypeRef and TypeDef mapping here
331 //
332 IfFailGo( RefToDefOptimization() );
333
334 // unmark everything in the MiniMd.
335 IfFailGo( m_pStgdb->m_MiniMd.UnmarkAll() );
336
337 // instantiate the filter manager
338 m_pFilterManager = new (nothrow) FilterManager( &(m_pStgdb->m_MiniMd) );
339 IfNullGo( m_pFilterManager );
340
341 // Mark all public typedefs.
342 iCount = m_pStgdb->m_MiniMd.getCountTypeDefs();
343
344 // Mark all of the public TypeDef. We need to skip over the <Module> typedef
345 for (i = 2; i <= iCount; i++)
346 {
347 IfFailGo(m_pStgdb->m_MiniMd.GetTypeDefRecord(i, &pRec));
348 if (m_OptionValue.m_LinkerOption == MDNetModule)
349 {
350 // Client is asking us to keep private type as well.
351 IfFailGo( m_pFilterManager->Mark(TokenFromRid(i, mdtTypeDef)) );
352 }
353 else if (i != 1)
354 {
355 // when client is not set to MDNetModule, global functions/fields won't be keep by default
356 //
357 if (IsTdPublic(pRec->GetFlags()))
358 {
359 IfFailGo( m_pFilterManager->Mark(TokenFromRid(i, mdtTypeDef)) );
360 }
361 else if ( IsTdNestedPublic(pRec->GetFlags()) ||
362 IsTdNestedFamily(pRec->GetFlags()) ||
363 IsTdNestedFamORAssem(pRec->GetFlags()) )
364 {
365 // This nested class would potentially be visible outside, either
366 // directly or through inheritence. If the enclosing class is
367 // marked, this nested class must be marked.
368 //
369 IfFailGo(m_pStgdb->m_MiniMd.FindNestedClassHelper(TokenFromRid(i, mdtTypeDef), &ulEncloser));
370 _ASSERTE( !InvalidRid(ulEncloser) &&
371 "Bad metadata for nested type!" );
372 IfFailGo(m_pStgdb->m_MiniMd.GetNestedClassRecord(ulEncloser, &pNestedClass));
373 tkParent = m_pStgdb->m_MiniMd.getEnclosingClassOfNestedClass(pNestedClass);
374 if ( m_pStgdb->m_MiniMd.GetFilterTable()->IsTypeDefMarked(tkParent))
375 IfFailGo( m_pFilterManager->Mark(TokenFromRid(i, mdtTypeDef)) );
376 }
377 }
378 }
379
380 if (m_OptionValue.m_LinkerOption == MDNetModule)
381 {
382 // Mark global function if NetModule. We will not keep _Delete method.
383 IfFailGo(m_pStgdb->m_MiniMd.GetTypeDefRecord(1, &pRec));
384 iStart = m_pStgdb->m_MiniMd.getMethodListOfTypeDef(pRec);
385 IfFailGo(m_pStgdb->m_MiniMd.getEndMethodListOfTypeDef(1, (RID *)&iEnd));
386 for ( i = iStart; i < iEnd; i ++ )
387 {
388 RID rid;
389 MethodRec *pMethodRec;
390 IfFailGo(m_pStgdb->m_MiniMd.GetMethodRid(i, &rid));
391 IfFailGo(m_pStgdb->m_MiniMd.GetMethodRecord(rid, &pMethodRec));
392
393 // check the name
394 if (IsMdRTSpecialName(pMethodRec->GetFlags()))
395 {
396 LPCUTF8 szName;
397 IfFailGo(m_pStgdb->m_MiniMd.getNameOfMethod(pMethodRec, &szName));
398
399 // Only mark method if not a _Deleted method
400 if (strcmp(szName, COR_DELETED_NAME_A) != 0)
401 IfFailGo( m_pFilterManager->Mark( TokenFromRid( rid, mdtMethodDef) ) );
402 }
403 else
404 {
405 //
406 if (!IsMiForwardRef(pMethodRec->GetImplFlags()) ||
407 IsMiRuntime(pMethodRec->GetImplFlags()) ||
408 IsMdPinvokeImpl(pMethodRec->GetFlags()) )
409
410 IfFailGo( m_pFilterManager->Mark( TokenFromRid( rid, mdtMethodDef) ) );
411 }
412 }
413 }
414
415 // mark the module property
416 IfFailGo( m_pFilterManager->Mark(TokenFromRid(1, mdtModule)) );
417
418 // We will also keep all of the TypeRef that has any CustomAttribute hang off it.
419 iCount = m_pStgdb->m_MiniMd.getCountCustomAttributes();
420
421 // Mark all of the TypeRef used by CA's
422 for (i = 1; i <= iCount; i++)
423 {
424 IfFailGo(m_pStgdb->m_MiniMd.GetCustomAttributeRecord(i, &pCARec));
425 tkParent = m_pStgdb->m_MiniMd.getParentOfCustomAttribute(pCARec);
426 if (TypeFromToken(tkParent) == mdtTypeRef)
427 {
428 m_pFilterManager->Mark(tkParent);
429 }
430 }
431ErrExit:
432
433 STOP_MD_PERF(UnmarkAll);
434
435 END_ENTRYPOINT_NOTHROW;
436
437 return hr;
438} // RegMeta::UnmarkAll
439
440#endif //FEATURE_METADATA_EMIT_ALL
441
442//*****************************************************************************
443// Mark everything in this module
444//*****************************************************************************
445HRESULT RegMeta::MarkAll()
446{
447 HRESULT hr = NOERROR;
448
449 // mark everything in the MiniMd.
450 IfFailGo( m_pStgdb->m_MiniMd.MarkAll() );
451
452 // instantiate the filter manager if not instantiated
453 if (m_pFilterManager == NULL)
454 {
455 m_pFilterManager = new (nothrow) FilterManager( &(m_pStgdb->m_MiniMd) );
456 IfNullGo( m_pFilterManager );
457 }
458ErrExit:
459
460 return hr;
461} // HRESULT RegMeta::MarkAll
462
463#ifdef FEATURE_METADATA_EMIT_ALL
464
465//*****************************************************************************
466// Mark the transitive closure of a token
467//@todo GENERICS: What about GenericParam, MethodSpec?
468//
469// Implements public API code:IMetaDataFilter::MarkToken.
470//*****************************************************************************
471STDMETHODIMP RegMeta::MarkToken( // Return code.
472 mdToken tk) // [IN] token to be Marked
473{
474 HRESULT hr = NOERROR;
475
476 BEGIN_ENTRYPOINT_NOTHROW;
477
478 // LOG((LOGMD, "RegMeta::MarkToken(0x%08x)\n", tk));
479 START_MD_PERF();
480 LOCKWRITE();
481
482 if (m_pStgdb->m_MiniMd.GetFilterTable() == NULL || m_pFilterManager == NULL)
483 {
484 // UnmarkAll has not been called. Everything is considered marked.
485 // No need to do anything extra!
486 IfFailGo( META_E_MUST_CALL_UNMARKALL );
487 }
488
489 switch ( TypeFromToken(tk) )
490 {
491 case mdtTypeDef:
492 case mdtMethodDef:
493 case mdtFieldDef:
494 case mdtMemberRef:
495 case mdtTypeRef:
496 case mdtTypeSpec:
497 case mdtMethodSpec:
498 case mdtSignature:
499 case mdtString:
500#if _DEBUG
501 if (TypeFromToken(tk) == mdtTypeDef)
502 {
503 TypeDefRec *pType;
504 IfFailGo(m_pStgdb->m_MiniMd.GetTypeDefRecord(RidFromToken(tk), &pType));
505 LPCSTR szTypeDefName;
506 if (m_pStgdb->m_MiniMd.getNameOfTypeDef(pType, &szTypeDefName) == S_OK)
507 {
508 LOG((LOGMD, "MarkToken: Host is marking typetoken 0x%08x with name <%s>\n", tk, szTypeDefName));
509 }
510 }
511 else
512 if (TypeFromToken(tk) == mdtMethodDef)
513 {
514 MethodRec *pMeth;
515 IfFailGo(m_pStgdb->m_MiniMd.GetMethodRecord(RidFromToken(tk), &pMeth));
516 LPCSTR szMethodName;
517 if (m_pStgdb->m_MiniMd.getNameOfMethod(pMeth, &szMethodName) == S_OK)
518 {
519 LOG((LOGMD, "MarkToken: Host is marking methodtoken 0x%08x with name <%s>\n", tk, szMethodName));
520 }
521 }
522 else
523 if (TypeFromToken(tk) == mdtFieldDef)
524 {
525 FieldRec *pField;
526 IfFailGo(m_pStgdb->m_MiniMd.GetFieldRecord(RidFromToken(tk), &pField));
527 LPCSTR szFieldName;
528 if (m_pStgdb->m_MiniMd.getNameOfField(pField, &szFieldName) == S_OK)
529 {
530 LOG((LOGMD, "MarkToken: Host is marking field token 0x%08x with name <%s>\n", tk, szFieldName));
531 }
532 }
533 else
534 {
535 LOG((LOGMD, "MarkToken: Host is marking token 0x%08x\n", tk));
536 }
537#endif // _DEBUG
538 if (!IsValidToken(tk))
539 IfFailGo( E_INVALIDARG );
540
541 IfFailGo( m_pFilterManager->Mark(tk) );
542 break;
543
544 case mdtBaseType:
545 // no need to mark base type
546 goto ErrExit;
547
548 default:
549 _ASSERTE(!"Bad token type!");
550 hr = E_INVALIDARG;
551 break;
552 }
553ErrExit:
554
555 STOP_MD_PERF(MarkToken);
556 END_ENTRYPOINT_NOTHROW;
557
558 return hr;
559} // RegMeta::MarkToken
560
561//*****************************************************************************
562// Unmark everything in this module
563//@todo GENERICS: What about GenericParam, MethodSpec?
564//
565// Implements public API code:IMetaDataFilter::IsTokenMarked.
566//*****************************************************************************
567HRESULT RegMeta::IsTokenMarked(
568 mdToken tk, // [IN] Token to check if marked or not
569 BOOL *pIsMarked) // [OUT] true if token is marked
570{
571 HRESULT hr = S_OK;
572
573 BEGIN_ENTRYPOINT_NOTHROW;
574
575 FilterTable *pFilter = NULL;
576
577 LOG((LOGMD, "RegMeta::IsTokenMarked(0x%08x)\n", tk));
578 START_MD_PERF();
579 LOCKREAD();
580
581 pFilter = m_pStgdb->m_MiniMd.GetFilterTable();
582 IfNullGo( pFilter );
583
584 if (!IsValidToken(tk))
585 IfFailGo( E_INVALIDARG );
586
587 switch ( TypeFromToken(tk) )
588 {
589 case mdtTypeRef:
590 *pIsMarked = pFilter->IsTypeRefMarked(tk);
591 break;
592 case mdtTypeDef:
593 *pIsMarked = pFilter->IsTypeDefMarked(tk);
594 break;
595 case mdtFieldDef:
596 *pIsMarked = pFilter->IsFieldMarked(tk);
597 break;
598 case mdtMethodDef:
599 *pIsMarked = pFilter->IsMethodMarked(tk);
600 break;
601 case mdtParamDef:
602 *pIsMarked = pFilter->IsParamMarked(tk);
603 break;
604 case mdtMemberRef:
605 *pIsMarked = pFilter->IsMemberRefMarked(tk);
606 break;
607 case mdtCustomAttribute:
608 *pIsMarked = pFilter->IsCustomAttributeMarked(tk);
609 break;
610 case mdtPermission:
611 *pIsMarked = pFilter->IsDeclSecurityMarked(tk);
612 break;
613 case mdtSignature:
614 *pIsMarked = pFilter->IsSignatureMarked(tk);
615 break;
616 case mdtEvent:
617 *pIsMarked = pFilter->IsEventMarked(tk);
618 break;
619 case mdtProperty:
620 *pIsMarked = pFilter->IsPropertyMarked(tk);
621 break;
622 case mdtModuleRef:
623 *pIsMarked = pFilter->IsModuleRefMarked(tk);
624 break;
625 case mdtTypeSpec:
626 *pIsMarked = pFilter->IsTypeSpecMarked(tk);
627 break;
628 case mdtInterfaceImpl:
629 *pIsMarked = pFilter->IsInterfaceImplMarked(tk);
630 break;
631 case mdtString:
632 default:
633 _ASSERTE(!"Bad token type!");
634 hr = E_INVALIDARG;
635 break;
636 }
637ErrExit:
638
639 STOP_MD_PERF(IsTokenMarked);
640 END_ENTRYPOINT_NOTHROW;
641
642 return hr;
643} // RegMeta::IsTokenMarked
644
645#endif //FEATURE_METADATA_EMIT_ALL
646
647//*****************************************************************************
648// Create and populate a new TypeDef record.
649//*****************************************************************************
650STDMETHODIMP RegMeta::DefineTypeDef( // S_OK or error.
651 LPCWSTR szTypeDef, // [IN] Name of TypeDef
652 DWORD dwTypeDefFlags, // [IN] CustomAttribute flags
653 mdToken tkExtends, // [IN] extends this TypeDef or typeref
654 mdToken rtkImplements[], // [IN] Implements interfaces
655 mdTypeDef *ptd) // [OUT] Put TypeDef token here
656{
657 HRESULT hr = S_OK; // A result.
658
659 BEGIN_ENTRYPOINT_NOTHROW;
660
661 LOG((LOGMD, "RegMeta::DefineTypeDef(%S, 0x%08x, 0x%08x, 0x%08x, 0x%08x)\n",
662 MDSTR(szTypeDef), dwTypeDefFlags, tkExtends,
663 rtkImplements, ptd));
664 START_MD_PERF();
665 LOCKWRITE();
666
667 IfFailGo(m_pStgdb->m_MiniMd.PreUpdate());
668
669 _ASSERTE(!IsTdNested(dwTypeDefFlags));
670
671 IfFailGo(_DefineTypeDef(szTypeDef, dwTypeDefFlags,
672 tkExtends, rtkImplements, mdTokenNil, ptd));
673ErrExit:
674 STOP_MD_PERF(DefineTypeDef);
675
676 END_ENTRYPOINT_NOTHROW;
677
678 return hr;
679} // STDMETHODIMP RegMeta::DefineTypeDef()
680
681
682//*****************************************************************************
683// Implements public API code:IMetaDataFilter::SetHandler.
684//*****************************************************************************
685STDMETHODIMP RegMeta::SetHandler( // S_OK.
686 IUnknown *pUnk) // [IN] The new error handler.
687{
688 HRESULT hr = S_OK; // A result.
689
690 BEGIN_ENTRYPOINT_NOTHROW;
691
692 IMapToken *pIMap = NULL;
693
694 LOG((LOGMD, "RegMeta::SetHandler(0x%08x)\n", pUnk));
695 START_MD_PERF();
696 LOCKWRITE();
697
698 m_pHandler = pUnk;
699
700 // Ignore the error return by SetHandler
701 IfFailGo(m_pStgdb->m_MiniMd.SetHandler(pUnk));
702
703 // Figure out up front if remap is supported.
704 if (pUnk)
705 pUnk->QueryInterface(IID_IMapToken, (PVOID *) &pIMap);
706 m_bRemap = (pIMap != 0);
707 if (pIMap)
708 pIMap->Release();
709
710ErrExit:
711
712 STOP_MD_PERF(SetHandler);
713 END_ENTRYPOINT_NOTHROW;
714
715 return hr;
716} // STDMETHODIMP RegMeta::SetHandler()
717
718//*******************************************************************************
719// Internal helper functions.
720//*******************************************************************************
721
722//*******************************************************************************
723// Perform optimizations of the metadata prior to saving.
724//*******************************************************************************
725HRESULT RegMeta::PreSave() // Return code.
726{
727 HRESULT hr = S_OK; // A result.
728 CMiniMdRW *pMiniMd; // The MiniMd with the data.
729 unsigned bRemapOld = m_bRemap;
730
731 // For convenience.
732 pMiniMd = &(m_pStgdb->m_MiniMd);
733
734 IfFailGo(m_pStgdb->m_MiniMd.PreUpdate());
735
736 // If the code has already been optimized there is nothing to do.
737 if (m_bSaveOptimized)
738 goto ErrExit;
739
740 IfFailGo(RefToDefOptimization());
741
742 // we need to update MethodImpl table here with ref to def result
743 if (pMiniMd->GetMemberRefToMemberDefMap() != NULL)
744 {
745 MethodImplRec *pMethodImplRec;
746 mdToken tkMethodBody;
747 mdToken tkMethodDecl;
748 mdToken newTK;
749 ULONG cMethodImplRecs; // Count of MemberRefs.
750 ULONG iMI;
751
752 cMethodImplRecs = pMiniMd->getCountMethodImpls();
753 // Enum through all member ref's looking for ref's to internal things.
754 for (iMI = 1; iMI <= cMethodImplRecs; iMI++)
755 { // Get a MethodImpl.
756 IfFailGo(pMiniMd->GetMethodImplRecord(iMI, &pMethodImplRec));
757 tkMethodBody = pMiniMd->getMethodBodyOfMethodImpl(pMethodImplRec);
758 if (TypeFromToken(tkMethodBody) == mdtMemberRef)
759 {
760 // did it get remapped to a def
761 newTK = *(pMiniMd->GetMemberRefToMemberDefMap()->Get(RidFromToken(tkMethodBody)));
762 if (!IsNilToken(newTK))
763 {
764 // yes... fix up the value...
765 IfFailGo(m_pStgdb->m_MiniMd.PutToken(TBL_MethodImpl,
766 MethodImplRec::COL_MethodBody,
767 pMethodImplRec,
768 newTK));
769 }
770 }
771 // do the same thing for MethodDecl
772 tkMethodDecl = pMiniMd->getMethodDeclarationOfMethodImpl(pMethodImplRec);
773 if (TypeFromToken(tkMethodDecl) == mdtMemberRef)
774 {
775 // did it get remapped to a def
776 newTK = *(pMiniMd->GetMemberRefToMemberDefMap()->Get(RidFromToken(tkMethodDecl)));
777 if (!IsNilToken(newTK))
778 {
779 // yes... fix up the value...
780 IfFailGo(m_pStgdb->m_MiniMd.PutToken(TBL_MethodImpl,
781 MethodImplRec::COL_MethodDeclaration,
782 pMethodImplRec,
783 newTK));
784 }
785 }
786 }
787 }
788
789 // reget the minimd because it can be swapped in the call of ProcessFilter
790 pMiniMd = &(m_pStgdb->m_MiniMd);
791
792 // Don't repeat this process again.
793 m_bSaveOptimized = true;
794
795 // call get save size to trigger the PreSaveXXX on MetaModelRW class.
796 IfFailGo(m_pStgdb->m_MiniMd.PreSave(m_ReorderingOptions, m_pCorProfileData));
797
798ErrExit:
799 m_bRemap = bRemapOld;
800
801 return hr;
802} // RegMeta::PreSave
803
804//*******************************************************************************
805// Perform optimizations of ref to def
806//*******************************************************************************
807HRESULT RegMeta::RefToDefOptimization()
808{
809 mdToken mfdef; // Method or Field Def.
810 LPCSTR szName; // MemberRef or TypeRef name.
811 const COR_SIGNATURE *pvSig; // Signature of the MemberRef.
812 ULONG cbSig; // Size of the signature blob.
813 HRESULT hr = S_OK; // A result.
814 ULONG iMR; // For iterating MemberRefs.
815 CMiniMdRW *pMiniMd; // The MiniMd with the data.
816 ULONG cMemberRefRecs; // Count of MemberRefs.
817 MemberRefRec *pMemberRefRec; // A MemberRefRec.
818
819
820
821 START_MD_PERF();
822
823 // the Ref to Def map is still up-to-date
824 if (IsMemberDefDirty() == false && IsTypeDefDirty() == false && m_hasOptimizedRefToDef == true)
825 goto ErrExit;
826
827 pMiniMd = &(m_pStgdb->m_MiniMd);
828
829 // The basic algorithm here is:
830 //
831 // calculate all of the TypeRef to TypeDef map and store it at TypeRefToTypeDefMap
832 // for each MemberRef mr
833 // {
834 // get the parent of mr
835 // if (parent of mr is a TypeRef and has been mapped to a TypeDef)
836 // {
837 // Remap MemberRef to MemberDef
838 // }
839 // }
840 //
841 // There are several places where errors are eaten, since this whole thing is
842 // an optimization step and not doing it would still be valid.
843 //
844
845 // Ensure the size
846 // initialize the token remap manager. This class will track all of the Refs to Defs map and also
847 // token movements due to removing pointer tables or sorting.
848 //
849 if ( pMiniMd->GetTokenRemapManager() == NULL)
850 {
851
852 IfFailGo( pMiniMd->InitTokenRemapManager() );
853 }
854 else
855 {
856 IfFailGo( pMiniMd->GetTokenRemapManager()->ClearAndEnsureCapacity(pMiniMd->getCountTypeRefs(), pMiniMd->getCountMemberRefs()));
857 }
858
859 // If this is the first time or more TypeDef has been introduced, recalculate the TypeRef to TypeDef map
860 if (IsTypeDefDirty() || m_hasOptimizedRefToDef == false)
861 {
862 IfFailGo( pMiniMd->CalculateTypeRefToTypeDefMap() );
863 }
864
865 // If this is the first time or more memberdefs has been introduced, recalculate the TypeRef to TypeDef map
866 if (IsMemberDefDirty() || m_hasOptimizedRefToDef == false)
867 {
868 mdToken tkParent;
869 cMemberRefRecs = pMiniMd->getCountMemberRefs();
870
871 // Enum through all member ref's looking for ref's to internal things.
872 for (iMR = 1; iMR<=cMemberRefRecs; iMR++)
873 { // Get a MemberRef.
874 IfFailGo(pMiniMd->GetMemberRefRecord(iMR, &pMemberRefRec));
875
876 // If not member of the TypeRef, skip it.
877 tkParent = pMiniMd->getClassOfMemberRef(pMemberRefRec);
878
879 if ( TypeFromToken(tkParent) == mdtMethodDef )
880 {
881 // always track the map even though it is already in the original scope
882 *(pMiniMd->GetMemberRefToMemberDefMap()->Get(iMR)) = tkParent;
883 continue;
884 }
885
886 if ( TypeFromToken(tkParent) != mdtTypeRef && TypeFromToken(tkParent) != mdtTypeDef )
887 {
888 // this has been either optimized to mdtMethodDef, mdtFieldDef or referring to
889 // ModuleRef
890 continue;
891 }
892
893 // In the case of global function, we have tkParent as m_tdModule.
894 // We will always do the optmization.
895 if (TypeFromToken(tkParent) == mdtTypeRef)
896 {
897 // If we're preserving local typerefs, skip this token
898 if (PreserveLocalRefs(MDPreserveLocalTypeRef))
899 {
900 continue;
901 }
902
903 // The parent is a TypeRef. We need to check to see if this TypeRef is optimized to a TypeDef
904 tkParent = *(pMiniMd->GetTypeRefToTypeDefMap()->Get(RidFromToken(tkParent)) );
905 // tkParent = pMapTypeRefToTypeDef[RidFromToken(tkParent)];
906 if ( RidFromToken(tkParent) == 0)
907 {
908 continue;
909 }
910 }
911
912 // If we're preserving local memberrefs, skip this token
913 if (PreserveLocalRefs(MDPreserveLocalMemberRef))
914 {
915 continue;
916 }
917
918 // Get the name and signature of this mr.
919 IfFailGo(pMiniMd->getNameOfMemberRef(pMemberRefRec, &szName));
920 IfFailGo(pMiniMd->getSignatureOfMemberRef(pMemberRefRec, &pvSig, &cbSig));
921
922 // Look for a member with the same def. Might not be found if it is
923 // inherited from a base class.
924 //<TODO>@future: this should support inheritence checking.
925 // Look for a member with the same name and signature.</TODO>
926 hr = ImportHelper::FindMember(pMiniMd, tkParent, szName, pvSig, cbSig, &mfdef);
927 if (hr != S_OK)
928 {
929 #if _TRACE_REMAPS
930 // Log the failure.
931 LOG((LF_METADATA, LL_INFO10, "Member %S//%S.%S not found\n", szNamespace, szTDName, rcMRName));
932 #endif
933 continue;
934 }
935
936 // We will only record this if mfdef is a methoddef. We don't support
937 // parent of MemberRef as fielddef. As if we can optimize MemberRef to FieldDef,
938 // we can remove this row.
939 //
940 if ( (TypeFromToken(mfdef) == mdtMethodDef) &&
941 (m_bRemap || tkParent == m_tdModule ) )
942 {
943 // Always change the parent if it is the global function.
944 // Or change the parent if we have a remap that we can send notification.
945 //
946 IfFailGo(pMiniMd->PutToken(TBL_MemberRef, MemberRefRec::COL_Class, pMemberRefRec, mfdef));
947 }
948
949 // We will always track the changes. In MiniMd::PreSaveFull, we will use this map to send
950 // notification to our host if there is any IMapToken provided.
951 //
952 *(pMiniMd->GetMemberRefToMemberDefMap()->Get(iMR)) = mfdef;
953
954 } // EnumMemberRefs
955 }
956
957 // Reset return code from likely search failures.
958 hr = S_OK;
959
960 SetMemberDefDirty(false);
961 SetTypeDefDirty(false);
962 m_hasOptimizedRefToDef = true;
963ErrExit:
964 STOP_MD_PERF(RefToDefOptimization);
965
966 return hr;
967} // RegMeta::RefToDefOptimization
968
969//*****************************************************************************
970// Define a TypeRef given the fully qualified name.
971//*****************************************************************************
972HRESULT RegMeta::_DefineTypeRef(
973 mdToken tkResolutionScope, // [IN] ModuleRef or AssemblyRef.
974 const void *szName, // [IN] Name of the TypeRef.
975 BOOL isUnicode, // [IN] Specifies whether the URL is unicode.
976 mdTypeRef *ptk, // [OUT] Put mdTypeRef here.
977 eCheckDups eCheck) // [IN] Specifies whether to check for duplicates.
978{
979 HRESULT hr = S_OK;
980 LPUTF8 szUTF8FullQualName;
981 CQuickBytes qbNamespace;
982 CQuickBytes qbName;
983 int bSuccess;
984 ULONG ulStringLen;
985
986
987
988
989 _ASSERTE(ptk && szName);
990 _ASSERTE (TypeFromToken(tkResolutionScope) == mdtModule ||
991 TypeFromToken(tkResolutionScope) == mdtModuleRef ||
992 TypeFromToken(tkResolutionScope) == mdtAssemblyRef ||
993 TypeFromToken(tkResolutionScope) == mdtTypeRef ||
994 tkResolutionScope == mdTokenNil);
995
996 if (isUnicode)
997 {
998 UTF8STR((LPCWSTR)szName, szUTF8FullQualName);
999 }
1000 else
1001 {
1002 szUTF8FullQualName = (LPUTF8)szName;
1003 }
1004 PREFIX_ASSUME(szUTF8FullQualName != NULL);
1005
1006 ulStringLen = (ULONG)(strlen(szUTF8FullQualName) + 1);
1007 IfFailGo(qbNamespace.ReSizeNoThrow(ulStringLen));
1008 IfFailGo(qbName.ReSizeNoThrow(ulStringLen));
1009 bSuccess = ns::SplitPath(szUTF8FullQualName,
1010 (LPUTF8)qbNamespace.Ptr(),
1011 ulStringLen,
1012 (LPUTF8)qbName.Ptr(),
1013 ulStringLen);
1014 _ASSERTE(bSuccess);
1015
1016 // Search for existing TypeRef record.
1017 if (eCheck==eCheckYes || (eCheck==eCheckDefault && CheckDups(MDDupTypeRef)))
1018 {
1019 hr = ImportHelper::FindTypeRefByName(&(m_pStgdb->m_MiniMd), tkResolutionScope,
1020 (LPCUTF8)qbNamespace.Ptr(),
1021 (LPCUTF8)qbName.Ptr(), ptk);
1022 if (SUCCEEDED(hr))
1023 {
1024 if (IsENCOn())
1025 {
1026 hr = S_OK;
1027 goto NormalExit;
1028 }
1029 else
1030 {
1031 hr = META_S_DUPLICATE;
1032 goto NormalExit;
1033 }
1034 }
1035 else if (hr != CLDB_E_RECORD_NOTFOUND)
1036 IfFailGo(hr);
1037 }
1038
1039 // Create TypeRef record.
1040 TypeRefRec *pRecord;
1041 RID iRecord;
1042
1043 IfFailGo(m_pStgdb->m_MiniMd.AddTypeRefRecord(&pRecord, &iRecord));
1044
1045 // record the more defs are introduced.
1046 SetTypeDefDirty(true);
1047
1048 // Give token back to caller.
1049 *ptk = TokenFromRid(iRecord, mdtTypeRef);
1050
1051 // Set the fields of the TypeRef record.
1052 IfFailGo(m_pStgdb->m_MiniMd.PutString(TBL_TypeRef, TypeRefRec::COL_Namespace,
1053 pRecord, (LPUTF8)qbNamespace.Ptr()));
1054
1055 IfFailGo(m_pStgdb->m_MiniMd.PutString(TBL_TypeRef, TypeRefRec::COL_Name,
1056 pRecord, (LPUTF8)qbName.Ptr()));
1057
1058 if (!IsNilToken(tkResolutionScope))
1059 IfFailGo(m_pStgdb->m_MiniMd.PutToken(TBL_TypeRef, TypeRefRec::COL_ResolutionScope,
1060 pRecord, tkResolutionScope));
1061 IfFailGo(UpdateENCLog(*ptk));
1062
1063 // Hash the name.
1064 IfFailGo(m_pStgdb->m_MiniMd.AddNamedItemToHash(TBL_TypeRef, *ptk, (LPUTF8)qbName.Ptr(), 0));
1065
1066ErrExit:
1067 ;
1068NormalExit:
1069
1070 return hr;
1071} // HRESULT RegMeta::_DefineTypeRef()
1072
1073//*******************************************************************************
1074// Define MethodSemantics
1075//*******************************************************************************
1076HRESULT RegMeta::_DefineMethodSemantics( // S_OK or error.
1077 USHORT usAttr, // [IN] CorMethodSemanticsAttr.
1078 mdMethodDef md, // [IN] Method.
1079 mdToken tkAssoc, // [IN] Association.
1080 BOOL bClear) // [IN] Specifies whether to delete the exisiting entries.
1081{
1082 HRESULT hr = S_OK;
1083 MethodSemanticsRec *pRecord = 0;
1084 MethodSemanticsRec *pRecord1; // Use this to recycle a MethodSemantics record.
1085 RID iRecord;
1086 HENUMInternal hEnum;
1087
1088
1089
1090 _ASSERTE(TypeFromToken(md) == mdtMethodDef || IsNilToken(md));
1091 _ASSERTE(RidFromToken(tkAssoc));
1092 memset(&hEnum, 0, sizeof(HENUMInternal));
1093
1094 // Clear all matching records by setting association to a Nil token.
1095 if (bClear)
1096 {
1097 RID i;
1098
1099 IfFailGo( m_pStgdb->m_MiniMd.FindMethodSemanticsHelper(tkAssoc, &hEnum) );
1100 while (HENUMInternal::EnumNext(&hEnum, (mdToken *)&i))
1101 {
1102 IfFailGo(m_pStgdb->m_MiniMd.GetMethodSemanticsRecord(i, &pRecord1));
1103 if (usAttr == pRecord1->GetSemantic())
1104 {
1105 pRecord = pRecord1;
1106 iRecord = i;
1107 IfFailGo(m_pStgdb->m_MiniMd.PutToken(TBL_MethodSemantics,
1108 MethodSemanticsRec::COL_Association, pRecord, mdPropertyNil));
1109 // In Whidbey, we should create ENC log record here.
1110 }
1111 }
1112 }
1113 // If setting (not just clearing) the association, do that now.
1114 if (!IsNilToken(md))
1115 {
1116 // Create a new record required
1117 if (pRecord == NULL)
1118 {
1119 IfFailGo(m_pStgdb->m_MiniMd.AddMethodSemanticsRecord(&pRecord, &iRecord));
1120 }
1121
1122 // Save the data.
1123 pRecord->SetSemantic(usAttr);
1124 IfFailGo(m_pStgdb->m_MiniMd.PutToken(TBL_MethodSemantics,
1125 MethodSemanticsRec::COL_Method, pRecord, md));
1126 IfFailGo(m_pStgdb->m_MiniMd.PutToken(TBL_MethodSemantics,
1127 MethodSemanticsRec::COL_Association, pRecord, tkAssoc));
1128
1129 // regardless if we reuse the record or create the record, add the MethodSemantics to the hash
1130 IfFailGo( m_pStgdb->m_MiniMd.AddMethodSemanticsToHash(iRecord) );
1131
1132 // Create log record for non-token table.
1133 IfFailGo(UpdateENCLog2(TBL_MethodSemantics, iRecord));
1134 }
1135
1136ErrExit:
1137 HENUMInternal::ClearEnum(&hEnum);
1138
1139 return hr;
1140} // HRESULT RegMeta::_DefineMethodSemantics()
1141
1142//*******************************************************************************
1143// Turn the specified internal flags on.
1144//*******************************************************************************
1145HRESULT RegMeta::_TurnInternalFlagsOn( // S_OK or error.
1146 mdToken tkObj, // [IN] Target object whose internal flags are targetted.
1147 DWORD flags) // [IN] Specifies flags to be turned on.
1148{
1149 HRESULT hr;
1150 MethodRec *pMethodRec;
1151 FieldRec *pFieldRec;
1152 TypeDefRec *pTypeDefRec;
1153
1154 switch (TypeFromToken(tkObj))
1155 {
1156 case mdtMethodDef:
1157 IfFailRet(m_pStgdb->m_MiniMd.GetMethodRecord(RidFromToken(tkObj), &pMethodRec));
1158 pMethodRec->AddFlags(flags);
1159 break;
1160 case mdtFieldDef:
1161 IfFailRet(m_pStgdb->m_MiniMd.GetFieldRecord(RidFromToken(tkObj), &pFieldRec));
1162 pFieldRec->AddFlags(flags);
1163 break;
1164 case mdtTypeDef:
1165 IfFailRet(m_pStgdb->m_MiniMd.GetTypeDefRecord(RidFromToken(tkObj), &pTypeDefRec));
1166 pTypeDefRec->AddFlags(flags);
1167 break;
1168 default:
1169 _ASSERTE(!"Not supported token type!");
1170 return E_INVALIDARG;
1171 }
1172 return S_OK;
1173} // RegMeta::_TurnInternalFlagsOn
1174
1175//*****************************************************************************
1176// Helper: Set the properties on the given TypeDef token.
1177//*****************************************************************************
1178HRESULT RegMeta::_SetTypeDefProps( // S_OK or error.
1179 mdTypeDef td, // [IN] The TypeDef.
1180 DWORD dwTypeDefFlags, // [IN] TypeDef flags.
1181 mdToken tkExtends, // [IN] Base TypeDef or TypeRef.
1182 mdToken rtkImplements[]) // [IN] Implemented interfaces.
1183{
1184 HRESULT hr = S_OK; // A result.
1185 BOOL bClear = IsENCOn() || IsCallerExternal(); // Specifies whether to clear the InterfaceImpl records.
1186 TypeDefRec *pRecord; // New TypeDef record.
1187
1188 _ASSERTE(TypeFromToken(td) == mdtTypeDef);
1189 _ASSERTE(TypeFromToken(tkExtends) == mdtTypeDef || TypeFromToken(tkExtends) == mdtTypeRef || TypeFromToken(tkExtends) == mdtTypeSpec ||
1190 IsNilToken(tkExtends) || tkExtends == ULONG_MAX);
1191
1192 // Get the record.
1193 IfFailGo(m_pStgdb->m_MiniMd.GetTypeDefRecord(RidFromToken(td), &pRecord));
1194
1195 if (dwTypeDefFlags != ULONG_MAX)
1196 {
1197 // No one should try to set the reserved flags explicitly.
1198 _ASSERTE((dwTypeDefFlags & (tdReservedMask&~tdRTSpecialName)) == 0);
1199 // Clear the reserved flags from the flags passed in.
1200 dwTypeDefFlags &= (~tdReservedMask);
1201 // Preserve the reserved flags stored.
1202 dwTypeDefFlags |= (pRecord->GetFlags() & tdReservedMask);
1203 // Set the flags.
1204 pRecord->SetFlags(dwTypeDefFlags);
1205 }
1206 if (tkExtends != ULONG_MAX)
1207 {
1208 if (IsNilToken(tkExtends))
1209 tkExtends = mdTypeDefNil;
1210 IfFailGo(m_pStgdb->m_MiniMd.PutToken(TBL_TypeDef, TypeDefRec::COL_Extends,
1211 pRecord, tkExtends));
1212 }
1213
1214 // Implemented interfaces.
1215 if (rtkImplements)
1216 IfFailGo(_SetImplements(rtkImplements, td, bClear));
1217
1218 IfFailGo(UpdateENCLog(td));
1219ErrExit:
1220 return hr;
1221} // HRESULT RegMeta::_SetTypeDefProps()
1222
1223//******************************************************************************
1224// Creates and sets a row in the InterfaceImpl table. Optionally clear
1225// pre-existing records for the owning class.
1226//******************************************************************************
1227HRESULT RegMeta::_SetImplements( // S_OK or error.
1228 mdToken rTk[], // Array of TypeRef or TypeDef or TypeSpec tokens for implemented interfaces.
1229 mdTypeDef td, // Implementing TypeDef.
1230 BOOL bClear) // Specifies whether to clear the existing records.
1231{
1232 HRESULT hr = S_OK;
1233 ULONG i = 0;
1234 ULONG j;
1235 InterfaceImplRec *pInterfaceImpl;
1236 RID iInterfaceImpl;
1237 RID ridStart;
1238 RID ridEnd;
1239 CQuickBytes cqbTk;
1240 const mdToken *pTk;
1241 bool fIsTableVirtualSortValid;
1242
1243
1244 _ASSERTE(TypeFromToken(td) == mdtTypeDef && rTk);
1245 _ASSERTE(!m_bSaveOptimized && "Cannot change records after PreSave() and before Save().");
1246
1247 // Clear all exising InterfaceImpl records by setting the parent to Nil.
1248 if (bClear)
1249 {
1250 IfFailGo(m_pStgdb->m_MiniMd.GetInterfaceImplsForTypeDef(
1251 RidFromToken(td), &ridStart, &ridEnd));
1252 for (j = ridStart; j < ridEnd; j++)
1253 {
1254 IfFailGo(m_pStgdb->m_MiniMd.GetInterfaceImplRecord(
1255 m_pStgdb->m_MiniMd.GetInterfaceImplRid(j),
1256 &pInterfaceImpl));
1257 _ASSERTE (td == m_pStgdb->m_MiniMd.getClassOfInterfaceImpl(pInterfaceImpl));
1258 IfFailGo(m_pStgdb->m_MiniMd.PutToken(TBL_InterfaceImpl, InterfaceImplRec::COL_Class,
1259 pInterfaceImpl, mdTypeDefNil));
1260 }
1261 }
1262
1263 // Eliminate duplicates from the array passed in.
1264 if (CheckDups(MDDupInterfaceImpl))
1265 {
1266 IfFailGo(_InterfaceImplDupProc(rTk, td, &cqbTk));
1267 pTk = (mdToken *)cqbTk.Ptr();
1268 }
1269 else
1270 pTk = rTk;
1271
1272 // Get the state of InterfaceImpl table's VirtualSort
1273 fIsTableVirtualSortValid = m_pStgdb->m_MiniMd.IsTableVirtualSorted(TBL_InterfaceImpl);
1274 // Loop for each implemented interface.
1275 while (!IsNilToken(pTk[i]))
1276 {
1277 _ASSERTE(TypeFromToken(pTk[i]) == mdtTypeRef || TypeFromToken(pTk[i]) == mdtTypeDef
1278 || TypeFromToken(pTk[i]) == mdtTypeSpec);
1279
1280 // Create the interface implementation record.
1281 IfFailGo(m_pStgdb->m_MiniMd.AddInterfaceImplRecord(&pInterfaceImpl, &iInterfaceImpl));
1282
1283 // Set data.
1284 IfFailGo(m_pStgdb->m_MiniMd.PutToken(TBL_InterfaceImpl, InterfaceImplRec::COL_Class,
1285 pInterfaceImpl, td));
1286 IfFailGo(m_pStgdb->m_MiniMd.PutToken(TBL_InterfaceImpl, InterfaceImplRec::COL_Interface,
1287 pInterfaceImpl, pTk[i]));
1288 // Had the table valid VirtualSort?
1289 if (fIsTableVirtualSortValid)
1290 { // Validate table's VistualSort after adding 1 record and store its
1291 // new validation state
1292 IfFailGo(m_pStgdb->m_MiniMd.ValidateVirtualSortAfterAddRecord(
1293 TBL_InterfaceImpl,
1294 &fIsTableVirtualSortValid));
1295 }
1296
1297 i++;
1298
1299 IfFailGo(UpdateENCLog(TokenFromRid(mdtInterfaceImpl, iInterfaceImpl)));
1300 }
1301ErrExit:
1302
1303 return hr;
1304} // HRESULT RegMeta::_SetImplements()
1305
1306//******************************************************************************
1307// This routine eliminates duplicates from the given list of InterfaceImpl tokens
1308// to be defined. It checks for duplicates against the database only if the
1309// TypeDef for which these tokens are being defined is not a new one.
1310//******************************************************************************
1311HRESULT RegMeta::_InterfaceImplDupProc( // S_OK or error.
1312 mdToken rTk[], // Array of TypeRef or TypeDef or TypeSpec tokens for implemented interfaces.
1313 mdTypeDef td, // Implementing TypeDef.
1314 CQuickBytes *pcqbTk) // Quick Byte object for placing the array of unique tokens.
1315{
1316 HRESULT hr = S_OK;
1317 ULONG i = 0;
1318 ULONG iUniqCount = 0;
1319 BOOL bDupFound;
1320
1321 while (!IsNilToken(rTk[i]))
1322 {
1323 _ASSERTE(TypeFromToken(rTk[i]) == mdtTypeRef || TypeFromToken(rTk[i]) == mdtTypeDef
1324 || TypeFromToken(rTk[i]) == mdtTypeSpec);
1325 bDupFound = false;
1326
1327 // Eliminate duplicates from the input list of tokens by looking within the list.
1328 for (ULONG j = 0; j < iUniqCount; j++)
1329 {
1330 if (rTk[i] == ((mdToken *)pcqbTk->Ptr())[j])
1331 {
1332 bDupFound = true;
1333 break;
1334 }
1335 }
1336
1337 // If no duplicate is found record it in the list.
1338 if (!bDupFound)
1339 {
1340 IfFailGo(pcqbTk->ReSizeNoThrow((iUniqCount+1) * sizeof(mdToken)));
1341 ((mdToken *)pcqbTk->Ptr())[iUniqCount] = rTk[i];
1342 iUniqCount++;
1343 }
1344 i++;
1345 }
1346
1347 // Create a Nil token to signify the end of list.
1348 IfFailGo(pcqbTk->ReSizeNoThrow((iUniqCount+1) * sizeof(mdToken)));
1349 ((mdToken *)pcqbTk->Ptr())[iUniqCount] = mdTokenNil;
1350ErrExit:
1351
1352 return hr;
1353} // HRESULT RegMeta::_InterfaceImplDupProc()
1354
1355//*******************************************************************************
1356// helper to define event
1357//*******************************************************************************
1358HRESULT RegMeta::_DefineEvent( // Return hresult.
1359 mdTypeDef td, // [IN] the class/interface on which the event is being defined
1360 LPCWSTR szEvent, // [IN] Name of the event
1361 DWORD dwEventFlags, // [IN] CorEventAttr
1362 mdToken tkEventType, // [IN] a reference (mdTypeRef or mdTypeRef) to the Event class
1363 mdEvent *pmdEvent) // [OUT] output event token
1364{
1365 HRESULT hr = S_OK;
1366 EventRec *pEventRec = NULL;
1367 RID iEventRec;
1368 EventMapRec *pEventMap;
1369 RID iEventMap;
1370 mdEvent mdEv;
1371 LPUTF8 szUTF8Event;
1372 UTF8STR(szEvent, szUTF8Event);
1373 PREFIX_ASSUME(szUTF8Event != NULL);
1374
1375
1376
1377 _ASSERTE(TypeFromToken(td) == mdtTypeDef && td != mdTypeDefNil);
1378 _ASSERTE(IsNilToken(tkEventType) || TypeFromToken(tkEventType) == mdtTypeDef ||
1379 TypeFromToken(tkEventType) == mdtTypeRef || TypeFromToken(tkEventType) == mdtTypeSpec);
1380 _ASSERTE(szEvent && pmdEvent);
1381
1382 if (CheckDups(MDDupEvent))
1383 {
1384 hr = ImportHelper::FindEvent(&(m_pStgdb->m_MiniMd), td, szUTF8Event, pmdEvent);
1385 if (SUCCEEDED(hr))
1386 {
1387 if (IsENCOn())
1388 IfFailGo(m_pStgdb->m_MiniMd.GetEventRecord(RidFromToken(*pmdEvent), &pEventRec));
1389 else
1390 {
1391 hr = META_S_DUPLICATE;
1392 goto ErrExit;
1393 }
1394 }
1395 else if (hr != CLDB_E_RECORD_NOTFOUND)
1396 IfFailGo(hr);
1397 }
1398
1399 if (! pEventRec)
1400 {
1401 // Create a new map if one doesn't exist already, else retrieve the existing one.
1402 // The event map must be created before the EventRecord, the new event map will
1403 // be pointing past the first event record.
1404 IfFailGo(m_pStgdb->m_MiniMd.FindEventMapFor(RidFromToken(td), &iEventMap));
1405 if (InvalidRid(iEventMap))
1406 {
1407 // Create new record.
1408 IfFailGo(m_pStgdb->m_MiniMd.AddEventMapRecord(&pEventMap, &iEventMap));
1409 // Set parent.
1410 IfFailGo(m_pStgdb->m_MiniMd.PutToken(TBL_EventMap,
1411 EventMapRec::COL_Parent, pEventMap, td));
1412 IfFailGo(UpdateENCLog2(TBL_EventMap, iEventMap));
1413 }
1414 else
1415 {
1416 IfFailGo(m_pStgdb->m_MiniMd.GetEventMapRecord(iEventMap, &pEventMap));
1417 }
1418
1419 // Create a new event record.
1420 IfFailGo(m_pStgdb->m_MiniMd.AddEventRecord(&pEventRec, &iEventRec));
1421
1422 // Set output parameter.
1423 *pmdEvent = TokenFromRid(iEventRec, mdtEvent);
1424
1425 // Add Event to EventMap.
1426 IfFailGo(m_pStgdb->m_MiniMd.AddEventToEventMap(RidFromToken(iEventMap), iEventRec));
1427
1428 IfFailGo(UpdateENCLog2(TBL_EventMap, iEventMap, CMiniMdRW::eDeltaEventCreate));
1429 }
1430
1431 mdEv = *pmdEvent;
1432
1433 // Set data
1434 IfFailGo(m_pStgdb->m_MiniMd.PutString(TBL_Event, EventRec::COL_Name, pEventRec, szUTF8Event));
1435 IfFailGo(_SetEventProps1(*pmdEvent, dwEventFlags, tkEventType));
1436
1437 // Add the <Event token, typedef token> to the lookup table
1438 if (m_pStgdb->m_MiniMd.HasIndirectTable(TBL_Event))
1439 IfFailGo( m_pStgdb->m_MiniMd.AddEventToLookUpTable(*pmdEvent, td) );
1440
1441 IfFailGo(UpdateENCLog(*pmdEvent));
1442
1443ErrExit:
1444
1445 return hr;
1446} // HRESULT RegMeta::_DefineEvent()
1447
1448
1449//******************************************************************************
1450// Set the specified properties on the Event Token.
1451//******************************************************************************
1452HRESULT RegMeta::_SetEventProps1( // Return hresult.
1453 mdEvent ev, // [IN] Event token.
1454 DWORD dwEventFlags, // [IN] Event flags.
1455 mdToken tkEventType) // [IN] Event type class.
1456{
1457 EventRec *pRecord;
1458 HRESULT hr = S_OK;
1459
1460 _ASSERTE(TypeFromToken(ev) == mdtEvent && RidFromToken(ev));
1461
1462 IfFailGo(m_pStgdb->m_MiniMd.GetEventRecord(RidFromToken(ev), &pRecord));
1463 if (dwEventFlags != ULONG_MAX)
1464 {
1465 // Don't let caller set reserved bits
1466 dwEventFlags &= ~evReservedMask;
1467 // Preserve reserved bits.
1468 dwEventFlags |= (pRecord->GetEventFlags() & evReservedMask);
1469
1470 pRecord->SetEventFlags(static_cast<USHORT>(dwEventFlags));
1471 }
1472 if (!IsNilToken(tkEventType))
1473 IfFailGo(m_pStgdb->m_MiniMd.PutToken(TBL_Event, EventRec::COL_EventType,
1474 pRecord, tkEventType));
1475ErrExit:
1476 return hr;
1477} // HRESULT RegMeta::_SetEventProps1()
1478
1479//******************************************************************************
1480// Set the specified properties on the given Event token.
1481//******************************************************************************
1482HRESULT RegMeta::_SetEventProps2( // Return hresult.
1483 mdEvent ev, // [IN] Event token.
1484 mdMethodDef mdAddOn, // [IN] Add method.
1485 mdMethodDef mdRemoveOn, // [IN] Remove method.
1486 mdMethodDef mdFire, // [IN] Fire method.
1487 mdMethodDef rmdOtherMethods[], // [IN] An array of other methods.
1488 BOOL bClear) // [IN] Specifies whether to clear the existing MethodSemantics records.
1489{
1490 EventRec *pRecord;
1491 HRESULT hr = S_OK;
1492
1493
1494
1495 _ASSERTE(TypeFromToken(ev) == mdtEvent && RidFromToken(ev));
1496
1497 IfFailGo(m_pStgdb->m_MiniMd.GetEventRecord(RidFromToken(ev), &pRecord));
1498
1499 // Remember the AddOn method.
1500 if (!IsNilToken(mdAddOn))
1501 {
1502 _ASSERTE(TypeFromToken(mdAddOn) == mdtMethodDef);
1503 IfFailGo(_DefineMethodSemantics(msAddOn, mdAddOn, ev, bClear));
1504 }
1505
1506 // Remember the RemoveOn method.
1507 if (!IsNilToken(mdRemoveOn))
1508 {
1509 _ASSERTE(TypeFromToken(mdRemoveOn) == mdtMethodDef);
1510 IfFailGo(_DefineMethodSemantics(msRemoveOn, mdRemoveOn, ev, bClear));
1511 }
1512
1513 // Remember the fire method.
1514 if (!IsNilToken(mdFire))
1515 {
1516 _ASSERTE(TypeFromToken(mdFire) == mdtMethodDef);
1517 IfFailGo(_DefineMethodSemantics(msFire, mdFire, ev, bClear));
1518 }
1519
1520 // Store all of the other methods.
1521 if (rmdOtherMethods)
1522 {
1523 int i = 0;
1524 mdMethodDef mb;
1525
1526 while (1)
1527 {
1528 mb = rmdOtherMethods[i++];
1529 if (IsNilToken(mb))
1530 break;
1531 _ASSERTE(TypeFromToken(mb) == mdtMethodDef);
1532 IfFailGo(_DefineMethodSemantics(msOther, mb, ev, bClear));
1533
1534 // The first call would've cleared all the existing ones.
1535 bClear = false;
1536 }
1537 }
1538ErrExit:
1539
1540 return hr;
1541} // HRESULT RegMeta::_SetEventProps2()
1542
1543//******************************************************************************
1544// Set Permission on the given permission token.
1545//******************************************************************************
1546HRESULT RegMeta::_SetPermissionSetProps( // Return hresult.
1547 mdPermission tkPerm, // [IN] Permission token.
1548 DWORD dwAction, // [IN] CorDeclSecurity.
1549 void const *pvPermission, // [IN] Permission blob.
1550 ULONG cbPermission) // [IN] Count of bytes of pvPermission.
1551{
1552 DeclSecurityRec *pRecord;
1553 HRESULT hr = S_OK;
1554
1555 _ASSERTE(TypeFromToken(tkPerm) == mdtPermission && cbPermission != ULONG_MAX);
1556 _ASSERTE(dwAction && dwAction <= dclMaximumValue);
1557
1558 IfFailGo(m_pStgdb->m_MiniMd.GetDeclSecurityRecord(RidFromToken(tkPerm), &pRecord));
1559
1560 IfFailGo(m_pStgdb->m_MiniMd.PutBlob(TBL_DeclSecurity, DeclSecurityRec::COL_PermissionSet,
1561 pRecord, pvPermission, cbPermission));
1562ErrExit:
1563 return hr;
1564} // HRESULT RegMeta::_SetPermissionSetProps()
1565
1566//******************************************************************************
1567// Define or set value on a constant record.
1568//******************************************************************************
1569HRESULT RegMeta::_DefineSetConstant( // Return hresult.
1570 mdToken tk, // [IN] Parent token.
1571 DWORD dwCPlusTypeFlag, // [IN] Flag for the value type, selected ELEMENT_TYPE_*
1572 void const *pValue, // [IN] Constant value.
1573 ULONG cchString, // [IN] Size of string in wide chars, or -1 for default.
1574 BOOL bSearch) // [IN] Specifies whether to search for an existing record.
1575{
1576 HRESULT hr = S_OK;
1577
1578
1579
1580 if ((dwCPlusTypeFlag != ELEMENT_TYPE_VOID && dwCPlusTypeFlag != ELEMENT_TYPE_END &&
1581 dwCPlusTypeFlag != ULONG_MAX) &&
1582 (pValue || (pValue == 0 && (dwCPlusTypeFlag == ELEMENT_TYPE_STRING ||
1583 dwCPlusTypeFlag == ELEMENT_TYPE_CLASS))))
1584 {
1585 ConstantRec *pConstRec = 0;
1586 RID iConstRec;
1587 ULONG cbBlob;
1588 ULONG ulValue = 0;
1589
1590 if (bSearch)
1591 {
1592 IfFailGo(m_pStgdb->m_MiniMd.FindConstantHelper(tk, &iConstRec));
1593 if (!InvalidRid(iConstRec))
1594 IfFailGo(m_pStgdb->m_MiniMd.GetConstantRecord(iConstRec, &pConstRec));
1595 }
1596 if (! pConstRec)
1597 {
1598 IfFailGo(m_pStgdb->m_MiniMd.AddConstantRecord(&pConstRec, &iConstRec));
1599 IfFailGo(m_pStgdb->m_MiniMd.PutToken(TBL_Constant, ConstantRec::COL_Parent,
1600 pConstRec, tk));
1601 IfFailGo( m_pStgdb->m_MiniMd.AddConstantToHash(iConstRec) );
1602 }
1603
1604 // Add values to the various columns of the constant value row.
1605 pConstRec->SetType(static_cast<BYTE>(dwCPlusTypeFlag));
1606 if (!pValue)
1607 pValue = &ulValue;
1608 cbBlob = _GetSizeOfConstantBlob(dwCPlusTypeFlag, (void *)pValue, cchString);
1609 if (cbBlob > 0)
1610 {
1611#if BIGENDIAN
1612 void *pValueTemp;
1613 pValueTemp = (void *)alloca(cbBlob);
1614 IfFailGo(m_pStgdb->m_MiniMd.SwapConstant(pValue, dwCPlusTypeFlag, pValueTemp, cbBlob));
1615 pValue = pValueTemp;
1616#endif
1617 IfFailGo(m_pStgdb->m_MiniMd.PutBlob(TBL_Constant, ConstantRec::COL_Value,
1618 pConstRec, pValue, cbBlob));
1619 }
1620
1621
1622 // Create log record for non-token record.
1623 IfFailGo(UpdateENCLog2(TBL_Constant, iConstRec));
1624 }
1625ErrExit:
1626
1627 return hr;
1628} // HRESULT RegMeta::_DefineSetConstant()
1629
1630
1631//*****************************************************************************
1632// Helper: Set the properties on the given Method token.
1633//*****************************************************************************
1634HRESULT RegMeta::_SetMethodProps( // S_OK or error.
1635 mdMethodDef md, // [IN] The MethodDef.
1636 DWORD dwMethodFlags, // [IN] Method attributes.
1637 ULONG ulCodeRVA, // [IN] Code RVA.
1638 DWORD dwImplFlags) // [IN] MethodImpl flags.
1639{
1640 MethodRec *pRecord;
1641 HRESULT hr = S_OK;
1642
1643 _ASSERTE(TypeFromToken(md) == mdtMethodDef && RidFromToken(md));
1644
1645 // Get the Method record.
1646 IfFailGo(m_pStgdb->m_MiniMd.GetMethodRecord(RidFromToken(md), &pRecord));
1647
1648 // Set the data.
1649 if (dwMethodFlags != ULONG_MAX)
1650 {
1651 // Preserve the reserved flags stored already and always keep the mdRTSpecialName
1652 dwMethodFlags |= (pRecord->GetFlags() & mdReservedMask);
1653
1654 // Set the flags.
1655 pRecord->SetFlags(static_cast<USHORT>(dwMethodFlags));
1656 }
1657 if (ulCodeRVA != ULONG_MAX)
1658 pRecord->SetRVA(ulCodeRVA);
1659 if (dwImplFlags != ULONG_MAX)
1660 pRecord->SetImplFlags(static_cast<USHORT>(dwImplFlags));
1661
1662 IfFailGo(UpdateENCLog(md));
1663ErrExit:
1664 return hr;
1665} // HRESULT RegMeta::_SetMethodProps()
1666
1667
1668//*****************************************************************************
1669// Helper: Set the properties on the given Field token.
1670//*****************************************************************************
1671HRESULT RegMeta::_SetFieldProps( // S_OK or error.
1672 mdFieldDef fd, // [IN] The FieldDef.
1673 DWORD dwFieldFlags, // [IN] Field attributes.
1674 DWORD dwCPlusTypeFlag, // [IN] Flag for the value type, selected ELEMENT_TYPE_*
1675 void const *pValue, // [IN] Constant value.
1676 ULONG cchValue) // [IN] size of constant value (string, in wide chars).
1677{
1678#ifdef FEATURE_METADATA_EMIT_IN_DEBUGGER
1679 return E_NOTIMPL;
1680#else //!FEATURE_METADATA_EMIT_IN_DEBUGGER
1681 FieldRec *pRecord;
1682 HRESULT hr = S_OK;
1683 int bHasDefault = false; // If defining a constant, in this call.
1684
1685 _ASSERTE (TypeFromToken(fd) == mdtFieldDef && RidFromToken(fd));
1686
1687 // Get the Field record.
1688 IfFailGo(m_pStgdb->m_MiniMd.GetFieldRecord(RidFromToken(fd), &pRecord));
1689
1690 // See if there is a Constant.
1691 if ((dwCPlusTypeFlag != ELEMENT_TYPE_VOID && dwCPlusTypeFlag != ELEMENT_TYPE_END &&
1692 dwCPlusTypeFlag != ULONG_MAX) &&
1693 (pValue || (pValue == 0 && (dwCPlusTypeFlag == ELEMENT_TYPE_STRING ||
1694 dwCPlusTypeFlag == ELEMENT_TYPE_CLASS))))
1695 {
1696 if (dwFieldFlags == ULONG_MAX)
1697 dwFieldFlags = pRecord->GetFlags();
1698 dwFieldFlags |= fdHasDefault;
1699
1700 bHasDefault = true;
1701 }
1702
1703 // Set the flags.
1704 if (dwFieldFlags != ULONG_MAX)
1705 {
1706 if ( IsFdHasFieldRVA(dwFieldFlags) && !IsFdHasFieldRVA(pRecord->GetFlags()) )
1707 {
1708 // This will trigger field RVA to be created if it is not yet created!
1709 _SetRVA(fd, 0, 0);
1710 }
1711
1712 // Preserve the reserved flags stored.
1713 dwFieldFlags |= (pRecord->GetFlags() & fdReservedMask);
1714 // Set the flags.
1715 pRecord->SetFlags(static_cast<USHORT>(dwFieldFlags));
1716 }
1717
1718 IfFailGo(UpdateENCLog(fd));
1719
1720 // Set the Constant.
1721 if (bHasDefault)
1722 {
1723 BOOL bSearch = IsCallerExternal() || IsENCOn();
1724 IfFailGo(_DefineSetConstant(fd, dwCPlusTypeFlag, pValue, cchValue, bSearch));
1725 }
1726
1727ErrExit:
1728 return hr;
1729#endif //!FEATURE_METADATA_EMIT_IN_DEBUGGER
1730} // RegMeta::_SetFieldProps
1731
1732//*****************************************************************************
1733// Helper: Set the properties on the given Property token.
1734//*****************************************************************************
1735HRESULT RegMeta::_SetPropertyProps( // S_OK or error.
1736 mdProperty pr, // [IN] Property token.
1737 DWORD dwPropFlags, // [IN] CorPropertyAttr.
1738 DWORD dwCPlusTypeFlag, // [IN] Flag for value type, selected ELEMENT_TYPE_*
1739 void const *pValue, // [IN] Constant value.
1740 ULONG cchValue, // [IN] size of constant value (string, in wide chars).
1741 mdMethodDef mdSetter, // [IN] Setter of the property.
1742 mdMethodDef mdGetter, // [IN] Getter of the property.
1743 mdMethodDef rmdOtherMethods[]) // [IN] Array of other methods.
1744{
1745 PropertyRec *pRecord;
1746 BOOL bClear = IsCallerExternal() || IsENCOn() || IsIncrementalOn();
1747 HRESULT hr = S_OK;
1748 int bHasDefault = false; // If true, constant value this call.
1749
1750
1751
1752 _ASSERTE(TypeFromToken(pr) == mdtProperty && RidFromToken(pr));
1753
1754 IfFailGo(m_pStgdb->m_MiniMd.GetPropertyRecord(RidFromToken(pr), &pRecord));
1755
1756 if (dwPropFlags != ULONG_MAX)
1757 {
1758 // Clear the reserved flags from the flags passed in.
1759 dwPropFlags &= (~prReservedMask);
1760 }
1761 // See if there is a constant.
1762 if ((dwCPlusTypeFlag != ELEMENT_TYPE_VOID && dwCPlusTypeFlag != ELEMENT_TYPE_END &&
1763 dwCPlusTypeFlag != ULONG_MAX) &&
1764 (pValue || (pValue == 0 && (dwCPlusTypeFlag == ELEMENT_TYPE_STRING ||
1765 dwCPlusTypeFlag == ELEMENT_TYPE_CLASS))))
1766 {
1767 if (dwPropFlags == ULONG_MAX)
1768 dwPropFlags = pRecord->GetPropFlags();
1769 dwPropFlags |= prHasDefault;
1770
1771 bHasDefault = true;
1772 }
1773 if (dwPropFlags != ULONG_MAX)
1774 {
1775 // Preserve the reserved flags.
1776 dwPropFlags |= (pRecord->GetPropFlags() & prReservedMask);
1777 // Set the flags.
1778 pRecord->SetPropFlags(static_cast<USHORT>(dwPropFlags));
1779 }
1780
1781 // store the getter (or clear out old one).
1782 if (mdGetter != ULONG_MAX)
1783 {
1784 _ASSERTE(TypeFromToken(mdGetter) == mdtMethodDef || IsNilToken(mdGetter));
1785 IfFailGo(_DefineMethodSemantics(msGetter, mdGetter, pr, bClear));
1786 }
1787
1788 // Store the setter (or clear out old one).
1789 if (mdSetter != ULONG_MAX)
1790 {
1791 _ASSERTE(TypeFromToken(mdSetter) == mdtMethodDef || IsNilToken(mdSetter));
1792 IfFailGo(_DefineMethodSemantics(msSetter, mdSetter, pr, bClear));
1793 }
1794
1795 // Store all of the other methods.
1796 if (rmdOtherMethods)
1797 {
1798 int i = 0;
1799 mdMethodDef mb;
1800
1801 while (1)
1802 {
1803 mb = rmdOtherMethods[i++];
1804 if (IsNilToken(mb))
1805 break;
1806 _ASSERTE(TypeFromToken(mb) == mdtMethodDef);
1807 IfFailGo(_DefineMethodSemantics(msOther, mb, pr, bClear));
1808
1809 // The first call to _DefineMethodSemantics would've cleared all the records
1810 // that match with msOther and pr.
1811 bClear = false;
1812 }
1813 }
1814
1815 IfFailGo(UpdateENCLog(pr));
1816
1817 // Set the constant.
1818 if (bHasDefault)
1819 {
1820 BOOL bSearch = IsCallerExternal() || IsENCOn() || IsIncrementalOn();
1821 IfFailGo(_DefineSetConstant(pr, dwCPlusTypeFlag, pValue, cchValue, bSearch));
1822 }
1823
1824ErrExit:
1825
1826 return hr;
1827} // HRESULT RegMeta::_SetPropertyProps()
1828
1829
1830//*****************************************************************************
1831// Helper: This routine sets properties on the given Param token.
1832//*****************************************************************************
1833HRESULT RegMeta::_SetParamProps( // Return code.
1834 mdParamDef pd, // [IN] Param token.
1835 LPCWSTR szName, // [IN] Param name.
1836 DWORD dwParamFlags, // [IN] Param flags.
1837 DWORD dwCPlusTypeFlag, // [IN] Flag for value type. selected ELEMENT_TYPE_*.
1838 void const *pValue, // [OUT] Constant value.
1839 ULONG cchValue) // [IN] size of constant value (string, in wide chars).
1840{
1841 HRESULT hr = S_OK;
1842 ParamRec *pRecord;
1843 int bHasDefault = false; // Is there a default for this call.
1844
1845 _ASSERTE(TypeFromToken(pd) == mdtParamDef && RidFromToken(pd));
1846
1847 IfFailGo(m_pStgdb->m_MiniMd.GetParamRecord(RidFromToken(pd), &pRecord));
1848
1849 // Set the properties.
1850 if (szName != NULL)
1851 {
1852 IfFailGo(m_pStgdb->m_MiniMd.PutStringW(TBL_Param, ParamRec::COL_Name, pRecord, szName));
1853 }
1854
1855 if (dwParamFlags != ULONG_MAX)
1856 {
1857 // No one should try to set the reserved flags explicitly.
1858 _ASSERTE((dwParamFlags & pdReservedMask) == 0);
1859 // Clear the reserved flags from the flags passed in.
1860 dwParamFlags &= (~pdReservedMask);
1861 }
1862 // See if there is a constant.
1863 if ((dwCPlusTypeFlag != ELEMENT_TYPE_VOID && dwCPlusTypeFlag != ELEMENT_TYPE_END &&
1864 dwCPlusTypeFlag != ULONG_MAX) &&
1865 (pValue || (pValue == 0 && (dwCPlusTypeFlag == ELEMENT_TYPE_STRING ||
1866 dwCPlusTypeFlag == ELEMENT_TYPE_CLASS))))
1867 {
1868 if (dwParamFlags == ULONG_MAX)
1869 dwParamFlags = pRecord->GetFlags();
1870 dwParamFlags |= pdHasDefault;
1871
1872 bHasDefault = true;
1873 }
1874 // Set the flags.
1875 if (dwParamFlags != ULONG_MAX)
1876 {
1877 // Preserve the reserved flags stored.
1878 dwParamFlags |= (pRecord->GetFlags() & pdReservedMask);
1879 // Set the flags.
1880 pRecord->SetFlags(static_cast<USHORT>(dwParamFlags));
1881 }
1882
1883 // ENC log for the param record.
1884 IfFailGo(UpdateENCLog(pd));
1885
1886 // Defer setting the constant until after the ENC log for the param. Due to the way that
1887 // parameter records are re-ordered, ENC needs the param record log entry to be IMMEDIATELY
1888 // after the param added function.
1889
1890 // Set the constant.
1891 if (bHasDefault)
1892 {
1893 BOOL bSearch = IsCallerExternal() || IsENCOn();
1894 IfFailGo(_DefineSetConstant(pd, dwCPlusTypeFlag, pValue, cchValue, bSearch));
1895 }
1896
1897ErrExit:
1898 return hr;
1899} // HRESULT RegMeta::_SetParamProps()
1900
1901//*****************************************************************************
1902// Create and populate a new TypeDef record.
1903//*****************************************************************************
1904HRESULT RegMeta::_DefineTypeDef( // S_OK or error.
1905 LPCWSTR szTypeDef, // [IN] Name of TypeDef
1906 DWORD dwTypeDefFlags, // [IN] CustomAttribute flags
1907 mdToken tkExtends, // [IN] extends this TypeDef or typeref
1908 mdToken rtkImplements[], // [IN] Implements interfaces
1909 mdTypeDef tdEncloser, // [IN] TypeDef token of the Enclosing Type.
1910 mdTypeDef *ptd) // [OUT] Put TypeDef token here
1911{
1912 HRESULT hr = S_OK; // A result.
1913 TypeDefRec *pRecord = NULL; // New TypeDef record.
1914 RID iRecord; // New TypeDef RID.
1915 CQuickBytes qbNamespace; // Namespace buffer.
1916 CQuickBytes qbName; // Name buffer.
1917 LPUTF8 szTypeDefUTF8; // Full name in UTF8.
1918 ULONG ulStringLen; // Length of the TypeDef string.
1919 int bSuccess; // Return value for SplitPath().
1920
1921
1922
1923 _ASSERTE(IsTdAutoLayout(dwTypeDefFlags) || IsTdSequentialLayout(dwTypeDefFlags) || IsTdExplicitLayout(dwTypeDefFlags));
1924
1925 _ASSERTE(ptd);
1926 _ASSERTE(TypeFromToken(tkExtends) == mdtTypeRef || TypeFromToken(tkExtends) == mdtTypeDef || TypeFromToken(tkExtends) == mdtTypeSpec
1927 || IsNilToken(tkExtends));
1928 _ASSERTE(szTypeDef && *szTypeDef);
1929 _ASSERTE(IsNilToken(tdEncloser) || IsTdNested(dwTypeDefFlags));
1930
1931 UTF8STR(szTypeDef, szTypeDefUTF8);
1932 PREFIX_ASSUME(szTypeDefUTF8 != NULL);
1933
1934 ulStringLen = (ULONG)(strlen(szTypeDefUTF8) + 1);
1935 IfFailGo(qbNamespace.ReSizeNoThrow(ulStringLen));
1936 IfFailGo(qbName.ReSizeNoThrow(ulStringLen));
1937 bSuccess = ns::SplitPath(szTypeDefUTF8,
1938 (LPUTF8)qbNamespace.Ptr(),
1939 ulStringLen,
1940 (LPUTF8)qbName.Ptr(),
1941 ulStringLen);
1942 _ASSERTE(bSuccess);
1943
1944 if (CheckDups(MDDupTypeDef))
1945 {
1946 // Check for existence. Do a query by namespace and name.
1947 hr = ImportHelper::FindTypeDefByName(&(m_pStgdb->m_MiniMd),
1948 (LPCUTF8)qbNamespace.Ptr(),
1949 (LPCUTF8)qbName.Ptr(),
1950 tdEncloser,
1951 ptd);
1952 if (SUCCEEDED(hr))
1953 {
1954 if (IsENCOn())
1955 {
1956 IfFailGo(m_pStgdb->m_MiniMd.GetTypeDefRecord(RidFromToken(*ptd), &pRecord));
1957 // <TODO>@FUTURE: Should we check to see if the GUID passed is correct?</TODO>
1958 }
1959 else
1960 {
1961 hr = META_S_DUPLICATE;
1962 goto ErrExit;
1963 }
1964 }
1965 else if (hr != CLDB_E_RECORD_NOTFOUND)
1966 IfFailGo(hr);
1967 }
1968
1969 if (!pRecord)
1970 {
1971 // Create the new record.
1972 IfFailGo(m_pStgdb->m_MiniMd.AddTypeDefRecord(&pRecord, &iRecord));
1973
1974 // Invalidate the ref to def optimization since more def is introduced
1975 SetTypeDefDirty(true);
1976
1977 if (!IsNilToken(tdEncloser))
1978 {
1979 NestedClassRec *pNestedClassRec;
1980 RID iNestedClassRec;
1981
1982 // Create a new NestedClass record.
1983 IfFailGo(m_pStgdb->m_MiniMd.AddNestedClassRecord(&pNestedClassRec, &iNestedClassRec));
1984 // Set the NestedClass value.
1985 IfFailGo(m_pStgdb->m_MiniMd.PutToken(TBL_NestedClass, NestedClassRec::COL_NestedClass,
1986 pNestedClassRec, TokenFromRid(iRecord, mdtTypeDef)));
1987 // Set the NestedClass value.
1988 IfFailGo(m_pStgdb->m_MiniMd.PutToken(TBL_NestedClass, NestedClassRec::COL_EnclosingClass,
1989 pNestedClassRec, tdEncloser));
1990
1991 IfFailGo( m_pStgdb->m_MiniMd.AddNestedClassToHash(iNestedClassRec) );
1992
1993 // Create the log record for the non-token record.
1994 IfFailGo(UpdateENCLog2(TBL_NestedClass, iNestedClassRec));
1995 }
1996
1997 // Give token back to caller.
1998 *ptd = TokenFromRid(iRecord, mdtTypeDef);
1999 }
2000
2001 // Set the namespace and name.
2002 IfFailGo(m_pStgdb->m_MiniMd.PutString(TBL_TypeDef, TypeDefRec::COL_Name,
2003 pRecord, (LPCUTF8)qbName.Ptr()));
2004 IfFailGo(m_pStgdb->m_MiniMd.PutString(TBL_TypeDef, TypeDefRec::COL_Namespace,
2005 pRecord, (LPCUTF8)qbNamespace.Ptr()));
2006
2007 SetCallerDefine();
2008 IfFailGo(_SetTypeDefProps(*ptd, dwTypeDefFlags, tkExtends, rtkImplements));
2009ErrExit:
2010 SetCallerExternal();
2011
2012 return hr;
2013} // RegMeta::_DefineTypeDef
2014
2015#endif //FEATURE_METADATA_EMIT
2016
2017#if defined(FEATURE_METADATA_IN_VM) && defined(FEATURE_PREJIT)
2018
2019//******************************************************************************
2020//--- IMetaDataCorProfileData
2021//******************************************************************************
2022
2023HRESULT RegMeta::SetCorProfileData(
2024 CorProfileData *pProfileData) // [IN] Pointer to profile data
2025{
2026 m_pCorProfileData = pProfileData;
2027
2028 return S_OK;
2029}
2030
2031//******************************************************************************
2032//--- IMDInternalMetadataReorderingOptions
2033//******************************************************************************
2034
2035HRESULT RegMeta::SetMetaDataReorderingOptions(
2036 MetaDataReorderingOptions options) // [IN] Metadata reordering options
2037{
2038 m_ReorderingOptions = options;
2039
2040 return S_OK;
2041}
2042
2043#endif //defined(FEATURE_METADATA_IN_VM) && defined(FEATURE_PREJIT)
2044