diff options
Diffstat (limited to 'src/vm/typectxt.h')
-rw-r--r-- | src/vm/typectxt.h | 191 |
1 files changed, 191 insertions, 0 deletions
diff --git a/src/vm/typectxt.h b/src/vm/typectxt.h new file mode 100644 index 0000000000..786860cc41 --- /dev/null +++ b/src/vm/typectxt.h @@ -0,0 +1,191 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. +// +// typectxt.h +// + +// + +#ifndef _H_TYPECTXT +#define _H_TYPECTXT + +//------------------------------------------------------------------------ +// A signature type context gives the information necessary to interpret +// the ELEMENT_TYPE_VAR and ELEMENT_TYPE_MVAR elements of a regular +// metadata signature. These are usually stack allocated at appropriate +// points where the SigPointer objects are created, or are allocated +// inside a MetaSig (which are themselves normally stack allocated) +// +// They are normally passed as "const SigTypeContext *". +//------------------------------------------------------------------------ + +class SigTypeContext +{ +public: + // Store pointers first and DWORDs second to ensure good packing on 64-bit + Instantiation m_classInst; + Instantiation m_methodInst; + + // Default constructor for non-generic code + inline SigTypeContext() + { WRAPPER_NO_CONTRACT; InitTypeContext(this); } + + + // Initialize a type context given instantiations. + inline SigTypeContext(Instantiation classInst, Instantiation methodInst) + { WRAPPER_NO_CONTRACT; InitTypeContext(classInst, methodInst, this); } + + + // Initialize a type context from a MethodDesc. If this is a MethodDesc that gets + // shared between generic instantiations (e.g. one being jitted by a code-sharing JIT) + // and a null declaring Type is passed then the type context will + // be a representative context, not an exact one. + // This is sufficient for most purposes, e.g. GC and field layout, because + // these operations are "parametric", i.e. behave the same for all shared types. + // + // If declaringType is non-null, then the MethodDesc is assumed to be + // shared between generic classes, and the type handle is used to give the + // exact type context. The method should be one of the methods supported by the + // given type handle. + // + // If the method is a method in an array type then the type context will + // contain one item in the class instantiation corresponding to the + // element type of the array. + // + // Finally, exactMethodInst should be specified if md might represent a generic method definition, + // as type parameters are not always available off the method desc for generic method definitions without + // forcing a load. Typically the caller will use MethodDesc::LoadMethodInstantiation. + inline SigTypeContext(MethodDesc *md) + { WRAPPER_NO_CONTRACT; InitTypeContext(md,this); } + + inline SigTypeContext(MethodDesc *md, TypeHandle declaringType) + { WRAPPER_NO_CONTRACT; InitTypeContext(md,declaringType,this); } + + inline SigTypeContext(MethodDesc *md, TypeHandle declaringType, Instantiation exactMethodInst) + { WRAPPER_NO_CONTRACT; InitTypeContext(md,declaringType,exactMethodInst,this); } + + // This is similar to the one above except that exact + // instantiations are provided explicitly. + // This will only normally be used when the code is shared + // between generic instantiations and after fetching the + // exact instantiations from the stack. + // + inline SigTypeContext(MethodDesc *md, Instantiation exactClassInst, Instantiation exactMethodInst) + { WRAPPER_NO_CONTRACT; InitTypeContext(md,exactClassInst,exactMethodInst,this); } + + // Initialize a type context from a type handle. This is used when + // generating the type context for a + // any of the metadata in the class covered by the type handle apart from + // the metadata for any generic methods in the class. + // If the type handle satisfies th.IsNull() then the created type context + // will be empty. + inline SigTypeContext(TypeHandle th) + { WRAPPER_NO_CONTRACT; InitTypeContext(th,this); } + + inline SigTypeContext(FieldDesc *pFD, TypeHandle declaringType = TypeHandle()) + { WRAPPER_NO_CONTRACT; InitTypeContext(pFD,declaringType,this); } + + // Copy contructor - try not to use this. The C++ compiler is not doing a good job + // of copy-constructor based code, and we've had perf regressions when using this too + // much for this simple objects. Use an explicit call to InitTypeContext instead, + // or use GetOptionalTypeContext. + inline SigTypeContext(const SigTypeContext &c) + { WRAPPER_NO_CONTRACT; InitTypeContext(&c,this); } + + // Copy contructor from a possibly-NULL pointer. + inline SigTypeContext(const SigTypeContext *c) + { WRAPPER_NO_CONTRACT; InitTypeContext(c,this); } + + static void InitTypeContext(MethodDesc *md, SigTypeContext *pRes); + static void InitTypeContext(MethodDesc *md, TypeHandle declaringType, SigTypeContext *pRes); + static void InitTypeContext(MethodDesc *md, TypeHandle declaringType, Instantiation exactMethodInst, SigTypeContext *pRes); + static void InitTypeContext(MethodDesc *md, Instantiation exactClassInst, Instantiation exactMethodInst, SigTypeContext *pRes); + static void InitTypeContext(TypeHandle th, SigTypeContext *pRes); + static void InitTypeContext(FieldDesc *pFD, TypeHandle declaringType, SigTypeContext *pRes); + inline static void InitTypeContext(Instantiation classInst, Instantiation methodInst, SigTypeContext *pRes); + inline static void InitTypeContext(SigTypeContext *); + inline static void InitTypeContext(const SigTypeContext *c, SigTypeContext *pRes); + + // These are allowed to return NULL if an empty type context is generated. The NULL value + // can then be passed around to represent the empty type context. + // pRes must be non-null. + // pRes must initially be zero-initialized, e.g. by the default SigTypeContext constructor. + static const SigTypeContext * GetOptionalTypeContext(MethodDesc *md, TypeHandle declaringType, SigTypeContext *pRes); + static const SigTypeContext * GetOptionalTypeContext(TypeHandle th, SigTypeContext *pRes); + + // SigTypeContexts are used as part of keys for various data structures indiexed by instantiation + static BOOL Equal(const SigTypeContext *pCtx1, const SigTypeContext *pCtx2); + static BOOL IsValidTypeOnlyInstantiationOf(const SigTypeContext *pCtxTypicalMethodInstantiation, const SigTypeContext *pCtxTypeOnlyInstantiation); + BOOL IsEmpty() const { LIMITED_METHOD_CONTRACT; return m_classInst.IsEmpty() && m_methodInst.IsEmpty(); } + +}; + +inline void SigTypeContext::InitTypeContext(SigTypeContext *pRes) +{ + LIMITED_METHOD_DAC_CONTRACT; +} + +inline void SigTypeContext::InitTypeContext(Instantiation classInst, + Instantiation methodInst, + SigTypeContext *pRes) +{ + LIMITED_METHOD_CONTRACT; + pRes->m_classInst = classInst; + pRes->m_methodInst = methodInst; +} + + +// Copy contructor from a possibly-NULL pointer. +inline void SigTypeContext::InitTypeContext(const SigTypeContext *c,SigTypeContext *pRes) +{ + LIMITED_METHOD_DAC_CONTRACT; + if (c) + { + pRes->m_classInst = c->m_classInst; + pRes->m_methodInst = c->m_methodInst; + } + else + { + pRes->m_classInst = Instantiation(); + pRes->m_methodInst = Instantiation(); + } +} + +//------------------------------------------------------------------------ +// Encapsulates pointers to code:SigTypeContext and code:Substitution chain +// that have been used to instantiate a generic type. The context is passed +// as "const InstantiationContext *" from code:SigPointer.GetTypeHandleThrowing +// down to code:TypeVarTypeDesc.SatisfiesConstraints where it is needed for +// instantiating constraints attached to type arguments. +// +// The reason why we need to pass these pointers down to the code that verifies +// that constraints are satisified is the case when another type variable is +// substituted for a type variable and this argument is constrained by a generic +// type. In order to verify that constraints of the argument satisfy constraints +// of the parameter, the argument constraints must be instantiated in the same +// "instantiation context" as the original signature - and unfortunately this +// context cannot be extracted from the rest of the information that we have +// about the type that is being loaded. +// +// See code:TypeVarTypeDesc.SatisfiesConstraints for more details and an +// example scenario in which we are unable to verify constraints without this +// context. +//------------------------------------------------------------------------ + +class InstantiationContext +{ +public: + const SigTypeContext *m_pArgContext; + const Substitution *m_pSubstChain; + + inline InstantiationContext(const SigTypeContext *pArgContext = NULL, const Substitution *pSubstChain = NULL) + { + LIMITED_METHOD_DAC_CONTRACT; + + m_pArgContext = pArgContext; + m_pSubstChain = pSubstChain; + } +}; + +#endif |