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.
5 /*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
11 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
12 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
20 #include "_typeinfo.h"
22 BOOL Compiler::tiCompatibleWith(const typeInfo& child, const typeInfo& parent, bool normalisedForStack) const
26 if (VERBOSE && tiVerificationNeeded)
29 printf(TI_DUMP_PADDING);
30 printf("Verifying compatibility against types: ");
35 #endif // VERBOSE_VERIFY
38 BOOL compatible = typeInfo::tiCompatibleWith(info.compCompHnd, child, parent, normalisedForStack);
42 if (VERBOSE && tiVerificationNeeded)
44 printf(compatible ? " [YES]" : " [NO]");
46 #endif // VERBOSE_VERIFY
52 BOOL Compiler::tiMergeCompatibleWith(const typeInfo& child, const typeInfo& parent, bool normalisedForStack) const
54 return typeInfo::tiMergeCompatibleWith(info.compCompHnd, child, parent, normalisedForStack);
57 BOOL Compiler::tiMergeToCommonParent(typeInfo* pDest, const typeInfo* pSrc, bool* changed) const
61 if (VERBOSE && tiVerificationNeeded)
64 printf(TI_DUMP_PADDING);
65 printf("Attempting to merge types: ");
71 #endif // VERBOSE_VERIFY
74 BOOL mergeable = typeInfo::tiMergeToCommonParent(info.compCompHnd, pDest, pSrc, changed);
78 if (VERBOSE && tiVerificationNeeded)
80 printf(TI_DUMP_PADDING);
81 printf((mergeable == TRUE) ? "Merge successful" : "Couldn't merge types");
85 printf(", destination type changed to: ");
90 #endif // VERBOSE_VERIFY
96 static BOOL tiCompatibleWithByRef(COMP_HANDLE CompHnd, const typeInfo& child, const typeInfo& parent)
98 assert(parent.IsByRef());
100 if (!child.IsByRef())
105 if (child.IsReadonlyByRef() && !parent.IsReadonlyByRef())
110 // Byrefs are compatible if the underlying types are equivalent
111 typeInfo childTarget = ::DereferenceByRef(child);
112 typeInfo parentTarget = ::DereferenceByRef(parent);
114 if (typeInfo::AreEquivalent(childTarget, parentTarget))
119 // Make sure that both types have a valid m_cls
120 if ((childTarget.IsType(TI_REF) || childTarget.IsType(TI_STRUCT)) &&
121 (parentTarget.IsType(TI_REF) || parentTarget.IsType(TI_STRUCT)))
123 return CompHnd->areTypesEquivalent(childTarget.GetClassHandle(), parentTarget.GetClassHandle());
129 /*****************************************************************************
130 * Verify child is compatible with the template parent. Basically, that
131 * child is a "subclass" of parent -it can be substituted for parent
132 * anywhere. Note that if parent contains fancy flags, such as "uninitialized"
133 * , "is this ptr", or "has byref local/field" info, then child must also
134 * contain those flags, otherwise FALSE will be returned !
136 * Rules for determining compatibility:
138 * If parent is a primitive type or value class, then child must be the
139 * same primitive type or value class. The exception is that the built in
140 * value classes System/Boolean etc. are treated as synonyms for
143 * If parent is a byref of a primitive type or value class, then child
144 * must be a byref of the same (rules same as above case).
146 * Byrefs are compatible only with byrefs.
148 * If parent is an object, child must be a subclass of it, implement it
149 * (if it is an interface), or be null.
151 * If parent is an array, child must be the same or subclassed array.
153 * If parent is a null objref, only null is compatible with it.
155 * If the "uninitialized", "by ref local/field", "this pointer" or other flags
156 * are different, the items are incompatible.
158 * parent CANNOT be an undefined (dead) item.
162 BOOL typeInfo::tiCompatibleWith(COMP_HANDLE CompHnd,
163 const typeInfo& child,
164 const typeInfo& parent,
165 bool normalisedForStack)
167 assert(child.IsDead() || !normalisedForStack || typeInfo::AreEquivalent(::NormaliseForStack(child), child));
168 assert(parent.IsDead() || !normalisedForStack || typeInfo::AreEquivalent(::NormaliseForStack(parent), parent));
170 if (typeInfo::AreEquivalent(child, parent))
175 if (parent.IsUnboxedGenericTypeVar() || child.IsUnboxedGenericTypeVar())
177 return (FALSE); // need to have had child == parent
179 else if (parent.IsType(TI_REF))
181 // An uninitialized objRef is not compatible to initialized.
182 if (child.IsUninitialisedObjRef() && !parent.IsUninitialisedObjRef())
187 if (child.IsNullObjRef())
188 { // NULL can be any reference type
191 if (!child.IsType(TI_REF))
196 return CompHnd->canCast(child.m_cls, parent.m_cls);
198 else if (parent.IsType(TI_METHOD))
200 if (!child.IsType(TI_METHOD))
205 // Right now we don't bother merging method handles
208 else if (parent.IsType(TI_STRUCT))
210 if (!child.IsType(TI_STRUCT))
215 // Structures are compatible if they are equivalent
216 return CompHnd->areTypesEquivalent(child.m_cls, parent.m_cls);
218 else if (parent.IsByRef())
220 return tiCompatibleWithByRef(CompHnd, child, parent);
222 #ifdef _TARGET_64BIT_
223 // On 64-bit targets we have precise representation for native int, so these rules
224 // represent the fact that the ECMA spec permits the implicit conversion
225 // between an int32 and a native int.
226 else if (parent.IsType(TI_INT) && typeInfo::AreEquivalent(nativeInt(), child))
230 else if (typeInfo::AreEquivalent(nativeInt(), parent) && child.IsType(TI_INT))
234 #endif // _TARGET_64BIT_
238 BOOL typeInfo::tiMergeCompatibleWith(COMP_HANDLE CompHnd,
239 const typeInfo& child,
240 const typeInfo& parent,
241 bool normalisedForStack)
243 if (!child.IsPermanentHomeByRef() && parent.IsPermanentHomeByRef())
248 return typeInfo::tiCompatibleWith(CompHnd, child, parent, normalisedForStack);
251 /*****************************************************************************
252 * Merge pDest and pSrc to find some commonality (e.g. a common parent).
253 * Copy the result to pDest, marking it dead if no commonality can be found.
255 * null ^ null -> null
256 * Object ^ null -> Object
258 * InputStream ^ OutputStream -> Stream
259 * InputStream ^ NULL -> InputStream
260 * [I4 ^ Object -> Object
261 * [I4 ^ [Object -> Array
264 * [Foo ^ [I1 -> Array
265 * [InputStream ^ [OutputStream -> Array
267 * [Intfc ^ [OutputStream -> Array
268 * Intf ^ [OutputStream -> Object
269 * [[InStream ^ [[OutStream -> Array
270 * [[InStream ^ [OutStream -> Array
271 * [[Foo ^ [Object -> Array
274 * [I1 ^ [U1 -> either [I1 or [U1
277 * Also, System/Int32 and I4 merge -> I4, etc.
279 * Returns FALSE if the merge was completely incompatible (i.e. the item became
284 BOOL typeInfo::tiMergeToCommonParent(COMP_HANDLE CompHnd, typeInfo* pDest, const typeInfo* pSrc, bool* changed)
286 assert(pSrc->IsDead() || typeInfo::AreEquivalent(::NormaliseForStack(*pSrc), *pSrc));
287 assert(pDest->IsDead() || typeInfo::AreEquivalent(::NormaliseForStack(*pDest), *pDest));
289 // Merge the auxiliary information like "this" pointer tracking, etc...
291 // Remember the pre-state, so we can tell if it changed.
293 DWORD destFlagsBefore = pDest->m_flags;
295 // This bit is only set if both pDest and pSrc have it set
296 pDest->m_flags &= (pSrc->m_flags | ~TI_FLAG_THIS_PTR);
298 // This bit is set if either pDest or pSrc have it set
299 pDest->m_flags |= (pSrc->m_flags & TI_FLAG_UNINIT_OBJREF);
301 // This bit is set if either pDest or pSrc have it set
302 pDest->m_flags |= (pSrc->m_flags & TI_FLAG_BYREF_READONLY);
304 // If the byref wasn't permanent home in both sides, then merge won't have the bit set
305 pDest->m_flags &= (pSrc->m_flags | ~TI_FLAG_BYREF_PERMANENT_HOME);
307 if (pDest->m_flags != destFlagsBefore)
312 // OK the main event. Merge the main types
313 if (typeInfo::AreEquivalent(*pDest, *pSrc))
318 if (pDest->IsUnboxedGenericTypeVar() || pSrc->IsUnboxedGenericTypeVar())
320 // Should have had *pDest == *pSrc
323 if (pDest->IsType(TI_REF))
325 if (pSrc->IsType(TI_NULL))
326 { // NULL can be any reference type
329 if (!pSrc->IsType(TI_REF))
334 // Ask the EE to find the common parent, This always succeeds since System.Object always works
335 CORINFO_CLASS_HANDLE pDestClsBefore = pDest->m_cls;
336 pDest->m_cls = CompHnd->mergeClasses(pDest->GetClassHandle(), pSrc->GetClassHandle());
337 if (pDestClsBefore != pDest->m_cls)
343 else if (pDest->IsType(TI_NULL))
345 if (pSrc->IsType(TI_REF)) // NULL can be any reference type
353 else if (pDest->IsType(TI_STRUCT))
355 if (pSrc->IsType(TI_STRUCT) && CompHnd->areTypesEquivalent(pDest->GetClassHandle(), pSrc->GetClassHandle()))
361 else if (pDest->IsByRef())
363 return tiCompatibleWithByRef(CompHnd, *pSrc, *pDest);
365 #ifdef _TARGET_64BIT_
366 // On 64-bit targets we have precise representation for native int, so these rules
367 // represent the fact that the ECMA spec permits the implicit conversion
368 // between an int32 and a native int.
369 else if (typeInfo::AreEquivalent(*pDest, typeInfo::nativeInt()) && pSrc->IsType(TI_INT))
373 else if (typeInfo::AreEquivalent(*pSrc, typeInfo::nativeInt()) && pDest->IsType(TI_INT))
379 #endif // _TARGET_64BIT_
388 // Utility method to have a detailed dump of a TypeInfo object
389 void typeInfo::Dump() const
393 flagsStr[0] = ((m_flags & TI_FLAG_UNINIT_OBJREF) != 0) ? 'U' : '-';
394 flagsStr[1] = ((m_flags & TI_FLAG_BYREF) != 0) ? 'B' : '-';
395 flagsStr[2] = ((m_flags & TI_FLAG_BYREF_READONLY) != 0) ? 'R' : '-';
396 flagsStr[3] = ((m_flags & TI_FLAG_NATIVE_INT) != 0) ? 'N' : '-';
397 flagsStr[4] = ((m_flags & TI_FLAG_THIS_PTR) != 0) ? 'T' : '-';
398 flagsStr[5] = ((m_flags & TI_FLAG_BYREF_PERMANENT_HOME) != 0) ? 'P' : '-';
399 flagsStr[6] = ((m_flags & TI_FLAG_GENERIC_TYPE_VAR) != 0) ? 'G' : '-';
402 printf("[%s(%X) {%s}]", tiType2Str(m_bits.type), m_cls, flagsStr);
404 #endif // VERBOSE_VERIFY