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 //*****************************************************************************
9 // Define implementation of ICorDebugType
10 //*****************************************************************************
18 //-----------------------------------------------------------------------------
19 // Public method to get the static field from a type.
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.
29 HRESULT CordbType::GetStaticFieldValue(mdFieldDef fieldDef,
30 ICorDebugFrame * pFrame,
31 ICorDebugValue ** ppValue)
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());
40 IMetaDataImport * pImport = NULL;
44 // Ensure we were actually passed a mdFieldDef. This is especially useful to protect
45 // against an accidental mdPropertyDef, because properties look like fields.
47 if (TypeFromToken(fieldDef) != mdtFieldDef)
49 ThrowHR(E_INVALIDARG);
52 pImport = m_pClass->GetModule()->GetMetaDataImporter(); // throws
54 if (((m_elementType != ELEMENT_TYPE_CLASS) && (m_elementType != ELEMENT_TYPE_VALUETYPE)) || (m_pClass == NULL))
56 ThrowHR(E_INVALIDARG);
61 BOOL fSyncBlockField = FALSE;
63 // If non generic type, then degenerate to CordbClass implementation.
64 if (m_inst.m_cInst == 0)
66 hr = m_pClass->GetStaticFieldValue(fieldDef, pFrame, ppValue);
72 // Validate the token.
73 if (!pImport->IsValidToken(fieldDef))
75 ThrowHR(hr = E_INVALIDARG);
78 // Make sure we have enough info about the class.
82 // Lookup the field given its metadata token.
83 FieldData * pFieldData;
85 hr = GetFieldInfo(fieldDef, &pFieldData);
87 if (hr == CORDBG_E_ENC_HANGING_FIELD)
89 // Generics + EnC is Not supported.
90 hr = CORDBG_E_STATIC_VAR_NOT_AVAILABLE;
95 hr = CordbClass::GetStaticFieldValue2(m_pClass->GetModule(),
101 // fall through to translate HR
105 EX_CATCH_HRESULT(hr);
108 hr = CordbClass::PostProcessUnavailableHRESULT(hr, pImport, fieldDef);
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)
118 //-----------------------------------------------------------------------------
120 // Builds a CordbType around a primitive.
121 //-----------------------------------------------------------------------------
122 CordbType::CordbType(CordbAppDomain *appdomain, CorElementType et, unsigned int rank)
123 : CordbBase(appdomain->GetProcess(), CORDBTYPE_ID(et,rank) , enumCordbType),
125 m_appdomain(appdomain),
130 m_fieldInfoNeedsInit(TRUE)
132 m_typeHandleExact = VMPTR_TypeHandle::NullPtr();
134 _ASSERTE(m_elementType != ELEMENT_TYPE_VALUETYPE);
139 m_appdomain->AddToTypeList(this);
141 EX_CATCH_HRESULT(hr);
142 SetUnrecoverableIfFailed(GetProcess(), hr);
145 //-----------------------------------------------------------------------------
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 //-----------------------------------------------------------------------------
151 CordbType::CordbType(CordbAppDomain *appdomain, CorElementType et, CordbClass *cls)
152 : CordbBase(appdomain->GetProcess(), et, enumCordbType),
154 m_appdomain(appdomain),
159 m_fieldInfoNeedsInit(TRUE)
161 m_typeHandleExact = VMPTR_TypeHandle::NullPtr();
162 _ASSERTE(m_elementType != ELEMENT_TYPE_VALUETYPE);
167 m_appdomain->AddToTypeList(this);
169 EX_CATCH_HRESULT(hr);
170 SetUnrecoverableIfFailed(GetProcess(), hr);
173 //-----------------------------------------------------------------------------
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 //-----------------------------------------------------------------------------
179 CordbType::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),
187 m_fieldInfoNeedsInit(TRUE)
188 // tyarg is added as part of instantiation -see below...
190 m_typeHandleExact = VMPTR_TypeHandle::NullPtr();
191 _ASSERTE(m_elementType != ELEMENT_TYPE_VALUETYPE);
196 m_appdomain->AddToTypeList(this);
198 EX_CATCH_HRESULT(hr);
199 SetUnrecoverableIfFailed(GetProcess(), hr);
203 ULONG STDMETHODCALLTYPE CordbType::AddRef()
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...
210 // m_class->AddRef();
211 return (BaseAddRef());
213 ULONG STDMETHODCALLTYPE CordbType::Release()
216 // m_class->Release();
217 return (BaseRelease());
221 A list of which resources owened by this object are accounted for.
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
230 //-----------------------------------------------------------------------------
231 // Cleanup memory for CordbTypes.
232 //-----------------------------------------------------------------------------
233 CordbType::~CordbType()
235 _ASSERTE(IsNeutered());
238 //-----------------------------------------------------------------------------
239 // Neutered by CordbModule
240 // See CordbBase::Neuter for neuter semantics.
241 //-----------------------------------------------------------------------------
242 void CordbType::Neuter()
244 _ASSERTE(GetProcess()->GetProcessLock()->HasLock());
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.
254 for (unsigned int i = 0; i < m_inst.m_cInst; i++)
256 m_inst.m_ppInst[i]->Release();
259 m_spinetypes.NeuterAndClear(GetProcess()->GetProcessLock());
263 delete [] m_inst.m_ppInst;
264 m_inst.m_ppInst = NULL;
266 m_fieldList.Dealloc();
271 //-----------------------------------------------------------------------------
272 // Public method for IUnknown::QueryInterface.
273 // Has standard QI semantics.
274 //-----------------------------------------------------------------------------
275 HRESULT CordbType::QueryInterface(REFIID id, void **pInterface)
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));
286 return E_NOINTERFACE;
294 //-----------------------------------------------------------------------------
295 // Make a simple type with no type arguments by specifying a CorElementType,
296 // e.g. ELEMENT_TYPE_I1
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.
304 // An AppDomain holds a cache of CordbTypes for each of the basic CorElementTypes.
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.
315 HRESULT CordbType::MkType(CordbAppDomain * pAppDomain,
316 CorElementType elementType,
317 CordbType ** ppResultType)
319 _ASSERTE(pAppDomain != NULL);
320 _ASSERTE(ppResultType != NULL);
322 RSLockHolder lockHolder(pAppDomain->GetProcess()->GetProcessLock());
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))
334 elementType = ELEMENT_TYPE_OBJECT;
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 approproiate instantiation.
342 case ELEMENT_TYPE_FNPTR:
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:
364 *ppResultType = pAppDomain->m_sharedtypes.GetBase(CORDBTYPE_ID(elementType, 0));
366 if (*ppResultType == NULL)
368 CordbType * pNewType = new (nothrow) CordbType(pAppDomain, elementType, (unsigned int) 0);
370 if (pNewType == NULL)
372 return E_OUTOFMEMORY;
375 HRESULT hr = pAppDomain->m_sharedtypes.AddBase(pNewType);
379 *ppResultType = pNewType;
383 _ASSERTE(!"unexpected failure!");
392 _ASSERTE(!"unexpected element type!");
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.
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
415 HRESULT CordbType::MkType(CordbAppDomain *pAppDomain,
416 CorElementType elementType,
419 CordbType ** ppResultType)
421 _ASSERTE(pAppDomain != NULL);
422 _ASSERTE(ppResultType != NULL);
424 RSLockHolder lockHolder(pAppDomain->GetProcess()->GetProcessLock());
429 case ELEMENT_TYPE_PTR:
430 case ELEMENT_TYPE_BYREF:
434 case ELEMENT_TYPE_SZARRAY:
438 case ELEMENT_TYPE_ARRAY:
441 CordbType * pFoundType = pAppDomain->m_sharedtypes.GetBase(CORDBTYPE_ID(elementType, rank));
443 if (pFoundType == NULL)
445 pFoundType = new (nothrow) CordbType(pAppDomain, elementType, rank);
447 if (pFoundType == NULL)
449 return E_OUTOFMEMORY;
452 HRESULT hr = pAppDomain->m_sharedtypes.AddBase(pFoundType);
456 _ASSERTE(!"unexpected failure!");
462 Instantiation inst(1, &pType);
464 return MkTyAppType(pAppDomain, pFoundType, &inst, ppResultType);
469 _ASSERTE(!"unexpected element type!");
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>)
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.
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.
495 HRESULT CordbType::MkTyAppType(CordbAppDomain * pAppDomain,
497 const Instantiation * pInst,
498 CordbType ** ppResultType)
500 _ASSERTE(pAppDomain == pType->GetAppDomain());
502 CordbType * pCordbType = pType;
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++)
508 CordbType * pCordbBaseType = pCordbType->m_spinetypes.GetBase((UINT_PTR) (pInst->m_ppInst[i]));
510 if (pCordbBaseType == NULL)
512 pCordbBaseType = new (nothrow) CordbType(pCordbType, pInst->m_ppInst[i]);
514 if (pCordbBaseType == NULL)
516 return E_OUTOFMEMORY;
519 HRESULT hr = pCordbType->m_spinetypes.AddBase(pCordbBaseType);
523 _ASSERTE(!"unexpected failure!");
524 delete pCordbBaseType;
525 // @dbgtodo Microsoft leaks: Release the previously created types if this fails later in the loop
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];
533 if (pCordbBaseType->m_inst.m_ppInst == NULL)
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;
540 for (unsigned int j = 0; j < (i + 1); j++)
542 // Constructed types include pointers across to other types - increase
543 // the reference counts on these....
544 pInst->m_ppInst[j]->AddRef();
546 pCordbBaseType->m_inst.m_ppInst[j] = pInst->m_ppInst[j];
549 pCordbType = pCordbBaseType;
552 *ppResultType = pCordbType;
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>)
561 // This really just converts CordbClass(List<T>) --> CordbType(List<T>), and then calls CordbType::MkTyAppType
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>))
574 HRESULT CordbType::MkType(CordbAppDomain * pAppDomain,
575 CorElementType elementType,
577 const Instantiation * pInst,
578 CordbType ** ppResultType)
580 _ASSERTE(pAppDomain != NULL);
581 _ASSERTE(ppResultType != NULL);
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:
589 _ASSERTE(((pClass != NULL) && (!pClass->IsValueClassKnown() || pClass->IsValueClassNoInit())) ||
590 !"A non-value class is being used with ELEMENT_TYPE_VALUETYPE");
592 pClass->SetIsValueClass(true);
593 pClass->SetIsValueClassKnown(true);
596 case ELEMENT_TYPE_CLASS:
598 // This probably isn't needed...
601 elementType = ELEMENT_TYPE_OBJECT;
605 CordbType * pType = NULL;
607 pType = pClass->GetType();
611 pType = new (nothrow) CordbType(pAppDomain, ELEMENT_TYPE_CLASS, pClass);
615 return E_OUTOFMEMORY;
618 pClass->SetType(pType);
621 _ASSERTE(pClass->GetType() != NULL);
623 return CordbType::MkTyAppType(pAppDomain, pType, pInst, ppResultType);
629 _ASSERTE(pInst->m_cInst == 0);
630 return MkType(pAppDomain, elementType, ppResultType);
635 //-----------------------------------------------------------------------------
636 // Make a CordbType for a function pointer type (ELEMENT_TYPE_FNPTR).
639 // pAppDomain - the Appdomian the type lives in.
640 // elementType - must be ELEMENT_TYPE_FNPTR.
641 // pInst - instantiation information.
642 // ppResultType - OUT: out-parameter to hold resulting CordbType
647 HRESULT CordbType::MkType(CordbAppDomain * pAppDomain,
648 CorElementType elementType,
649 const Instantiation * pInst,
650 CordbType ** ppResultType)
654 _ASSERTE(elementType == ELEMENT_TYPE_FNPTR);
656 HRESULT hr = MkType(pAppDomain, elementType, &pType);
662 return CordbType::MkTyAppType(pAppDomain, pType, pInst, ppResultType);
666 //-----------------------------------------------------------------------------
667 // Public API to get the CorElementType of the type.
670 // pType - OUT: on return, gets the CorElementType
673 // S_OK on success. CORDBG_E_CLASS_NOT_LOADED or synchronization errors on failure
674 //-----------------------------------------------------------------------------
675 HRESULT CordbType::GetType(CorElementType *pType)
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)
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
694 isVC = m_pClass->IsValueClass();
696 EX_CATCH_HRESULT(hr);
697 if (!FAILED(hr) && isVC)
699 *pType = ELEMENT_TYPE_VALUETYPE;
703 *pType = m_elementType;
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>).
713 // pClass - OUT: gets class on return.
715 // S_OK on success. CORDBG_E_CLASS_NOT_LOADED if the class is not loaded.
716 // Else some other error.
717 //-----------------------------------------------------------------------------
718 HRESULT CordbType::GetClass(ICorDebugClass **pClass)
720 PUBLIC_REENTRANT_API_ENTRY(this);
721 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
723 if ((m_pClass == NULL) && (m_elementType == ELEMENT_TYPE_STRING ||
724 m_elementType == ELEMENT_TYPE_OBJECT))
728 if (m_pClass == NULL)
731 return CORDBG_E_CLASS_NOT_LOADED;
734 m_pClass->ExternalAddRef();
738 //-----------------------------------------------------------------------------
739 // Public method to get array rank. This is only valid for arrays.
742 // pnRank - OUT: *pnRank is set to rank on return
745 // S_OK if success. E_INVALIDARG is this Type doesn't have a rank.
746 //-----------------------------------------------------------------------------
747 HRESULT CordbType::GetRank(ULONG32 *pnRank)
749 PUBLIC_REENTRANT_API_ENTRY(this);
750 VALIDATE_POINTER_TO_OBJECT(pnRank, ULONG32 *);
752 if (m_elementType != ELEMENT_TYPE_SZARRAY &&
753 m_elementType != ELEMENT_TYPE_ARRAY)
756 *pnRank = (ULONG32) m_rank;
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.
767 // pType - OUT: get the ICorDebugType for the first type-parameter.
770 //-----------------------------------------------------------------------------
771 HRESULT CordbType::GetFirstTypeParameter(ICorDebugType **pType)
773 PUBLIC_REENTRANT_API_ENTRY(this);
774 VALIDATE_POINTER_TO_OBJECT(pType, ICorDebugType **);
776 // Since this is a public API, make sure there actually is at least 1 type-parameter.
777 if (m_inst.m_cInst == 0)
782 _ASSERTE(m_inst.m_ppInst != NULL);
783 _ASSERTE(m_inst.m_ppInst[0] != NULL);
785 *pType = m_inst.m_ppInst[0];
791 //-----------------------------------------------------------------------------
792 // Internal worker to create a CordbType around a CordbClass.
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.
801 //-----------------------------------------------------------------------------
802 HRESULT CordbType::MkUnparameterizedType(CordbAppDomain *appdomain, CorElementType et, CordbClass *cl,CordbType **pRes)
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;
808 return CordbType::MkType(appdomain, et, cl, &emptyInstantiation, pRes);
812 //-----------------------------------------------------------------------------
813 // Internal helper to get the First type parameter.
814 // This is an internal convenience function for the public GetFirstTypeParameter.
817 // pRes - OUT: out-param to get the unary type-parameter.
818 //-----------------------------------------------------------------------------
820 CordbType::DestUnaryType(CordbType **pRes)
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];
833 //-----------------------------------------------------------------------------
834 // Internal method to get the Class and type-parameters from a CordbType.
835 //-----------------------------------------------------------------------------
837 CordbType::DestConstructedType(CordbClass **cls, Instantiation *inst)
839 ASSERT(m_elementType == ELEMENT_TYPE_CLASS);
844 //-----------------------------------------------------------------------------
845 // Internal method to get all the type-parameters for a FnPtr
846 //-----------------------------------------------------------------------------
848 CordbType::DestNaryType(Instantiation *inst)
850 ASSERT(m_elementType == ELEMENT_TYPE_FNPTR);
855 //-----------------------------------------------------------------------------
856 // CordbType::SigToType
857 // Internal helper to create a CordbType from a Metadata signature (SigParser)
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.
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.
875 //-----------------------------------------------------------------------------
877 CordbType::SigToType(CordbModule * pModule,
878 SigParser * pSigParser,
879 const Instantiation * pInst,
880 CordbType ** ppResultType)
882 FAIL_IF_NEUTERED(pModule);
883 INTERNAL_SYNC_API_ENTRY(pModule->GetProcess());
885 _ASSERTE(pSigParser != NULL);
889 // Make a local copy of the SigParser since we are going to mutate it.
891 SigParser sigParser = *pSigParser;
893 CorElementType elementType;
896 IfFailRet(sigParser.GetElemType(&elementType));
900 case ELEMENT_TYPE_VAR:
901 case ELEMENT_TYPE_MVAR:
905 IfFailRet(sigParser.GetData(&tyvar_num));
908 if (elementType == ELEMENT_TYPE_VAR)
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))
917 _ASSERTE (pInst->m_ppInst != NULL);
918 *ppResultType = pInst->m_ppInst[tyvar_num];
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
927 _ASSERTE(elementType == ELEMENT_TYPE_MVAR);
930 _ASSERTE (tyvar_num < (pInst->m_cInst - pInst->m_cClassTyPars));
931 if (tyvar_num >= (pInst->m_cInst - pInst->m_cClassTyPars))
934 _ASSERTE (pInst->m_ppInst != NULL);
935 *ppResultType = pInst->m_ppInst[tyvar_num + pInst->m_cClassTyPars];
940 case ELEMENT_TYPE_GENERICINST:
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).
949 // ignore "WITH", look at next ELEMENT_TYPE to get CLASS or VALUE
951 IfFailRet(sigParser.GetElemType(&elementType));
955 IfFailRet(sigParser.GetToken(&token));
959 IfFailRet( pModule->ResolveTypeRefOrDef(token, &pClass));
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");
966 pClass->SetIsValueClass(elementType == ELEMENT_TYPE_VALUETYPE);
967 pClass->SetIsValueClassKnown(true);
969 // Build up the array of generic arguments.
970 ULONG cArgs; // number of generic arguments in the type.
972 IfFailRet(sigParser.GetData(&cArgs));
974 S_UINT32 allocSize = S_UINT32( cArgs ) * S_UINT32( sizeof(CordbType *) );
976 if (allocSize.IsOverflow())
978 IfFailRet(E_OUTOFMEMORY);
981 CordbType ** ppTypeInstantiations = reinterpret_cast<CordbType **>(_alloca( allocSize.Value()));
983 for (unsigned int i = 0; i < cArgs;i++)
985 IfFailRet(CordbType::SigToType(pModule, &sigParser, pInst, &ppTypeInstantiations[i]));
987 IfFailRet(sigParser.SkipExactlyOne());
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);
993 return CordbType::MkType(pModule->GetAppDomain(), elementType, pClass, &typeInstantiation, ppResultType);
995 case ELEMENT_TYPE_CLASS:
996 case ELEMENT_TYPE_VALUETYPE: // OK: this E_T_VALUETYPE comes from signature
998 // Path for non-generic types
1002 IfFailRet(sigParser.GetToken(&token));
1004 CordbClass * pClass;
1006 IfFailRet(pModule->ResolveTypeRefOrDef(token, &pClass));
1008 // The use of a class in a signature provides definite evidence as to whether it is a VC or not.
1010 _ASSERTE(!pClass->IsValueClassKnown() ||
1011 (pClass->IsValueClassNoInit() == (elementType == ELEMENT_TYPE_VALUETYPE)) ||
1012 !"A non-value class is being used with ELEMENT_TYPE_VALUETYPE");
1014 pClass->SetIsValueClass(elementType == ELEMENT_TYPE_VALUETYPE);
1015 pClass->SetIsValueClassKnown(true);
1017 return CordbType::MkUnparameterizedType(pModule->GetAppDomain(), elementType, pClass, ppResultType);
1019 case ELEMENT_TYPE_SENTINEL:
1020 case ELEMENT_TYPE_MODIFIER:
1021 case ELEMENT_TYPE_PINNED:
1023 IfFailRet(CordbType::SigToType(pModule, &sigParser, pInst, ppResultType));
1024 // Throw away SENTINELS on all CordbTypes...
1027 case ELEMENT_TYPE_CMOD_REQD:
1028 case ELEMENT_TYPE_CMOD_OPT:
1032 IfFailRet(sigParser.GetToken(&token));
1034 IfFailRet(CordbType::SigToType(pModule, &sigParser, pInst, ppResultType));
1035 // Throw away CMOD on all CordbTypes...
1039 case ELEMENT_TYPE_ARRAY:
1043 IfFailRet(CordbType::SigToType(pModule, &sigParser, pInst, &pType));
1045 IfFailRet(sigParser.SkipExactlyOne());
1049 IfFailRet(sigParser.GetData(&rank));
1051 return CordbType::MkType(pModule->GetAppDomain(), elementType, rank, pType, ppResultType);
1053 case ELEMENT_TYPE_SZARRAY:
1057 IfFailRet(CordbType::SigToType(pModule, &sigParser, pInst, &pType));
1059 return CordbType::MkType(pModule->GetAppDomain(), elementType, 1, pType, ppResultType);
1062 case ELEMENT_TYPE_PTR:
1063 case ELEMENT_TYPE_BYREF:
1067 IfFailRet(CordbType::SigToType(pModule, &sigParser, pInst, &pType));
1069 return CordbType::MkType(pModule->GetAppDomain(),elementType, 0, pType, ppResultType);
1072 case ELEMENT_TYPE_FNPTR:
1076 IfFailRet(sigParser.GetData(&cArgs)); // Skip callingConv
1078 IfFailRet(sigParser.GetData(&cArgs)); // Get number of parameters
1080 S_UINT32 allocSize = ( S_UINT32(cArgs) + S_UINT32(1) ) * S_UINT32( sizeof(CordbType *) );
1082 if (allocSize.IsOverflow())
1084 IfFailRet(E_OUTOFMEMORY);
1087 CordbType ** ppTypeInstantiations = (CordbType **) _alloca( allocSize.Value() );
1089 for (unsigned int i = 0; i <= cArgs; i++)
1091 IfFailRet(CordbType::SigToType(pModule, &sigParser, pInst, &ppTypeInstantiations[i]));
1093 IfFailRet(sigParser.SkipExactlyOne());
1096 Instantiation typeInstantiation(cArgs + 1, ppTypeInstantiations);
1098 return CordbType::MkType(pModule->GetAppDomain(), elementType, &typeInstantiation, ppResultType);
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);
1122 _ASSERTE(!"unexpected element type!");
1125 } // CordbType::SigToType
1127 //-----------------------------------------------------------------------------
1128 // Marshal a DebuggerIPCE_BasicTypeData --> CordbType.
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.
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.
1141 //-----------------------------------------------------------------------------
1142 HRESULT CordbType::TypeDataToType(CordbAppDomain *pAppDomain, DebuggerIPCE_BasicTypeData *data, CordbType **pRes)
1144 FAIL_IF_NEUTERED(pAppDomain);
1145 INTERNAL_SYNC_API_ENTRY(pAppDomain->GetProcess()); //
1150 CorElementType et = data->elementType;
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...
1162 DebuggerIPCE_ExpandedTypeData typeInfo;
1163 CordbProcess * pProcess = pAppDomain->GetProcess();
1166 RSLockHolder lockHolder(pProcess->GetProcessLock());
1167 pProcess->GetDAC()->TypeHandleToExpandedTypeInfo(NoValueTypeBoxing, // could be generics
1168 // which are never boxed
1169 pAppDomain->GetADToken(),
1174 IfFailThrow(CordbType::TypeDataToType(pAppDomain,&typeInfo, pRes));
1176 EX_CATCH_HRESULT(hr);
1181 case ELEMENT_TYPE_FNPTR:
1183 DebuggerIPCE_ExpandedTypeData e;
1185 e.NaryTypeData.typeHandle = data->vmTypeHandle;
1186 return CordbType::TypeDataToType(pAppDomain, &e, pRes);
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;
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);
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.
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.
1214 //-----------------------------------------------------------------------------
1215 HRESULT CordbType::TypeDataToType(CordbAppDomain *pAppDomain, DebuggerIPCE_ExpandedTypeData *data, CordbType **pRes)
1217 INTERNAL_SYNC_API_ENTRY(pAppDomain->GetProcess()); //
1219 CorElementType et = data->elementType;
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:
1243 // It's a primitive (therefore non-generic) type, so we can just create it immediately.
1244 IfFailRet (CordbType::MkType(pAppDomain, et, pRes));
1247 case ELEMENT_TYPE_CLASS:
1248 case ELEMENT_TYPE_VALUETYPE: // OK: this E_T_VALUETYPE comes from the EE
1251 if (data->ClassTypeData.metadataToken == mdTokenNil) {
1252 et = ELEMENT_TYPE_OBJECT;
1255 CordbModule * pClassModule = NULL;
1258 pClassModule = pAppDomain->LookupOrCreateModule(data->ClassTypeData.vmModule, data->ClassTypeData.vmDomainFile);
1260 EX_CATCH_HRESULT(hr);
1261 if( pClassModule == NULL )
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;
1270 IfFailRet (pClassModule->LookupOrCreateClass(data->ClassTypeData.metadataToken,&tycon));
1271 if (!(data->ClassTypeData.typeHandle.IsNull()))
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.
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
1283 (*pRes)->m_typeHandleExact = data->ClassTypeData.typeHandle;
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));
1295 case ELEMENT_TYPE_ARRAY:
1296 case ELEMENT_TYPE_SZARRAY:
1299 IfFailRet (CordbType::TypeDataToType(pAppDomain, &(data->ArrayTypeData.arrayTypeArg), &argty));
1300 IfFailRet (CordbType::MkType(pAppDomain, et, data->ArrayTypeData.arrayRank, argty, pRes));
1304 case ELEMENT_TYPE_PTR:
1305 case ELEMENT_TYPE_BYREF:
1308 IfFailRet (CordbType::TypeDataToType(pAppDomain, &(data->UnaryTypeData.unaryTypeArg), &argty));
1309 IfFailRet (CordbType::MkType(pAppDomain, et, 0, argty, pRes));
1312 case ELEMENT_TYPE_FNPTR:
1314 IfFailRet (CordbType::InstantiateFromTypeHandle(pAppDomain, data->NaryTypeData.typeHandle, et, NULL, pRes));
1317 (*pRes)->m_typeHandleExact = data->NaryTypeData.typeHandle;
1321 case ELEMENT_TYPE_END:
1326 _ASSERTE(!"unexpected element type!");
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.
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.
1354 //-----------------------------------------------------------------------------
1355 HRESULT CordbType::InstantiateFromTypeHandle(CordbAppDomain * pAppDomain,
1356 VMPTR_TypeHandle vmTypeHandle,
1357 CorElementType elementType,
1358 CordbClass * typeConstructor,
1359 CordbType ** pResultType)
1363 // Should already by synced by caller.
1364 INTERNAL_SYNC_API_ENTRY(pAppDomain->GetProcess()); //
1365 _ASSERTE((pAppDomain->GetProcess()->GetShim() == NULL) || (pAppDomain->GetProcess()->GetSynchronized()));
1369 CordbProcess * pProcess = pAppDomain->GetProcess();
1371 // Step 1) Ask DacDbi interface for a list of type-parameters given a TypeHandle.
1374 TypeParamsList params;
1376 RSLockHolder lockHolder(pProcess->GetProcessLock());
1377 pProcess->GetDAC()->GetTypeHandleParams(pAppDomain->GetADToken(), vmTypeHandle, ¶ms);
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)
1387 IfFailThrow(TypeDataToType(pAppDomain, &(params[i]), &(typeList[i])));
1390 // now make an instance of CordbType from an instantiation
1391 Instantiation instantiation(params.Count(), &(typeList[0]));
1392 if (elementType == ELEMENT_TYPE_FNPTR)
1394 IfFailThrow(CordbType::MkType(pAppDomain, elementType, &instantiation, pResultType));
1398 IfFailThrow(CordbType::MkType(pAppDomain, elementType, typeConstructor, &instantiation, pResultType));
1401 EX_CATCH_HRESULT(hr);
1403 } // CordbType::InstantiateFromTypeHandle
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.
1412 // fForceInit - if false, may skip initialization if TypeHandle already known.
1415 // S_OK if success, CORDBG_E_CLASS_NOT_LOADED, E_INVALIDARG, OOM on failure
1416 //-----------------------------------------------------------------------------
1417 HRESULT CordbType::Init(BOOL fForceInit)
1419 INTERNAL_SYNC_API_ENTRY(GetProcess()); //
1423 if (m_pClass && m_pClass->GetLoadLevel() != CordbClass::FullInfo)
1426 // Step 1. initialize the type constructor (if one exists)
1427 // and the (class) type parameters....
1428 if (m_elementType == ELEMENT_TYPE_CLASS)
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);
1439 m_pClass->Init(CordbClass::BasicInfo);
1441 EX_CATCH_HRESULT(hr);
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())
1450 m_pClass->Init(CordbClass::FullInfo);
1452 EX_CATCH_HRESULT(hr);
1455 return S_OK; // Non-generic, that's all - no clean-up required
1459 _ASSERTE(m_elementType != ELEMENT_TYPE_CLASS || m_pClass->HasTypeParams());
1461 for (unsigned int i = 0; i<m_inst.m_cClassTyPars; i++)
1463 _ASSERTE(m_inst.m_ppInst != NULL);
1464 _ASSERTE(m_inst.m_ppInst[i] != NULL);
1465 IfFailRet( m_inst.m_ppInst[i]->Init(fForceInit) );
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
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.
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()))
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)
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)
1505 IfFailRet(InitStringOrObjectClass(fForceInit));
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.
1512 // Note that the exact and/or approximate type handles may not be available.
1513 if ((m_elementType == ELEMENT_TYPE_CLASS) && m_pClass->HasTypeParams())
1515 IfFailRet(InitInstantiationFieldInfo(fForceInit));
1521 //-----------------------------------------------------------------------------
1522 // Internal function to communicate with Left-Side to get an exact TypeHandle
1523 // (runtime type representation) for this CordbType.
1526 // fForceInit - if false, may skip initialization if TypeHandle already known.
1529 // S_OK on success or failure HR E_INVALIDARG, OOM, CORDBG_E_CLASS_NOT_LOADED
1531 //-----------------------------------------------------------------------------
1532 HRESULT CordbType::InitInstantiationTypeHandle(BOOL fForceInit)
1535 // Check if we've already done this Init
1536 if (!fForceInit && !m_typeHandleExact.IsNull())
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);
1548 if( bufferSize.IsOverflow() )
1550 ThrowHR(E_INVALIDARG);
1552 NewHolder<DebuggerIPCE_BasicTypeData> pArgTypeData(new DebuggerIPCE_BasicTypeData[bufferSize.Value()]);
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++)
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]));
1563 DebuggerIPCE_ExpandedTypeData typeData;
1565 // get the top-level type information
1566 TypeToExpandedTypeData(&typeData);
1568 ArgInfoList argInfo(pArgTypeData, m_inst.m_cClassTyPars);
1571 // Get the TypeHandle based on the type data
1572 RSLockHolder lockHolder(GetProcess()->GetProcessLock());
1573 hr = pProcess->GetDAC()->GetExactTypeHandle(&typeData, &argInfo, m_typeHandleExact);
1576 EX_CATCH_HRESULT(hr);
1579 } // CordbType::InitInstantiationTypeHandle
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.
1587 // fForceInit - force re-initialization if already initialized.
1590 // S_OK on success or CORDBG_E_CLASS_NOT_LOADED on failure.
1592 // Note: verification with IPC result may assert
1593 //-----------------------------------------------------------------------------
1595 HRESULT CordbType::InitStringOrObjectClass(BOOL fForceInit)
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.
1600 // Check if we've already done this Init
1601 if (!fForceInit && m_pClass != NULL)
1611 // Step 1a) Send a request to the DAC to map: CorElementType --> {token, Module}
1613 CordbProcess *pProcess = GetProcess();
1614 mdTypeDef metadataToken;
1615 VMPTR_DomainFile vmDomainFile = VMPTR_DomainFile::NullPtr();
1616 VMPTR_Module vmModule = VMPTR_Module::NullPtr();
1619 RSLockHolder lockHolder(GetProcess()->GetProcessLock());
1620 pProcess->GetDAC()->GetSimpleType(m_appdomain->GetADToken(),
1628 // Step 2) Lookup CordbClass based off token + Module.
1630 CordbModule * pTypeModule = m_appdomain->LookupOrCreateModule(vmModule, vmDomainFile);
1632 _ASSERTE(pTypeModule != NULL);
1633 IfFailThrow(pTypeModule->LookupOrCreateClass(metadataToken, &m_pClass));
1635 _ASSERTE(m_pClass != NULL);
1637 _ASSERTE(SUCCEEDED(hr));
1641 EX_CATCH_HRESULT(hr);
1643 } // CordbType::InitStringOrObjectClass
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.
1650 // fForceInit - force re-initialization if already initialized?
1654 //-----------------------------------------------------------------------------
1655 HRESULT CordbType::InitInstantiationFieldInfo(BOOL fForceInit)
1659 // Check if we've already done this Init
1660 if (!m_fieldInfoNeedsInit && !fForceInit)
1665 _ASSERTE(m_elementType == ELEMENT_TYPE_CLASS);
1666 _ASSERTE(m_pClass->HasTypeParams());
1668 VMPTR_TypeHandle typeHandleApprox = m_typeHandleExact;
1670 // If the exact type handle is not available then get the approximate type handle.
1671 if (typeHandleApprox.IsNull())
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);
1680 // allocate a buffer to hold the parameter data
1681 TypeInfoList typeData;
1683 typeData.Alloc(typeDataNodeCount);
1686 DebuggerIPCE_TypeArgData * pCurrent = &(typeData[0]);
1687 GatherTypeData(this, &pCurrent);
1689 // request the type handle from the DAC
1690 CordbProcess *pProcess = GetProcess();
1692 RSLockHolder lockHolder(pProcess->GetProcessLock());
1693 typeHandleApprox = pProcess->GetDAC()->GetApproxTypeHandle(&typeData);
1696 EX_CATCH_HRESULT(hr);
1697 if(FAILED(hr)) return hr;
1700 // OK, now get the field info if we can.
1701 CordbProcess *pProcess = GetProcess();
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(),
1715 EX_CATCH_HRESULT(hr);
1720 HRESULT CordbType::ReturnedByValue()
1728 ULONG32 unboxedSize = 0;
1729 IfFailRet(GetUnboxedObjectSize(&unboxedSize));
1731 if (unboxedSize > sizeof(SIZE_T))
1734 mdToken mdClass = m_pClass->GetToken();
1737 bool unsupported = false;
1739 HCORENUM fields = 0;
1742 IMetaDataImport *pImport = m_pClass->GetModule()->GetMetaDataImporter();
1743 IfFailRet(pImport->EnumFields(&fields, mdClass, &mdField, 1, &fetched));
1745 while (hr == S_OK && fetched == 1)
1748 PCCOR_SIGNATURE sigBlob = 0;
1750 hr = pImport->GetFieldProps(mdField, NULL, NULL, 0, NULL, &attr, &sigBlob, &sigLen, NULL, NULL, NULL);
1755 if ((attr & 0x10) == 0)
1761 SigParser parser(sigBlob, sigLen);
1762 parser.GetByte(NULL); // 0x6, field signature
1763 parser.SkipCustomModifiers();
1764 hr = parser.GetElemType(&et);
1769 case ELEMENT_TYPE_R4:
1770 case ELEMENT_TYPE_R8:
1774 case ELEMENT_TYPE_CLASS:
1775 case ELEMENT_TYPE_STRING:
1776 case ELEMENT_TYPE_PTR:
1781 if (!CorIsPrimitiveType(et))
1791 hr = pImport->EnumFields(&fields, mdClass, &mdField, 1, &fetched);
1796 pImport->CloseEnum(fields);
1801 pImport->CloseEnum(fields);
1806 return fieldCount <= 1 ? S_OK : S_FALSE;
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
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.
1817 // This should only be called on Value-types and Primitives (eg, i4, FnPtr).
1818 // It should not be called on Reference types.
1821 // pObjectSize - OUT: out-parameter to get the size in bytes.
1825 //-----------------------------------------------------------------------------
1827 CordbType::GetUnboxedObjectSize(ULONG32 *pObjectSize)
1829 INTERNAL_SYNC_API_ENTRY(GetProcess()); //
1836 isVC = IsValueType();
1838 EX_CATCH_HRESULT(hr);
1851 *pObjectSize = (ULONG) ((!m_pClass->HasTypeParams()) ? m_pClass->ObjectSize() : this->m_objectSize);
1857 // Caller gaurantees 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.
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);
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;
1869 SigParser sigParser(&corSig, sizeof(corSig));
1873 IfFailRet(sigParser.PeekElemTypeSize(&size));
1875 *pObjectSize = size;
1880 VMPTR_DomainFile CordbType::GetDomainFile()
1882 if (m_pClass != NULL)
1884 CordbModule * pModule = m_pClass->GetModule();
1887 return pModule->m_vmDomainFile;
1891 return VMPTR_DomainFile::NullPtr();
1896 return VMPTR_DomainFile::NullPtr();
1901 VMPTR_Module CordbType::GetModule()
1903 if (m_pClass != NULL)
1905 CordbModule * pModule = m_pClass->GetModule();
1908 return pModule->GetRuntimeModule();
1912 return VMPTR_Module::NullPtr();
1917 return VMPTR_Module::NullPtr();
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
1926 // data - OUT: BasicTypeData instance to fill out.
1929 // S_OK on success, CORDBG_E_CLASS_NOT_LOADED on failure
1930 //-----------------------------------------------------------------------------
1931 HRESULT CordbType::TypeToBasicTypeData(DebuggerIPCE_BasicTypeData *data)
1933 switch (m_elementType)
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())
1945 return CORDBG_E_CLASS_NOT_LOADED;
1947 _ASSERTE(!data->vmTypeHandle.IsNull());
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())
1958 return CORDBG_E_CLASS_NOT_LOADED;
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();
1972 //-----------------------------------------------------------------------------
1973 // Internal method to marshal: CordbType --> ExpandedTypeData
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.
1980 // data - OUT: outgoing ExpandedTypeData to fill in with stats about CordbType.
1981 //-----------------------------------------------------------------------------
1982 void CordbType::TypeToExpandedTypeData(DebuggerIPCE_ExpandedTypeData *data)
1985 switch (m_elementType)
1987 case ELEMENT_TYPE_ARRAY:
1988 case ELEMENT_TYPE_SZARRAY:
1990 data->ArrayTypeData.arrayRank = m_rank;
1991 data->elementType = m_elementType;
1994 case ELEMENT_TYPE_BYREF:
1995 case ELEMENT_TYPE_PTR:
1996 case ELEMENT_TYPE_FNPTR:
1998 data->elementType = m_elementType;
2001 case ELEMENT_TYPE_CLASS:
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();
2011 case ELEMENT_TYPE_END:
2012 _ASSERTE(!"bad element type!");
2015 data->elementType = m_elementType;
2021 void CordbType::TypeToTypeArgData(DebuggerIPCE_TypeArgData *data)
2023 TypeToExpandedTypeData(&(data->data));
2024 data->numTypeArgs = m_inst.m_cClassTyPars;
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)
2034 // indicates whether this is a value type
2037 //-----------------------------------------------------------------------------
2038 bool CordbType::IsValueType()
2040 if (m_elementType == ELEMENT_TYPE_CLASS)
2042 return m_pClass->IsValueClass();
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 //------------------------------------------------------------------------
2055 CordbType * CordbType::GetPointerElementType()
2057 if ((m_elementType != ELEMENT_TYPE_PTR) && (m_elementType != ELEMENT_TYPE_BYREF))
2063 DestUnaryType(&pOut);
2065 _ASSERTE(pOut != NULL);
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.
2075 // et - An element type.
2077 // True if variables of et can be used as a GC root.
2078 //------------------------------------------------------------------------
2079 static inline bool IsElementTypeNonGcRoot(CorElementType et)
2081 // Functon ptrs are raw data, not GC-roots.
2082 if (et == ELEMENT_TYPE_FNPTR)
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
2093 //------------------------------------------------------------------------
2094 // Helper for IsGcRoot
2095 // Non-gc roots include Value types + non-gc elemement types (like E_T_I4, E_T_FNPTR)
2098 // pType - type to check whether it's a GC-root.
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 //------------------------------------------------------------------------
2103 static inline bool _IsNonGCRootHelper(CordbType * pType)
2105 _ASSERTE(pType != NULL);
2107 CorElementType et = pType->GetElementType();
2108 if (IsElementTypeNonGcRoot(et))
2114 bool fValueClass = false;
2116 // If we are a value-type, then we can't be a Gc-root.
2119 fValueClass = pType->IsValueType();
2121 EX_CATCH_HRESULT(hr);
2122 if (FAILED(hr) || fValueClass)
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.
2136 // True - if this is a GC-root.
2137 // False - not a GC root.
2138 //-----------------------------------------------------------------------------
2139 bool CordbType::IsGCRoot()
2141 // If it's a E_T_PTR type, then look at what it's a a pointer of.
2142 CordbType * pPtr = this->GetPointerElementType();
2145 // If non pointer, than we can just look at our current type.
2146 return !_IsNonGCRootHelper(this);
2149 return !_IsNonGCRootHelper(pPtr);
2153 //------------------------------------------------------------------------
2154 // Public function to enumerate type-parameters.
2156 // ppTypeParameterEnum - OUT: on return, get an enumerator.
2159 //------------------------------------------------------------------------
2160 HRESULT CordbType::EnumerateTypeParameters(ICorDebugTypeEnum **ppTypeParameterEnum)
2162 PUBLIC_API_ENTRY(this);
2163 VALIDATE_POINTER_TO_OBJECT(ppTypeParameterEnum, ICorDebugTypeEnum **);
2164 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
2167 CordbTypeEnum *icdTPE = CordbTypeEnum::Build(m_appdomain, m_appdomain->GetLongExitNeuterList(), this->m_inst.m_cInst, this->m_inst.m_ppInst);
2168 if ( icdTPE == NULL )
2170 (*ppTypeParameterEnum) = NULL;
2171 return E_OUTOFMEMORY;
2174 (*ppTypeParameterEnum) = static_cast<ICorDebugTypeEnum*> (icdTPE);
2175 icdTPE->ExternalAddRef();
2180 //-----------------------------------------------------------------------------
2181 // CordbType::GetBase
2182 // Public convenience method to get the instantiated base type.
2185 // ppType - OUT: yields the base type for the current type.
2188 // S_OK if succeeded.
2190 HRESULT CordbType::GetBase(ICorDebugType ** ppType)
2192 PUBLIC_REENTRANT_API_ENTRY(this);
2193 ATT_ALLOW_LIVE_DO_STOPGO(this->GetProcess()); // @todo - can this by RequiredStopped?
2197 LOG((LF_CORDB, LL_EVERYTHING, "CordbType::GetBase called\n"));
2199 VALIDATE_POINTER_TO_OBJECT(ppType, ICorDebugType **);
2201 if (m_elementType != ELEMENT_TYPE_CLASS)
2203 return E_INVALIDARG;
2208 CordbType * pType = NULL;
2210 _ASSERTE(m_pClass != NULL);
2212 // Get the supertype from metadata for m_class
2213 mdToken extendsToken;
2215 IMetaDataImport * pImport = m_pClass->GetModule()->GetMetaDataImporter(); // throws
2217 hr = pImport->GetTypeDefProps(m_pClass->MDToken(), NULL, 0, NULL, NULL, &extendsToken);
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))
2226 else if (TypeFromToken(extendsToken) == mdtTypeSpec)
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.
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.
2236 PCCOR_SIGNATURE pSig;
2239 // Get the signature for the constructed supertype...
2240 hr = pImport->GetTypeSpecFromToken(extendsToken, &pSig, &sigSize);
2243 _ASSERTE(pSig != NULL);
2245 SigParser sigParser(pSig, sigSize);
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);
2252 else if ((TypeFromToken(extendsToken) == mdtTypeRef) || (TypeFromToken(extendsToken) == mdtTypeDef))
2254 // TypeDef/TypeRef for non-generic base-class class.
2255 CordbClass * pSuperClass;
2257 hr = m_pClass->GetModule()->ResolveTypeRefOrDef(extendsToken, &pSuperClass);
2260 _ASSERTE(pSuperClass != NULL);
2262 hr = MkUnparameterizedType(m_appdomain, ELEMENT_TYPE_CLASS, pSuperClass, &pType);
2268 _ASSERTE(!"unexpected token!");
2271 // At this point, we've succeeded
2272 _ASSERTE(SUCCEEDED(hr));
2281 EX_CATCH_HRESULT(hr);
2285 //-----------------------------------------------------------------------------
2286 // CordbType::GetTypeID
2287 // Method to get the COR_TYPEID corresponding to this CordbType.
2290 // pId - OUT: gives the COR_TYPEID for this CordbType
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.
2299 HRESULT CordbType::GetTypeID(COR_TYPEID *pId)
2301 LOG((LF_CORDB, LL_INFO1000, "GetTypeID\n"));
2307 PUBLIC_API_ENTRY(this);
2308 RSLockHolder stopGoLock(GetProcess()->GetStopGoLock());
2309 RSLockHolder procLock(GetProcess()->GetProcessLock());
2316 VMPTR_TypeHandle vmTypeHandle;
2318 CorElementType et = GetElementType();
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:
2341 VMPTR_Module vmModule = VMPTR_Module::NullPtr();
2342 VMPTR_DomainFile vmDomainFile = VMPTR_DomainFile::NullPtr();
2344 // get module and token of the simple type
2345 GetProcess()->GetDAC()->GetSimpleType(GetAppDomain()->GetADToken(),
2351 vmTypeHandle = GetProcess()->GetDAC()->GetTypeHandle(vmModule, mdToken);
2354 case ELEMENT_TYPE_ARRAY:
2355 case ELEMENT_TYPE_SZARRAY:
2357 LOG((LF_CORDB, LL_INFO1000, "GetTypeID: parameterized type\n"));
2358 if (m_typeHandleExact.IsNull())
2360 hr = InitInstantiationTypeHandle(FALSE);
2363 vmTypeHandle = m_typeHandleExact;
2366 case ELEMENT_TYPE_CLASS:
2368 ICorDebugClass *pICDClass = NULL;
2369 hr = GetClass(&pICDClass);
2371 CordbClass *pClass = (CordbClass*)pICDClass;
2372 _ASSERTE(pClass != NULL);
2374 if (pClass->HasTypeParams())
2376 vmTypeHandle = m_typeHandleExact;
2381 hr = pClass->GetToken(&mdToken);
2384 VMPTR_Module vmModule = GetModule();
2385 vmTypeHandle = GetProcess()->GetDAC()->GetTypeHandle(vmModule, mdToken);
2389 case ELEMENT_TYPE_PTR:
2390 case ELEMENT_TYPE_BYREF:
2391 case ELEMENT_TYPE_FNPTR:
2392 IfFailThrow(CORDBG_E_UNSUPPORTED);
2394 _ASSERTE(!"unexpected element type!");
2395 IfFailThrow(CORDBG_E_UNSUPPORTED);
2399 GetProcess()->GetDAC()->GetTypeIDForType(vmTypeHandle, pId);
2401 EX_CATCH_HRESULT(hr);
2406 //-----------------------------------------------------------------------------
2407 // Get rich field information given a token.
2410 // fldToken - metadata field token specifying a field on this Type.
2411 // ppFieldData - OUT: get the rich field information for the given field
2414 // S_OK on success. CORDBG_E_ENC_HANGING_FIELD for EnC fields (common case)
2415 // Other errors on failure case.
2416 //-----------------------------------------------------------------------------
2417 HRESULT CordbType::GetFieldInfo(mdFieldDef fldToken, FieldData ** ppFieldData)
2419 INTERNAL_SYNC_API_ENTRY(GetProcess()); //
2422 *ppFieldData = NULL;
2426 if (m_elementType != ELEMENT_TYPE_CLASS)
2428 ThrowHR(E_INVALIDARG);
2431 // Initialize so that the field information is up-to-date.
2435 if (m_pClass->HasTypeParams())
2437 if (m_fieldList.IsEmpty())
2439 ThrowHR(CORDBG_E_FIELD_NOT_AVAILABLE);
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(),
2447 m_pClass->MDToken(),
2450 // fall through and return.
2451 // Let possible CORDBG_E_ENC_HANGING_FIELD errors propogate
2456 hr = m_pClass->GetFieldInfo(fldToken, ppFieldData); // this is for non-generic types....
2457 // Let possible CORDBG_E_ENC_HANGING_FIELD errors propogate
2460 EX_CATCH_HRESULT(hr);
2461 _ASSERTE(SUCCEEDED(hr) == (*ppFieldData != NULL));
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.
2473 // For example, given:
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.
2480 // Adds a reference to the resulting type. Since this is for internal
2481 // use only we probably don't need todo this...
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.
2488 // S_OK on success. CORDBG_E_OBJECT_NEUTERED, CORDBG_E_CLASS_NOT_LOADED, E_INVALIDARG, OOM
2489 //-----------------------------------------------------------------------------
2490 HRESULT CordbType::GetParentType(CordbClass *baseClass, CordbType **ppRes)
2492 INTERNAL_SYNC_API_ENTRY(GetProcess()); //
2494 // Ensure that we're not trying to match up against a neutered class.
2495 if (baseClass->IsNeutered())
2497 return CORDBG_E_OBJECT_NEUTERED;
2503 CordbType *res = this;
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
2508 if (res->m_pClass == NULL)
2510 if (FAILED(hr = res->Init(FALSE)))
2516 _ASSERTE(res->m_pClass);
2517 if (res->m_pClass == baseClass)
2523 // Another way to determine if we're talking about the
2524 // same class... Compare tokens and module.
2526 mdTypeDef targetTok;
2527 if (FAILED(hr = res->m_pClass->GetToken(&tok))
2528 || FAILED(hr = baseClass->GetToken(&targetTok)))
2533 if (tok == targetTok && res->m_pClass->GetModule() == baseClass->GetModule())
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)))
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)
2551 // Did not find it...
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
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)
2566 res->Release(); // matches the one left over from the loop
2567 IfFailRet(CordbType::MkUnparameterizedType(baseClass->GetAppDomain(), ELEMENT_TYPE_CLASS, baseClass, &res));
2577 //-----------------------------------------------------------------------------
2578 // Walk a type tree, writing the number of type args including internal nodes.
2581 // count - IN/OUT: counter to update.
2582 //-----------------------------------------------------------------------------
2583 void CordbType::CountTypeDataNodes(unsigned int *count)
2586 for (unsigned int i = 0; i < this->m_inst.m_cClassTyPars; i++)
2588 this->m_inst.m_ppInst[i]->CountTypeDataNodes(count);
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.
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 //-----------------------------------------------------------------------------
2603 void CordbType::CountTypeDataNodesForInstantiation(unsigned int genericArgsCount, ICorDebugType *genericArgs[], unsigned int *count)
2605 for (unsigned int i = 0; i < genericArgsCount; i++)
2607 (static_cast<CordbType *>(genericArgs[i]))->CountTypeDataNodes(count);
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
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 //-----------------------------------------------------------------------------
2622 void CordbType::GatherTypeData(CordbType *type, DebuggerIPCE_TypeArgData **curr_tyargData)
2624 type->TypeToTypeArgData(*curr_tyargData);
2625 (*curr_tyargData)++;
2626 for (unsigned int i = 0; i < type->m_inst.m_cClassTyPars; i++)
2628 GatherTypeData(type->m_inst.m_ppInst[i], curr_tyargData);
2632 //-----------------------------------------------------------------------------
2633 // Flatten Instantiation into a linear buffer of TypeArgData
2634 // Use CountTypeDataNodesForInstantiation on the instantiation to get a large
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.
2645 //-----------------------------------------------------------------------------
2646 void CordbType::GatherTypeDataForInstantiation(unsigned int genericArgsCount, ICorDebugType *genericArgs[], DebuggerIPCE_TypeArgData **curr_tyargData)
2648 for (unsigned int i = 0; i < genericArgsCount; i++)
2650 GatherTypeData(static_cast<CordbType *> (genericArgs[i]), curr_tyargData);
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
2657 HRESULT CordbType::RequiresAlign8(BOOL* isRequired)
2659 if (isRequired == NULL)
2660 return E_INVALIDARG;
2666 *isRequired = FALSE;
2669 GetUnboxedObjectSize(&size);
2673 CorElementType type;
2676 if (type != ELEMENT_TYPE_TYPEDBYREF)
2678 if (type == ELEMENT_TYPE_VALUETYPE)
2680 if (m_typeHandleExact.IsNull())
2681 InitInstantiationTypeHandle(FALSE);
2683 *isRequired = GetProcess()->GetDAC()->RequiresAlign8(m_typeHandleExact);
2692 EX_CATCH_HRESULT(hr);
2698 /* ------------------------------------------------------------------------- *
2699 * TypeParameter Enumerator class
2700 * ------------------------------------------------------------------------- */
2703 CordbTypeEnum* CordbTypeEnum::Build(CordbAppDomain * pAppDomain, NeuterList * pNeuterList, unsigned int cTypars, CordbType **ppTypars)
2705 return BuildImpl( pAppDomain, pNeuterList, cTypars, ppTypars );
2708 CordbTypeEnum* CordbTypeEnum::Build(CordbAppDomain * pAppDomain, NeuterList * pNeuterList, unsigned int cTypars, RSSmartPtr<CordbType> *ppTypars)
2710 return BuildImpl( pAppDomain, pNeuterList, cTypars, ppTypars );
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 //-----------------------------------------------------------------------------
2720 template<class T> CordbTypeEnum* CordbTypeEnum::BuildImpl(CordbAppDomain * pAppDomain, NeuterList * pNeuterList, unsigned int cTypars, T* ppTypars)
2722 CordbTypeEnum* newEnum = new (nothrow) CordbTypeEnum( pAppDomain, pNeuterList );
2723 if( NULL == newEnum )
2728 _ASSERTE( newEnum->m_ppTypars == NULL );
2729 newEnum->m_ppTypars = new (nothrow) RSSmartPtr<CordbType> [cTypars];
2730 if( newEnum->m_ppTypars == NULL )
2736 newEnum->m_iMax = cTypars;
2737 for (unsigned int i = 0; i < cTypars; i++)
2739 newEnum->m_ppTypars[i].Assign(ppTypars[i]);
2745 // Private, called only by Build above
2746 CordbTypeEnum::CordbTypeEnum(CordbAppDomain * pAppDomain, NeuterList * pNeuterList) :
2747 CordbBase(pAppDomain->GetProcess(), 0),
2752 _ASSERTE(pAppDomain != NULL);
2753 _ASSERTE(pNeuterList != NULL);
2755 m_pAppDomain = pAppDomain;
2760 pNeuterList->Add(GetProcess(), this);
2762 EX_CATCH_HRESULT(hr);
2763 SetUnrecoverableIfFailed(GetProcess(), hr);
2766 CordbTypeEnum::~CordbTypeEnum()
2768 _ASSERTE(this->IsNeutered());
2771 void CordbTypeEnum::Neuter()
2773 delete [] m_ppTypars;
2775 m_pAppDomain = NULL;
2777 CordbBase::Neuter();
2781 HRESULT CordbTypeEnum::QueryInterface(REFIID id, void **pInterface)
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));
2792 return E_NOINTERFACE;
2799 HRESULT CordbTypeEnum::Skip(ULONG celt)
2801 PUBLIC_API_ENTRY(this);
2802 FAIL_IF_NEUTERED(this);
2803 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
2805 HRESULT hr = E_FAIL;
2806 if ( (m_iCurrent+celt) < m_iMax ||
2816 HRESULT CordbTypeEnum::Reset(void)
2818 PUBLIC_API_ENTRY(this);
2819 FAIL_IF_NEUTERED(this);
2820 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
2826 HRESULT CordbTypeEnum::Clone(ICorDebugEnum **ppEnum)
2828 PUBLIC_API_ENTRY(this);
2829 FAIL_IF_NEUTERED(this);
2830 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
2833 VALIDATE_POINTER_TO_OBJECT(ppEnum, ICorDebugEnum **);
2837 CordbTypeEnum *pCVE = CordbTypeEnum::Build( m_pAppDomain, m_pAppDomain->GetLongExitNeuterList(), m_iMax, m_ppTypars );
2846 (*ppEnum) = (ICorDebugEnum*)pCVE;
2852 HRESULT CordbTypeEnum::GetCount(ULONG *pcelt)
2854 PUBLIC_API_ENTRY(this);
2855 FAIL_IF_NEUTERED(this);
2856 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
2858 VALIDATE_POINTER_TO_OBJECT(pcelt, ULONG *);
2861 return E_INVALIDARG;
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.
2873 HRESULT CordbTypeEnum::Next(ULONG celt, ICorDebugType *values[], ULONG *pceltFetched)
2875 PUBLIC_API_ENTRY(this);
2876 FAIL_IF_NEUTERED(this);
2877 ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
2880 VALIDATE_POINTER_TO_OBJECT_ARRAY(values, ICorDebugClass *,
2882 VALIDATE_POINTER_TO_OBJECT_OR_NULL(pceltFetched, ULONG *);
2884 if ((pceltFetched == NULL) && (celt != 1))
2886 return E_INVALIDARG;
2891 if (pceltFetched != NULL)
2900 int iMax = min( m_iMax, m_iCurrent+celt);
2903 for (i = m_iCurrent; i < iMax; i++)
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();
2910 int count = (i - m_iCurrent);
2913 { //we failed: +1 pushes us past troublesome element
2914 m_iCurrent += 1 + count;
2918 m_iCurrent += count;
2921 if (pceltFetched != NULL)
2923 *pceltFetched = count;
2927 // If we reached the end of the enumeration, but not the end
2928 // of the number of requested items, we return S_FALSE.
2930 if (((ULONG)count) < celt)