summaryrefslogtreecommitdiff
path: root/src/vm/typectxt.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/vm/typectxt.h')
-rw-r--r--src/vm/typectxt.h191
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