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: rstype.cpp
6//
7
8//
9// Define implementation of ICorDebugType
10//*****************************************************************************
11
12
13#include "stdafx.h"
14#include "winbase.h"
15#include "corpriv.h"
16
17
18//-----------------------------------------------------------------------------
19// Public method to get the static field from a type.
20//
21// Parameters:
22// fieldDef - metadata token for which field on this type to retrieve.
23// pFrame - context for Thread/AppDomains statics.
24// ppValue - OUT: out-parameter to get value.
25//
26// Returns:
27// S_OK on success.
28//
29HRESULT CordbType::GetStaticFieldValue(mdFieldDef fieldDef,
30 ICorDebugFrame * pFrame,
31 ICorDebugValue ** ppValue)
32{
33 PUBLIC_REENTRANT_API_ENTRY(this);
34 FAIL_IF_NEUTERED(this);
35 VALIDATE_POINTER_TO_OBJECT(ppValue, ICorDebugValue **);
36 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
37
38 HRESULT hr = S_OK;
39
40 IMetaDataImport * pImport = NULL;
41
42 EX_TRY
43 {
44 // Ensure we were actually passed a mdFieldDef. This is especially useful to protect
45 // against an accidental mdPropertyDef, because properties look like fields.
46 //
47 if (TypeFromToken(fieldDef) != mdtFieldDef)
48 {
49 ThrowHR(E_INVALIDARG);
50 }
51
52 pImport = m_pClass->GetModule()->GetMetaDataImporter(); // throws
53
54 if (((m_elementType != ELEMENT_TYPE_CLASS) && (m_elementType != ELEMENT_TYPE_VALUETYPE)) || (m_pClass == NULL))
55 {
56 ThrowHR(E_INVALIDARG);
57 }
58
59
60
61 BOOL fSyncBlockField = FALSE;
62
63 // If non generic type, then degenerate to CordbClass implementation.
64 if (m_inst.m_cInst == 0)
65 {
66 hr = m_pClass->GetStaticFieldValue(fieldDef, pFrame, ppValue);
67 }
68 else
69 {
70 *ppValue = NULL;
71
72 // Validate the token.
73 if (!pImport->IsValidToken(fieldDef))
74 {
75 ThrowHR(hr = E_INVALIDARG);
76 }
77
78 // Make sure we have enough info about the class.
79 hr = Init(FALSE);
80 IfFailThrow(hr);
81
82 // Lookup the field given its metadata token.
83 FieldData * pFieldData;
84
85 hr = GetFieldInfo(fieldDef, &pFieldData);
86
87 if (hr == CORDBG_E_ENC_HANGING_FIELD)
88 {
89 // Generics + EnC is Not supported.
90 hr = CORDBG_E_STATIC_VAR_NOT_AVAILABLE;
91 }
92
93 IfFailThrow(hr);
94
95 hr = CordbClass::GetStaticFieldValue2(m_pClass->GetModule(),
96 pFieldData,
97 fSyncBlockField,
98 &m_inst,
99 pFrame,
100 ppValue);
101 // fall through to translate HR
102 }
103
104 }
105 EX_CATCH_HRESULT(hr);
106 if (pImport != NULL)
107 {
108 hr = CordbClass::PostProcessUnavailableHRESULT(hr, pImport, fieldDef);
109 }
110 return hr;
111
112}
113
114// Combine E_T_s and rank together to get an id for the m_sharedtypes table
115#define CORDBTYPE_ID(elementType,rank) ((unsigned int) elementType * (rank + 1) + 1)
116
117
118//-----------------------------------------------------------------------------
119// Constructor
120// Builds a CordbType around a primitive.
121//-----------------------------------------------------------------------------
122CordbType::CordbType(CordbAppDomain *appdomain, CorElementType et, unsigned int rank)
123: CordbBase(appdomain->GetProcess(), CORDBTYPE_ID(et,rank) , enumCordbType),
124 m_elementType(et),
125 m_appdomain(appdomain),
126 m_pClass(NULL),
127 m_rank(rank),
128 m_spinetypes(2),
129 m_objectSize(0),
130 m_fieldInfoNeedsInit(TRUE)
131{
132 m_typeHandleExact = VMPTR_TypeHandle::NullPtr();
133
134 _ASSERTE(m_elementType != ELEMENT_TYPE_VALUETYPE);
135
136 HRESULT hr = S_OK;
137 EX_TRY
138 {
139 m_appdomain->AddToTypeList(this);
140 }
141 EX_CATCH_HRESULT(hr);
142 SetUnrecoverableIfFailed(GetProcess(), hr);
143}
144
145//-----------------------------------------------------------------------------
146// Constructor
147// Builds a CordbType around a class. This is an Open CordbType.
148// For a generic type, this CordbType will not have the generic parameters,
149// but it will be a subordinate type to another Closed (instantiated) CordbType
150//-----------------------------------------------------------------------------
151CordbType::CordbType(CordbAppDomain *appdomain, CorElementType et, CordbClass *cls)
152: CordbBase(appdomain->GetProcess(), et, enumCordbType),
153 m_elementType(et),
154 m_appdomain(appdomain),
155 m_pClass(cls),
156 m_rank(0),
157 m_spinetypes(2),
158 m_objectSize(0),
159 m_fieldInfoNeedsInit(TRUE)
160{
161 m_typeHandleExact = VMPTR_TypeHandle::NullPtr();
162 _ASSERTE(m_elementType != ELEMENT_TYPE_VALUETYPE);
163
164 HRESULT hr = S_OK;
165 EX_TRY
166 {
167 m_appdomain->AddToTypeList(this);
168 }
169 EX_CATCH_HRESULT(hr);
170 SetUnrecoverableIfFailed(GetProcess(), hr);
171}
172
173//-----------------------------------------------------------------------------
174// Constructor
175// Builds a Partial-Type, instantiation is tycon's instantation plus tyarg.
176// Eg, if tycon is "Dict<int>", and tyarg is "string", then this yields
177// "Dict<int, string>"
178//-----------------------------------------------------------------------------
179CordbType::CordbType(CordbType *tycon, CordbType *tyarg)
180: CordbBase(tycon->GetProcess(), (UINT_PTR)tyarg, enumCordbType),
181 m_elementType(tycon->m_elementType),
182 m_appdomain(tycon->m_appdomain),
183 m_pClass(tycon->m_pClass),
184 m_rank(tycon->m_rank),
185 m_spinetypes(2),
186 m_objectSize(0),
187 m_fieldInfoNeedsInit(TRUE)
188 // tyarg is added as part of instantiation -see below...
189{
190 m_typeHandleExact = VMPTR_TypeHandle::NullPtr();
191 _ASSERTE(m_elementType != ELEMENT_TYPE_VALUETYPE);
192
193 HRESULT hr = S_OK;
194 EX_TRY
195 {
196 m_appdomain->AddToTypeList(this);
197 }
198 EX_CATCH_HRESULT(hr);
199 SetUnrecoverableIfFailed(GetProcess(), hr);
200}
201
202
203ULONG STDMETHODCALLTYPE CordbType::AddRef()
204{
205 // This AddRef/Release pair creates a weak ref-counted reference to the class for this
206 // type. This avoids a circularity in ref-counted references between
207 // classes and types - if we had a circularity the objects would never get
208 // collected at all...
209 //if (m_class)
210 // m_class->AddRef();
211 return (BaseAddRef());
212}
213ULONG STDMETHODCALLTYPE CordbType::Release()
214{
215 // if (m_class)
216 // m_class->Release();
217 return (BaseRelease());
218}
219
220/*
221 A list of which resources owened by this object are accounted for.
222
223 HANDLED:
224 CordbClass *m_class; Weakly referenced by increasing count directly in AddRef() and Release()
225 Instantiation m_inst; // Internal pointers to CordbClass released in CordbClass::Neuter
226 CordbHashTable m_spinetypes; // Neutered
227 CordbHashTable m_fields; // Deleted in ~CordbType
228*/
229
230//-----------------------------------------------------------------------------
231// Cleanup memory for CordbTypes.
232//-----------------------------------------------------------------------------
233CordbType::~CordbType()
234{
235 _ASSERTE(IsNeutered());
236}
237
238//-----------------------------------------------------------------------------
239// Neutered by CordbModule
240// See CordbBase::Neuter for neuter semantics.
241//-----------------------------------------------------------------------------
242void CordbType::Neuter()
243{
244 _ASSERTE(GetProcess()->GetProcessLock()->HasLock());
245
246 // We have some direct releases below. If we call Neuter twice, that could
247 // result in double-releases. So check if we're already neutered, and
248 // if so, no work left to do.
249 if (IsNeutered())
250 {
251 return;
252 }
253
254 for (unsigned int i = 0; i < m_inst.m_cInst; i++)
255 {
256 m_inst.m_ppInst[i]->Release();
257 }
258
259 m_spinetypes.NeuterAndClear(GetProcess()->GetProcessLock());
260
261 if(m_inst.m_ppInst)
262 {
263 delete [] m_inst.m_ppInst;
264 m_inst.m_ppInst = NULL;
265 }
266 m_fieldList.Dealloc();
267
268 CordbBase::Neuter();
269}
270
271//-----------------------------------------------------------------------------
272// Public method for IUnknown::QueryInterface.
273// Has standard QI semantics.
274//-----------------------------------------------------------------------------
275HRESULT CordbType::QueryInterface(REFIID id, void **pInterface)
276{
277 if (id == IID_ICorDebugType)
278 *pInterface = static_cast<ICorDebugType*>(this);
279 else if (id == IID_ICorDebugType2)
280 *pInterface = static_cast<ICorDebugType2*>(this);
281 else if (id == IID_IUnknown)
282 *pInterface = static_cast<IUnknown*>(static_cast<ICorDebugType*>(this));
283 else
284 {
285 *pInterface = NULL;
286 return E_NOINTERFACE;
287 }
288
289 ExternalAddRef();
290 return S_OK;
291}
292
293
294//-----------------------------------------------------------------------------
295// Make a simple type with no type arguments by specifying a CorElementType,
296// e.g. ELEMENT_TYPE_I1
297//
298// CordbType's are effectively a full representation of
299// structured types. They are hashed via a combination of their constituent
300// elements (e.g. CordbClass's or CordbType's) and the element type that is used to
301// combine the elements, or if they have no elements then via
302// the element type alone. The following is used to create all CordbTypes.
303//
304// An AppDomain holds a cache of CordbTypes for each of the basic CorElementTypes.
305//
306// Arguments:
307// pAppDomain - the AppDomain that the type lives in.
308// elementType - element_type to create the CordbType around.
309// ppResultType - OUT: out-parameter to get the CordbType.
310//
311// Returns:
312// S_OK on success.
313//
314//
315HRESULT CordbType::MkType(CordbAppDomain * pAppDomain,
316 CorElementType elementType,
317 CordbType ** ppResultType)
318{
319 _ASSERTE(pAppDomain != NULL);
320 _ASSERTE(ppResultType != NULL);
321
322 RSLockHolder lockHolder(pAppDomain->GetProcess()->GetProcessLock());
323
324 // Some points in the code create types via element types that are clearly objects but where
325 // no further information is given. This is always done when creating a CordbValue, prior
326 // to actually going over to the EE to discover what kind of value it is. In all these
327 // cases we can just use the type for "Object" - the code for dereferencing the value
328 // will update the type correctly once it has been determined. We don't do this for ELEMENT_TYPE_STRING
329 // as that is actually a NullaryType and at other places in the code we will want exactly that type!
330 if ((elementType == ELEMENT_TYPE_CLASS) ||
331 (elementType == ELEMENT_TYPE_SZARRAY) ||
332 (elementType == ELEMENT_TYPE_ARRAY))
333 {
334 elementType = ELEMENT_TYPE_OBJECT;
335 }
336
337 switch (elementType)
338 {
339 // this one is included because we need a "seed" type to uniquely hash FNPTR types,
340 // i.e. the nullary FNPTR type is used as the type constructor for all function pointer types,
341 // when combined with an appropriate instantiation.
342 case ELEMENT_TYPE_FNPTR:
343 // fall through ...
344
345 case ELEMENT_TYPE_VOID:
346 case ELEMENT_TYPE_BOOLEAN:
347 case ELEMENT_TYPE_CHAR:
348 case ELEMENT_TYPE_I1:
349 case ELEMENT_TYPE_U1:
350 case ELEMENT_TYPE_I2:
351 case ELEMENT_TYPE_U2:
352 case ELEMENT_TYPE_I4:
353 case ELEMENT_TYPE_U4:
354 case ELEMENT_TYPE_I8:
355 case ELEMENT_TYPE_U8:
356 case ELEMENT_TYPE_R4:
357 case ELEMENT_TYPE_R8:
358 case ELEMENT_TYPE_STRING:
359 case ELEMENT_TYPE_OBJECT:
360 case ELEMENT_TYPE_TYPEDBYREF:
361 case ELEMENT_TYPE_I:
362 case ELEMENT_TYPE_U:
363
364 *ppResultType = pAppDomain->m_sharedtypes.GetBase(CORDBTYPE_ID(elementType, 0));
365
366 if (*ppResultType == NULL)
367 {
368 CordbType * pNewType = new (nothrow) CordbType(pAppDomain, elementType, (unsigned int) 0);
369
370 if (pNewType == NULL)
371 {
372 return E_OUTOFMEMORY;
373 }
374
375 HRESULT hr = pAppDomain->m_sharedtypes.AddBase(pNewType);
376
377 if (SUCCEEDED(hr))
378 {
379 *ppResultType = pNewType;
380 }
381 else
382 {
383 _ASSERTE(!"unexpected failure!");
384 delete pNewType;
385 }
386
387 return hr;
388 }
389 return S_OK;
390
391 default:
392 _ASSERTE(!"unexpected element type!");
393 return E_FAIL;
394 }
395
396}
397
398//-----------------------------------------------------------------------------
399// Internal method to make a type with exactly one type argument by specifying
400// ELEMENT_TYPE_PTR, ELEMENT_TYPE_BYREF, ELEMENT_TYPE_SZARRAY or
401// ELEMENT_TYPE_ARRAY.
402//
403// Arguments:
404// pAppDomain - appdomain containing the type.
405// elementType - element type to create around. This is limited to: ELEMENT_TYPE_PTR,
406// ELEMENT_TYPE_BYREF, ELEMENT_TYPE_SZARRAY or ELEMENT_TYPE_ARRAY.
407// rank - for non-arrays, this must be 0. For szarray, this must be 1.
408// For multi-dimensional arrays, this is the rank.
409// pType - the single input type-parameter required for the specified element type.
410// ppResultType - OUT: the output parameter to get the corresponding CordbType
411//
412// Returns:
413// S_OK on success.
414//
415HRESULT CordbType::MkType(CordbAppDomain *pAppDomain,
416 CorElementType elementType,
417 ULONG rank,
418 CordbType * pType,
419 CordbType ** ppResultType)
420{
421 _ASSERTE(pAppDomain != NULL);
422 _ASSERTE(ppResultType != NULL);
423
424 RSLockHolder lockHolder(pAppDomain->GetProcess()->GetProcessLock());
425
426 switch (elementType)
427 {
428
429 case ELEMENT_TYPE_PTR:
430 case ELEMENT_TYPE_BYREF:
431 _ASSERTE(rank == 0);
432 goto LUnary;
433
434 case ELEMENT_TYPE_SZARRAY:
435 _ASSERTE(rank == 1);
436 goto LUnary;
437
438 case ELEMENT_TYPE_ARRAY:
439LUnary:
440 {
441 CordbType * pFoundType = pAppDomain->m_sharedtypes.GetBase(CORDBTYPE_ID(elementType, rank));
442
443 if (pFoundType == NULL)
444 {
445 pFoundType = new (nothrow) CordbType(pAppDomain, elementType, rank);
446
447 if (pFoundType == NULL)
448 {
449 return E_OUTOFMEMORY;
450 }
451
452 HRESULT hr = pAppDomain->m_sharedtypes.AddBase(pFoundType);
453
454 if (FAILED(hr))
455 {
456 _ASSERTE(!"unexpected failure!");
457 delete pFoundType;
458 return hr;
459 }
460 }
461
462 Instantiation inst(1, &pType);
463
464 return MkTyAppType(pAppDomain, pFoundType, &inst, ppResultType);
465
466 }
467
468 default:
469 _ASSERTE(!"unexpected element type!");
470 return E_FAIL;
471 }
472
473}
474
475//-----------------------------------------------------------------------------
476// Internal method to make a type for an instantiation of a class or value type, or just for the
477// class or value type if it accepts no type parameters.
478// Creates a CordbType instantiation around an uninstantiated CordbType and TypeParameter list.
479// In other words, this does:
480// CordbType(List<T>) + Instantiation({T=int}) --> CordbType(List<int>)
481//
482// This will create the subordinate types. Eg, for Triple<x,y,z>, it will create:
483// CordbType(Triple<x>), CordbType(Triple<x,y>), and CordbType(Triple<x,y,z)).
484// The fully instantiated one (the last one) is returned via the out parameter *pRes.
485//
486// Arguments:
487// pAppDomain - the appdomain that the type lives in.
488// pType - the open type to instantiate. Eg, CordbType(List<T>)
489// pInst - instantiation parameters.
490// ppResultType - OUT: out parameter to hold resulting type.
491//
492// Returns:
493// S_OK on success.
494//
495HRESULT CordbType::MkTyAppType(CordbAppDomain * pAppDomain,
496 CordbType * pType,
497 const Instantiation * pInst,
498 CordbType ** ppResultType)
499{
500 _ASSERTE(pAppDomain == pType->GetAppDomain());
501
502 CordbType * pCordbType = pType;
503
504 // Loop through and create each of the subordinate types, building up to the final fully Closed type.
505 for (unsigned int i = 0; i < pInst->m_cClassTyPars; i++)
506 {
507
508 CordbType * pCordbBaseType = pCordbType->m_spinetypes.GetBase((UINT_PTR) (pInst->m_ppInst[i]));
509
510 if (pCordbBaseType == NULL)
511 {
512 pCordbBaseType = new (nothrow) CordbType(pCordbType, pInst->m_ppInst[i]);
513
514 if (pCordbBaseType == NULL)
515 {
516 return E_OUTOFMEMORY;
517 }
518
519 HRESULT hr = pCordbType->m_spinetypes.AddBase(pCordbBaseType);
520
521 if (FAILED(hr))
522 {
523 _ASSERTE(!"unexpected failure!");
524 delete pCordbBaseType;
525 // @dbgtodo Microsoft leaks: Release the previously created types if this fails later in the loop
526 return hr;
527 }
528
529 pCordbBaseType->m_inst.m_cInst = i + 1;
530 pCordbBaseType->m_inst.m_cClassTyPars = i + 1;
531 pCordbBaseType->m_inst.m_ppInst = new (nothrow) CordbType *[i+1];
532
533 if (pCordbBaseType->m_inst.m_ppInst == NULL)
534 {
535 delete pCordbBaseType;
536 // @dbgtodo Microsoft leaks: Doesn't release the previously created types if this fails later in the loop
537 return E_OUTOFMEMORY;
538 }
539
540 for (unsigned int j = 0; j < (i + 1); j++)
541 {
542 // Constructed types include pointers across to other types - increase
543 // the reference counts on these....
544 pInst->m_ppInst[j]->AddRef();
545
546 pCordbBaseType->m_inst.m_ppInst[j] = pInst->m_ppInst[j];
547 }
548 }
549 pCordbType = pCordbBaseType;
550 }
551
552 *ppResultType = pCordbType;
553 return S_OK;
554}
555
556//-----------------------------------------------------------------------------
557// Creates a CordbType instantation around a cordbClass and TypeParameter list.
558// In other words, this does:
559// CordbClass(List<T>) + Instantiation({T=int}) --> CordbType(List<int>)
560//
561// This really just converts CordbClass(List<T>) --> CordbType(List<T>), and then calls CordbType::MkTyAppType
562//
563// Arguments:
564// pAppDomain - the AD that the class lives in.
565// elementType - element type of the class. Either ELEMENT_TYPE_CLASS or ELEMENT_TYPE_VALUETYPE
566// pClass - the uninstantiated class (eg, List<T>). This function will fill out the tycon->m_type field
567// to an uninstantiated CordbType (eg CordbType(List<T>))
568// pInst - the list of type parameters to instantiate with.
569// ppResultType - OUT: the CordbType instantiated with the type parameters (eg, CordbType(List<int>))
570//
571// Returns:
572// S_OK on success.
573//
574HRESULT CordbType::MkType(CordbAppDomain * pAppDomain,
575 CorElementType elementType,
576 CordbClass * pClass,
577 const Instantiation * pInst,
578 CordbType ** ppResultType)
579{
580 _ASSERTE(pAppDomain != NULL);
581 _ASSERTE(ppResultType != NULL);
582
583 switch (elementType)
584 {
585 // Normalize E_T_VALUETYPE away, so types do not record whether they are VCs or not, but CorDebugClass does.
586 // Update our view of whether a class is a VC based on the evidence we have here.
587 case ELEMENT_TYPE_VALUETYPE:
588
589 _ASSERTE(((pClass != NULL) && (!pClass->IsValueClassKnown() || pClass->IsValueClassNoInit())) ||
590 !"A non-value class is being used with ELEMENT_TYPE_VALUETYPE");
591
592 pClass->SetIsValueClass(true);
593 pClass->SetIsValueClassKnown(true);
594 // drop through
595
596 case ELEMENT_TYPE_CLASS:
597 {
598 // This probably isn't needed...
599 if (pClass == NULL)
600 {
601 elementType = ELEMENT_TYPE_OBJECT;
602 goto LReallyObject;
603 }
604
605 CordbType * pType = NULL;
606
607 pType = pClass->GetType();
608
609 if (pType == NULL)
610 {
611 pType = new (nothrow) CordbType(pAppDomain, ELEMENT_TYPE_CLASS, pClass);
612
613 if (pType == NULL)
614 {
615 return E_OUTOFMEMORY;
616 }
617
618 pClass->SetType(pType);
619 }
620
621 _ASSERTE(pClass->GetType() != NULL);
622
623 return CordbType::MkTyAppType(pAppDomain, pType, pInst, ppResultType);
624 }
625
626 default:
627LReallyObject:
628
629 _ASSERTE(pInst->m_cInst == 0);
630 return MkType(pAppDomain, elementType, ppResultType);
631
632 }
633}
634
635//-----------------------------------------------------------------------------
636// Make a CordbType for a function pointer type (ELEMENT_TYPE_FNPTR).
637//
638// Arguments:
639// pAppDomain - the Appdomain the type lives in.
640// elementType - must be ELEMENT_TYPE_FNPTR.
641// pInst - instantiation information.
642// ppResultType - OUT: out-parameter to hold resulting CordbType
643//
644// Return:
645// S_OK on success.
646//
647HRESULT CordbType::MkType(CordbAppDomain * pAppDomain,
648 CorElementType elementType,
649 const Instantiation * pInst,
650 CordbType ** ppResultType)
651{
652 CordbType * pType;
653
654 _ASSERTE(elementType == ELEMENT_TYPE_FNPTR);
655
656 HRESULT hr = MkType(pAppDomain, elementType, &pType);
657
658 if (!SUCCEEDED(hr))
659 {
660 return hr;
661 }
662 return CordbType::MkTyAppType(pAppDomain, pType, pInst, ppResultType);
663}
664
665
666//-----------------------------------------------------------------------------
667// Public API to get the CorElementType of the type.
668//
669// Parameters:
670// pType - OUT: on return, gets the CorElementType
671//
672// Returns:
673// S_OK on success. CORDBG_E_CLASS_NOT_LOADED or synchronization errors on failure
674//-----------------------------------------------------------------------------
675HRESULT CordbType::GetType(CorElementType *pType)
676{
677 PUBLIC_REENTRANT_API_ENTRY(this);
678 FAIL_IF_NEUTERED(this);
679 // See if this E_T_CLASS is really a value type?
680 if (m_elementType == ELEMENT_TYPE_CLASS)
681 {
682 _ASSERTE(m_pClass);
683 bool isVC = false;
684 // Determining if something is a VC or not can involve asking the EE.
685 // We could do it ourselves based on the metadata but it's non-trivial
686 // determining if a class has System.ValueType as a parent (we have
687 // to find and OpenScope the mscorlib.dll which we don't currently do
688 // on the right-side). But the IsValueClass call can fail if the
689 // class is not yet loaded on the right side. In that case we
690 // ignore the failure and return ELEMENT_TYPE_CLASS
691 HRESULT hr = S_OK;
692 EX_TRY
693 {
694 isVC = m_pClass->IsValueClass();
695 }
696 EX_CATCH_HRESULT(hr);
697 if (!FAILED(hr) && isVC)
698 {
699 *pType = ELEMENT_TYPE_VALUETYPE;
700 return S_OK;
701 }
702 }
703 *pType = m_elementType;
704 return S_OK;
705}
706
707//-----------------------------------------------------------------------------
708// Public method to get the ICorDebugClass that matches this type.
709// ICorDebugType has instantiated type-params (eg, List<int>), whereas
710// ICorDebugClass is open (eg, List<T>).
711//
712// Parameters:
713// pClass - OUT: gets class on return.
714// Returns:
715// S_OK on success. CORDBG_E_CLASS_NOT_LOADED if the class is not loaded.
716// Else some other error.
717//-----------------------------------------------------------------------------
718HRESULT CordbType::GetClass(ICorDebugClass **pClass)
719{
720 PUBLIC_REENTRANT_API_ENTRY(this);
721 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
722
723 if ((m_pClass == NULL) && (m_elementType == ELEMENT_TYPE_STRING ||
724 m_elementType == ELEMENT_TYPE_OBJECT))
725 {
726 Init(FALSE);
727 }
728 if (m_pClass == NULL)
729 {
730 *pClass = NULL;
731 return CORDBG_E_CLASS_NOT_LOADED;
732 }
733 *pClass = m_pClass;
734 m_pClass->ExternalAddRef();
735 return S_OK;
736}
737
738//-----------------------------------------------------------------------------
739// Public method to get array rank. This is only valid for arrays.
740//
741// Parameters:
742// pnRank - OUT: *pnRank is set to rank on return
743//
744// Return:
745// S_OK if success. E_INVALIDARG is this Type doesn't have a rank.
746//-----------------------------------------------------------------------------
747HRESULT CordbType::GetRank(ULONG32 *pnRank)
748{
749 PUBLIC_REENTRANT_API_ENTRY(this);
750 VALIDATE_POINTER_TO_OBJECT(pnRank, ULONG32 *);
751
752 if (m_elementType != ELEMENT_TYPE_SZARRAY &&
753 m_elementType != ELEMENT_TYPE_ARRAY)
754 return E_INVALIDARG;
755
756 *pnRank = (ULONG32) m_rank;
757
758 return S_OK;
759}
760
761//-----------------------------------------------------------------------------
762// Public convenience method to get the first type parameter.
763// This is purely to avoid needing to call EnumerateTypeParameters for
764// the set of types that only have 1 type-parameter.
765//
766// Parameters:
767// pType - OUT: get the ICorDebugType for the first type-parameter.
768// Returns:
769// S_OK on success.
770//-----------------------------------------------------------------------------
771HRESULT CordbType::GetFirstTypeParameter(ICorDebugType **pType)
772{
773 PUBLIC_REENTRANT_API_ENTRY(this);
774 VALIDATE_POINTER_TO_OBJECT(pType, ICorDebugType **);
775
776 // Since this is a public API, make sure there actually is at least 1 type-parameter.
777 if (m_inst.m_cInst == 0)
778 {
779 return E_INVALIDARG;
780 }
781
782 _ASSERTE(m_inst.m_ppInst != NULL);
783 _ASSERTE(m_inst.m_ppInst[0] != NULL);
784
785 *pType = m_inst.m_ppInst[0];
786 if (*pType)
787 (*pType)->AddRef();
788 return S_OK;
789}
790
791//-----------------------------------------------------------------------------
792// Internal worker to create a CordbType around a CordbClass.
793// Parameters:
794// appdomain - AD that the type lives in.
795// et - CorElementType of the incoming CordbClass
796// cl - CordbClass representing the type to build a CordbType for
797// pRes - OUT: out parameter to return the newly created CordbType object.
798//
799// Return:
800// S_OK on success.
801//-----------------------------------------------------------------------------
802HRESULT CordbType::MkUnparameterizedType(CordbAppDomain *appdomain, CorElementType et, CordbClass *cl,CordbType **pRes)
803{
804 // Pass in empty instantiation since CordbClass has no generic info.
805 // We should make some assert between et and cl->GetType().
806 Instantiation emptyInstantiation;
807
808 return CordbType::MkType(appdomain, et, cl, &emptyInstantiation, pRes);
809}
810
811
812//-----------------------------------------------------------------------------
813// Internal helper to get the First type parameter.
814// This is an internal convenience function for the public GetFirstTypeParameter.
815//
816// Parameters:
817// pRes - OUT: out-param to get the unary type-parameter.
818//-----------------------------------------------------------------------------
819void
820CordbType::DestUnaryType(CordbType **pRes)
821{
822 _ASSERTE(m_elementType == ELEMENT_TYPE_PTR
823 || m_elementType == ELEMENT_TYPE_BYREF
824 || m_elementType == ELEMENT_TYPE_ARRAY
825 || m_elementType == ELEMENT_TYPE_SZARRAY);
826 _ASSERTE(m_inst.m_cInst == 1);
827 _ASSERTE(m_inst.m_ppInst != NULL);
828 *pRes = m_inst.m_ppInst[0];
829}
830
831
832
833//-----------------------------------------------------------------------------
834// Internal method to get the Class and type-parameters from a CordbType.
835//-----------------------------------------------------------------------------
836void
837CordbType::DestConstructedType(CordbClass **cls, Instantiation *inst)
838{
839 ASSERT(m_elementType == ELEMENT_TYPE_CLASS);
840 *cls = m_pClass;
841 *inst = m_inst;
842}
843
844//-----------------------------------------------------------------------------
845// Internal method to get all the type-parameters for a FnPtr
846//-----------------------------------------------------------------------------
847void
848CordbType::DestNaryType(Instantiation *inst)
849{
850 ASSERT(m_elementType == ELEMENT_TYPE_FNPTR);
851 *inst = m_inst;
852}
853
854
855//-----------------------------------------------------------------------------
856// CordbType::SigToType
857// Internal helper to create a CordbType from a Metadata signature (SigParser)
858//
859// This parses a metadata signature in the context of a module to return a CordbType.
860// This heavily relies on the metadata and signature format. See ECMA Partition II for details.
861// Since signatures may be recursive, this function can be called recursively.
862// Since metadata signatures exist all over, this can be called in many different scenarios, including
863// resolving a TypeSpec, looking up a field.
864//
865// pModule - module that the signature lives in.
866// pSigParse - Signature, positioned at the point to read the Type from.
867// This will not change the SigParser's current position.
868// inst - instantiation containing Type Params for the context of the SigParser.
869// For a local var or argument lookup, this would be the type-params from the Frame.
870// For a field lookup, this would be the type-params for the containing type.
871// pRes - OUT: yields the CordbType for this signature.
872//
873// Returns:
874// S_OK on success
875//-----------------------------------------------------------------------------
876HRESULT
877CordbType::SigToType(CordbModule * pModule,
878 SigParser * pSigParser,
879 const Instantiation * pInst,
880 CordbType ** ppResultType)
881{
882 FAIL_IF_NEUTERED(pModule);
883 INTERNAL_SYNC_API_ENTRY(pModule->GetProcess());
884
885 _ASSERTE(pSigParser != NULL);
886
887
888 //
889 // Make a local copy of the SigParser since we are going to mutate it.
890 //
891 SigParser sigParser = *pSigParser;
892
893 CorElementType elementType;
894 HRESULT hr;
895
896 IfFailRet(sigParser.GetElemType(&elementType));
897
898 switch (elementType)
899 {
900 case ELEMENT_TYPE_VAR:
901 case ELEMENT_TYPE_MVAR:
902 {
903 ULONG tyvar_num;
904
905 IfFailRet(sigParser.GetData(&tyvar_num));
906
907
908 if (elementType == ELEMENT_TYPE_VAR)
909 {
910 // ELEMENT_TYPE_VAR refers to an indexed type-parameter in the containing Type.
911 // Eg, we may be doing a field lookup on 'List<T> { T m_head}', and the field's return type 'T' is Type-parameter #0.
912 // Or this maybe part of a base class's TypeSpec.
913 _ASSERTE (tyvar_num < (pInst->m_cClassTyPars));
914 if (tyvar_num >= (pInst->m_cClassTyPars))
915 return E_FAIL;
916
917 _ASSERTE (pInst->m_ppInst != NULL);
918 *ppResultType = pInst->m_ppInst[tyvar_num];
919 }
920 else
921 {
922 //ELEMENT_TYPE_MVAR refers to an indexed type-parameter in the containing Method.
923 // Eg, we may be in Class::Func<T> and refering to T.
924 // The Instantiation array has Type type-parameters first, and then any Method Type-parameters.
925 // The m_cClassTyPars field indicats where the split is between Type and Method type-parameters. Type type-params
926 // come first.
927 _ASSERTE(elementType == ELEMENT_TYPE_MVAR);
928
929
930 _ASSERTE (tyvar_num < (pInst->m_cInst - pInst->m_cClassTyPars));
931 if (tyvar_num >= (pInst->m_cInst - pInst->m_cClassTyPars))
932 return E_FAIL;
933
934 _ASSERTE (pInst->m_ppInst != NULL);
935 *ppResultType = pInst->m_ppInst[tyvar_num + pInst->m_cClassTyPars];
936 }
937
938 return S_OK;
939 }
940 case ELEMENT_TYPE_GENERICINST:
941 {
942 //ELEMENT_TYPE_GENERICINST is that start of a instantiated generic type.
943 //Format for the signature blob is:
944 // 1) CorElementType, Token - this is the uninstantiated type (eg, for Pair<int, string>, it would be token for Pair<T,U>)
945 // 2) int - Count of generic args - eg, for Pair<T,U>, it would be "2".
946 // 3) type1,type2, ... - meteadata representation for generic args. For example above, it would be Type(int), Type(string).
947
948
949 // ignore "WITH", look at next ELEMENT_TYPE to get CLASS or VALUE
950
951 IfFailRet(sigParser.GetElemType(&elementType));
952
953 mdToken token;
954
955 IfFailRet(sigParser.GetToken(&token));
956
957 CordbClass * pClass;
958
959 IfFailRet( pModule->ResolveTypeRefOrDef(token, &pClass));
960
961 // The use of a class in a signature provides definite evidence as to whether it is a VC or not.
962 _ASSERTE(!pClass->IsValueClassKnown() ||
963 (pClass->IsValueClassNoInit() == (elementType == ELEMENT_TYPE_VALUETYPE)) ||
964 !"A value class is being used with ELEMENT_TYPE_GENERICINST");
965
966 pClass->SetIsValueClass(elementType == ELEMENT_TYPE_VALUETYPE);
967 pClass->SetIsValueClassKnown(true);
968
969 // Build up the array of generic arguments.
970 ULONG cArgs; // number of generic arguments in the type.
971
972 IfFailRet(sigParser.GetData(&cArgs));
973
974 S_UINT32 allocSize = S_UINT32( cArgs ) * S_UINT32( sizeof(CordbType *) );
975
976 if (allocSize.IsOverflow())
977 {
978 IfFailRet(E_OUTOFMEMORY);
979 }
980
981 CordbType ** ppTypeInstantiations = reinterpret_cast<CordbType **>(_alloca( allocSize.Value()));
982
983 for (unsigned int i = 0; i < cArgs;i++)
984 {
985 IfFailRet(CordbType::SigToType(pModule, &sigParser, pInst, &ppTypeInstantiations[i]));
986
987 IfFailRet(sigParser.SkipExactlyOne());
988 }
989
990 // Now we have the Open type (eg, Pair<T,U>) and the instantiation list, so create the Closed CordbType..
991 Instantiation typeInstantiation(cArgs, ppTypeInstantiations);
992
993 return CordbType::MkType(pModule->GetAppDomain(), elementType, pClass, &typeInstantiation, ppResultType);
994 }
995 case ELEMENT_TYPE_CLASS:
996 case ELEMENT_TYPE_VALUETYPE: // OK: this E_T_VALUETYPE comes from signature
997 {
998 // Path for non-generic types
999
1000 mdToken token;
1001
1002 IfFailRet(sigParser.GetToken(&token));
1003
1004 CordbClass * pClass;
1005
1006 IfFailRet(pModule->ResolveTypeRefOrDef(token, &pClass));
1007
1008 // The use of a class in a signature provides definite evidence as to whether it is a VC or not.
1009
1010 _ASSERTE(!pClass->IsValueClassKnown() ||
1011 (pClass->IsValueClassNoInit() == (elementType == ELEMENT_TYPE_VALUETYPE)) ||
1012 !"A non-value class is being used with ELEMENT_TYPE_VALUETYPE");
1013
1014 pClass->SetIsValueClass(elementType == ELEMENT_TYPE_VALUETYPE);
1015 pClass->SetIsValueClassKnown(true);
1016
1017 return CordbType::MkUnparameterizedType(pModule->GetAppDomain(), elementType, pClass, ppResultType);
1018 }
1019 case ELEMENT_TYPE_SENTINEL:
1020 case ELEMENT_TYPE_MODIFIER:
1021 case ELEMENT_TYPE_PINNED:
1022 {
1023 IfFailRet(CordbType::SigToType(pModule, &sigParser, pInst, ppResultType));
1024 // Throw away SENTINELS on all CordbTypes...
1025 return S_OK;
1026 }
1027 case ELEMENT_TYPE_CMOD_REQD:
1028 case ELEMENT_TYPE_CMOD_OPT:
1029 {
1030 mdToken token;
1031
1032 IfFailRet(sigParser.GetToken(&token));
1033
1034 IfFailRet(CordbType::SigToType(pModule, &sigParser, pInst, ppResultType));
1035 // Throw away CMOD on all CordbTypes...
1036 return S_OK;
1037 }
1038
1039 case ELEMENT_TYPE_ARRAY:
1040 {
1041 CordbType * pType;
1042
1043 IfFailRet(CordbType::SigToType(pModule, &sigParser, pInst, &pType));
1044
1045 IfFailRet(sigParser.SkipExactlyOne());
1046
1047 ULONG rank;
1048
1049 IfFailRet(sigParser.GetData(&rank));
1050
1051 return CordbType::MkType(pModule->GetAppDomain(), elementType, rank, pType, ppResultType);
1052 }
1053 case ELEMENT_TYPE_SZARRAY:
1054 {
1055 CordbType * pType;
1056
1057 IfFailRet(CordbType::SigToType(pModule, &sigParser, pInst, &pType));
1058
1059 return CordbType::MkType(pModule->GetAppDomain(), elementType, 1, pType, ppResultType);
1060 }
1061
1062 case ELEMENT_TYPE_PTR:
1063 case ELEMENT_TYPE_BYREF:
1064 {
1065 CordbType * pType;
1066
1067 IfFailRet(CordbType::SigToType(pModule, &sigParser, pInst, &pType));
1068
1069 return CordbType::MkType(pModule->GetAppDomain(),elementType, 0, pType, ppResultType);
1070 }
1071
1072 case ELEMENT_TYPE_FNPTR:
1073 {
1074 ULONG cArgs;
1075
1076 IfFailRet(sigParser.GetData(&cArgs)); // Skip callingConv
1077
1078 IfFailRet(sigParser.GetData(&cArgs)); // Get number of parameters
1079
1080 S_UINT32 allocSize = ( S_UINT32(cArgs) + S_UINT32(1) ) * S_UINT32( sizeof(CordbType *) );
1081
1082 if (allocSize.IsOverflow())
1083 {
1084 IfFailRet(E_OUTOFMEMORY);
1085 }
1086
1087 CordbType ** ppTypeInstantiations = (CordbType **) _alloca( allocSize.Value() );
1088
1089 for (unsigned int i = 0; i <= cArgs; i++)
1090 {
1091 IfFailRet(CordbType::SigToType(pModule, &sigParser, pInst, &ppTypeInstantiations[i]));
1092
1093 IfFailRet(sigParser.SkipExactlyOne());
1094 }
1095
1096 Instantiation typeInstantiation(cArgs + 1, ppTypeInstantiations);
1097
1098 return CordbType::MkType(pModule->GetAppDomain(), elementType, &typeInstantiation, ppResultType);
1099 }
1100
1101 case ELEMENT_TYPE_VOID:
1102 case ELEMENT_TYPE_BOOLEAN:
1103 case ELEMENT_TYPE_CHAR:
1104 case ELEMENT_TYPE_I1:
1105 case ELEMENT_TYPE_U1:
1106 case ELEMENT_TYPE_I2:
1107 case ELEMENT_TYPE_U2:
1108 case ELEMENT_TYPE_I4:
1109 case ELEMENT_TYPE_U4:
1110 case ELEMENT_TYPE_I8:
1111 case ELEMENT_TYPE_U8:
1112 case ELEMENT_TYPE_R4:
1113 case ELEMENT_TYPE_R8:
1114 case ELEMENT_TYPE_STRING:
1115 case ELEMENT_TYPE_TYPEDBYREF:
1116 case ELEMENT_TYPE_OBJECT:
1117 case ELEMENT_TYPE_I:
1118 case ELEMENT_TYPE_U:
1119 return CordbType::MkType(pModule->GetAppDomain(), elementType, ppResultType);
1120
1121 default:
1122 _ASSERTE(!"unexpected element type!");
1123 return E_FAIL;
1124 }
1125} // CordbType::SigToType
1126
1127//-----------------------------------------------------------------------------
1128// Marshal a DebuggerIPCE_BasicTypeData --> CordbType.
1129//
1130// This will build up a DebuggerIPCE_ExpandedTypeData and convert that into
1131// a CordbType. This may send additional IPC events if needed to
1132// go from Basic --> Expanded data. Note that this is designed to handle generics.
1133//
1134// Parameters:
1135// pAppDomain - the AppDomain the type lives in.
1136// data - DebuggerIPCE_BasicTypeData from Left-Side containing type description.
1137// pRes - OUT: out-parameter to hold built type.
1138//
1139// Returns:
1140// S_OK on success.
1141//-----------------------------------------------------------------------------
1142HRESULT CordbType::TypeDataToType(CordbAppDomain *pAppDomain, DebuggerIPCE_BasicTypeData *data, CordbType **pRes)
1143{
1144 FAIL_IF_NEUTERED(pAppDomain);
1145 INTERNAL_SYNC_API_ENTRY(pAppDomain->GetProcess()); //
1146
1147
1148
1149 HRESULT hr = S_OK;
1150 CorElementType et = data->elementType;
1151 switch (et)
1152 {
1153 case ELEMENT_TYPE_ARRAY:
1154 case ELEMENT_TYPE_SZARRAY:
1155 case ELEMENT_TYPE_PTR:
1156 case ELEMENT_TYPE_BYREF:
1157 // For these element types the "Basic" type data only contains the type handle.
1158 // So we fetch some more data, and the go onto the "Expanded" case...
1159 {
1160 EX_TRY
1161 {
1162 DebuggerIPCE_ExpandedTypeData typeInfo;
1163 CordbProcess * pProcess = pAppDomain->GetProcess();
1164
1165 {
1166 RSLockHolder lockHolder(pProcess->GetProcessLock());
1167 pProcess->GetDAC()->TypeHandleToExpandedTypeInfo(NoValueTypeBoxing, // could be generics
1168 // which are never boxed
1169 pAppDomain->GetADToken(),
1170 data->vmTypeHandle,
1171 &typeInfo);
1172 }
1173
1174 IfFailThrow(CordbType::TypeDataToType(pAppDomain,&typeInfo, pRes));
1175 }
1176 EX_CATCH_HRESULT(hr);
1177 return hr;
1178
1179 }
1180
1181 case ELEMENT_TYPE_FNPTR:
1182 {
1183 DebuggerIPCE_ExpandedTypeData e;
1184 e.elementType = et;
1185 e.NaryTypeData.typeHandle = data->vmTypeHandle;
1186 return CordbType::TypeDataToType(pAppDomain, &e, pRes);
1187 }
1188 default:
1189 // For all other element types the "Basic" view of a type
1190 // contains the same information as the "expanded"
1191 // view, so just reuse the code for the Expanded view...
1192 DebuggerIPCE_ExpandedTypeData e;
1193 e.elementType = et;
1194 e.ClassTypeData.metadataToken = data->metadataToken;
1195 e.ClassTypeData.vmDomainFile = data->vmDomainFile;
1196 e.ClassTypeData.vmModule = data->vmModule;
1197 e.ClassTypeData.typeHandle = data->vmTypeHandle;
1198 return CordbType::TypeDataToType(pAppDomain, &e, pRes);
1199 }
1200}
1201
1202//-----------------------------------------------------------------------------
1203// Marshal DebuggerIPCE_ExpandedTypeData --> CordbType
1204// The ExpandedTypeData just contains top level generic info, and so
1205// the RS may need to send more IPC events to fill out details.
1206//
1207// Parameters:
1208// pAppDomain - the appdomain that all the types live in.
1209// data - data used to build up CordbType
1210// pRes - OUT: out param to get back CordbType on return.
1211//
1212// Returns:
1213// S_OK on success.
1214//-----------------------------------------------------------------------------
1215HRESULT CordbType::TypeDataToType(CordbAppDomain *pAppDomain, DebuggerIPCE_ExpandedTypeData *data, CordbType **pRes)
1216{
1217 INTERNAL_SYNC_API_ENTRY(pAppDomain->GetProcess()); //
1218
1219 CorElementType et = data->elementType;
1220 HRESULT hr = S_OK;
1221 switch (et)
1222 {
1223
1224 case ELEMENT_TYPE_OBJECT:
1225 case ELEMENT_TYPE_VOID:
1226 case ELEMENT_TYPE_BOOLEAN:
1227 case ELEMENT_TYPE_CHAR:
1228 case ELEMENT_TYPE_I1:
1229 case ELEMENT_TYPE_U1:
1230 case ELEMENT_TYPE_I2:
1231 case ELEMENT_TYPE_U2:
1232 case ELEMENT_TYPE_I4:
1233 case ELEMENT_TYPE_U4:
1234 case ELEMENT_TYPE_I8:
1235 case ELEMENT_TYPE_U8:
1236 case ELEMENT_TYPE_R4:
1237 case ELEMENT_TYPE_R8:
1238 case ELEMENT_TYPE_STRING:
1239 case ELEMENT_TYPE_TYPEDBYREF:
1240 case ELEMENT_TYPE_I:
1241 case ELEMENT_TYPE_U:
1242ETObject:
1243 // It's a primitive (therefore non-generic) type, so we can just create it immediately.
1244 IfFailRet (CordbType::MkType(pAppDomain, et, pRes));
1245 break;
1246
1247 case ELEMENT_TYPE_CLASS:
1248 case ELEMENT_TYPE_VALUETYPE: // OK: this E_T_VALUETYPE comes from the EE
1249 {
1250 //
1251 if (data->ClassTypeData.metadataToken == mdTokenNil) {
1252 et = ELEMENT_TYPE_OBJECT;
1253 goto ETObject;
1254 }
1255 CordbModule * pClassModule = NULL;
1256 EX_TRY
1257 {
1258 pClassModule = pAppDomain->LookupOrCreateModule(data->ClassTypeData.vmModule, data->ClassTypeData.vmDomainFile);
1259 }
1260 EX_CATCH_HRESULT(hr);
1261 if( pClassModule == NULL )
1262 {
1263 // We don't know anything about this module - shouldn't happen.
1264 // <TODO>This can be hit by the issue described in VSWhidbey 465120</TODO>
1265 _ASSERTE(!"Unrecognized module");
1266 return CORDBG_E_MODULE_NOT_LOADED;
1267 }
1268
1269 CordbClass *tycon;
1270 IfFailRet (pClassModule->LookupOrCreateClass(data->ClassTypeData.metadataToken,&tycon));
1271 if (!(data->ClassTypeData.typeHandle.IsNull()))
1272 {
1273 // It's a generic type. We have the typehandle, use that to query for the rest of
1274 // the tyeparameters and build up the instantiation for the CordbType.
1275
1276 IfFailRet (CordbType::InstantiateFromTypeHandle(pAppDomain, data->ClassTypeData.typeHandle, et, tycon, pRes));
1277 // Set the type handle regardless of how we found
1278 // the type. For example if type was already
1279 // constructed without the type handle still set
1280 // it here.
1281 if (*pRes)
1282 {
1283 (*pRes)->m_typeHandleExact = data->ClassTypeData.typeHandle;
1284 }
1285 break;
1286 }
1287 else
1288 {
1289 // Non generic type. Since we already have the CordbClass for it, we can trivially create the CordbType
1290 IfFailRet (CordbType::MkUnparameterizedType(pAppDomain, et,tycon,pRes));
1291 break;
1292 }
1293
1294 }
1295 case ELEMENT_TYPE_ARRAY:
1296 case ELEMENT_TYPE_SZARRAY:
1297 {
1298 CordbType *argty;
1299 IfFailRet (CordbType::TypeDataToType(pAppDomain, &(data->ArrayTypeData.arrayTypeArg), &argty));
1300 IfFailRet (CordbType::MkType(pAppDomain, et, data->ArrayTypeData.arrayRank, argty, pRes));
1301 break;
1302 }
1303
1304 case ELEMENT_TYPE_PTR:
1305 case ELEMENT_TYPE_BYREF:
1306 {
1307 CordbType *argty;
1308 IfFailRet (CordbType::TypeDataToType(pAppDomain, &(data->UnaryTypeData.unaryTypeArg), &argty));
1309 IfFailRet (CordbType::MkType(pAppDomain, et, 0, argty, pRes));
1310 break;
1311 }
1312 case ELEMENT_TYPE_FNPTR:
1313 {
1314 IfFailRet (CordbType::InstantiateFromTypeHandle(pAppDomain, data->NaryTypeData.typeHandle, et, NULL, pRes));
1315 if (*pRes)
1316 {
1317 (*pRes)->m_typeHandleExact = data->NaryTypeData.typeHandle;
1318 }
1319 break;
1320 }
1321 case ELEMENT_TYPE_END:
1322 *pRes = NULL;
1323 return E_FAIL;
1324
1325 default:
1326 _ASSERTE(!"unexpected element type!");
1327 return E_FAIL;
1328
1329 }
1330 return S_OK;
1331}
1332
1333//-----------------------------------------------------------------------------
1334// CordbType::InstantiateFromTypeHandle
1335// Internal helper method.
1336// Builds (Left-Side) TypeHandle --> (Right-Side) CordbType
1337// This is very useful when we get a typehandle from the LeftSide. A common
1338// scenario is when we get an Object back from the LS, which happens when
1339// we build the CordbType corresponding to a Cordb*Value.
1340//
1341// Parameters:
1342// pAppdomain - the appdomain the type lives in.
1343// vmTypeHandle - a Left-Side typehandle describing the type.
1344// elementType - convenient way to indicate whether we've got ELEMENT_TYPE_FNPTR or
1345// something else. We should be able to retrieve this from the TypeHandle,
1346// but our caller already has it available.
1347// typeConstructor - CordbClass corresponding to the typeHandle. This could be built
1348// up from typehandle, but our caller already has it.
1349// Will be NULL for ELEMENT_TYPE_FNPTR
1350// pResultType - OUT: out parameter to yield CordbType for the TypeHandle.
1351//
1352// Returns:
1353// S_OK on success.
1354//-----------------------------------------------------------------------------
1355HRESULT CordbType::InstantiateFromTypeHandle(CordbAppDomain * pAppDomain,
1356 VMPTR_TypeHandle vmTypeHandle,
1357 CorElementType elementType,
1358 CordbClass * typeConstructor,
1359 CordbType ** pResultType)
1360{
1361 HRESULT hr = S_OK;
1362
1363 // Should already by synced by caller.
1364 INTERNAL_SYNC_API_ENTRY(pAppDomain->GetProcess()); //
1365 _ASSERTE((pAppDomain->GetProcess()->GetShim() == NULL) || (pAppDomain->GetProcess()->GetSynchronized()));
1366
1367 EX_TRY
1368 {
1369 CordbProcess * pProcess = pAppDomain->GetProcess();
1370 //
1371 // Step 1) Ask DacDbi interface for a list of type-parameters given a TypeHandle.
1372 //
1373
1374 TypeParamsList params;
1375 {
1376 RSLockHolder lockHolder(pProcess->GetProcessLock());
1377 pProcess->GetDAC()->GetTypeHandleParams(pAppDomain->GetADToken(), vmTypeHandle, &params);
1378 }
1379
1380 // convert the parameter type information to a list of CordbTypeInstances (one for each parameter)
1381 // note: typeList will be destroyed on exit, running destructors for each element. In this case, that
1382 // means it will simply assert IsNeutered.
1383 DacDbiArrayList<CordbType *> typeList;
1384 typeList.Alloc(params.Count());
1385 for (int i = 0; i < params.Count(); ++i)
1386 {
1387 IfFailThrow(TypeDataToType(pAppDomain, &(params[i]), &(typeList[i])));
1388 }
1389
1390 // now make an instance of CordbType from an instantiation
1391 Instantiation instantiation(params.Count(), &(typeList[0]));
1392 if (elementType == ELEMENT_TYPE_FNPTR)
1393 {
1394 IfFailThrow(CordbType::MkType(pAppDomain, elementType, &instantiation, pResultType));
1395 }
1396 else
1397 {
1398 IfFailThrow(CordbType::MkType(pAppDomain, elementType, typeConstructor, &instantiation, pResultType));
1399 }
1400 }
1401 EX_CATCH_HRESULT(hr);
1402 return hr;
1403} // CordbType::InstantiateFromTypeHandle
1404
1405//-----------------------------------------------------------------------------
1406// Initialize the CordbType.
1407// This will involve a lot of queries to the Left-side.
1408// This means finding the type-handle, getting / creating associated CordbClass,
1409// filling out the instantiation, getting field info, etc.
1410//
1411// Parameters:
1412// fForceInit - if false, may skip initialization if TypeHandle already known.
1413//
1414// Returns:
1415// S_OK if success, CORDBG_E_CLASS_NOT_LOADED, E_INVALIDARG, OOM on failure
1416//-----------------------------------------------------------------------------
1417HRESULT CordbType::Init(BOOL fForceInit)
1418{
1419 INTERNAL_SYNC_API_ENTRY(GetProcess()); //
1420
1421 HRESULT hr = S_OK;
1422
1423 if (m_pClass && m_pClass->GetLoadLevel() != CordbClass::FullInfo)
1424 fForceInit = TRUE;
1425
1426 // Step 1. initialize the type constructor (if one exists)
1427 // and the (class) type parameters....
1428 if (m_elementType == ELEMENT_TYPE_CLASS)
1429 {
1430
1431 // start by initing only enough so that we can determine whether
1432 // or not this is a generic class. When dealing with generic
1433 // type instantiations there is no guarantee the open generic
1434 // type is fully restored. If we load too eagerly it might fail
1435 // and we wouldn't actually need that extra data anyways.
1436 _ASSERTE(m_pClass != NULL);
1437 EX_TRY
1438 {
1439 m_pClass->Init(CordbClass::BasicInfo);
1440 }
1441 EX_CATCH_HRESULT(hr);
1442 IfFailRet(hr);
1443
1444 // non-generic classes need the class object to be fully inited
1445 // in the generic case we won't ever use that data
1446 if (!m_pClass->HasTypeParams())
1447 {
1448 EX_TRY
1449 {
1450 m_pClass->Init(CordbClass::FullInfo);
1451 }
1452 EX_CATCH_HRESULT(hr);
1453 IfFailRet(hr);
1454
1455 return S_OK; // Non-generic, that's all - no clean-up required
1456 }
1457 }
1458
1459 _ASSERTE(m_elementType != ELEMENT_TYPE_CLASS || m_pClass->HasTypeParams());
1460
1461 for (unsigned int i = 0; i<m_inst.m_cClassTyPars; i++)
1462 {
1463 _ASSERTE(m_inst.m_ppInst != NULL);
1464 _ASSERTE(m_inst.m_ppInst[i] != NULL);
1465 IfFailRet( m_inst.m_ppInst[i]->Init(fForceInit) );
1466 }
1467
1468 // Step 2. Try to fetch the type handle if necessary (only
1469 // for instantiated class types, pointer types etc.)
1470 // We do this by preparing an event specifying the type and
1471 // then fetching the type handle from the left-side. This
1472 // will not always succeed, as forcing the load of the type handle would be the
1473 // equivalent of doing a FuncEval, i.e. the instantiation may
1474 // not have been created. But we try anyway to reduce the number of
1475 // failures.
1476 //
1477 // Note that in the normal case we will have the type handle from the EE
1478 // anyway, e.g. if the CordbType was created when reporting the type
1479 // of an actual object.
1480
1481 // Initialize m_typeHandleExact if it needs it
1482 if (m_elementType == ELEMENT_TYPE_ARRAY ||
1483 m_elementType == ELEMENT_TYPE_SZARRAY ||
1484 m_elementType == ELEMENT_TYPE_BYREF ||
1485 m_elementType == ELEMENT_TYPE_PTR ||
1486 m_elementType == ELEMENT_TYPE_FNPTR ||
1487 (m_elementType == ELEMENT_TYPE_CLASS && m_pClass->HasTypeParams()))
1488 {
1489 // It is OK if getting an exact type handle
1490 // fails with CORDBG_E_CLASS_NOT_LOADED. In that case we leave
1491 // the type information incomplete and subsequent operations
1492 // will try to call Init() again. The immediate operation will fail later if
1493 // TypeToBasicTypeData requests the exact type information for this type.
1494 hr = InitInstantiationTypeHandle(fForceInit);
1495 if (hr != CORDBG_E_CLASS_NOT_LOADED)
1496 IfFailRet(hr);
1497 }
1498
1499
1500 // For OBJECT and STRING we may not have a value for m_class
1501 // object. Go try and get it.
1502 if (m_elementType == ELEMENT_TYPE_STRING ||
1503 m_elementType == ELEMENT_TYPE_OBJECT)
1504 {
1505 IfFailRet(InitStringOrObjectClass(fForceInit));
1506 }
1507
1508 // Step 3. Fetch the information that is specific to the type where necessary...
1509 // Now we have the type handle for the constructed type, we can ask for the size of
1510 // the object. Only do this for constructed value types.
1511 //
1512 // Note that the exact and/or approximate type handles may not be available.
1513 if ((m_elementType == ELEMENT_TYPE_CLASS) && m_pClass->HasTypeParams())
1514 {
1515 IfFailRet(InitInstantiationFieldInfo(fForceInit));
1516 }
1517
1518 return S_OK;
1519}
1520
1521//-----------------------------------------------------------------------------
1522// Internal function to communicate with Left-Side to get an exact TypeHandle
1523// (runtime type representation) for this CordbType.
1524//
1525// Parameters:
1526// fForceInit - if false, may skip initialization if TypeHandle already known.
1527//
1528// Returns:
1529// S_OK on success or failure HR E_INVALIDARG, OOM, CORDBG_E_CLASS_NOT_LOADED
1530// on failure
1531//-----------------------------------------------------------------------------
1532HRESULT CordbType::InitInstantiationTypeHandle(BOOL fForceInit)
1533{
1534
1535 // Check if we've already done this Init
1536 if (!fForceInit && !m_typeHandleExact.IsNull())
1537 return S_OK;
1538
1539 HRESULT hr = S_OK;
1540
1541 // Create an array of DebuggerIPCE_BasicTypeData structures from the array of type parameters.
1542 // First, get a buffer to hold the information
1543 CordbProcess *pProcess = GetProcess();
1544 S_UINT32 bufferSize = S_UINT32(sizeof(DebuggerIPCE_BasicTypeData)) *
1545 S_UINT32(m_inst.m_cClassTyPars);
1546 EX_TRY
1547 {
1548 if( bufferSize.IsOverflow() )
1549 {
1550 ThrowHR(E_INVALIDARG);
1551 }
1552 NewHolder<DebuggerIPCE_BasicTypeData> pArgTypeData(new DebuggerIPCE_BasicTypeData[bufferSize.Value()]);
1553
1554 // We will have already called Init on each of the type parameters further above. Now we build a
1555 // list of type information for each type parameter.
1556 for (unsigned int i = 0; i < m_inst.m_cClassTyPars; i++)
1557 {
1558 _ASSERTE(m_inst.m_ppInst != NULL);
1559 _ASSERTE(m_inst.m_ppInst[i] != NULL);
1560 IfFailThrow(m_inst.m_ppInst[i]->TypeToBasicTypeData(&pArgTypeData[i]));
1561 }
1562
1563 DebuggerIPCE_ExpandedTypeData typeData;
1564
1565 // get the top-level type information
1566 TypeToExpandedTypeData(&typeData);
1567
1568 ArgInfoList argInfo(pArgTypeData, m_inst.m_cClassTyPars);
1569
1570 {
1571 // Get the TypeHandle based on the type data
1572 RSLockHolder lockHolder(GetProcess()->GetProcessLock());
1573 hr = pProcess->GetDAC()->GetExactTypeHandle(&typeData, &argInfo, m_typeHandleExact);
1574 }
1575 }
1576 EX_CATCH_HRESULT(hr);
1577
1578 return hr;
1579} // CordbType::InitInstantiationTypeHandle
1580
1581//-----------------------------------------------------------------------------
1582// Internal helper for CordbType::Init to finish initialize types for
1583// System.String or System.Object.
1584// This just needs to set the m_class field.
1585//
1586// Parameters:
1587// fForceInit - force re-initialization if already initialized.
1588//
1589// Returns:
1590// S_OK on success or CORDBG_E_CLASS_NOT_LOADED on failure.
1591//
1592// Note: verification with IPC result may assert
1593//-----------------------------------------------------------------------------
1594
1595HRESULT CordbType::InitStringOrObjectClass(BOOL fForceInit)
1596{
1597 // This CordbType is a non-generic class, either System.String or System.Object.
1598 // Need to find the CordbClass instance (in the proper AppDomain) that matches that type.
1599
1600 // Check if we've already done this Init
1601 if (!fForceInit && m_pClass != NULL)
1602 {
1603 return S_OK;
1604 }
1605
1606 HRESULT hr = S_OK;
1607
1608 EX_TRY
1609 {
1610 //
1611 // Step 1a) Send a request to the DAC to map: CorElementType --> {token, Module}
1612 //
1613 CordbProcess *pProcess = GetProcess();
1614 mdTypeDef metadataToken;
1615 VMPTR_DomainFile vmDomainFile = VMPTR_DomainFile::NullPtr();
1616 VMPTR_Module vmModule = VMPTR_Module::NullPtr();
1617
1618 {
1619 RSLockHolder lockHolder(GetProcess()->GetProcessLock());
1620 pProcess->GetDAC()->GetSimpleType(m_appdomain->GetADToken(),
1621 m_elementType,
1622 &metadataToken,
1623 &vmModule,
1624 &vmDomainFile);
1625 }
1626
1627 //
1628 // Step 2) Lookup CordbClass based off token + Module.
1629 //
1630 CordbModule * pTypeModule = m_appdomain->LookupOrCreateModule(vmModule, vmDomainFile);
1631
1632 _ASSERTE(pTypeModule != NULL);
1633 IfFailThrow(pTypeModule->LookupOrCreateClass(metadataToken, &m_pClass));
1634
1635 _ASSERTE(m_pClass != NULL);
1636
1637 _ASSERTE(SUCCEEDED(hr));
1638 m_pClass->AddRef();
1639
1640 }
1641 EX_CATCH_HRESULT(hr);
1642 return hr;
1643} // CordbType::InitStringOrObjectClass
1644
1645//-----------------------------------------------------------------------------
1646// Internal helper for CordbType::Init to get FieldInfos for a generic Type.
1647// Non-generic types can use the FieldInfos off their associated CordbClass.
1648//
1649// Parameters:
1650// fForceInit - force re-initialization if already initialized?
1651//
1652// Returns:
1653// S_OK on success.
1654//-----------------------------------------------------------------------------
1655HRESULT CordbType::InitInstantiationFieldInfo(BOOL fForceInit)
1656{
1657 HRESULT hr = S_OK;
1658
1659 // Check if we've already done this Init
1660 if (!m_fieldInfoNeedsInit && !fForceInit)
1661 {
1662 return hr;
1663 }
1664
1665 _ASSERTE(m_elementType == ELEMENT_TYPE_CLASS);
1666 _ASSERTE(m_pClass->HasTypeParams());
1667
1668 VMPTR_TypeHandle typeHandleApprox = m_typeHandleExact;
1669
1670 // If the exact type handle is not available then get the approximate type handle.
1671 if (typeHandleApprox.IsNull())
1672 {
1673 // set up a buffer to hold type parameter information for the type. (See
1674 // code:CordbType::GatherTypeData for more information). First, compute its size.
1675 unsigned int typeDataNodeCount = 0;
1676 this->CountTypeDataNodes(&typeDataNodeCount);
1677
1678 EX_TRY
1679 {
1680 // allocate a buffer to hold the parameter data
1681 TypeInfoList typeData;
1682
1683 typeData.Alloc(typeDataNodeCount);
1684
1685 // fill the buffer
1686 DebuggerIPCE_TypeArgData * pCurrent = &(typeData[0]);
1687 GatherTypeData(this, &pCurrent);
1688
1689 // request the type handle from the DAC
1690 CordbProcess *pProcess = GetProcess();
1691 {
1692 RSLockHolder lockHolder(pProcess->GetProcessLock());
1693 typeHandleApprox = pProcess->GetDAC()->GetApproxTypeHandle(&typeData);
1694 }
1695 }
1696 EX_CATCH_HRESULT(hr);
1697 if(FAILED(hr)) return hr;
1698 }
1699
1700 // OK, now get the field info if we can.
1701 CordbProcess *pProcess = GetProcess();
1702 EX_TRY
1703 {
1704 {
1705 // this may be called multiple times. Each call will discard previous values in m_fieldList and reinitialize
1706 // the list with updated information
1707 RSLockHolder lockHolder(pProcess->GetProcessLock());
1708 pProcess->GetDAC()->GetInstantiationFieldInfo(m_pClass->GetModule()->GetRuntimeDomainFile(),
1709 m_typeHandleExact,
1710 typeHandleApprox,
1711 &m_fieldList,
1712 &m_objectSize);
1713 }
1714 }
1715 EX_CATCH_HRESULT(hr);
1716
1717 return hr;
1718}
1719
1720HRESULT CordbType::ReturnedByValue()
1721{
1722 HRESULT hr = S_OK;
1723
1724 if (!IsValueType())
1725 return S_OK;
1726
1727
1728 ULONG32 unboxedSize = 0;
1729 IfFailRet(GetUnboxedObjectSize(&unboxedSize));
1730
1731 if (unboxedSize > sizeof(SIZE_T))
1732 return S_FALSE;
1733
1734 mdToken mdClass = m_pClass->GetToken();
1735
1736 int fieldCount = 0;
1737 bool unsupported = false;
1738
1739 HCORENUM fields = 0;
1740 ULONG fetched = 0;
1741 mdToken mdField;
1742 IMetaDataImport *pImport = m_pClass->GetModule()->GetMetaDataImporter();
1743 IfFailRet(pImport->EnumFields(&fields, mdClass, &mdField, 1, &fetched));
1744
1745 while (hr == S_OK && fetched == 1)
1746 {
1747 DWORD attr = 0;
1748 PCCOR_SIGNATURE sigBlob = 0;
1749 ULONG sigLen = 0;
1750 hr = pImport->GetFieldProps(mdField, NULL, NULL, 0, NULL, &attr, &sigBlob, &sigLen, NULL, NULL, NULL);
1751
1752 if (SUCCEEDED(hr))
1753 {
1754 // !static
1755 if ((attr & 0x10) == 0)
1756 {
1757 if (fieldCount++)
1758 break;
1759
1760 CorElementType et;
1761 SigParser parser(sigBlob, sigLen);
1762 parser.GetByte(NULL); // 0x6, field signature
1763 parser.SkipCustomModifiers();
1764 hr = parser.GetElemType(&et);
1765 if (SUCCEEDED(hr))
1766 {
1767 switch (et)
1768 {
1769 case ELEMENT_TYPE_R4:
1770 case ELEMENT_TYPE_R8:
1771 unsupported = true;
1772 break;
1773
1774 case ELEMENT_TYPE_CLASS:
1775 case ELEMENT_TYPE_STRING:
1776 case ELEMENT_TYPE_PTR:
1777 // OK
1778 break;
1779
1780 default:
1781 if (!CorIsPrimitiveType(et))
1782 unsupported = true;
1783 break;
1784 }
1785
1786 if (unsupported)
1787 break;
1788 }
1789 }
1790
1791 hr = pImport->EnumFields(&fields, mdClass, &mdField, 1, &fetched);
1792 }
1793
1794 if (FAILED(hr))
1795 {
1796 pImport->CloseEnum(fields);
1797 return hr;
1798 }
1799 }
1800
1801 pImport->CloseEnum(fields);
1802
1803 if (unsupported)
1804 return S_FALSE;
1805
1806 return fieldCount <= 1 ? S_OK : S_FALSE;
1807}
1808
1809
1810//-----------------------------------------------------------------------------
1811// Internal helper to get the size (in bytes) of the unboxed object.
1812// For a generic type, the size of the type depends on the size of the
1813// type-parameters.
1814// This is commonly used by Cordb*Value in their Initialization when they
1815// need to cache the size of the Target object they refer to.
1816//
1817// This should only be called on Value-types and Primitives (eg, i4, FnPtr).
1818// It should not be called on Reference types.
1819//
1820// Parameters:
1821// pObjectSize - OUT: out-parameter to get the size in bytes.
1822//
1823// Returns:
1824// S_OK on success.
1825//-----------------------------------------------------------------------------
1826HRESULT
1827CordbType::GetUnboxedObjectSize(ULONG32 *pObjectSize)
1828{
1829 INTERNAL_SYNC_API_ENTRY(GetProcess()); //
1830
1831 HRESULT hr = S_OK;
1832 bool isVC = false;
1833
1834 EX_TRY
1835 {
1836 isVC = IsValueType();
1837 }
1838 EX_CATCH_HRESULT(hr);
1839
1840 IfFailRet(hr);
1841
1842 if (isVC)
1843 {
1844 *pObjectSize = 0;
1845
1846 hr = Init(FALSE);
1847
1848 if (!SUCCEEDED(hr))
1849 return hr;
1850
1851 *pObjectSize = (ULONG) ((!m_pClass->HasTypeParams()) ? m_pClass->ObjectSize() : this->m_objectSize);
1852
1853 return hr;
1854 }
1855 else
1856 {
1857 // Caller guarantees that we're not a class. And the check above guarantees we're not a value-type.
1858 // So we're some sort of primitive, and thus we can determine size from the signature.
1859 //
1860 // @dbgtodo inspection - We didn't have this assert in Whidbey, and it's firing in vararg
1861 // scenarios even though it's returning the right value for reference types (i.e. 4 on x86 and 8 on
1862 // 64-bit). Commenting it out for now.
1863 //_ASSERTE(m_elementType != ELEMENT_TYPE_CLASS);
1864
1865 // We need to use a temporary variable here -- attempting to cast among pointer types
1866 // (i.e., (PCCOR_SIGNATURE) &m_elementType) yields incorrect results on big-endian machines
1867 COR_SIGNATURE corSig = (COR_SIGNATURE) m_elementType;
1868
1869 SigParser sigParser(&corSig, sizeof(corSig));
1870
1871 ULONG size;
1872
1873 IfFailRet(sigParser.PeekElemTypeSize(&size));
1874
1875 *pObjectSize = size;
1876 return hr;
1877 }
1878}
1879
1880VMPTR_DomainFile CordbType::GetDomainFile()
1881{
1882 if (m_pClass != NULL)
1883 {
1884 CordbModule * pModule = m_pClass->GetModule();
1885 if (pModule)
1886 {
1887 return pModule->m_vmDomainFile;
1888 }
1889 else
1890 {
1891 return VMPTR_DomainFile::NullPtr();
1892 }
1893 }
1894 else
1895 {
1896 return VMPTR_DomainFile::NullPtr();
1897 }
1898}
1899
1900
1901VMPTR_Module CordbType::GetModule()
1902{
1903 if (m_pClass != NULL)
1904 {
1905 CordbModule * pModule = m_pClass->GetModule();
1906 if (pModule)
1907 {
1908 return pModule->GetRuntimeModule();
1909 }
1910 else
1911 {
1912 return VMPTR_Module::NullPtr();
1913 }
1914 }
1915 else
1916 {
1917 return VMPTR_Module::NullPtr();
1918 }
1919}
1920//-----------------------------------------------------------------------------
1921// Internal method to Marshal: CordbType --> DebuggerIPCE_BasicTypeData
1922// Nb. CordbType::Init will call this. The operation
1923// fails if the exact type information has been requested but was not available
1924//
1925// Parameters:
1926// data - OUT: BasicTypeData instance to fill out.
1927//
1928// Returns:
1929// S_OK on success, CORDBG_E_CLASS_NOT_LOADED on failure
1930//-----------------------------------------------------------------------------
1931HRESULT CordbType::TypeToBasicTypeData(DebuggerIPCE_BasicTypeData *data)
1932{
1933 switch (m_elementType)
1934 {
1935 case ELEMENT_TYPE_ARRAY:
1936 case ELEMENT_TYPE_SZARRAY:
1937 case ELEMENT_TYPE_BYREF:
1938 case ELEMENT_TYPE_PTR:
1939 data->elementType = m_elementType;
1940 data->metadataToken = mdTokenNil;
1941 data->vmDomainFile = VMPTR_DomainFile::NullPtr();
1942 data->vmTypeHandle = m_typeHandleExact;
1943 if (data->vmTypeHandle.IsNull())
1944 {
1945 return CORDBG_E_CLASS_NOT_LOADED;
1946 }
1947 _ASSERTE(!data->vmTypeHandle.IsNull());
1948 break;
1949
1950 case ELEMENT_TYPE_CLASS:
1951 _ASSERTE(m_pClass != NULL);
1952 data->elementType = m_pClass->IsValueClassNoInit() ? ELEMENT_TYPE_VALUETYPE : ELEMENT_TYPE_CLASS;
1953 data->metadataToken = m_pClass->MDToken();
1954 data->vmDomainFile = GetDomainFile();
1955 data->vmTypeHandle = m_typeHandleExact;
1956 if (m_pClass->HasTypeParams() && data->vmTypeHandle.IsNull())
1957 {
1958 return CORDBG_E_CLASS_NOT_LOADED;
1959 }
1960 break;
1961 default:
1962 // This includes all the "primitive" types, in which CorElementType is a sufficient description.
1963 data->elementType = m_elementType;
1964 data->metadataToken = mdTokenNil;
1965 data->vmDomainFile = VMPTR_DomainFile::NullPtr();
1966 data->vmTypeHandle = VMPTR_TypeHandle::NullPtr();
1967 break;
1968 }
1969 return S_OK;
1970}
1971
1972//-----------------------------------------------------------------------------
1973// Internal method to marshal: CordbType --> ExpandedTypeData
1974//
1975// Nb. CordbType::Init need NOT have been called before this...
1976// Also, this does not write the type arguments. How this is done depends
1977// depends on where this is called from.
1978//
1979// Parameters:
1980// data - OUT: outgoing ExpandedTypeData to fill in with stats about CordbType.
1981//-----------------------------------------------------------------------------
1982void CordbType::TypeToExpandedTypeData(DebuggerIPCE_ExpandedTypeData *data)
1983{
1984
1985 switch (m_elementType)
1986 {
1987 case ELEMENT_TYPE_ARRAY:
1988 case ELEMENT_TYPE_SZARRAY:
1989
1990 data->ArrayTypeData.arrayRank = m_rank;
1991 data->elementType = m_elementType;
1992 break;
1993
1994 case ELEMENT_TYPE_BYREF:
1995 case ELEMENT_TYPE_PTR:
1996 case ELEMENT_TYPE_FNPTR:
1997
1998 data->elementType = m_elementType;
1999 break;
2000
2001 case ELEMENT_TYPE_CLASS:
2002 {
2003 data->elementType = m_pClass->IsValueClassNoInit() ? ELEMENT_TYPE_VALUETYPE : ELEMENT_TYPE_CLASS;
2004 data->ClassTypeData.metadataToken = m_pClass->GetToken();
2005 data->ClassTypeData.vmDomainFile = GetDomainFile();
2006 data->ClassTypeData.vmModule = GetModule();
2007 data->ClassTypeData.typeHandle = VMPTR_TypeHandle::NullPtr();
2008
2009 break;
2010 }
2011 case ELEMENT_TYPE_END:
2012 _ASSERTE(!"bad element type!");
2013
2014 default:
2015 data->elementType = m_elementType;
2016 break;
2017 }
2018}
2019
2020
2021void CordbType::TypeToTypeArgData(DebuggerIPCE_TypeArgData *data)
2022{
2023 TypeToExpandedTypeData(&(data->data));
2024 data->numTypeArgs = m_inst.m_cClassTyPars;
2025}
2026
2027
2028//-----------------------------------------------------------------------------
2029// Query if this CordbType represents a ValueType (Does not include primitives).
2030// Since CordbType doesn't record ValueType status, this may involve querying
2031// the CordbClass or even asking the Left-Side (if the CordbClass is not init)
2032//
2033// Return Value:
2034// indicates whether this is a value type
2035// Note:
2036// Throws.
2037//-----------------------------------------------------------------------------
2038bool CordbType::IsValueType()
2039{
2040 if (m_elementType == ELEMENT_TYPE_CLASS)
2041 {
2042 return m_pClass->IsValueClass();
2043 }
2044 else
2045 return false;
2046}
2047
2048//------------------------------------------------------------------------
2049// If this is a ptr type, get the CordbType that it points to.
2050// Eg, for CordbType("Int*") or CordbType("Int&"), returns CordbType("Int").
2051// If not a ptr type, returns null.
2052// Since it's all internal, no reference counting.
2053// This is effectively a specialized version of DestUnaryType.
2054//------------------------------------------------------------------------
2055CordbType * CordbType::GetPointerElementType()
2056{
2057 if ((m_elementType != ELEMENT_TYPE_PTR) && (m_elementType != ELEMENT_TYPE_BYREF))
2058 {
2059 return NULL;
2060 }
2061
2062 CordbType * pOut;
2063 DestUnaryType(&pOut);
2064
2065 _ASSERTE(pOut != NULL);
2066 return pOut;
2067}
2068//------------------------------------------------------------------------
2069// Helper for IsGcRoot.
2070// Determine if the element type is a non GC-root candidate.
2071// Updating GC-roots requires coordinating with the GC's write-barrier.
2072// Whereas non-GC roots can be updated more freely.
2073//
2074// Parameters:
2075// et - An element type.
2076// Returns:
2077// True if variables of et can be used as a GC root.
2078//------------------------------------------------------------------------
2079static inline bool IsElementTypeNonGcRoot(CorElementType et)
2080{
2081 // Functon ptrs are raw data, not GC-roots.
2082 if (et == ELEMENT_TYPE_FNPTR)
2083 {
2084 return true;
2085 }
2086
2087 // This is almost exactly if we're a primitive, but
2088 // primitives include some things that could be GC-roots, so we strip those out,
2089 return CorIsPrimitiveType(et)
2090 && (et != ELEMENT_TYPE_STRING) && (et != ELEMENT_TYPE_VOID); // exlcude these from primitives
2091
2092}
2093//------------------------------------------------------------------------
2094// Helper for IsGcRoot
2095// Non-gc roots include Value types + non-gc elemement types (like E_T_I4, E_T_FNPTR)
2096//
2097// Parameters:
2098// pType - type to check whether it's a GC-root.
2099// Returns:
2100// true if we know we're not a GC-root
2101// false if we still might be (so caller must do further checkin)
2102//------------------------------------------------------------------------
2103static inline bool _IsNonGCRootHelper(CordbType * pType)
2104{
2105 _ASSERTE(pType != NULL);
2106
2107 CorElementType et = pType->GetElementType();
2108 if (IsElementTypeNonGcRoot(et))
2109 {
2110 return true;
2111 }
2112
2113 HRESULT hr = S_OK;
2114 bool fValueClass = false;
2115
2116 // If we are a value-type, then we can't be a Gc-root.
2117 EX_TRY
2118 {
2119 fValueClass = pType->IsValueType();
2120 }
2121 EX_CATCH_HRESULT(hr);
2122 if (FAILED(hr) || fValueClass)
2123 {
2124 return true;
2125 }
2126
2127 // Don't know
2128 return false;
2129}
2130
2131//-----------------------------------------------------------------------------
2132// Is this type a GC-root. (Not to be confused w/ "does this contain embedded GC roots")
2133// All object references are GC-roots. E_T_PTR are actually not GC-roots.
2134//
2135// Returns:
2136// True - if this is a GC-root.
2137// False - not a GC root.
2138//-----------------------------------------------------------------------------
2139bool CordbType::IsGCRoot()
2140{
2141 // If it's a E_T_PTR type, then look at what it's a a pointer of.
2142 CordbType * pPtr = this->GetPointerElementType();
2143 if (pPtr == NULL)
2144 {
2145 // If non pointer, than we can just look at our current type.
2146 return !_IsNonGCRootHelper(this);
2147 }
2148
2149 return !_IsNonGCRootHelper(pPtr);
2150}
2151
2152
2153//------------------------------------------------------------------------
2154// Public function to enumerate type-parameters.
2155// Parameters:
2156// ppTypeParameterEnum - OUT: on return, get an enumerator.
2157// Returns:
2158// S_OK on success.
2159//------------------------------------------------------------------------
2160HRESULT CordbType::EnumerateTypeParameters(ICorDebugTypeEnum **ppTypeParameterEnum)
2161{
2162 PUBLIC_API_ENTRY(this);
2163 VALIDATE_POINTER_TO_OBJECT(ppTypeParameterEnum, ICorDebugTypeEnum **);
2164 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
2165
2166
2167 CordbTypeEnum *icdTPE = CordbTypeEnum::Build(m_appdomain, m_appdomain->GetLongExitNeuterList(), this->m_inst.m_cInst, this->m_inst.m_ppInst);
2168 if ( icdTPE == NULL )
2169 {
2170 (*ppTypeParameterEnum) = NULL;
2171 return E_OUTOFMEMORY;
2172 }
2173
2174 (*ppTypeParameterEnum) = static_cast<ICorDebugTypeEnum*> (icdTPE);
2175 icdTPE->ExternalAddRef();
2176 return S_OK;
2177}
2178
2179
2180//-----------------------------------------------------------------------------
2181// CordbType::GetBase
2182// Public convenience method to get the instantiated base type.
2183//
2184// Parameters:
2185// ppType - OUT: yields the base type for the current type.
2186//
2187// Returns:
2188// S_OK if succeeded.
2189//
2190HRESULT CordbType::GetBase(ICorDebugType ** ppType)
2191{
2192 PUBLIC_REENTRANT_API_ENTRY(this);
2193 ATT_ALLOW_LIVE_DO_STOPGO(this->GetProcess()); // @todo - can this by RequiredStopped?
2194
2195 HRESULT hr = S_OK;
2196
2197 LOG((LF_CORDB, LL_EVERYTHING, "CordbType::GetBase called\n"));
2198
2199 VALIDATE_POINTER_TO_OBJECT(ppType, ICorDebugType **);
2200
2201 if (m_elementType != ELEMENT_TYPE_CLASS)
2202 {
2203 return E_INVALIDARG;
2204 }
2205
2206 EX_TRY
2207 {
2208 CordbType * pType = NULL;
2209
2210 _ASSERTE(m_pClass != NULL);
2211
2212 // Get the supertype from metadata for m_class
2213 mdToken extendsToken;
2214
2215 IMetaDataImport * pImport = m_pClass->GetModule()->GetMetaDataImporter(); // throws
2216
2217 hr = pImport->GetTypeDefProps(m_pClass->MDToken(), NULL, 0, NULL, NULL, &extendsToken);
2218 IfFailThrow(hr);
2219
2220 // Now create a CordbType instance for the base type that has the same type parameters as the derived type.
2221 if ((extendsToken == mdTypeDefNil) || (extendsToken == mdTypeRefNil) || (extendsToken == mdTokenNil))
2222 {
2223 // No base class.
2224 pType = NULL;
2225 }
2226 else if (TypeFromToken(extendsToken) == mdtTypeSpec)
2227 {
2228 // TypeSpec has a signature. So get the sig and convert it to a CordbType.
2229 // generic base class of a generic type is a TypeSpec.
2230 // If we have:
2231 // class Triple<T,U,V> derives from Pair<T,V>,
2232 // then the base class for Triple would be a TypeSpec:
2233 // Class(Pair<T,V>), 2 args, ELEMENT_TYPE_VAR #0, ELEMENT_TYPE_VAR#2.
2234 // m_inst provides the type-parameters to resolve the ELEMENT_TYPE_VAR types.
2235
2236 PCCOR_SIGNATURE pSig;
2237 ULONG sigSize;
2238
2239 // Get the signature for the constructed supertype...
2240 hr = pImport->GetTypeSpecFromToken(extendsToken, &pSig, &sigSize);
2241 IfFailThrow(hr);
2242
2243 _ASSERTE(pSig != NULL);
2244
2245 SigParser sigParser(pSig, sigSize);
2246
2247 // Instantiate the signature of the supertype using the type instantiation for
2248 // the current type....
2249 hr = SigToType(m_pClass->GetModule(), &sigParser, &m_inst, &pType);
2250 IfFailThrow(hr);
2251 }
2252 else if ((TypeFromToken(extendsToken) == mdtTypeRef) || (TypeFromToken(extendsToken) == mdtTypeDef))
2253 {
2254 // TypeDef/TypeRef for non-generic base-class class.
2255 CordbClass * pSuperClass;
2256
2257 hr = m_pClass->GetModule()->ResolveTypeRefOrDef(extendsToken, &pSuperClass);
2258 IfFailThrow(hr);
2259
2260 _ASSERTE(pSuperClass != NULL);
2261
2262 hr = MkUnparameterizedType(m_appdomain, ELEMENT_TYPE_CLASS, pSuperClass, &pType);
2263 IfFailThrow(hr);
2264 }
2265 else
2266 {
2267 pType = NULL;
2268 _ASSERTE(!"unexpected token!");
2269 }
2270
2271 // At this point, we've succeeded
2272 _ASSERTE(SUCCEEDED(hr));
2273
2274 (*ppType) = pType;
2275
2276 if (*ppType)
2277 {
2278 pType->AddRef();
2279 }
2280 }
2281 EX_CATCH_HRESULT(hr);
2282 return hr;
2283}
2284
2285//-----------------------------------------------------------------------------
2286// CordbType::GetTypeID
2287// Method to get the COR_TYPEID corresponding to this CordbType.
2288//
2289// Parameters:
2290// pId - OUT: gives the COR_TYPEID for this CordbType
2291//
2292// Returns:
2293// S_OK if succeeded.
2294// CORDBG_E_CLASS_NOT_LOADED if the type which this CordbType represents has
2295// not been loaded in the runtime.
2296// E_POINTER if pId is NULL
2297// CORDBG_E_UNSUPPORTED for unsupported types.
2298//
2299HRESULT CordbType::GetTypeID(COR_TYPEID *pId)
2300{
2301 LOG((LF_CORDB, LL_INFO1000, "GetTypeID\n"));
2302 if (pId == NULL)
2303 return E_POINTER;
2304
2305 HRESULT hr = S_OK;
2306
2307 PUBLIC_API_ENTRY(this);
2308 RSLockHolder stopGoLock(GetProcess()->GetStopGoLock());
2309 RSLockHolder procLock(GetProcess()->GetProcessLock());
2310
2311 EX_TRY
2312 {
2313 hr = Init(FALSE);
2314 IfFailThrow(hr);
2315
2316 VMPTR_TypeHandle vmTypeHandle;
2317
2318 CorElementType et = GetElementType();
2319 switch (et)
2320 {
2321 case ELEMENT_TYPE_OBJECT:
2322 case ELEMENT_TYPE_VOID:
2323 case ELEMENT_TYPE_BOOLEAN:
2324 case ELEMENT_TYPE_CHAR:
2325 case ELEMENT_TYPE_I1:
2326 case ELEMENT_TYPE_U1:
2327 case ELEMENT_TYPE_I2:
2328 case ELEMENT_TYPE_U2:
2329 case ELEMENT_TYPE_I4:
2330 case ELEMENT_TYPE_U4:
2331 case ELEMENT_TYPE_I8:
2332 case ELEMENT_TYPE_U8:
2333 case ELEMENT_TYPE_R4:
2334 case ELEMENT_TYPE_R8:
2335 case ELEMENT_TYPE_STRING:
2336 case ELEMENT_TYPE_TYPEDBYREF:
2337 case ELEMENT_TYPE_I:
2338 case ELEMENT_TYPE_U:
2339 {
2340 mdTypeDef mdToken;
2341 VMPTR_Module vmModule = VMPTR_Module::NullPtr();
2342 VMPTR_DomainFile vmDomainFile = VMPTR_DomainFile::NullPtr();
2343
2344 // get module and token of the simple type
2345 GetProcess()->GetDAC()->GetSimpleType(GetAppDomain()->GetADToken(),
2346 et,
2347 &mdToken,
2348 &vmModule,
2349 &vmDomainFile);
2350
2351 vmTypeHandle = GetProcess()->GetDAC()->GetTypeHandle(vmModule, mdToken);
2352 }
2353 break;
2354 case ELEMENT_TYPE_ARRAY:
2355 case ELEMENT_TYPE_SZARRAY:
2356 {
2357 LOG((LF_CORDB, LL_INFO1000, "GetTypeID: parameterized type\n"));
2358 if (m_typeHandleExact.IsNull())
2359 {
2360 hr = InitInstantiationTypeHandle(FALSE);
2361 IfFailThrow(hr);
2362 }
2363 vmTypeHandle = m_typeHandleExact;
2364 }
2365 break;
2366 case ELEMENT_TYPE_CLASS:
2367 {
2368 ICorDebugClass *pICDClass = NULL;
2369 hr = GetClass(&pICDClass);
2370 IfFailThrow(hr);
2371 CordbClass *pClass = (CordbClass*)pICDClass;
2372 _ASSERTE(pClass != NULL);
2373
2374 if (pClass->HasTypeParams())
2375 {
2376 vmTypeHandle = m_typeHandleExact;
2377 }
2378 else
2379 {
2380 mdTypeDef mdToken;
2381 hr = pClass->GetToken(&mdToken);
2382 IfFailThrow(hr);
2383
2384 VMPTR_Module vmModule = GetModule();
2385 vmTypeHandle = GetProcess()->GetDAC()->GetTypeHandle(vmModule, mdToken);
2386 }
2387 }
2388 break;
2389 case ELEMENT_TYPE_PTR:
2390 case ELEMENT_TYPE_BYREF:
2391 case ELEMENT_TYPE_FNPTR:
2392 IfFailThrow(CORDBG_E_UNSUPPORTED);
2393 default:
2394 _ASSERTE(!"unexpected element type!");
2395 IfFailThrow(CORDBG_E_UNSUPPORTED);
2396 break;
2397 }
2398
2399 GetProcess()->GetDAC()->GetTypeIDForType(vmTypeHandle, pId);
2400 }
2401 EX_CATCH_HRESULT(hr);
2402
2403 return hr;
2404}
2405
2406//-----------------------------------------------------------------------------
2407// Get rich field information given a token.
2408//
2409// Parameters:
2410// fldToken - metadata field token specifying a field on this Type.
2411// ppFieldData - OUT: get the rich field information for the given field
2412//
2413// Returns:
2414// S_OK on success. CORDBG_E_ENC_HANGING_FIELD for EnC fields (common case)
2415// Other errors on failure case.
2416//-----------------------------------------------------------------------------
2417HRESULT CordbType::GetFieldInfo(mdFieldDef fldToken, FieldData ** ppFieldData)
2418{
2419 INTERNAL_SYNC_API_ENTRY(GetProcess()); //
2420 HRESULT hr = S_OK;
2421
2422 *ppFieldData = NULL;
2423
2424 EX_TRY
2425 {
2426 if (m_elementType != ELEMENT_TYPE_CLASS)
2427 {
2428 ThrowHR(E_INVALIDARG);
2429 }
2430
2431 // Initialize so that the field information is up-to-date.
2432 hr = Init(FALSE);
2433 IfFailThrow(hr);
2434
2435 if (m_pClass->HasTypeParams())
2436 {
2437 if (m_fieldList.IsEmpty())
2438 {
2439 ThrowHR(CORDBG_E_FIELD_NOT_AVAILABLE);
2440 }
2441 else
2442 {
2443 // Use a static helper function in CordbClass, though we're really
2444 // searching through this->m_fields
2445 hr = CordbClass::SearchFieldInfo(m_pClass->GetModule(),
2446 &m_fieldList,
2447 m_pClass->MDToken(),
2448 fldToken,
2449 ppFieldData);
2450 // fall through and return.
2451 // Let possible CORDBG_E_ENC_HANGING_FIELD errors propogate
2452 }
2453 }
2454 else
2455 {
2456 hr = m_pClass->GetFieldInfo(fldToken, ppFieldData); // this is for non-generic types....
2457 // Let possible CORDBG_E_ENC_HANGING_FIELD errors propogate
2458 }
2459 }
2460 EX_CATCH_HRESULT(hr);
2461 _ASSERTE(SUCCEEDED(hr) == (*ppFieldData != NULL));
2462 return hr;
2463}
2464
2465
2466//-----------------------------------------------------------------------------
2467// Class is a class somewhere on the hierarchy for m_type. Search for
2468// a CordbType corresponding to the CordbClass, but which has the type-parameters
2469// from the current CordbType.
2470// In other words, instantiate a CordbType from baseClass, using the type-params
2471// in the current Type.
2472//
2473// For example, given:
2474// class C<T>
2475// class D : C<int>
2476// then if the CordbObjectValue is of type D and pClass is the class
2477// for "C", then searching will set relevantType to C<int>. This
2478// type is then used to fetch fields from the object.
2479//
2480// Adds a reference to the resulting type. Since this is for internal
2481// use only we probably don't need todo this...
2482//
2483// Parameters:
2484// baseClass - open Type that needs to be instantiated with this CordbType's params.
2485// ppRes - OUT: out-parameter to get CordbType. ppRes->GetClass() should equal baseClass.
2486//
2487// Returns:
2488// S_OK on success. CORDBG_E_OBJECT_NEUTERED, CORDBG_E_CLASS_NOT_LOADED, E_INVALIDARG, OOM
2489//-----------------------------------------------------------------------------
2490HRESULT CordbType::GetParentType(CordbClass *baseClass, CordbType **ppRes)
2491{
2492 INTERNAL_SYNC_API_ENTRY(GetProcess()); //
2493
2494 // Ensure that we're not trying to match up against a neutered class.
2495 if (baseClass->IsNeutered())
2496 {
2497 return CORDBG_E_OBJECT_NEUTERED;
2498 }
2499
2500 HRESULT hr = S_OK;
2501 _ASSERTE(ppRes);
2502 *ppRes = NULL;
2503 CordbType *res = this;
2504 res->AddRef();
2505 int safety = 20000; // no inheritance hierarchy is 20000 deep... we include this just in case there's a issue below and we don't terminate
2506 while (safety--)
2507 {
2508 if (res->m_pClass == NULL)
2509 {
2510 if (FAILED(hr = res->Init(FALSE)))
2511 {
2512 res->Release();
2513 return hr;
2514 }
2515 }
2516 _ASSERTE(res->m_pClass);
2517 if (res->m_pClass == baseClass)
2518 {
2519 // Found it!
2520 break;
2521 }
2522
2523 // Another way to determine if we're talking about the
2524 // same class... Compare tokens and module.
2525 mdTypeDef tok;
2526 mdTypeDef targetTok;
2527 if (FAILED(hr = res->m_pClass->GetToken(&tok))
2528 || FAILED(hr = baseClass->GetToken(&targetTok)))
2529 {
2530 res->Release();
2531 return hr;
2532 }
2533 if (tok == targetTok && res->m_pClass->GetModule() == baseClass->GetModule())
2534 {
2535 // Found it!
2536 break;
2537 }
2538
2539 // OK, this is not the right class so look up the inheritance chain
2540 ICorDebugType *nextType = NULL;
2541 if (FAILED(hr = res->GetBase(&nextType)))
2542 {
2543 res->Release();
2544 return hr;
2545 }
2546
2547 res->Release(); // matches the AddRef above and/or the one implicit in GetBase, for all but last time around the loop
2548 res = static_cast<CordbType *> (nextType);
2549 if (!res || res->m_elementType == ELEMENT_TYPE_OBJECT)
2550 {
2551 // Did not find it...
2552 break;
2553 }
2554 }
2555 // We exit the loop above owning one reference to res.
2556 // Upon exit res will either be the appropriate type for the
2557 // class we're looking for or will be the CordbType for System.Object
2558 // or will be NULL
2559
2560 // If it's System.Object then assume something's gone wrong with
2561 // the way we did the search and bail out to an old fashioned
2562 // MkUnparameterizedType on the class given originally
2563 if (!res || res->m_elementType == ELEMENT_TYPE_OBJECT)
2564 {
2565 if (res)
2566 res->Release(); // matches the one left over from the loop
2567 IfFailRet(CordbType::MkUnparameterizedType(baseClass->GetAppDomain(), ELEMENT_TYPE_CLASS, baseClass, &res));
2568 res->AddRef();
2569 }
2570
2571
2572 *ppRes = res;
2573 return hr;
2574}
2575
2576
2577//-----------------------------------------------------------------------------
2578// Walk a type tree, writing the number of type args including internal nodes.
2579//
2580// Parameters:
2581// count - IN/OUT: counter to update.
2582//-----------------------------------------------------------------------------
2583void CordbType::CountTypeDataNodes(unsigned int *count)
2584{
2585 (*count)++;
2586 for (unsigned int i = 0; i < this->m_inst.m_cClassTyPars; i++)
2587 {
2588 this->m_inst.m_ppInst[i]->CountTypeDataNodes(count);
2589 }
2590}
2591
2592//-----------------------------------------------------------------------------
2593// Internal helper method.
2594// Counts the total generic args (including sub-args) for an Instantiation.
2595// Eg, for List<int, Pair<string, float>>, it would return 3.
2596//
2597// Parameters:
2598// genericArgsCount - size of the genericArgs array in elements.
2599// genericArgs - array of type parameters.
2600// count - IN/OUT - will increment with total number of generic args.
2601// caller must intialize this (likely to 0).
2602//-----------------------------------------------------------------------------
2603void CordbType::CountTypeDataNodesForInstantiation(unsigned int genericArgsCount, ICorDebugType *genericArgs[], unsigned int *count)
2604{
2605 for (unsigned int i = 0; i < genericArgsCount; i++)
2606 {
2607 (static_cast<CordbType *>(genericArgs[i]))->CountTypeDataNodes(count);
2608 }
2609}
2610
2611//-----------------------------------------------------------------------------
2612// Recursively walk a type tree, writing the type args into a linear.
2613// Eg, for List<A, Pair<B, C>>, this will write the TypeArgData buffer
2614// for { A, B, C }.
2615//
2616// Parameters:
2617// curr_tyargData - IN/OUT: Pointer into buffer of TypeArgData structures.
2618// Caller must ensure this buffer is large enough (probably by calling
2619// CountTypeDataNodes).
2620// On output, set to the next element in the buffer.
2621//-----------------------------------------------------------------------------
2622void CordbType::GatherTypeData(CordbType *type, DebuggerIPCE_TypeArgData **curr_tyargData)
2623{
2624 type->TypeToTypeArgData(*curr_tyargData);
2625 (*curr_tyargData)++;
2626 for (unsigned int i = 0; i < type->m_inst.m_cClassTyPars; i++)
2627 {
2628 GatherTypeData(type->m_inst.m_ppInst[i], curr_tyargData);
2629 }
2630}
2631
2632//-----------------------------------------------------------------------------
2633// Flatten Instantiation into a linear buffer of TypeArgData
2634// Use CountTypeDataNodesForInstantiation on the instantiation to get a large
2635// enough buffer.
2636//
2637// Parameters:
2638// genericArgsCount - size of genericArgs array in elements.
2639// genericArgs - incoming array to walk
2640// curr_tyargData - IN/OUT: Pointer into buffer of TypeArgData structures.
2641// Caller must ensure this buffer is large enough (probably by calling
2642// CountTypeDataNodes).
2643// On output, set to the next element in the buffer.
2644//
2645//-----------------------------------------------------------------------------
2646void CordbType::GatherTypeDataForInstantiation(unsigned int genericArgsCount, ICorDebugType *genericArgs[], DebuggerIPCE_TypeArgData **curr_tyargData)
2647{
2648 for (unsigned int i = 0; i < genericArgsCount; i++)
2649 {
2650 GatherTypeData(static_cast<CordbType *> (genericArgs[i]), curr_tyargData);
2651 }
2652}
2653
2654#ifdef FEATURE_64BIT_ALIGNMENT
2655// checks if the type requires 8-byte alignment. the algorithm used here
2656// was adapted from AdjustArgPtrForAlignment() in bcltype/VarArgsNative.cpp
2657HRESULT CordbType::RequiresAlign8(BOOL* isRequired)
2658{
2659 if (isRequired == NULL)
2660 return E_INVALIDARG;
2661
2662 HRESULT hr = S_OK;
2663
2664 EX_TRY
2665 {
2666 *isRequired = FALSE;
2667
2668 ULONG32 size = 0;
2669 GetUnboxedObjectSize(&size);
2670
2671 if (size >= 8)
2672 {
2673 CorElementType type;
2674 GetType(&type);
2675
2676 if (type != ELEMENT_TYPE_TYPEDBYREF)
2677 {
2678 if (type == ELEMENT_TYPE_VALUETYPE)
2679 {
2680 if (m_typeHandleExact.IsNull())
2681 InitInstantiationTypeHandle(FALSE);
2682
2683 *isRequired = GetProcess()->GetDAC()->RequiresAlign8(m_typeHandleExact);
2684 }
2685 else
2686 {
2687 *isRequired = TRUE;
2688 }
2689 }
2690 }
2691 }
2692 EX_CATCH_HRESULT(hr);
2693
2694 return hr;
2695}
2696#endif
2697
2698/* ------------------------------------------------------------------------- *
2699 * TypeParameter Enumerator class
2700 * ------------------------------------------------------------------------- */
2701
2702// Factory methods
2703CordbTypeEnum* CordbTypeEnum::Build(CordbAppDomain * pAppDomain, NeuterList * pNeuterList, unsigned int cTypars, CordbType **ppTypars)
2704{
2705 return BuildImpl( pAppDomain, pNeuterList, cTypars, ppTypars );
2706}
2707
2708CordbTypeEnum* CordbTypeEnum::Build(CordbAppDomain * pAppDomain, NeuterList * pNeuterList, unsigned int cTypars, RSSmartPtr<CordbType> *ppTypars)
2709{
2710 return BuildImpl( pAppDomain, pNeuterList, cTypars, ppTypars );
2711}
2712
2713//-----------------------------------------------------------------------------
2714// We need to support taking both an array of CordbType* and an array of RSSmartPtr<CordbType>,
2715// but the code is identical in both cases. Rather than duplicate any code explicity, it's better to
2716// have the compiler do it for us using this template method.
2717// Another option would be to create an IList<T> interface and implementations for both arrays
2718// of T* and arrays of RSSmartPtr<T>. This would be more generally useful, but much more code.
2719//-----------------------------------------------------------------------------
2720template<class T> CordbTypeEnum* CordbTypeEnum::BuildImpl(CordbAppDomain * pAppDomain, NeuterList * pNeuterList, unsigned int cTypars, T* ppTypars)
2721{
2722 CordbTypeEnum* newEnum = new (nothrow) CordbTypeEnum( pAppDomain, pNeuterList );
2723 if( NULL == newEnum )
2724 {
2725 return NULL;
2726 }
2727
2728 _ASSERTE( newEnum->m_ppTypars == NULL );
2729 newEnum->m_ppTypars = new (nothrow) RSSmartPtr<CordbType> [cTypars];
2730 if( newEnum->m_ppTypars == NULL )
2731 {
2732 delete newEnum;
2733 return NULL;
2734 }
2735
2736 newEnum->m_iMax = cTypars;
2737 for (unsigned int i = 0; i < cTypars; i++)
2738 {
2739 newEnum->m_ppTypars[i].Assign(ppTypars[i]);
2740 }
2741
2742 return newEnum;
2743}
2744
2745// Private, called only by Build above
2746CordbTypeEnum::CordbTypeEnum(CordbAppDomain * pAppDomain, NeuterList * pNeuterList) :
2747 CordbBase(pAppDomain->GetProcess(), 0),
2748 m_ppTypars(NULL),
2749 m_iCurrent(0),
2750 m_iMax(0)
2751{
2752 _ASSERTE(pAppDomain != NULL);
2753 _ASSERTE(pNeuterList != NULL);
2754
2755 m_pAppDomain = pAppDomain;
2756
2757 HRESULT hr = S_OK;
2758 EX_TRY
2759 {
2760 pNeuterList->Add(GetProcess(), this);
2761 }
2762 EX_CATCH_HRESULT(hr);
2763 SetUnrecoverableIfFailed(GetProcess(), hr);
2764}
2765
2766CordbTypeEnum::~CordbTypeEnum()
2767{
2768 _ASSERTE(this->IsNeutered());
2769}
2770
2771void CordbTypeEnum::Neuter()
2772{
2773 delete [] m_ppTypars;
2774 m_ppTypars = NULL;
2775 m_pAppDomain = NULL;
2776
2777 CordbBase::Neuter();
2778}
2779
2780
2781HRESULT CordbTypeEnum::QueryInterface(REFIID id, void **pInterface)
2782{
2783 if (id == IID_ICorDebugEnum)
2784 *pInterface = static_cast<ICorDebugEnum*>(this);
2785 else if (id == IID_ICorDebugTypeEnum)
2786 *pInterface = static_cast<ICorDebugTypeEnum*>(this);
2787 else if (id == IID_IUnknown)
2788 *pInterface = static_cast<IUnknown*>(static_cast<ICorDebugTypeEnum*>(this));
2789 else
2790 {
2791 *pInterface = NULL;
2792 return E_NOINTERFACE;
2793 }
2794
2795 ExternalAddRef();
2796 return S_OK;
2797}
2798
2799HRESULT CordbTypeEnum::Skip(ULONG celt)
2800{
2801 PUBLIC_API_ENTRY(this);
2802 FAIL_IF_NEUTERED(this);
2803 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
2804
2805 HRESULT hr = E_FAIL;
2806 if ( (m_iCurrent+celt) < m_iMax ||
2807 celt == 0)
2808 {
2809 m_iCurrent += celt;
2810 hr = S_OK;
2811 }
2812
2813 return hr;
2814}
2815
2816HRESULT CordbTypeEnum::Reset(void)
2817{
2818 PUBLIC_API_ENTRY(this);
2819 FAIL_IF_NEUTERED(this);
2820 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
2821
2822 m_iCurrent = 0;
2823 return S_OK;
2824}
2825
2826HRESULT CordbTypeEnum::Clone(ICorDebugEnum **ppEnum)
2827{
2828 PUBLIC_API_ENTRY(this);
2829 FAIL_IF_NEUTERED(this);
2830 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
2831
2832
2833 VALIDATE_POINTER_TO_OBJECT(ppEnum, ICorDebugEnum **);
2834
2835 HRESULT hr = S_OK;
2836
2837 CordbTypeEnum *pCVE = CordbTypeEnum::Build( m_pAppDomain, m_pAppDomain->GetLongExitNeuterList(), m_iMax, m_ppTypars );
2838 if ( pCVE == NULL )
2839 {
2840 (*ppEnum) = NULL;
2841 hr = E_OUTOFMEMORY;
2842 goto LExit;
2843 }
2844
2845 pCVE->AddRef();
2846 (*ppEnum) = (ICorDebugEnum*)pCVE;
2847
2848LExit:
2849 return hr;
2850}
2851
2852HRESULT CordbTypeEnum::GetCount(ULONG *pcelt)
2853{
2854 PUBLIC_API_ENTRY(this);
2855 FAIL_IF_NEUTERED(this);
2856 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
2857
2858 VALIDATE_POINTER_TO_OBJECT(pcelt, ULONG *);
2859
2860 if( pcelt == NULL)
2861 return E_INVALIDARG;
2862
2863 (*pcelt) = m_iMax;
2864 return S_OK;
2865}
2866
2867//
2868// In the event of failure, the current pointer will be left at
2869// one element past the troublesome element. Thus, if one were
2870// to repeatedly ask for one element to iterate through the
2871// array, you would iterate exactly m_iMax times, regardless
2872// of individual failures.
2873HRESULT CordbTypeEnum::Next(ULONG celt, ICorDebugType *values[], ULONG *pceltFetched)
2874{
2875 PUBLIC_API_ENTRY(this);
2876 FAIL_IF_NEUTERED(this);
2877 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
2878
2879
2880 VALIDATE_POINTER_TO_OBJECT_ARRAY(values, ICorDebugClass *,
2881 celt, true, true);
2882 VALIDATE_POINTER_TO_OBJECT_OR_NULL(pceltFetched, ULONG *);
2883
2884 if ((pceltFetched == NULL) && (celt != 1))
2885 {
2886 return E_INVALIDARG;
2887 }
2888
2889 if (celt == 0)
2890 {
2891 if (pceltFetched != NULL)
2892 {
2893 *pceltFetched = 0;
2894 }
2895 return S_OK;
2896 }
2897
2898 HRESULT hr = S_OK;
2899
2900 int iMax = min( m_iMax, m_iCurrent+celt);
2901 int i;
2902
2903 for (i = m_iCurrent; i < iMax; i++)
2904 {
2905 //printf("CordbTypeEnum::Next, returning = 0x%08x.\n", m_ppTypars[i]);
2906 values[i-m_iCurrent] = m_ppTypars[i];
2907 values[i-m_iCurrent]->AddRef();
2908 }
2909
2910 int count = (i - m_iCurrent);
2911
2912 if ( FAILED( hr ) )
2913 { //we failed: +1 pushes us past troublesome element
2914 m_iCurrent += 1 + count;
2915 }
2916 else
2917 {
2918 m_iCurrent += count;
2919 }
2920
2921 if (pceltFetched != NULL)
2922 {
2923 *pceltFetched = count;
2924 }
2925
2926 //
2927 // If we reached the end of the enumeration, but not the end
2928 // of the number of requested items, we return S_FALSE.
2929 //
2930 if (((ULONG)count) < celt)
2931 {
2932 return S_FALSE;
2933 }
2934
2935 return hr;
2936}
2937
2938