Fix reading Time zone rules using Julian days (#17672)
[platform/upstream/coreclr.git] / src / jit / typeinfo.cpp
1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4
5 /*XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
6 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
7 XX                                                                           XX
8 XX                          typeInfo                                         XX
9 XX                                                                           XX
10 XX                                                                           XX
11 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
12 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
13 */
14
15 #include "jitpch.h"
16 #ifdef _MSC_VER
17 #pragma hdrstop
18 #endif
19
20 #include "_typeinfo.h"
21
22 BOOL Compiler::tiCompatibleWith(const typeInfo& child, const typeInfo& parent, bool normalisedForStack) const
23 {
24 #ifdef DEBUG
25 #if VERBOSE_VERIFY
26     if (VERBOSE && tiVerificationNeeded)
27     {
28         printf("\n");
29         printf(TI_DUMP_PADDING);
30         printf("Verifying compatibility against types: ");
31         child.Dump();
32         printf(" and ");
33         parent.Dump();
34     }
35 #endif // VERBOSE_VERIFY
36 #endif // DEBUG
37
38     BOOL compatible = typeInfo::tiCompatibleWith(info.compCompHnd, child, parent, normalisedForStack);
39
40 #ifdef DEBUG
41 #if VERBOSE_VERIFY
42     if (VERBOSE && tiVerificationNeeded)
43     {
44         printf(compatible ? " [YES]" : " [NO]");
45     }
46 #endif // VERBOSE_VERIFY
47 #endif // DEBUG
48
49     return compatible;
50 }
51
52 BOOL Compiler::tiMergeCompatibleWith(const typeInfo& child, const typeInfo& parent, bool normalisedForStack) const
53 {
54     return typeInfo::tiMergeCompatibleWith(info.compCompHnd, child, parent, normalisedForStack);
55 }
56
57 BOOL Compiler::tiMergeToCommonParent(typeInfo* pDest, const typeInfo* pSrc, bool* changed) const
58 {
59 #ifdef DEBUG
60 #if VERBOSE_VERIFY
61     if (VERBOSE && tiVerificationNeeded)
62     {
63         printf("\n");
64         printf(TI_DUMP_PADDING);
65         printf("Attempting to merge types: ");
66         pDest->Dump();
67         printf(" and ");
68         pSrc->Dump();
69         printf("\n");
70     }
71 #endif // VERBOSE_VERIFY
72 #endif // DEBUG
73
74     BOOL mergeable = typeInfo::tiMergeToCommonParent(info.compCompHnd, pDest, pSrc, changed);
75
76 #ifdef DEBUG
77 #if VERBOSE_VERIFY
78     if (VERBOSE && tiVerificationNeeded)
79     {
80         printf(TI_DUMP_PADDING);
81         printf((mergeable == TRUE) ? "Merge successful" : "Couldn't merge types");
82         if (*changed)
83         {
84             assert(mergeable);
85             printf(", destination type changed to: ");
86             pDest->Dump();
87         }
88         printf("\n");
89     }
90 #endif // VERBOSE_VERIFY
91 #endif // DEBUG
92
93     return mergeable;
94 }
95
96 static BOOL tiCompatibleWithByRef(COMP_HANDLE CompHnd, const typeInfo& child, const typeInfo& parent)
97 {
98     assert(parent.IsByRef());
99
100     if (!child.IsByRef())
101     {
102         return FALSE;
103     }
104
105     if (child.IsReadonlyByRef() && !parent.IsReadonlyByRef())
106     {
107         return FALSE;
108     }
109
110     // Byrefs are compatible if the underlying types are equivalent
111     typeInfo childTarget  = ::DereferenceByRef(child);
112     typeInfo parentTarget = ::DereferenceByRef(parent);
113
114     if (typeInfo::AreEquivalent(childTarget, parentTarget))
115     {
116         return TRUE;
117     }
118
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)))
122     {
123         return CompHnd->areTypesEquivalent(childTarget.GetClassHandle(), parentTarget.GetClassHandle());
124     }
125
126     return FALSE;
127 }
128
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 !
135  *
136  * Rules for determining compatibility:
137  *
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
141  * TI_BYTE etc.
142  *
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).
145  *
146  * Byrefs are compatible only with byrefs.
147  *
148  * If parent is an object, child must be a subclass of it, implement it
149  * (if it is an interface), or be null.
150  *
151  * If parent is an array, child must be the same or subclassed array.
152  *
153  * If parent is a null objref, only null is compatible with it.
154  *
155  * If the "uninitialized", "by ref local/field", "this pointer" or other flags
156  * are different, the items are incompatible.
157  *
158  * parent CANNOT be an undefined (dead) item.
159  *
160  */
161
162 BOOL typeInfo::tiCompatibleWith(COMP_HANDLE     CompHnd,
163                                 const typeInfo& child,
164                                 const typeInfo& parent,
165                                 bool            normalisedForStack)
166 {
167     assert(child.IsDead() || !normalisedForStack || typeInfo::AreEquivalent(::NormaliseForStack(child), child));
168     assert(parent.IsDead() || !normalisedForStack || typeInfo::AreEquivalent(::NormaliseForStack(parent), parent));
169
170     if (typeInfo::AreEquivalent(child, parent))
171     {
172         return TRUE;
173     }
174
175     if (parent.IsUnboxedGenericTypeVar() || child.IsUnboxedGenericTypeVar())
176     {
177         return (FALSE); // need to have had child == parent
178     }
179     else if (parent.IsType(TI_REF))
180     {
181         // An uninitialized objRef is not compatible to initialized.
182         if (child.IsUninitialisedObjRef() && !parent.IsUninitialisedObjRef())
183         {
184             return FALSE;
185         }
186
187         if (child.IsNullObjRef())
188         { // NULL can be any reference type
189             return TRUE;
190         }
191         if (!child.IsType(TI_REF))
192         {
193             return FALSE;
194         }
195
196         return CompHnd->canCast(child.m_cls, parent.m_cls);
197     }
198     else if (parent.IsType(TI_METHOD))
199     {
200         if (!child.IsType(TI_METHOD))
201         {
202             return FALSE;
203         }
204
205         // Right now we don't bother merging method handles
206         return FALSE;
207     }
208     else if (parent.IsType(TI_STRUCT))
209     {
210         if (!child.IsType(TI_STRUCT))
211         {
212             return FALSE;
213         }
214
215         // Structures are compatible if they are equivalent
216         return CompHnd->areTypesEquivalent(child.m_cls, parent.m_cls);
217     }
218     else if (parent.IsByRef())
219     {
220         return tiCompatibleWithByRef(CompHnd, child, parent);
221     }
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))
227     {
228         return TRUE;
229     }
230     else if (typeInfo::AreEquivalent(nativeInt(), parent) && child.IsType(TI_INT))
231     {
232         return TRUE;
233     }
234 #endif // _TARGET_64BIT_
235     return FALSE;
236 }
237
238 BOOL typeInfo::tiMergeCompatibleWith(COMP_HANDLE     CompHnd,
239                                      const typeInfo& child,
240                                      const typeInfo& parent,
241                                      bool            normalisedForStack)
242 {
243     if (!child.IsPermanentHomeByRef() && parent.IsPermanentHomeByRef())
244     {
245         return FALSE;
246     }
247
248     return typeInfo::tiCompatibleWith(CompHnd, child, parent, normalisedForStack);
249 }
250
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.
254  *
255  * null ^ null                  -> null
256  * Object ^ null                -> Object
257  * [I4 ^ null                   -> [I4
258  * InputStream ^ OutputStream   -> Stream
259  * InputStream ^ NULL           -> InputStream
260  * [I4 ^ Object                 -> Object
261  * [I4 ^ [Object                -> Array
262  * [I4 ^ [R8                    -> Array
263  * [Foo ^ I4                    -> DEAD
264  * [Foo ^ [I1                   -> Array
265  * [InputStream ^ [OutputStream -> Array
266  * DEAD ^ X                     -> DEAD
267  * [Intfc ^ [OutputStream       -> Array
268  * Intf ^ [OutputStream         -> Object
269  * [[InStream ^ [[OutStream     -> Array
270  * [[InStream ^ [OutStream      -> Array
271  * [[Foo ^ [Object              -> Array
272  *
273  * Importantly:
274  * [I1 ^ [U1                    -> either [I1 or [U1
275  * etc.
276  *
277  * Also, System/Int32 and I4 merge -> I4, etc.
278  *
279  * Returns FALSE if the merge was completely incompatible (i.e. the item became
280  * dead).
281  *
282  */
283
284 BOOL typeInfo::tiMergeToCommonParent(COMP_HANDLE CompHnd, typeInfo* pDest, const typeInfo* pSrc, bool* changed)
285 {
286     assert(pSrc->IsDead() || typeInfo::AreEquivalent(::NormaliseForStack(*pSrc), *pSrc));
287     assert(pDest->IsDead() || typeInfo::AreEquivalent(::NormaliseForStack(*pDest), *pDest));
288
289     // Merge the auxiliary information like "this" pointer tracking, etc...
290
291     // Remember the pre-state, so we can tell if it changed.
292     *changed              = false;
293     DWORD destFlagsBefore = pDest->m_flags;
294
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);
297
298     // This bit is set if either pDest or pSrc have it set
299     pDest->m_flags |= (pSrc->m_flags & TI_FLAG_UNINIT_OBJREF);
300
301     // This bit is set if either pDest or pSrc have it set
302     pDest->m_flags |= (pSrc->m_flags & TI_FLAG_BYREF_READONLY);
303
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);
306
307     if (pDest->m_flags != destFlagsBefore)
308     {
309         *changed = true;
310     }
311
312     // OK the main event.  Merge the main types
313     if (typeInfo::AreEquivalent(*pDest, *pSrc))
314     {
315         return (TRUE);
316     }
317
318     if (pDest->IsUnboxedGenericTypeVar() || pSrc->IsUnboxedGenericTypeVar())
319     {
320         // Should have had *pDest == *pSrc
321         goto FAIL;
322     }
323     if (pDest->IsType(TI_REF))
324     {
325         if (pSrc->IsType(TI_NULL))
326         { // NULL can be any reference type
327             return TRUE;
328         }
329         if (!pSrc->IsType(TI_REF))
330         {
331             goto FAIL;
332         }
333
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)
338         {
339             *changed = true;
340         }
341         return TRUE;
342     }
343     else if (pDest->IsType(TI_NULL))
344     {
345         if (pSrc->IsType(TI_REF)) // NULL can be any reference type
346         {
347             *pDest   = *pSrc;
348             *changed = true;
349             return TRUE;
350         }
351         goto FAIL;
352     }
353     else if (pDest->IsType(TI_STRUCT))
354     {
355         if (pSrc->IsType(TI_STRUCT) && CompHnd->areTypesEquivalent(pDest->GetClassHandle(), pSrc->GetClassHandle()))
356         {
357             return TRUE;
358         }
359         goto FAIL;
360     }
361     else if (pDest->IsByRef())
362     {
363         return tiCompatibleWithByRef(CompHnd, *pSrc, *pDest);
364     }
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))
370     {
371         return TRUE;
372     }
373     else if (typeInfo::AreEquivalent(*pSrc, typeInfo::nativeInt()) && pDest->IsType(TI_INT))
374     {
375         *pDest   = *pSrc;
376         *changed = true;
377         return TRUE;
378     }
379 #endif // _TARGET_64BIT_
380
381 FAIL:
382     *pDest = typeInfo();
383     return FALSE;
384 }
385
386 #ifdef DEBUG
387 #if VERBOSE_VERIFY
388 // Utility method to have a detailed dump of a TypeInfo object
389 void typeInfo::Dump() const
390 {
391     char flagsStr[8];
392
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' : '-';
400     flagsStr[7] = '\0';
401
402     printf("[%s(%X) {%s}]", tiType2Str(m_bits.type), m_cls, flagsStr);
403 }
404 #endif // VERBOSE_VERIFY
405 #endif // DEBUG