LCOV - code coverage report
Current view: top level - vm/jit/verify - typeinfo.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 467 793 58.9 %
Date: 2017-07-14 10:03:36 Functions: 27 41 65.9 %

          Line data    Source code
       1             : /* src/vm/jit/verify/typeinfo.cpp - type system used by the type checker
       2             : 
       3             :    Copyright (C) 1996-2014
       4             :    CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
       5             : 
       6             :    This file is part of CACAO.
       7             : 
       8             :    This program is free software; you can redistribute it and/or
       9             :    modify it under the terms of the GNU General Public License as
      10             :    published by the Free Software Foundation; either version 2, or (at
      11             :    your option) any later version.
      12             : 
      13             :    This program is distributed in the hope that it will be useful, but
      14             :    WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      16             :    General Public License for more details.
      17             : 
      18             :    You should have received a copy of the GNU General Public License
      19             :    along with this program; if not, write to the Free Software
      20             :    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
      21             :    02110-1301, USA.
      22             : 
      23             : */
      24             : 
      25             : 
      26             : #include "config.h"
      27             : 
      28             : #include <assert.h>
      29             : #include <string.h>
      30             : 
      31             : #include "mm/dumpmemory.hpp"
      32             : 
      33             : #include "toolbox/logging.hpp"
      34             : 
      35             : #include "vm/array.hpp"
      36             : #include "vm/class.hpp"
      37             : #include "vm/descriptor.hpp"
      38             : #include "vm/exceptions.hpp"
      39             : #include "vm/globals.hpp"
      40             : #include "vm/primitive.hpp"
      41             : #include "vm/resolve.hpp"
      42             : 
      43             : #include "vm/jit/jit.hpp"
      44             : #include "vm/jit/verify/typeinfo.hpp"
      45             : 
      46             : #include "vm/jit/ir/instruction.hpp"
      47             : 
      48             : 
      49             : /* check if a linked class is an array class. Only use for linked classes! */
      50             : #define CLASSINFO_IS_ARRAY(clsinfo)  ((clsinfo)->vftbl->arraydesc != NULL)
      51             : 
      52             : /* check if a linked class implements the interface with the given index */
      53             : #define CLASSINFO_IMPLEMENTS_INTERFACE(cls,index)                   \
      54             :     ( ((index) < (cls)->vftbl->interfacetablelength)            \
      55             :       && ( (cls)->vftbl->interfacetable[-(index)] != NULL ) )
      56             : 
      57             : /******************************************************************************/
      58             : /* DEBUG HELPERS                                                              */
      59             : /******************************************************************************/
      60             : 
      61             : #ifdef TYPEINFO_DEBUG
      62             : #define TYPEINFO_ASSERT(cond)  assert(cond)
      63             : #else
      64             : #define TYPEINFO_ASSERT(cond)
      65             : #endif
      66             : 
      67             : /**********************************************************************/
      68             : /* TYPEVECTOR FUNCTIONS                                               */
      69             : /**********************************************************************/
      70             : 
      71             : #if defined(ENABLE_VERIFIER)
      72             : 
      73             : /* typevector_copy *************************************************************
      74             :  
      75             :    Return a copy of the given typevector.
      76             :   
      77             :    IN:
      78             :            src..............typevector set to copy, must be != NULL
      79             :            size.............number of elements per typevector
      80             : 
      81             :    RETURN VALUE:
      82             :        a pointer to the new typevector set
      83             : 
      84             : *******************************************************************************/
      85             : 
      86             : varinfo *
      87           0 : typevector_copy(varinfo *src, int size)
      88             : {
      89             :         varinfo *dst;
      90             :         
      91           0 :         TYPEINFO_ASSERT(src);
      92             :         
      93           0 :         dst = DNEW_TYPEVECTOR(size);
      94           0 :         memcpy(dst,src,TYPEVECTOR_SIZE(size));
      95             : 
      96           0 :         return dst;
      97             : }
      98             : 
      99             : /* typevector_copy_inplace *****************************************************
     100             :  
     101             :    Copy a typevector to a given destination.
     102             : 
     103             :    IN:
     104             :            src..............typevector to copy, must be != NULL
     105             :            dst..............destination to write the copy to
     106             :            size.............number of elements per typevector
     107             : 
     108             : *******************************************************************************/
     109             : 
     110             : void
     111      560781 : typevector_copy_inplace(varinfo *src,varinfo *dst,int size)
     112             : {
     113      560781 :         memcpy(dst,src,TYPEVECTOR_SIZE(size));
     114      560781 : }
     115             : 
     116             : /* typevector_checktype ********************************************************
     117             :  
     118             :    Check if the typevector contains a given type at a given index.
     119             :   
     120             :    IN:
     121             :            vec..............typevector set, must be != NULL
     122             :            index............index of component to check
     123             :            type.............TYPE_* constant to check against
     124             : 
     125             :    RETURN VALUE:
     126             :        true if the typevector contains TYPE at INDEX,
     127             :            false otherwise
     128             : 
     129             : *******************************************************************************/
     130             : 
     131             : bool
     132      564964 : typevector_checktype(varinfo *vec,int index,int type)
     133             : {
     134      564964 :         TYPEINFO_ASSERT(vec);
     135             : 
     136      564964 :         return vec[index].type == type;
     137             : }
     138             : 
     139             : /* typevector_checkreference ***************************************************
     140             : 
     141             :    Check if the typevector contains a reference at a given index.
     142             : 
     143             :    IN:
     144             :            vec..............typevector, must be != NULL
     145             :            index............index of component to check
     146             : 
     147             :    RETURN VALUE:
     148             :        true if the typevector contains a reference at INDEX,
     149             :            false otherwise
     150             : 
     151             : *******************************************************************************/
     152             : 
     153             : bool
     154           0 : typevector_checkreference(varinfo *vec, int index)
     155             : {
     156           0 :         TYPEINFO_ASSERT(vec);
     157           0 :         return vec[index].is_reference();
     158             : }
     159             : 
     160             : /* typevectorset_checkretaddr **************************************************
     161             : 
     162             :    Check if the typevectors contains a returnAddress at a given index.
     163             : 
     164             :    IN:
     165             :            vec..............typevector, must be != NULL
     166             :            index............index of component to check
     167             : 
     168             :    RETURN VALUE:
     169             :        true if the typevector contains a returnAddress at INDEX,
     170             :            false otherwise
     171             : 
     172             : *******************************************************************************/
     173             : 
     174             : bool
     175          15 : typevector_checkretaddr(varinfo *vec,int index)
     176             : {
     177          15 :         TYPEINFO_ASSERT(vec);
     178          15 :         return vec[index].is_returnaddress();
     179             : }
     180             : 
     181             : /* typevector_store ************************************************************
     182             : 
     183             :    Store a type at a given index in the typevector.
     184             : 
     185             :    IN:
     186             :            vec..............typevector set, must be != NULL
     187             :            index............index of component to set
     188             :            type.............TYPE_* constant of type to set
     189             :            info.............typeinfo of type to set, may be NULL,
     190             :                             if TYPE != TYPE_ADR
     191             : 
     192             : *******************************************************************************/
     193             : 
     194             : void
     195      125849 : typevector_store(varinfo *vec,int index, Type type, typeinfo_t *info)
     196             : {
     197      125849 :         TYPEINFO_ASSERT(vec);
     198             : 
     199      125849 :         vec[index].type = type;
     200      125849 :         if (info)
     201           0 :                 vec[index].typeinfo = *info;
     202      125849 : }
     203             : 
     204             : /* typevector_store_retaddr ****************************************************
     205             : 
     206             :    Store a returnAddress type at a given index in the typevector.
     207             : 
     208             :    IN:
     209             :            vec..............typevector set, must be != NULL
     210             :            index............index of component to set
     211             :            info.............typeinfo of the returnAddress.
     212             : 
     213             : *******************************************************************************/
     214             : 
     215             : void
     216           0 : typevector_store_retaddr(varinfo *vec,int index,typeinfo_t *info)
     217             : {
     218           0 :         TYPEINFO_ASSERT(vec);
     219           0 :         TYPEINFO_ASSERT(info->is_primitive());
     220             : 
     221           0 :         vec[index].type = TYPE_ADR;
     222           0 :         vec[index].typeinfo.init_returnaddress(info->returnaddress());
     223           0 : }
     224             : 
     225             : /* typevector_init_object ******************************************************
     226             : 
     227             :    Replace all uninitialized object types in the typevector set which were
     228             :    created by the given instruction by initialized object types.
     229             : 
     230             :    IN:
     231             :            set..............typevector set
     232             :            ins..............instruction which created the uninitialized object type
     233             :            initclass........class of the initialized object type to set
     234             :            size.............number of elements per typevector
     235             : 
     236             :    RETURN VALUE:
     237             :        true.............success
     238             :            false............an exception has been thrown
     239             : 
     240             :    XXX maybe we should do the lazy resolving before calling this function
     241             : 
     242             : *******************************************************************************/
     243             : 
     244             : bool
     245       78462 : typevector_init_object(varinfo *set,void *ins,
     246             :                                            classref_or_classinfo initclass,
     247             :                                            int size)
     248             : {
     249             :         int i;
     250             : 
     251      411708 :         for (i=0; i<size; ++i) {
     252      497665 :                 if (set[i].type == TYPE_ADR
     253      164130 :                         && set[i].typeinfo.is_newobject()
     254         289 :                         && set[i].typeinfo.newobject_instruction() == ins)
     255             :                 {
     256         284 :                         if (!set[i].typeinfo.init_class(initclass))
     257           0 :                                 return false;
     258             :                 }
     259             :         }
     260       78462 :         return true;
     261             : }
     262             : 
     263             : /* typevector_merge ************************************************************
     264             :  
     265             :    Merge a typevector with another one.
     266             :    The given typevectors must have the same number of components.
     267             :   
     268             :    IN:
     269             :        m................method for exception messages
     270             :            dst..............the first typevector
     271             :            y................the second typevector
     272             :            size.............number of elements per typevector
     273             : 
     274             :    OUT:
     275             :        *dst.............the resulting typevector
     276             : 
     277             :    RETURN VALUE:
     278             :        typecheck_TRUE...dst has been modified
     279             :            typecheck_FALSE..dst has not been modified
     280             :            typecheck_FAIL...an exception has been thrown
     281             : 
     282             : *******************************************************************************/
     283             : 
     284             : typecheck_result
     285      191330 : typevector_merge(methodinfo *m,varinfo *dst,varinfo *y,int size)
     286             : {
     287      191330 :         bool changed = false;
     288             :         typecheck_result r;
     289             : 
     290      191330 :         varinfo *a = dst;
     291      191330 :         varinfo *b = y;
     292     2129047 :         while (size--) {
     293     1749270 :                 if (a->type != TYPE_VOID && a->type != b->type) {
     294        2883 :                         a->type = TYPE_VOID;
     295        2883 :                         changed = true;
     296             :                 }
     297     1743504 :                 else if (a->type == TYPE_ADR) {
     298      737114 :                         if (a->typeinfo.is_primitive()) {
     299             :                                 /* 'a' is a returnAddress */
     300           0 :                                 if (!b->typeinfo.is_primitive()
     301             :                                         || (a->typeinfo.returnaddress() != b->typeinfo.returnaddress()))
     302             :                                 {
     303           0 :                                         a->type = TYPE_VOID;
     304           0 :                                         changed = true;
     305             :                                 }
     306             :                         }
     307             :                         else {
     308             :                                 /* 'a' is a reference */
     309      737114 :                                 if (b->typeinfo.is_primitive()) {
     310           0 :                                         a->type = TYPE_VOID;
     311           0 :                                         changed = true;
     312             :                                 }
     313             :                                 else {
     314             :                                         /* two reference types are merged. There cannot be */
     315             :                                         /* a merge error. In the worst case we get j.l.O.  */
     316      737114 :                                         r = a->typeinfo.merge(m, &(b->typeinfo));
     317      737114 :                                         if (r == typecheck_FAIL)
     318           0 :                                                 return r;
     319      737114 :                                         changed |= r;
     320             :                                 }
     321             :                         }
     322             :                 }
     323     1746387 :                 a++;
     324     1746387 :                 b++;
     325             :         }
     326      191330 :         return (typecheck_result) changed;
     327             : }
     328             : 
     329             : /**********************************************************************/
     330             : /* READ-ONLY FUNCTIONS                                                */
     331             : /* The following functions don't change typeinfo data.                */
     332             : /**********************************************************************/
     333             : 
     334             : /* interface_extends_interface *************************************************
     335             : 
     336             :    Check if a resolved interface extends a given resolved interface.
     337             : 
     338             :    IN:
     339             :            cls..............the interface, must be linked
     340             :            interf...........the interface to check against
     341             : 
     342             :    RETURN VALUE:
     343             :        true.............CLS extends INTERF
     344             :            false............CLS does not extend INTERF
     345             : 
     346             : *******************************************************************************/
     347             : 
     348             : static bool
     349         441 : interface_extends_interface(classinfo *cls,classinfo *interf)
     350             : {
     351             :     int i;
     352             :     
     353         441 :         TYPEINFO_ASSERT(cls);
     354         441 :         TYPEINFO_ASSERT(interf);
     355         441 :         TYPEINFO_ASSERT((interf->flags & ACC_INTERFACE) != 0);
     356         441 :         TYPEINFO_ASSERT((cls->flags & ACC_INTERFACE) != 0);
     357         441 :         TYPEINFO_ASSERT(cls->state & CLASS_LINKED);
     358             : 
     359             :     /* first check direct superinterfaces */
     360         441 :     for (i=0; i<cls->interfacescount; ++i) {
     361         441 :         if (cls->interfaces[i] == interf)
     362         441 :             return true;
     363             :     }
     364             :     
     365             :     /* check indirect superinterfaces */
     366           0 :     for (i=0; i<cls->interfacescount; ++i) {
     367           0 :         if (interface_extends_interface(cls->interfaces[i],interf))
     368           0 :             return true;
     369             :     }
     370             :     
     371           0 :     return false;
     372             : }
     373             : 
     374             : /* classinfo_implements_interface **********************************************
     375             :  
     376             :    Check if a resolved class implements a given resolved interface.
     377             :    
     378             :    IN:
     379             :            cls..............the class
     380             :            interf...........the interface
     381             : 
     382             :    RETURN VALUE:
     383             :        typecheck_TRUE...CLS implements INTERF
     384             :            typecheck_FALSE..CLS does not implement INTERF
     385             :            typecheck_FAIL...an exception has been thrown
     386             : 
     387             : *******************************************************************************/
     388             : 
     389             : static typecheck_result
     390        6179 : classinfo_implements_interface(classinfo *cls,classinfo *interf)
     391             : {
     392        6179 :         TYPEINFO_ASSERT(cls);
     393        6179 :         TYPEINFO_ASSERT(interf);
     394        6179 :         TYPEINFO_ASSERT((interf->flags & ACC_INTERFACE) != 0);
     395             : 
     396        6179 :         if (!(cls->state & CLASS_LINKED))
     397           0 :                 if (!link_class(cls))
     398           0 :                         return typecheck_FAIL;
     399             : 
     400        6179 :     if (cls->flags & ACC_INTERFACE) {
     401             :         /* cls is an interface */
     402        1750 :         if (cls == interf)
     403        1309 :             return typecheck_TRUE;
     404             : 
     405             :         /* check superinterfaces */
     406         441 :         return (typecheck_result) interface_extends_interface(cls,interf);
     407             :     }
     408             : 
     409        4429 :         TYPEINFO_ASSERT(cls->state & CLASS_LINKED);
     410        4429 :     return (typecheck_result) CLASSINFO_IMPLEMENTS_INTERFACE(cls,interf->index);
     411             : }
     412             : 
     413             : /* mergedlist_implements_interface *********************************************
     414             :  
     415             :    Check if all the classes in a given merged list implement a given resolved
     416             :    interface.
     417             :    
     418             :    IN:
     419             :            merged...........the list of merged class types
     420             :            interf...........the interface to check against
     421             : 
     422             :    RETURN VALUE:
     423             :        typecheck_TRUE...all classes implement INTERF
     424             :            typecheck_FALSE..there is at least one class that does not implement
     425             :                             INTERF
     426             :            typecheck_MAYBE..check cannot be performed now because of unresolved
     427             :                             classes
     428             :            typecheck_FAIL...an exception has been thrown
     429             : 
     430             : *******************************************************************************/
     431             : 
     432             : static typecheck_result
     433         143 : mergedlist_implements_interface(typeinfo_mergedlist_t *merged,
     434             :                                 classinfo *interf)
     435             : {
     436             :     int i;
     437             :     classref_or_classinfo *mlist;
     438             :         typecheck_result r;
     439             : 
     440         143 :         TYPEINFO_ASSERT(interf);
     441         143 :         TYPEINFO_ASSERT((interf->flags & ACC_INTERFACE) != 0);
     442             : 
     443             :     /* Check if there is an non-empty mergedlist. */
     444         143 :     if (!merged)
     445           2 :         return typecheck_FALSE;
     446             : 
     447             :     /* If all classinfos in the (non-empty) merged array implement the
     448             :      * interface return true, otherwise false.
     449             :      */
     450         141 :     mlist = merged->list;
     451         141 :     i = merged->count;
     452         423 :     while (i--) {
     453         282 :                 if (mlist->is_classref()) {
     454         141 :                         return typecheck_MAYBE;
     455             :                 }
     456         141 :         r = classinfo_implements_interface((mlist++)->cls,interf);
     457         141 :         if (r != typecheck_TRUE)
     458           0 :                         return r;
     459             :     }
     460           0 :     return typecheck_TRUE;
     461             : }
     462             : 
     463             : /* merged_implements_interface *************************************************
     464             : 
     465             :    Check if a possible merged type implements a given resolved interface
     466             :    interface.
     467             : 
     468             :    IN:
     469             :        typeclass........(common) class of the (merged) type
     470             :            merged...........the list of merged class types
     471             :            interf...........the interface to check against
     472             : 
     473             :    RETURN VALUE:
     474             :        typecheck_TRUE...the type implement INTERF
     475             :            typecheck_FALSE..the type does not implement INTERF
     476             :            typecheck_MAYBE..check cannot be performed now because of unresolved
     477             :                             classes
     478             :            typecheck_FAIL...an exception has been thrown
     479             : 
     480             : *******************************************************************************/
     481             : 
     482             : static typecheck_result
     483        6038 : merged_implements_interface(classinfo *typeclass,typeinfo_mergedlist_t *merged,
     484             :                             classinfo *interf)
     485             : {
     486             :         typecheck_result r;
     487             :         
     488             :     /* primitive types don't support interfaces. */
     489        6038 :     if (!typeclass)
     490           0 :         return typecheck_FALSE;
     491             : 
     492             :     /* the null type can be cast to any interface type. */
     493        6038 :     if (typeclass == pseudo_class_Null)
     494           0 :         return typecheck_TRUE;
     495             : 
     496             :     /* check if typeclass implements the interface. */
     497        6038 :     r = classinfo_implements_interface(typeclass,interf);
     498        6038 :         if (r != typecheck_FALSE)
     499        5897 :         return r;
     500             : 
     501             :     /* check the mergedlist */
     502         141 :         if (!merged)
     503           0 :                 return typecheck_FALSE;
     504         141 :     return mergedlist_implements_interface(merged,interf);
     505             : }
     506             : 
     507             : /* merged_is_subclass **********************************************************
     508             :  
     509             :    Check if a possible merged type is a subclass of a given class.
     510             :    A merged type is a subclass of a class C if all types in the merged list
     511             :    are subclasses of C. A sufficient condition for this is that the
     512             :    common type of the merged type is a subclass of C.
     513             : 
     514             :    IN:
     515             :        typeclass........(common) class of the (merged) type
     516             :                             MUST be a loaded and linked class
     517             :            merged...........the list of merged class types
     518             :            cls..............the class to theck against
     519             : 
     520             :    RETURN VALUE:
     521             :        typecheck_TRUE...the type is a subclass of CLS
     522             :            typecheck_FALSE..the type is not a subclass of CLS
     523             :            typecheck_MAYBE..check cannot be performed now because of unresolved
     524             :                             classes
     525             :            typecheck_FAIL...an exception has been thrown
     526             : 
     527             : *******************************************************************************/
     528             : 
     529             : static typecheck_result
     530       71185 : merged_is_subclass(classinfo *typeclass,typeinfo_mergedlist_t *merged,
     531             :                 classinfo *cls)
     532             : {
     533             :     int i;
     534             :     classref_or_classinfo *mlist;
     535             : 
     536       71185 :         TYPEINFO_ASSERT(cls);
     537             :         
     538             :     /* primitive types aren't subclasses of anything. */
     539       71185 :     if (!typeclass)
     540           0 :         return typecheck_FALSE;
     541             : 
     542             :     /* the null type can be cast to any reference type. */
     543       71185 :     if (typeclass == pseudo_class_Null)
     544           0 :         return typecheck_TRUE;
     545             : 
     546       71185 :         TYPEINFO_ASSERT(typeclass->state & CLASS_LOADED);
     547       71185 :         TYPEINFO_ASSERT(typeclass->state & CLASS_LINKED);
     548             : 
     549             :     /* check if the common typeclass is a subclass of CLS. */
     550       71185 :         if (class_issubclass(typeclass,cls))
     551       71179 :                 return typecheck_TRUE;
     552             : 
     553             :     /* check the mergedlist */
     554           6 :         if (!merged)
     555           6 :                 return typecheck_FALSE;
     556             :     /* If all classinfos in the (non-empty) merged list are subclasses
     557             :          * of CLS, return true, otherwise false.
     558             :          * If there is at least one unresolved type in the list,
     559             :          * return typecheck_MAYBE.
     560             :      */
     561           0 :     mlist = merged->list;
     562           0 :     i = merged->count;
     563           0 :     while (i--) {
     564           0 :                 if (mlist->is_classref()) {
     565           0 :                         return typecheck_MAYBE;
     566             :                 }
     567           0 :                 if (!(mlist->cls->state & CLASS_LINKED))
     568           0 :                         if (!link_class(mlist->cls))
     569           0 :                                 return typecheck_FAIL;
     570           0 :                 if (!class_issubclass(mlist->cls,cls))
     571           0 :                         return typecheck_FALSE;
     572           0 :                 mlist++;
     573             :     }
     574           0 :     return typecheck_TRUE;
     575             : }
     576             : 
     577             : /***
     578             :  *      Check if a type is assignable to a given class type.
     579             :  *
     580             :  *      RETURN VALUE:
     581             :  *              typecheck_TRUE...the type is assignable
     582             :  *              typecheck_FALSE..the type is not assignable
     583             :  *              typecheck_MAYBE..check cannot be performed now because of unresolved classes
     584             :  *              typecheck_FAIL...an exception has been thrown
     585             :  */
     586      106174 : typecheck_result typeinfo_t::is_assignable_to_class(classref_or_classinfo dest) const {
     587      106174 :     classref_or_classinfo c = typeclass;
     588             : 
     589             :     /* assignments of primitive values are not checked here. */
     590      106174 :     if (!c.any && !dest.any)
     591           0 :         return typecheck_TRUE;
     592             : 
     593             :     /* primitive and reference types are not assignment compatible. */
     594      106174 :     if (!c.any || !dest.any)
     595           0 :         return typecheck_FALSE;
     596             : 
     597             :     /* the null type can be assigned to any type */
     598      106174 :     if (is_nulltype())
     599        3127 :         return typecheck_TRUE;
     600             : 
     601             :     /* uninitialized objects are not assignable */
     602      103047 :     if (is_newobject())
     603           0 :         return typecheck_FALSE;
     604             : 
     605      103047 :     Utf8String classname = CLASSREF_OR_CLASSINFO_NAME(c);
     606             : 
     607      103047 :         if (dest.is_classref()) {
     608             :                 /* the destination type is an unresolved class reference */
     609             :                 /* In this case we cannot tell a lot about assignability. */
     610             : 
     611             :                 /* the common case of value and dest type having the same classname */
     612        7177 :                 if (dest.ref->name == classname && !merged)
     613        2972 :                         return typecheck_TRUE;
     614             : 
     615             :                 /* we cannot tell if value is assignable to dest, so we */
     616             :                 /* leave it up to the resolving code to check this      */
     617        4205 :                 return typecheck_MAYBE;
     618             :         }
     619             : 
     620             :         /* { we know that dest is a loaded class } */
     621             : 
     622       95870 :         if (c.is_classref()) {
     623             :                 /* the value type is an unresolved class reference */
     624             : 
     625             :                 /* the common case of value and dest type having the same classname */
     626       17506 :                 if (dest.cls->name == classname)
     627           2 :                         return typecheck_TRUE;
     628             : 
     629             :                 /* we cannot tell if value is assignable to dest, so we */
     630             :                 /* leave it up to the resolving code to check this      */
     631       17504 :                 return typecheck_MAYBE;
     632             :         }
     633             : 
     634             :         /* { we know that both c and dest are loaded classes } */
     635             :         /* (c may still have a merged list containing unresolved classrefs!) */
     636             : 
     637       78364 :         TYPEINFO_ASSERT(c.is_classinfo());
     638       78364 :         TYPEINFO_ASSERT(dest.is_classinfo());
     639             : 
     640       78364 :         classinfo *cls = c.cls;
     641             : 
     642       78364 :         TYPEINFO_ASSERT(cls->state & CLASS_LOADED);
     643       78364 :         TYPEINFO_ASSERT(dest.cls->state & CLASS_LOADED);
     644             : 
     645             :         /* maybe we need to link the classes */
     646       78364 :         if (!(cls->state & CLASS_LINKED))
     647           0 :                 if (!link_class(cls))
     648           0 :                         return typecheck_FAIL;
     649       78364 :         if (!(dest.cls->state & CLASS_LINKED))
     650           0 :                 if (!link_class(dest.cls))
     651           0 :                         return typecheck_FAIL;
     652             : 
     653             :         /* { we know that both c and dest are linked classes } */
     654       78364 :         TYPEINFO_ASSERT(cls->state & CLASS_LINKED);
     655       78364 :         TYPEINFO_ASSERT(dest.cls->state & CLASS_LINKED);
     656             : 
     657       78364 :     if (dest.cls->flags & ACC_INTERFACE) {
     658             :         /* We are assigning to an interface type. */
     659        5988 :         return merged_implements_interface(cls, merged, dest.cls);
     660             :     }
     661             : 
     662       72376 :     if (CLASSINFO_IS_ARRAY(dest.cls)) {
     663        3156 :                 arraydescriptor *arraydesc    = dest.cls->vftbl->arraydesc;
     664        3156 :                 int              dimension    = arraydesc->dimension;
     665        3156 :                 classinfo       *elementclass = (arraydesc->elementvftbl) ? arraydesc->elementvftbl->clazz : NULL;
     666             :                         
     667             :         /* We are assigning to an array type. */
     668        3156 :         if (!is_array())
     669           0 :             return typecheck_FALSE;
     670             : 
     671             :         /* {Both value and dest.cls are array types.} */
     672             : 
     673             :         /* value must have at least the dimension of dest.cls. */
     674        3156 :         if (this->dimension < dimension)
     675           0 :             return typecheck_FALSE;
     676             : 
     677        3156 :         if (this->dimension > dimension) {
     678             :             /* value has higher dimension so we need to check
     679             :              * if its component array can be assigned to the
     680             :              * element type of dest.cls */
     681             : 
     682           3 :                         if (!elementclass) return typecheck_FALSE;
     683             :             
     684           3 :             if (elementclass->flags & ACC_INTERFACE) {
     685             :                 /* We are assigning to an interface type. */
     686           0 :                 return classinfo_implements_interface(pseudo_class_Arraystub, elementclass);
     687             :             }
     688             : 
     689             :             /* We are assigning to a class type. */
     690           3 :             return (typecheck_result) class_issubclass(pseudo_class_Arraystub, elementclass);
     691             :         }
     692             : 
     693             :         /* {value and dest.cls have the same dimension} */
     694             : 
     695        3153 :         if (elementtype != arraydesc->elementtype)
     696           0 :             return typecheck_FALSE;
     697             : 
     698        3153 :         if (this->elementclass.any) {
     699             :             /* We are assigning an array of objects so we have to
     700             :              * check if the elements are assignable.
     701             :              */
     702             : 
     703        2089 :             if (elementclass->flags & ACC_INTERFACE) {
     704             :                 /* We are assigning to an interface type. */
     705             : 
     706          50 :                 return merged_implements_interface(this->elementclass.cls, merged, elementclass);
     707             :             }
     708             : 
     709             :             /* We are assigning to a class type. */
     710        2039 :             return merged_is_subclass(this->elementclass.cls, merged, elementclass);
     711             :         }
     712             : 
     713        1064 :         return typecheck_TRUE;
     714             :     }
     715             : 
     716             :     /* {dest.cls is not an array} */
     717             :     /* {dest.cls is a loaded class} */
     718             : 
     719             :         /* If there are any unresolved references in the merged list, we cannot */
     720             :         /* tell if the assignment will be ok.                                   */
     721             :         /* This can only happen when cls is java.lang.Object                    */
     722       69220 :         if (cls == class_java_lang_Object && merged) {
     723          89 :                 classref_or_classinfo *mlist = merged->list;
     724          89 :                 int i = merged->count;
     725         237 :                 while (i--) {
     726         133 :                         if (mlist->is_classref())
     727          74 :                                 return typecheck_MAYBE;
     728          59 :                         mlist++;
     729             :                 }
     730             :         }
     731             : 
     732             :     /* We are assigning to a class type */
     733       69146 :     if (cls->flags & ACC_INTERFACE)
     734         143 :         cls = class_java_lang_Object;
     735             : 
     736       69146 :     return merged_is_subclass(cls, merged, dest.cls);
     737             : }
     738             : 
     739             : /***
     740             :  *
     741             :  *      Check if a type is assignable to a given type.
     742             :  *
     743             :  *      @param dest  the type of the destination, must not be a merged type
     744             :  *
     745             :  *      RETURN VALUE:
     746             :  *              typecheck_TRUE...the type is assignable
     747             :  *              typecheck_FALSE..the type is not assignable
     748             :  *              typecheck_MAYBE..check cannot be performed now because of unresolved classes
     749             :  *              typecheck_FAIL...an exception has been thrown
     750             :  */
     751       39056 : typecheck_result typeinfo_t::is_assignable_to(typeinfo_t *dest) const {
     752       39056 :         TYPEINFO_ASSERT(dest);
     753       39056 :         TYPEINFO_ASSERT(dest->merged == NULL);
     754             : 
     755       39056 :         return is_assignable_to_class(dest->typeclass);
     756             : }
     757             : 
     758             : /**********************************************************************/
     759             : /* INITIALIZATION FUNCTIONS                                           */
     760             : /* The following functions fill in uninitialized typeinfo structures. */
     761             : /**********************************************************************/
     762             : 
     763             : /* internally used macros ***************************************************/
     764             : 
     765             : #define TYPEINFO_ALLOCMERGED(mergedlist,count)                                  \
     766             :     do {(mergedlist) = (typeinfo_mergedlist_t *) DumpMemory::allocate(sizeof(typeinfo_mergedlist_t) \
     767             :             + ((count)-1)*sizeof(classinfo*));} while(0)
     768             : 
     769             : #define TYPEINFO_FREEMERGED(mergedlist)
     770             : 
     771             : #define TYPEINFO_FREEMERGED_IF_ANY(mergedlist)
     772             : 
     773             : 
     774             : /* typeinfo_t::init_class ******************************************************
     775             : 
     776             :    Initialize a typeinfo to a resolved class.
     777             : 
     778             :    IN:
     779             :            c................the class
     780             : 
     781             :    OUT:
     782             :        *info............is initialized
     783             : 
     784             :    RETURN VALUE:
     785             :        true.............success
     786             :            false............an exception has been thrown
     787             : 
     788             : *******************************************************************************/
     789             : 
     790      658999 : void typeinfo_t::init_class(classinfo *c) {
     791      658999 :         if ((typeclass.cls = c)->vftbl->arraydesc) {
     792       79568 :                 if (c->vftbl->arraydesc->elementvftbl)
     793       39557 :                         elementclass.cls = c->vftbl->arraydesc->elementvftbl->clazz;
     794             :                 else
     795       40011 :                         elementclass.any = NULL;
     796       79568 :                 dimension   = c->vftbl->arraydesc->dimension;
     797       79568 :                 elementtype = c->vftbl->arraydesc->elementtype;
     798             :         }
     799             :         else {
     800      579431 :                 elementclass.any = NULL;
     801      579431 :                 dimension        = 0;
     802      579431 :                 elementtype      = ARRAYTYPE_INT;
     803             :         }
     804      658999 :         merged = NULL;
     805      658999 : }
     806             : 
     807             : /* typeinfo_t::init_class ******************************************************
     808             : 
     809             :    Initialize a typeinfo to a possibly unresolved class type.
     810             : 
     811             :    IN:
     812             :            c................the class type
     813             : 
     814             :    OUT:
     815             :        *info............is initialized
     816             : 
     817             :    RETURN VALUE:
     818             :        true.............success
     819             :            false............an exception has been thrown
     820             : 
     821             : *******************************************************************************/
     822             : 
     823      456281 : bool typeinfo_t::init_class(classref_or_classinfo c) {
     824      456281 :         TYPEINFO_ASSERT(c.any);
     825             : 
     826             :         classinfo  *cls;
     827             : 
     828             :         /* if necessary, try to resolve lazily */
     829      456281 :         if (!resolve_classref_or_classinfo(NULL /* XXX should know method */,
     830             :                                 c,resolveLazy,false,true,&cls))
     831             :         {
     832           0 :                 return false;
     833             :         }
     834             : 
     835      456281 :         if (cls) {
     836      366213 :                 init_class(cls);
     837      366213 :                 return true;
     838             :         }
     839             : 
     840             :         /* {the type could no be resolved lazily} */
     841             : 
     842       90068 :         typeclass.ref    = c.ref;
     843       90068 :         elementclass.any = NULL;
     844       90068 :         dimension        = 0;
     845       90068 :         merged           = NULL;
     846             : 
     847             :         /* handle array type references */
     848       90068 :         const char *utf_ptr = c.ref->name.begin();
     849       90068 :         int         len     = c.ref->name.size();
     850       90068 :         if (*utf_ptr == '[') {
     851             :                 /* count dimensions */
     852        8272 :                 while (*utf_ptr == '[') {
     853        2760 :                         utf_ptr++;
     854        2760 :                         dimension++;
     855        2760 :                         len--;
     856             :                 }
     857        2756 :                 if (*utf_ptr == 'L') {
     858        2756 :                         utf_ptr++;
     859        2756 :                         len -= 2;
     860        2756 :                         elementtype      = ARRAYTYPE_OBJECT;
     861        2756 :                         elementclass.ref = class_get_classref(c.ref->referer, Utf8String::from_utf8(utf_ptr,len));
     862             :                 }
     863             :                 else {
     864             :                         /* an array with primitive element type */
     865             :                         /* should have been resolved above */
     866           0 :                         TYPEINFO_ASSERT(false);
     867             :                 }
     868             :         }
     869       90068 :         return true;
     870             : }
     871             : 
     872             : /* typeinfo_t::init_from_typedesc **********************************************
     873             : 
     874             :    Initialize a typeinfo from a typedesc.
     875             :    
     876             :    IN:
     877             :            desc.............the typedesc
     878             : 
     879             :    OUT:
     880             :        *type............set to the TYPE_* constant of DESC (if type != NULL)
     881             :        *info............receives the typeinfo (if info != NULL)
     882             : 
     883             :    RETURN VALUE:
     884             :        true.............success
     885             :            false............an exception has been thrown
     886             : 
     887             : *******************************************************************************/
     888             : 
     889      282924 : bool typeinfo_t::init_from_typedesc(const typedesc *desc, u1 *type) {
     890             : #ifdef TYPEINFO_VERBOSE
     891             :         fprintf(stderr,"typeinfo_init_from_typedesc(");
     892             :         descriptor_debug_print_typedesc(stderr,this);
     893             :         fprintf(stderr,")\n");
     894             : #endif
     895             : 
     896      282924 :         if (type)
     897           0 :                 *type = desc->type;
     898             : 
     899      282924 :         if (desc->type == TYPE_ADR) {
     900      228950 :                 TYPEINFO_ASSERT(desc->classref);
     901      228950 :                 if (!init_class(desc->classref))
     902           0 :                         return false;
     903             :         }
     904             :         else {
     905       53974 :                 init_primitive();
     906             :         }
     907      282924 :         return true;
     908             : }
     909             : 
     910             : 
     911             : /* typedescriptor_init_from_typedesc *******************************************
     912             :  
     913             :    Initialize a typedescriptor from a typedesc.
     914             :    
     915             :    IN:
     916             :            desc.............the typedesc
     917             : 
     918             :    OUT:
     919             :        *td..............receives the typedescriptor
     920             :                             td must be != NULL
     921             : 
     922             :    RETURN VALUE:
     923             :        true.............success
     924             :            false............an exception has been thrown
     925             : 
     926             : *******************************************************************************/
     927             : 
     928       86416 : static bool typedescriptor_init_from_typedesc(typedescriptor_t *td, typedesc *desc) {
     929       86416 :         TYPEINFO_ASSERT(td);
     930       86416 :         TYPEINFO_ASSERT(desc);
     931             : 
     932       86416 :         td->type = desc->type;
     933       86416 :         if (td->type == TYPE_ADR) {
     934       29037 :                 if (!td->typeinfo.init_class(desc->classref))
     935           0 :                         return false;
     936             :         }
     937             :         else {
     938       57379 :                 td->typeinfo.init_primitive();
     939             :         }
     940       86416 :         return true;
     941             : }
     942             : 
     943             : /* typeinfo_init_varinfo_from_typedesc *****************************************
     944             :  
     945             :    Initialize a varinfo from a typedesc.
     946             :    
     947             :    IN:
     948             :            desc.............the typedesc
     949             : 
     950             :    OUT:
     951             :        *var.............receives the type
     952             :                             var must be != NULL
     953             : 
     954             :    RETURN VALUE:
     955             :        true.............success
     956             :            false............an exception has been thrown
     957             : 
     958             : *******************************************************************************/
     959             : 
     960       72140 : static bool typeinfo_init_varinfo_from_typedesc(varinfo *var, typedesc *desc) {
     961       72140 :         TYPEINFO_ASSERT(var);
     962       72140 :         TYPEINFO_ASSERT(desc);
     963             : 
     964       72140 :         var->type = desc->type;
     965       72140 :         if (var->type == TYPE_ADR) {
     966       47477 :                 if (!var->typeinfo.init_class(desc->classref))
     967           0 :                         return false;
     968             :         }
     969             :         else {
     970       24663 :                 var->typeinfo.init_primitive();
     971             :         }
     972       72140 :         return true;
     973             : }
     974             : 
     975             : /* typeinfo_init_varinfos_from_methoddesc **************************************
     976             :  
     977             :    Initialize an array of varinfos from a methoddesc.
     978             :    
     979             :    IN:
     980             :        desc.............the methoddesc
     981             :        buflen...........number of parameters the buffer can hold
     982             :            startindex.......the zero-based index of the first parameter to
     983             :                             write to the array. In other words the number of
     984             :                                                 parameters to skip at the beginning of the methoddesc.
     985             :            map..............map from parameter indices to varinfo indices
     986             :                             (indexed like jitdata.local_map)
     987             : 
     988             :    OUT:
     989             :        *vars............array receiving the varinfos
     990             :                             td[0] receives the type of the
     991             :                                                 (startindex+1)th parameter of the method
     992             :        *returntype......receives the typedescriptor of the return type.
     993             :                             returntype may be NULL
     994             : 
     995             :    RETURN VALUE:
     996             :        true.............everything ok
     997             :            false............an exception has been thrown
     998             : 
     999             :    NOTE:
    1000             :        If (according to BUFLEN) the buffer is to small to hold the
    1001             :            parameter types, an internal error is thrown. This must be
    1002             :            avoided by checking the number of parameters and allocating enough
    1003             :            space before calling this function.
    1004             : 
    1005             : *******************************************************************************/
    1006             : 
    1007             : bool
    1008       86416 : typeinfo_init_varinfos_from_methoddesc(varinfo *vars,
    1009             :                                                                          methoddesc *desc,
    1010             :                                                                          int buflen, int startindex,
    1011             :                                                                          s4 *map,
    1012             :                                                                          typedescriptor_t *returntype)
    1013             : {
    1014             :         s4 i;
    1015             :     s4 varindex;
    1016             :         s4 type;
    1017       86416 :         s4 slot = 0;
    1018             : 
    1019             :         /* skip arguments */
    1020      154009 :         for (i=0; i<startindex; ++i) {
    1021       67593 :                 slot++;
    1022       67593 :                 if (IS_2_WORD_TYPE(desc->paramtypes[i].type))
    1023           0 :                         slot++;
    1024             :         }
    1025             : 
    1026             :     /* check arguments */
    1027      160088 :     for (i=startindex; i<desc->paramcount; ++i) {
    1028       73672 :                 type = desc->paramtypes[i].type;
    1029       73672 :                 varindex = map[5*slot + type];
    1030             : 
    1031       73672 :                 slot++;
    1032       73672 :                 if (IS_2_WORD_TYPE(type))
    1033         412 :                         slot++;
    1034             : 
    1035       73672 :                 if (varindex == jitdata::UNUSED)
    1036        1532 :                         continue;
    1037             : 
    1038       72140 :                 if (varindex >= buflen) {
    1039           0 :                         exceptions_throw_internalerror("Buffer too small for method arguments.");
    1040           0 :                         return false;
    1041             :                 }
    1042             : 
    1043       72140 :                 if (!typeinfo_init_varinfo_from_typedesc(vars + varindex, desc->paramtypes + i))
    1044           0 :                         return false;
    1045             :     }
    1046             : 
    1047             :     /* check returntype */
    1048       86416 :     if (returntype) {
    1049       86416 :                 if (!typedescriptor_init_from_typedesc(returntype,&(desc->returntype)))
    1050           0 :                         return false;
    1051             :         }
    1052             : 
    1053       86416 :         return true;
    1054             : }
    1055             : 
    1056             : /* typedescriptors_init_from_methoddesc ****************************************
    1057             :  
    1058             :    Initialize an array of typedescriptors from a methoddesc.
    1059             :    
    1060             :    IN:
    1061             :        desc.............the methoddesc
    1062             :        buflen...........number of parameters the buffer can hold
    1063             :        twoword..........if true, use two parameter slots for two-word types
    1064             :            startindex.......the zero-based index of the first parameter to
    1065             :                             write to the array. In other words the number of
    1066             :                                                 parameters to skip at the beginning of the methoddesc.
    1067             : 
    1068             :    OUT:
    1069             :        *td..............array receiving the typedescriptors.
    1070             :                             td[0] receives the typedescriptor of the
    1071             :                                                 (startindex+1)th parameter of the method
    1072             :        *returntype......receives the typedescriptor of the return type.
    1073             :                             returntype may be NULL
    1074             : 
    1075             :    RETURN VALUE:
    1076             :        >= 0.............number of typedescriptors filled in TD
    1077             :            -1...............an exception has been thrown
    1078             : 
    1079             :    NOTE:
    1080             :        If (according to BUFLEN) the buffer is to small to hold the
    1081             :            parameter types, an internal error is thrown. This must be
    1082             :            avoided by checking the number of parameters and allocating enough
    1083             :            space before calling this function.
    1084             : 
    1085             : *******************************************************************************/
    1086             : 
    1087             : int
    1088           0 : typedescriptors_init_from_methoddesc(typedescriptor_t *td,
    1089             :                                                                          methoddesc *desc,
    1090             :                                                                          int buflen,bool twoword,int startindex,
    1091             :                                                                          typedescriptor_t *returntype)
    1092             : {
    1093             :         int i;
    1094           0 :     int args = 0;
    1095             : 
    1096             :     /* check arguments */
    1097           0 :     for (i=startindex; i<desc->paramcount; ++i) {
    1098           0 :                 if (++args > buflen) {
    1099           0 :                         exceptions_throw_internalerror("Buffer too small for method arguments.");
    1100           0 :                         return -1;
    1101             :                 }
    1102             : 
    1103           0 :                 if (!typedescriptor_init_from_typedesc(td,desc->paramtypes + i))
    1104           0 :                         return -1;
    1105           0 :                 td++;
    1106             : 
    1107           0 :                 if (twoword && (td[-1].type == TYPE_LNG || td[-1].type == TYPE_DBL)) {
    1108           0 :                         if (++args > buflen) {
    1109           0 :                                 exceptions_throw_internalerror("Buffer too small for method arguments.");
    1110           0 :                                 return -1;
    1111             :                         }
    1112             : 
    1113           0 :                         td->type = TYPE_VOID;
    1114           0 :                         td->typeinfo.init_primitive();
    1115           0 :                         td++;
    1116             :                 }
    1117             :     }
    1118             : 
    1119             :     /* check returntype */
    1120           0 :     if (returntype) {
    1121           0 :                 if (!typedescriptor_init_from_typedesc(returntype,&(desc->returntype)))
    1122           0 :                         return -1;
    1123             :         }
    1124             : 
    1125           0 :         return args;
    1126             : }
    1127             : 
    1128             : /* typeinfo_t::init_component ***************************************************
    1129             : 
    1130             :    Initialize a typeinfo with the component type of a given array type.
    1131             :    
    1132             :    IN:
    1133             :            srcarray.........the typeinfo of the array type
    1134             : 
    1135             :    OUT:
    1136             :        *dst.............receives the typeinfo of the component type
    1137             : 
    1138             :    RETURN VALUE:
    1139             :        true.............success
    1140             :            false............an exception has been thrown
    1141             : 
    1142             : *******************************************************************************/
    1143             : 
    1144       21280 : bool typeinfo_t::init_component(const typeinfo_t& srcarray) {
    1145       21280 :         if (srcarray.is_nulltype()) {
    1146           1 :                 init_nulltype();
    1147           1 :                 return true;
    1148             :         }
    1149             : 
    1150       21279 :         if (!srcarray.is_array()) {
    1151             :                 /* XXX should we make that a verify error? */
    1152           0 :                 exceptions_throw_internalerror("Trying to access component of non-array");
    1153           0 :                 return false;
    1154             :         }
    1155             : 
    1156             :         /* save the mergedlist (maybe this == srcarray) */
    1157             : 
    1158       21279 :         typeinfo_mergedlist_t *merged = srcarray.merged;
    1159             : 
    1160       21279 :         if (srcarray.typeclass.is_classref()) {
    1161         181 :                 constant_classref *comp = class_get_classref_component_of(srcarray.typeclass.ref);
    1162             : 
    1163         181 :                 if (comp) {
    1164         181 :                         if (!init_class(comp))
    1165           0 :                                 return false;
    1166             :                 }
    1167             :                 else {
    1168           0 :                         init_primitive();
    1169             :                 }
    1170             :         }
    1171             :         else {
    1172       21098 :                 if (!(srcarray.typeclass.cls->state & CLASS_LINKED)) {
    1173           0 :                         if (!link_class(srcarray.typeclass.cls)) {
    1174           0 :                                 return false;
    1175             :                         }
    1176             :                 }
    1177             : 
    1178       21098 :                 TYPEINFO_ASSERT(srcarray.typeclass.cls->vftbl);
    1179       21098 :                 TYPEINFO_ASSERT(srcarray.typeclass.cls->vftbl->arraydesc);
    1180             : 
    1181       21098 :                 if (vftbl_t *comp = srcarray.typeclass.cls->vftbl->arraydesc->componentvftbl)
    1182       21098 :                         init_class(comp->clazz);
    1183             :                 else
    1184           0 :                         init_primitive();
    1185             :         }
    1186             :     
    1187       21279 :     this->merged = merged; /* XXX should we do a deep copy? */
    1188       21279 :         return true;
    1189             : }
    1190             : 
    1191             : /***
    1192             :  * Create a deep copy of the `merged' list of a typeinfo
    1193             :  */
    1194        2268 : void typeinfo_t::clone_merged(const typeinfo_t& src, typeinfo_t& dst) {
    1195        2268 :         int count = src.merged->count;
    1196        2268 :         TYPEINFO_ALLOCMERGED(dst.merged,count);
    1197        2268 :         dst.merged->count = count;
    1198             : 
    1199        2268 :         classref_or_classinfo *srclist = src.merged->list;
    1200        2268 :         classref_or_classinfo *dstlist = dst.merged->list;
    1201             :         
    1202       38556 :         while (count--)
    1203       34020 :                 *dstlist++ = *srclist++;
    1204        2268 : }
    1205             : 
    1206             : 
    1207             : /**********************************************************************/
    1208             : /* MISCELLANEOUS FUNCTIONS                                            */
    1209             : /**********************************************************************/
    1210             : 
    1211             : /**********************************************************************/
    1212             : /* MERGING FUNCTIONS                                                  */
    1213             : /* The following functions are used to merge the types represented by */
    1214             : /* two typeinfo structures into one typeinfo structure.               */
    1215             : /**********************************************************************/
    1216             : 
    1217           3 : static void typeinfo_merge_error(methodinfo *m, const char *str, const typeinfo_t *x, const typeinfo_t *y) {
    1218             : #ifdef TYPEINFO_VERBOSE
    1219             :     fprintf(stderr,"Error in typeinfo_merge: %s\n",str);
    1220             :     fprintf(stderr,"Typeinfo x:\n");
    1221             :     typeinfo_print(stderr,x,1);
    1222             :     fprintf(stderr,"Typeinfo y:\n");
    1223             :     typeinfo_print(stderr,y,1);
    1224             :     log_text(str);
    1225             : #endif
    1226             : 
    1227           3 :         exceptions_throw_verifyerror(m, str);
    1228           3 : }
    1229             : 
    1230             : /* Condition: clsx != clsy. */
    1231             : /* Returns: true if dest was changed (currently always true). */
    1232             : static
    1233             : bool
    1234        1040 : typeinfo_merge_two(typeinfo_t *dest,classref_or_classinfo clsx,classref_or_classinfo clsy)
    1235             : {
    1236        1040 :         TYPEINFO_ASSERT(dest);
    1237             :     TYPEINFO_FREEMERGED_IF_ANY(dest->merged);
    1238        1040 :     TYPEINFO_ALLOCMERGED(dest->merged,2);
    1239        1040 :     dest->merged->count = 2;
    1240             : 
    1241        1040 :         TYPEINFO_ASSERT(clsx.any != clsy.any);
    1242             : 
    1243        1040 :     if (clsx.any < clsy.any) {
    1244         445 :         dest->merged->list[0] = clsx;
    1245         445 :         dest->merged->list[1] = clsy;
    1246             :     }
    1247             :     else {
    1248         595 :         dest->merged->list[0] = clsy;
    1249         595 :         dest->merged->list[1] = clsx;
    1250             :     }
    1251             : 
    1252        1040 :     return true;
    1253             : }
    1254             : 
    1255             : /* Returns: true if dest was changed. */
    1256             : static
    1257             : bool
    1258        2673 : typeinfo_merge_add(typeinfo_t *dest,typeinfo_mergedlist_t *m,classref_or_classinfo cls)
    1259             : {
    1260             :     int count;
    1261             :     typeinfo_mergedlist_t *newmerged;
    1262             :     classref_or_classinfo *mlist,*newlist;
    1263             : 
    1264        2673 :     count = m->count;
    1265        2673 :     mlist = m->list;
    1266             : 
    1267             :     /* Check if cls is already in the mergedlist m. */
    1268       10602 :     while (count--) {
    1269        7489 :         if ((mlist++)->any == cls.any) { /* XXX check equal classrefs? */
    1270             :             /* cls is in the list, so m is the resulting mergedlist */
    1271        2233 :             if (dest->merged == m)
    1272        1951 :                 return false;
    1273             : 
    1274             :             /* We have to copy the mergedlist */
    1275             :             TYPEINFO_FREEMERGED_IF_ANY(dest->merged);
    1276         282 :             count = m->count;
    1277         282 :             TYPEINFO_ALLOCMERGED(dest->merged,count);
    1278         282 :             dest->merged->count = count;
    1279         282 :             newlist = dest->merged->list;
    1280         282 :             mlist = m->list;
    1281        1128 :             while (count--) {
    1282         564 :                 *newlist++ = *mlist++;
    1283             :             }
    1284         282 :             return true;
    1285             :         }
    1286             :     }
    1287             : 
    1288             :     /* Add cls to the mergedlist. */
    1289         440 :     count = m->count;
    1290         440 :     TYPEINFO_ALLOCMERGED(newmerged,count+1);
    1291         440 :     newmerged->count = count+1;
    1292         440 :     newlist = newmerged->list;    
    1293         440 :     mlist = m->list;
    1294        2055 :     while (count) {
    1295        1307 :         if (mlist->any > cls.any)
    1296         132 :             break;
    1297        1175 :         *newlist++ = *mlist++;
    1298        1175 :         count--;
    1299             :     }
    1300         440 :     *newlist++ = cls;
    1301        1161 :     while (count--) {
    1302         281 :         *newlist++ = *mlist++;
    1303             :     }
    1304             : 
    1305             :     /* Put the new mergedlist into dest. */
    1306             :     TYPEINFO_FREEMERGED_IF_ANY(dest->merged);
    1307         440 :     dest->merged = newmerged;
    1308             :     
    1309         440 :     return true;
    1310             : }
    1311             : 
    1312             : /* Returns: true if dest was changed. */
    1313             : static
    1314             : bool
    1315        2021 : typeinfo_merge_mergedlists(typeinfo_t *dest,typeinfo_mergedlist_t *x,
    1316             :                            typeinfo_mergedlist_t *y)
    1317             : {
    1318        2021 :     int count = 0;
    1319             :     int countx,county;
    1320             :     typeinfo_mergedlist_t *temp,*result;
    1321             :     classref_or_classinfo *clsx,*clsy,*newlist;
    1322             : 
    1323             :     /* count the elements that will be in the resulting list */
    1324             :     /* (Both lists are sorted, equal elements are counted only once.) */
    1325        2021 :     clsx = x->list;
    1326        2021 :     clsy = y->list;
    1327        2021 :     countx = x->count;
    1328        2021 :     county = y->count;
    1329       23707 :     while (countx && county) {
    1330       19665 :         if (clsx->any == clsy->any) {
    1331       19581 :             clsx++;
    1332       19581 :             clsy++;
    1333       19581 :             countx--;
    1334       19581 :             county--;
    1335             :         }
    1336          84 :         else if (clsx->any < clsy->any) {
    1337          60 :             clsx++;
    1338          60 :             countx--;
    1339             :         }
    1340             :         else {
    1341          24 :             clsy++;
    1342          24 :             county--;
    1343             :         }
    1344       19665 :         count++;
    1345             :     }
    1346        2021 :     count += countx + county;
    1347             : 
    1348             :     /* {The new mergedlist will have count entries.} */
    1349             : 
    1350        2021 :     if ((x->count != count) && (y->count == count)) {
    1351           0 :         temp = x; x = y; y = temp;
    1352             :     }
    1353             :     /* {If one of x,y is already the result it is x.} */
    1354        2021 :     if (x->count == count) {
    1355             :         /* x->merged is equal to the result */
    1356        2015 :         if (x == dest->merged)
    1357        2015 :             return false;
    1358             : 
    1359           0 :         if (!dest->merged || dest->merged->count != count) {
    1360             :             TYPEINFO_FREEMERGED_IF_ANY(dest->merged);
    1361           0 :             TYPEINFO_ALLOCMERGED(dest->merged,count);
    1362           0 :             dest->merged->count = count;
    1363             :         }
    1364             : 
    1365           0 :         newlist = dest->merged->list;
    1366           0 :         clsx = x->list;
    1367           0 :         while (count--) {
    1368           0 :             *newlist++ = *clsx++;
    1369             :         }
    1370           0 :         return true;
    1371             :     }
    1372             : 
    1373             :     /* {We have to merge two lists.} */
    1374             : 
    1375             :     /* allocate the result list */
    1376           6 :     TYPEINFO_ALLOCMERGED(result,count);
    1377           6 :     result->count = count;
    1378           6 :     newlist = result->list;
    1379             : 
    1380             :     /* merge the sorted lists */
    1381           6 :     clsx = x->list;
    1382           6 :     clsy = y->list;
    1383           6 :     countx = x->count;
    1384           6 :     county = y->count;
    1385          48 :     while (countx && county) {
    1386          36 :         if (clsx->any == clsy->any) {
    1387           0 :             *newlist++ = *clsx++;
    1388           0 :             clsy++;
    1389           0 :             countx--;
    1390           0 :             county--;
    1391             :         }
    1392          36 :         else if (clsx->any < clsy->any) {
    1393          12 :             *newlist++ = *clsx++;
    1394          12 :             countx--;
    1395             :         }
    1396             :         else {
    1397          24 :             *newlist++ = *clsy++;
    1398          24 :             county--;
    1399             :         }
    1400             :     }
    1401          18 :     while (countx--)
    1402           6 :             *newlist++ = *clsx++;
    1403          12 :     while (county--)
    1404           0 :             *newlist++ = *clsy++;
    1405             : 
    1406             :     /* replace the list in dest with the result list */
    1407             :     TYPEINFO_FREEMERGED_IF_ANY(dest->merged);
    1408           6 :     dest->merged = result;
    1409             : 
    1410           6 :     return true;
    1411             : }
    1412             : 
    1413             : /* typeinfo_merge_nonarrays ****************************************************
    1414             :  
    1415             :    Merge two non-array types.
    1416             :    
    1417             :    IN:
    1418             :        x................the first type
    1419             :            y................the second type
    1420             :            mergedx..........merged list of the first type, may be NULL
    1421             :            mergedy..........merged list of the descond type, may be NULL
    1422             : 
    1423             :    OUT:
    1424             :        *dest............receives the resulting merged list
    1425             :            *result..........receives the resulting type
    1426             : 
    1427             :    RETURN VALUE:
    1428             :        typecheck_TRUE...*dest has been modified
    1429             :            typecheck_FALSE..*dest has not been modified
    1430             :            typecheck_FAIL...an exception has been thrown
    1431             : 
    1432             :    NOTE:
    1433             :        RESULT is an extra parameter so it can point to dest->typeclass or to
    1434             :            dest->elementclass.
    1435             : 
    1436             : *******************************************************************************/
    1437             : 
    1438             : static typecheck_result
    1439        5788 : typeinfo_merge_nonarrays(typeinfo_t *dest,
    1440             :                          classref_or_classinfo *result,
    1441             :                          classref_or_classinfo x,classref_or_classinfo y,
    1442             :                          typeinfo_mergedlist_t *mergedx,
    1443             :                          typeinfo_mergedlist_t *mergedy)
    1444             : {
    1445             :         classinfo *tcls,*common;
    1446             :         bool changed;
    1447             :         typecheck_result r;
    1448             : 
    1449        5788 :         TYPEINFO_ASSERT(dest && result && x.any && y.any);
    1450        5788 :         TYPEINFO_ASSERT(x.cls != pseudo_class_Null);
    1451        5788 :         TYPEINFO_ASSERT(y.cls != pseudo_class_Null);
    1452        5788 :         TYPEINFO_ASSERT(x.cls != pseudo_class_New);
    1453        5788 :         TYPEINFO_ASSERT(y.cls != pseudo_class_New);
    1454             : 
    1455             :         /*--------------------------------------------------*/
    1456             :         /* common cases                                     */
    1457             :         /*--------------------------------------------------*/
    1458             : 
    1459             :     /* Common case 1: x and y are the same class or class reference */
    1460             :     /* (This case is very simple unless *both* x and y really represent
    1461             :      *  merges of subclasses of clsx==clsy.)
    1462             :      */
    1463        5788 :     if ( (x.any == y.any) && (!mergedx || !mergedy) ) {
    1464             :   return_simple_x:
    1465             :         /* DEBUG */ /* log_text("return simple x"); */
    1466          54 :         changed = (dest->merged != NULL);
    1467             :         TYPEINFO_FREEMERGED_IF_ANY(dest->merged);
    1468          54 :         dest->merged = NULL;
    1469          54 :         *result = x;
    1470             :         /* DEBUG */ /* log_text("returning"); */
    1471          54 :         return (typecheck_result) changed;
    1472             :     }
    1473             : 
    1474        5788 :         Utf8String xname = CLASSREF_OR_CLASSINFO_NAME(x);
    1475        5788 :         Utf8String yname = CLASSREF_OR_CLASSINFO_NAME(y);
    1476             : 
    1477             :         /* Common case 2: xname == yname, at least one unresolved */
    1478        5788 :         if ((xname == yname) && (x.is_classref() || y.is_classref()))
    1479             :         {
    1480             :                 /* use the loaded one if any */
    1481           0 :                 if (y.is_classinfo())
    1482           0 :                         x = y;
    1483           0 :                 goto return_simple_x;
    1484             :         }
    1485             : 
    1486             :         /*--------------------------------------------------*/
    1487             :         /* non-trivial cases                                */
    1488             :         /*--------------------------------------------------*/
    1489             : 
    1490             : #ifdef TYPEINFO_VERBOSE
    1491             :         {
    1492             :                 typeinfo_t dbgx,dbgy;
    1493             :                 fprintf(stderr,"merge_nonarrays:\n");
    1494             :                 fprintf(stderr,"    ");if(x.is_classref())fprintf(stderr,"<ref>");utf_fprint_printable_ascii(stderr,xname);fprintf(stderr,"\n");
    1495             :                 fprintf(stderr,"    ");if(y.is_classref())fprintf(stderr,"<ref>");utf_fprint_printable_ascii(stderr,yname);fprintf(stderr,"\n");
    1496             :                 fflush(stderr);
    1497             :                 dbgx.init_class(x);
    1498             :                 dbgx.merged = mergedx;
    1499             :                 dbgy.init_class(y);
    1500             :                 dbgy.merged = mergedy;
    1501             :                 typeinfo_print(stderr,&dbgx,4);
    1502             :                 fprintf(stderr,"  with:\n");
    1503             :                 typeinfo_print(stderr,&dbgy,4);
    1504             :         }
    1505             : #endif
    1506             : 
    1507        5788 :         TYPEINFO_ASSERT(x.is_classref() || (x.cls->state & CLASS_LOADED));
    1508        5788 :         TYPEINFO_ASSERT(y.is_classref() || (y.cls->state & CLASS_LOADED));
    1509             : 
    1510             :         /* If y is unresolved or an interface, swap x and y. */
    1511        5788 :         if (y.is_classref() || (x.is_classinfo() && y.cls->flags & ACC_INTERFACE)) {
    1512        1793 :                 classref_or_classinfo  tmp     = x;       x       = y;       y       = tmp;
    1513        1793 :                 typeinfo_mergedlist_t *tmerged = mergedx; mergedx = mergedy; mergedy = tmerged;
    1514             :         }
    1515             : 
    1516             :     /* {We know: If only one of x,y is unresolved it is x,} */
    1517             :     /* {         If both x,y are resolved and only one of x,y is an interface it is x.} */
    1518             : 
    1519        5788 :         if (x.is_classref()) {
    1520             :                 /* {We know: x and y have different class names} */
    1521             : 
    1522             :         /* Check if we are merging an unresolved type with java.lang.Object */
    1523        1798 :         if (y.cls == class_java_lang_Object && !mergedy) {
    1524          17 :             x = y;
    1525          17 :             goto return_simple_x;
    1526             :         }
    1527             : 
    1528        1781 :                 common = class_java_lang_Object;
    1529        1781 :                 goto merge_with_simple_x;
    1530             :         }
    1531             : 
    1532             :         /* {We know: both x and y are resolved} */
    1533             :     /* {We know: If only one of x,y is an interface it is x.} */
    1534             : 
    1535        3990 :         TYPEINFO_ASSERT(x.is_classinfo() && y.is_classinfo());
    1536        3990 :         TYPEINFO_ASSERT(x.cls->state & CLASS_LOADED);
    1537        3990 :         TYPEINFO_ASSERT(y.cls->state & CLASS_LOADED);
    1538             : 
    1539             :     /* Handle merging of interfaces: */
    1540        3990 :     if (x.cls->flags & ACC_INTERFACE) {
    1541             :         /* {x.cls is an interface and mergedx == NULL.} */
    1542             : 
    1543          27 :         if (y.cls->flags & ACC_INTERFACE) {
    1544             :             /* We are merging two interfaces. */
    1545             :             /* {mergedy == NULL} */
    1546             : 
    1547             :             /* {We know that x.cls!=y.cls (see common case at beginning.)} */
    1548           0 :             result->cls = class_java_lang_Object;
    1549           0 :             return (typecheck_result) typeinfo_merge_two(dest,x,y);
    1550             :         }
    1551             : 
    1552             :         /* {We know: x is an interface, y is a class.} */
    1553             : 
    1554             :         /* Check if we are merging an interface with java.lang.Object */
    1555          27 :         if (y.cls == class_java_lang_Object && !mergedy) {
    1556           3 :             x = y;
    1557           3 :             goto return_simple_x;
    1558             :         }
    1559             : 
    1560             :         /* If the type y implements x then the result of the merge
    1561             :          * is x regardless of mergedy.
    1562             :          */
    1563             : 
    1564             :                 /* we may have to link the classes */
    1565          24 :                 if (!(x.cls->state & CLASS_LINKED))
    1566           0 :                         if (!link_class(x.cls))
    1567           0 :                                 return typecheck_FAIL;
    1568          24 :                 if (!(y.cls->state & CLASS_LINKED))
    1569           0 :                         if (!link_class(y.cls))
    1570           0 :                                 return typecheck_FAIL;
    1571             :         
    1572          24 :                 TYPEINFO_ASSERT(x.cls->state & CLASS_LINKED);
    1573          24 :                 TYPEINFO_ASSERT(y.cls->state & CLASS_LINKED);
    1574             : 
    1575          24 :         if (CLASSINFO_IMPLEMENTS_INTERFACE(y.cls,x.cls->index))
    1576             :                 {
    1577             :             /* y implements x, so the result of the merge is x. */
    1578          22 :             goto return_simple_x;
    1579             :                 }
    1580             :                 
    1581           2 :         r = mergedlist_implements_interface(mergedy,x.cls);
    1582           2 :                 if (r == typecheck_FAIL)
    1583           0 :                         return r;
    1584           2 :                 if (r == typecheck_TRUE)
    1585             :         {
    1586             :             /* y implements x, so the result of the merge is x. */
    1587           0 :             goto return_simple_x;
    1588             :         }
    1589             :         
    1590             :         /* {We know: x is an interface, the type y a class or a merge
    1591             :          * of subclasses and is not guaranteed to implement x.} */
    1592             : 
    1593           2 :         common = class_java_lang_Object;
    1594           2 :         goto merge_with_simple_x;
    1595             :     }
    1596             : 
    1597             :     /* {We know: x and y are classes (not interfaces).} */
    1598             :     
    1599             :         /* we may have to link the classes */
    1600        3963 :         if (!(x.cls->state & CLASS_LINKED))
    1601           0 :                 if (!link_class(x.cls))
    1602           0 :                         return typecheck_FAIL;
    1603        3963 :         if (!(y.cls->state & CLASS_LINKED))
    1604           0 :                 if (!link_class(y.cls))
    1605           0 :                         return typecheck_FAIL;
    1606             :         
    1607        3963 :         TYPEINFO_ASSERT(x.cls->state & CLASS_LINKED);
    1608        3963 :         TYPEINFO_ASSERT(y.cls->state & CLASS_LINKED);
    1609             : 
    1610             :     /* If *x is deeper in the inheritance hierarchy swap x and y. */
    1611        3963 :         if (x.cls->index > y.cls->index) {
    1612         282 :                 classref_or_classinfo  tmp     = x;       x       = y;       y       = tmp;
    1613         282 :                 typeinfo_mergedlist_t *tmerged = mergedx; mergedx = mergedy; mergedy = tmerged;
    1614             :         }
    1615             : 
    1616             :     /* {We know: y is at least as deep in the hierarchy as x.} */
    1617             : 
    1618             :     /* Find nearest common anchestor for the classes. */
    1619             : 
    1620        3963 :     common = x.cls;
    1621        3963 :     tcls   = y.cls;
    1622             : 
    1623        9552 :     while (tcls->index > common->index)
    1624        1626 :         tcls = tcls->super;
    1625             : 
    1626        8419 :     while (common != tcls) {
    1627         493 :         common = common->super;
    1628         493 :         tcls = tcls->super;
    1629             :     }
    1630             : 
    1631             :     /* {common == nearest common anchestor of x and y.} */
    1632             : 
    1633             :     /* If x.cls==common and x is a whole class (not a merge of subclasses)
    1634             :      * then the result of the merge is x.
    1635             :      */
    1636        3963 :     if (x.cls == common && !mergedx) {
    1637          12 :         goto return_simple_x;
    1638             :     }
    1639             :    
    1640        3951 :     if (mergedx) {
    1641        3458 :         result->cls = common;
    1642        3458 :         if (mergedy)
    1643        2021 :             return (typecheck_result) typeinfo_merge_mergedlists(dest,mergedx,mergedy);
    1644             :         else
    1645        1437 :             return (typecheck_result) typeinfo_merge_add(dest,mergedx,y);
    1646             :     }
    1647             : 
    1648             : merge_with_simple_x:
    1649        2276 :     result->cls = common;
    1650        2276 :     if (mergedy)
    1651        1236 :         return (typecheck_result) typeinfo_merge_add(dest,mergedy,x);
    1652             :     else
    1653        1040 :         return (typecheck_result) typeinfo_merge_two(dest,x,y);
    1654             : }
    1655             : 
    1656             : /***
    1657             :  *
    1658             :  *      Merge two types, stores result of merge in `this'.
    1659             :  *
    1660             :  *      @param m  method for exception messages
    1661             :  *      @param t  the second type
    1662             :  *
    1663             :  *      RETURN VALUE:
    1664             :  *              typecheck_TRUE...*dest has been modified
    1665             :  *              typecheck_FALSE..*dest has not been modified
    1666             :  *              typecheck_FAIL...an exception has been thrown
    1667             :  *
    1668             :  *      @pre
    1669             :  *              1) *dest must be a valid initialized typeinfo
    1670             :  *              2) dest != y
    1671             :  */
    1672      839745 : typecheck_result typeinfo_t::merge(methodinfo *m, const typeinfo_t *src) {
    1673             :         const typeinfo_t *x;
    1674             :         classref_or_classinfo common;
    1675             :         classref_or_classinfo elementclass;
    1676             :         int dimension;
    1677             :         ArrayType new_elementtype;
    1678             :         bool changed;
    1679             :         typecheck_result r;
    1680             : 
    1681             :         /*--------------------------------------------------*/
    1682             :         /* fast checks                                      */
    1683             :         /*--------------------------------------------------*/
    1684             : 
    1685             :         /* Merging something with itself is a nop */
    1686      839745 :         if (this == src)
    1687           1 :                 return typecheck_FALSE;
    1688             : 
    1689             :         /* Merging two returnAddress types is ok. */
    1690             :         /* Merging two different returnAddresses never happens, as the verifier */
    1691             :         /* keeps them separate in order to check all the possible return paths  */
    1692             :         /* from JSR subroutines.                                                */
    1693      839744 :         if (!typeclass.any && !src->typeclass.any) {
    1694           0 :                 TYPEINFO_ASSERT(returnaddress() == src->returnaddress());
    1695           0 :                 return typecheck_FALSE;
    1696             :         }
    1697             : 
    1698             :         /* Primitive types cannot be merged with reference types */
    1699             :         /* This must be checked before calls to typeinfo_merge.  */
    1700      839744 :         TYPEINFO_ASSERT(this->typeclass.any && src->typeclass.any);
    1701             : 
    1702             :         /* handle uninitialized object types */
    1703      839744 :         if (is_newobject() || src->is_newobject()) {
    1704        1515 :                 if (!is_newobject() || !src->is_newobject()) {
    1705           1 :                         typeinfo_merge_error(m,(char*) "Trying to merge uninitialized object type.", this, src);
    1706           1 :                         return typecheck_FAIL;
    1707             :                 }
    1708        1514 :                 if (newobject_instruction() != src->newobject_instruction()) {
    1709           2 :                         typeinfo_merge_error(m,(char*) "Trying to merge different uninitialized objects.", this, src);
    1710           2 :                         return typecheck_FAIL;
    1711             :                 }
    1712             :                 /* the same uninitialized object -- no change */
    1713        1512 :                 return typecheck_FALSE;
    1714             :         }
    1715             : 
    1716             :         /*--------------------------------------------------*/
    1717             :         /* common cases                                     */
    1718             :         /*--------------------------------------------------*/
    1719             : 
    1720             :     /* Common case: dest and y are the same class or class reference */
    1721             :     /* (This case is very simple unless *both* dest and y really represent
    1722             :      *  merges of subclasses of class dest==class y.)
    1723             :      */
    1724      838229 :         if ((this->typeclass.any == src->typeclass.any) && (!this->merged || !src->merged)) {
    1725             : return_simple:
    1726      811191 :                 changed = (merged != NULL);
    1727             :                 TYPEINFO_FREEMERGED_IF_ANY(merged);
    1728      811191 :                 merged = NULL;
    1729      811191 :                 return (typecheck_result) changed;
    1730             :         }
    1731             : 
    1732             :     /* Handle null types: */
    1733       27045 :         if (src->is_nulltype()) {
    1734        5870 :                 return typecheck_FALSE;
    1735             :         }
    1736       21175 :         if (is_nulltype()) {
    1737             :                 TYPEINFO_FREEMERGED_IF_ANY(dest->merged);
    1738       15380 :                 typeinfo_t::clone(*src, *this);
    1739       15380 :                 return typecheck_TRUE;
    1740             :         }
    1741             : 
    1742             :         /* Common case: two types with the same name, at least one unresolved */
    1743        5795 :         if (typeclass.is_classref()) {
    1744         223 :                 if (src->typeclass.is_classref()) {
    1745         201 :                         if (typeclass.ref->name == src->typeclass.ref->name)
    1746           0 :                                 goto return_simple;
    1747             :                 }
    1748             :                 else {
    1749             :                         /* XXX should we take y instead of dest here? */
    1750          22 :                         if (typeclass.ref->name == src->typeclass.cls->name)
    1751           0 :                                 goto return_simple;
    1752             :                 }
    1753             :         }
    1754             :         else {
    1755        5572 :                 if (src->typeclass.is_classref() && (typeclass.cls->name == src->typeclass.ref->name))
    1756             :                 {
    1757           7 :                         goto return_simple;
    1758             :                 }
    1759             :         }
    1760             : 
    1761             :         /*--------------------------------------------------*/
    1762             :         /* non-trivial cases                                */
    1763             :         /*--------------------------------------------------*/
    1764             : 
    1765             : #ifdef TYPEINFO_VERBOSE
    1766             :         fprintf(stderr,"merge:\n");
    1767             :     typeinfo_print(stderr,dest,4);
    1768             :     typeinfo_print(stderr,y,4);
    1769             : #endif
    1770             : 
    1771             :     /* This function uses x internally, so x and y can be swapped
    1772             :      * without changing dest. */
    1773        5788 :     x       = this;
    1774        5788 :     changed = false;
    1775             :     
    1776             :     /* Handle merging of arrays: */
    1777        5788 :     if (x->is_array() && src->is_array()) {
    1778             :         
    1779             :         /* Make x the one with lesser dimension */
    1780        1974 :         if (x->dimension > src->dimension) {
    1781           0 :             const typeinfo_t *tmp = x; x = src; src = tmp;
    1782             :         }
    1783             : 
    1784             :         /* If one array (y) has higher dimension than the other,
    1785             :          * interpret it as an array (same dim. as x) of Arraystubs. */
    1786        1974 :         if (x->dimension < src->dimension) {
    1787           0 :             dimension = x->dimension;
    1788           0 :             new_elementtype = ARRAYTYPE_OBJECT;
    1789           0 :             elementclass.cls = pseudo_class_Arraystub;
    1790             :         }
    1791             :         else {
    1792        1974 :             dimension    = src->dimension;
    1793        1974 :             new_elementtype = src->elementtype;
    1794        1974 :             elementclass = src->elementclass;
    1795             :         }
    1796             :         
    1797             :         /* {The arrays are of the same dimension.} */
    1798             :         
    1799        1974 :         if (x->elementtype != new_elementtype) {
    1800             :             /* Different element types are merged, so the resulting array
    1801             :              * type has one accessible dimension less. */
    1802           0 :             if (--dimension == 0) {
    1803           0 :                 common.cls       = pseudo_class_Arraystub;
    1804           0 :                 new_elementtype = ARRAYTYPE_INT;
    1805           0 :                 elementclass.any = NULL;
    1806             :             }
    1807             :             else {
    1808           0 :                 common.cls = class_multiarray_of(dimension,pseudo_class_Arraystub,true);
    1809           0 :                                 if (!common.cls) {
    1810           0 :                                         exceptions_throw_internalerror("XXX Coult not create array class");
    1811           0 :                                         return typecheck_FAIL;
    1812             :                                 }
    1813             : 
    1814           0 :                 new_elementtype = ARRAYTYPE_OBJECT;
    1815           0 :                 elementclass.cls = pseudo_class_Arraystub;
    1816             :             }
    1817             :         }
    1818             :         else {
    1819             :             /* {The arrays have the same dimension and elementtype.} */
    1820             : 
    1821        1974 :             if (new_elementtype == ARRAYTYPE_OBJECT) {
    1822             :                 /* The elements are references, so their respective
    1823             :                  * types must be merged.
    1824             :                  */
    1825             :                                 r = typeinfo_merge_nonarrays(this,
    1826             :                                                              &elementclass,
    1827             :                                                              x->elementclass,
    1828             :                                                              elementclass,
    1829        1974 :                                                              x->merged, src->merged);
    1830        1974 :                                 TYPEINFO_ASSERT(r != typecheck_MAYBE);
    1831        1974 :                                 if (r == typecheck_FAIL)
    1832           0 :                                         return r;
    1833        1974 :                                 changed |= r;
    1834             : 
    1835             :                 /* DEBUG */ /* log_text("finding resulting array class: "); */
    1836        1974 :                                 if (elementclass.is_classref())
    1837           0 :                                         common.ref = class_get_classref_multiarray_of(dimension,elementclass.ref);
    1838             :                                 else {
    1839        1974 :                                         common.cls = class_multiarray_of(dimension,elementclass.cls,true);
    1840        1974 :                                         if (!common.cls) {
    1841           0 :                                                 exceptions_throw_internalerror("XXX Coult not create array class");
    1842           0 :                                                 return typecheck_FAIL;
    1843             :                                         }
    1844             :                                 }
    1845             :                 /* DEBUG */ /* utf_display_printable_ascii(common->name); printf("\n"); */
    1846             :             }
    1847             :                         else {
    1848           0 :                                 common.any = src->typeclass.any;
    1849             :                         }
    1850             :         }
    1851             :     }
    1852             :     else {
    1853             :         /* {We know that at least one of x or y is no array, so the
    1854             :          *  result cannot be an array.} */
    1855             : 
    1856             :                 r = typeinfo_merge_nonarrays(this,
    1857             :                                              &common,
    1858             :                                              x->typeclass, src->typeclass,
    1859        3814 :                                              x->merged,    src->merged);
    1860        3814 :                 TYPEINFO_ASSERT(r != typecheck_MAYBE);
    1861        3814 :                 if (r == typecheck_FAIL)
    1862           0 :                         return r;
    1863        3814 :                 changed |= r;
    1864             : 
    1865        3814 :         dimension        = 0;
    1866        3814 :         new_elementtype = ARRAYTYPE_INT;
    1867        3814 :         elementclass.any = NULL;
    1868             :     }
    1869             : 
    1870             :     /* Put the new values into dest if neccessary. */
    1871             : 
    1872        5788 :     if (this->typeclass.any != common.any) {
    1873        1334 :         this->typeclass.any = common.any;
    1874        1334 :         changed = true;
    1875             :     }
    1876        5788 :     if (this->dimension != dimension) {
    1877          14 :         this->dimension = dimension;
    1878          14 :         changed = true;
    1879             :     }
    1880        5788 :     if (elementtype != new_elementtype) {
    1881          11 :         elementtype = new_elementtype;
    1882          11 :         changed = true;
    1883             :     }
    1884        5788 :     if (this->elementclass.any != elementclass.any) {
    1885         431 :         this->elementclass.any = elementclass.any;
    1886         431 :         changed = true;
    1887             :     }
    1888             : 
    1889        5788 :     return (typecheck_result) changed;
    1890             : }
    1891             : #endif /* ENABLE_VERIFER */
    1892             : 
    1893             : 
    1894             : /**********************************************************************/
    1895             : /* DEBUGGING HELPERS                                                  */
    1896             : /**********************************************************************/
    1897             : 
    1898             : #ifdef TYPEINFO_DEBUG
    1899             : 
    1900             : #if 0
    1901             : static int
    1902             : typeinfo_test_compare(classref_or_classinfo *a,classref_or_classinfo *b)
    1903             : {
    1904             :     if (a->any == b->any) return 0;
    1905             :     if (a->any < b->any) return -1;
    1906             :     return +1;
    1907             : }
    1908             : 
    1909             : static void
    1910             : typeinfo_test_parse(typeinfo_t *info,char *str)
    1911             : {
    1912             :     int num;
    1913             :     int i;
    1914             :     typeinfo_t *infobuf;
    1915             :     u1 *typebuf;
    1916             :     int returntype;
    1917             :     Utf8String desc = Utf8String::from_utf8(str);
    1918             :     
    1919             :     num = typeinfo_count_method_args(desc,false);
    1920             :     if (num) {
    1921             :         typebuf = (u1*) DumpMemory::allocate(sizeof(u1) * num);
    1922             :         infobuf = (typeinfo_t*) DumpMemory::allocate(sizeof(typeinfo_t) * num);
    1923             :         
    1924             :         typeinfo_init_from_method_args(desc,typebuf,infobuf,num,false,
    1925             :                                        &returntype,info);
    1926             : 
    1927             :         TYPEINFO_ALLOCMERGED(info->merged,num);
    1928             :         info->merged->count = num;
    1929             : 
    1930             :         for (i=0; i<num; ++i) {
    1931             :             if (typebuf[i] != TYPE_ADR) {
    1932             :                 log_text("non-reference type in mergedlist");
    1933             :                                 assert(0);
    1934             :                         }
    1935             : 
    1936             :             info->merged->list[i].any = infobuf[i].typeclass.any;
    1937             :         }
    1938             :         qsort(info->merged->list,num,sizeof(classref_or_classinfo),
    1939             :               (int(*)(const void *,const void *))&typeinfo_test_compare);
    1940             :     }
    1941             :     else {
    1942             :         typeinfo_init_from_method_args(desc,NULL,NULL,0,false,
    1943             :                                        &returntype,info);
    1944             :     }
    1945             : }
    1946             : #endif
    1947             : 
    1948             : #define TYPEINFO_TEST_BUFLEN  4000
    1949             : 
    1950             : static bool
    1951           0 : typeinfo_equal(typeinfo_t *x,typeinfo_t *y)
    1952             : {
    1953             :     int i;
    1954             :     
    1955           0 :     if (x->typeclass.any != y->typeclass.any) return false;
    1956           0 :     if (x->dimension != y->dimension) return false;
    1957           0 :     if (x->dimension) {
    1958           0 :         if (x->elementclass.any != y->elementclass.any) return false;
    1959           0 :         if (x->elementtype != y->elementtype) return false;
    1960             :     }
    1961             : 
    1962           0 :     if (x->is_newobject())
    1963           0 :         if (x->newobject_instruction() != y->newobject_instruction())
    1964           0 :             return false;
    1965             : 
    1966           0 :     if (x->merged || y->merged) {
    1967           0 :         if (!(x->merged && y->merged)) return false;
    1968           0 :         if (x->merged->count != y->merged->count) return false;
    1969           0 :         for (i=0; i<x->merged->count; ++i)
    1970           0 :             if (x->merged->list[i].any != y->merged->list[i].any)
    1971           0 :                 return false;
    1972             :     }
    1973           0 :     return true;
    1974             : }
    1975             : 
    1976             : static void
    1977           0 : typeinfo_testmerge(typeinfo_t *a,typeinfo_t *b,typeinfo_t *result,int *failed)
    1978             : {
    1979             :         typeinfo_t dest;
    1980             : 
    1981           0 :         typeinfo_t::clone(*a,dest);
    1982             : 
    1983           0 :     printf("\n          ");
    1984           0 :     typeinfo_print_short(stdout,&dest);
    1985           0 :     printf("\n          ");
    1986           0 :     typeinfo_print_short(stdout,b);
    1987           0 :     printf("\n");
    1988             : 
    1989           0 :         typecheck_result r = dest.merge(NULL, b);
    1990           0 :         if (r == typecheck_FAIL) {
    1991           0 :                 printf("EXCEPTION\n");
    1992           0 :                 return;
    1993             :         }
    1994             : 
    1995           0 :         bool changed           = (r) ? 1 : 0;
    1996           0 :         bool changed_should_be = (!typeinfo_equal(&dest,a)) ? 1 : 0;
    1997             : 
    1998           0 :     printf("          %s\n",(changed) ? "changed" : "=");
    1999             : 
    2000           0 :     if (typeinfo_equal(&dest,result)) {
    2001           0 :         printf("OK        ");
    2002           0 :         typeinfo_print_short(stdout,&dest);
    2003           0 :         printf("\n");
    2004           0 :         if (changed != changed_should_be) {
    2005           0 :             printf("WRONG RETURN VALUE!\n");
    2006           0 :             (*failed)++;
    2007             :         }
    2008             :     }
    2009             :     else {
    2010           0 :         printf("RESULT    ");
    2011           0 :         typeinfo_print_short(stdout,&dest);
    2012           0 :         printf("\n");
    2013           0 :         printf("SHOULD BE ");
    2014           0 :         typeinfo_print_short(stdout,result);
    2015           0 :         printf("\n");
    2016           0 :         (*failed)++;
    2017             :     }
    2018             : }
    2019             : 
    2020             : #if 0
    2021             : static void
    2022             : typeinfo_inc_dimension(typeinfo_t *info)
    2023             : {
    2024             :     if (info->dimension++ == 0) {
    2025             :         info->elementtype = ARRAYTYPE_OBJECT;
    2026             :         info->elementclass = info->typeclass;
    2027             :     }
    2028             :     info->typeclass = class_array_of(info->typeclass,true);
    2029             : }
    2030             : #endif
    2031             : 
    2032             : #define TYPEINFO_TEST_MAXDIM  10
    2033             : 
    2034             : static void
    2035           0 : typeinfo_testrun(const char *filename)
    2036             : {
    2037             :     char buf[TYPEINFO_TEST_BUFLEN];
    2038             :     char bufa[TYPEINFO_TEST_BUFLEN];
    2039             :     char bufb[TYPEINFO_TEST_BUFLEN];
    2040             :     char bufc[TYPEINFO_TEST_BUFLEN];
    2041             :     typeinfo_t a,b,c;
    2042             :     int maxdim;
    2043           0 :     int failed = 0;
    2044           0 :     FILE *file = fopen(filename,"rt");
    2045             :         int res;
    2046             :     
    2047           0 :     if (!file) {
    2048           0 :         log_text("could not open typeinfo test file");
    2049           0 :                 assert(0);
    2050             :         }
    2051             : 
    2052           0 :     while (fgets(buf,TYPEINFO_TEST_BUFLEN,file)) {
    2053           0 :         if (buf[0] == '#' || !strlen(buf))
    2054           0 :             continue;
    2055             : 
    2056           0 :         res = sscanf(buf,"%s\t%s\t%s\n",bufa,bufb,bufc);
    2057           0 :         if (res != 3 || !strlen(bufa) || !strlen(bufb) || !strlen(bufc)) {
    2058           0 :             log_text("Invalid line in typeinfo test file (none of empty, comment or test)");
    2059           0 :                         assert(0);
    2060             :                 }
    2061             : 
    2062             : #if 0
    2063             :         typeinfo_test_parse(&a,bufa);
    2064             :         typeinfo_test_parse(&b,bufb);
    2065             :         typeinfo_test_parse(&c,bufc);
    2066             : #endif
    2067             : #if 0
    2068             :         do {
    2069             : #endif
    2070           0 :             typeinfo_testmerge(&a,&b,&c,&failed); /* check result */
    2071           0 :             typeinfo_testmerge(&b,&a,&c,&failed); /* check commutativity */
    2072             : 
    2073           0 :             if (a.is_nulltype()) break;
    2074           0 :             if (b.is_nulltype()) break;
    2075           0 :             if (c.is_nulltype()) break;
    2076             : 
    2077           0 :             maxdim = a.dimension;
    2078           0 :             if (b.dimension > maxdim) maxdim = b.dimension;
    2079           0 :             if (c.dimension > maxdim) maxdim = c.dimension;
    2080             : 
    2081             : #if 0
    2082             :             if (maxdim < TYPEINFO_TEST_MAXDIM) {
    2083             :                 typeinfo_inc_dimension(&a);
    2084             :                 typeinfo_inc_dimension(&b);
    2085             :                 typeinfo_inc_dimension(&c);
    2086             :             }
    2087             :         } while (maxdim < TYPEINFO_TEST_MAXDIM);
    2088             : #endif
    2089             :     }
    2090             : 
    2091           0 :     fclose(file);
    2092             : 
    2093           0 :     if (failed) {
    2094           0 :         fprintf(stderr,"Failed typeinfo_merge tests: %d\n",failed);
    2095           0 :         log_text("Failed test");
    2096           0 :                 assert(0);
    2097             :     }
    2098           0 : }
    2099             : 
    2100             : void
    2101           0 : typeinfo_test()
    2102             : {
    2103           0 :     log_text("Running typeinfo test file...");
    2104           0 :     typeinfo_testrun("typeinfo.tst");
    2105           0 :     log_text("Finished typeinfo test file.");
    2106           0 : }
    2107             : 
    2108             : #if 0
    2109             : void
    2110             : typeinfo_init_from_fielddescriptor(typeinfo_t *info,char *desc)
    2111             : {
    2112             :     typeinfo_init_from_descriptor(info,desc,desc+strlen(desc));
    2113             : }
    2114             : #endif
    2115             : 
    2116             : #define TYPEINFO_MAXINDENT  80
    2117             : 
    2118             : void
    2119           0 : typeinfo_print_class(FILE *file,classref_or_classinfo c)
    2120             : {
    2121             :         /*fprintf(file,"<class %p>",c.any);*/
    2122             : 
    2123           0 :         if (!c.any) {
    2124           0 :                 fprintf(file,"<null>");
    2125             :         }
    2126             :         else {
    2127           0 :                 if (c.is_classref()) {
    2128           0 :                         fprintf(file,"<ref>");
    2129           0 :                         utf_fprint_printable_ascii(file,c.ref->name);
    2130             :                 }
    2131             :                 else {
    2132           0 :                         utf_fprint_printable_ascii(file,c.cls->name);
    2133             :                 }
    2134             :         }
    2135           0 : }
    2136             : 
    2137             : void
    2138           0 : typeinfo_print(FILE *file, const typeinfo_t *info, int indent)
    2139             : {
    2140             :         char ind[TYPEINFO_MAXINDENT + 1];
    2141             : 
    2142           0 :         if (indent > TYPEINFO_MAXINDENT)
    2143           0 :                 indent = TYPEINFO_MAXINDENT;
    2144             : 
    2145           0 :         for (int i = 0; i < indent; ++i)
    2146           0 :                 ind[i] = ' ';
    2147           0 :         ind[indent] = (char) 0;
    2148             : 
    2149           0 :         if (info->is_primitive()) {
    2150           0 :                 if (basicblock *bptr = (basicblock*) info->returnaddress())
    2151           0 :                         fprintf(file,"%sreturnAddress (L%03d)\n",ind,bptr->nr);
    2152             :                 else
    2153           0 :                         fprintf(file,"%sprimitive\n",ind);
    2154           0 :                 return;
    2155             :         }
    2156             : 
    2157           0 :     if (info->is_nulltype()) {
    2158           0 :         fprintf(file,"%snull\n",ind);
    2159           0 :         return;
    2160             :     }
    2161             : 
    2162           0 :     if (info->is_newobject()) {
    2163           0 :         if (instruction *ins = info->newobject_instruction()) {
    2164           0 :             fprintf(file,"%sNEW(%p):",ind,(void*)ins);
    2165           0 :                         typeinfo_print_class(file,ins[-1].sx.val.c);
    2166           0 :             fprintf(file,"\n");
    2167             :         }
    2168             :         else {
    2169           0 :             fprintf(file,"%sNEW(this)",ind);
    2170             :         }
    2171           0 :         return;
    2172             :     }
    2173             : 
    2174           0 :     fprintf(file,"%sClass:      ",ind);
    2175           0 :         typeinfo_print_class(file,info->typeclass);
    2176           0 :     fprintf(file,"\n");
    2177             : 
    2178           0 :     if (info->is_array()) {
    2179           0 :         fprintf(file,"%sDimension:    %d",ind,(int)info->dimension);
    2180           0 :         fprintf(file,"\n%sElements:     ",ind);
    2181           0 :         switch (info->elementtype) {
    2182           0 :           case ARRAYTYPE_INT     : fprintf(file,"int\n"); break;
    2183           0 :           case ARRAYTYPE_LONG    : fprintf(file,"long\n"); break;
    2184           0 :           case ARRAYTYPE_FLOAT   : fprintf(file,"float\n"); break;
    2185           0 :           case ARRAYTYPE_DOUBLE  : fprintf(file,"double\n"); break;
    2186           0 :           case ARRAYTYPE_BYTE    : fprintf(file,"byte\n"); break;
    2187           0 :           case ARRAYTYPE_CHAR    : fprintf(file,"char\n"); break;
    2188           0 :           case ARRAYTYPE_SHORT   : fprintf(file,"short\n"); break;
    2189           0 :           case ARRAYTYPE_BOOLEAN : fprintf(file,"boolean\n"); break;
    2190             :               
    2191             :           case ARRAYTYPE_OBJECT:
    2192           0 :                           typeinfo_print_class(file,info->elementclass);
    2193           0 :               fprintf(file,"\n");
    2194           0 :               break;
    2195             :               
    2196             :           default:
    2197           0 :               fprintf(file,"INVALID ARRAYTYPE!\n");
    2198             :         }
    2199             :     }
    2200             : 
    2201           0 :     if (info->merged) {
    2202           0 :         fprintf(file,"%sMerged:     ",ind);
    2203           0 :         for (int i = 0; i < info->merged->count; ++i) {
    2204           0 :             if (i) fprintf(file,", ");
    2205           0 :                         typeinfo_print_class(file,info->merged->list[i]);
    2206             :         }
    2207           0 :         fprintf(file,"\n");
    2208             :     }
    2209             : }
    2210             : 
    2211             : void
    2212           0 : typeinfo_print_short(FILE *file, const typeinfo_t *info)
    2213             : {
    2214             :     int i;
    2215             :     instruction *ins;
    2216             :         basicblock *bptr;
    2217             : 
    2218             :         /*fprintf(file,"<typeinfo %p>",info);*/
    2219             : 
    2220           0 :         if (!info) {
    2221           0 :                 fprintf(file,"(typeinfo*)NULL");
    2222           0 :                 return;
    2223             :         }
    2224             : 
    2225           0 :     if (info->is_primitive()) {
    2226           0 :                 bptr = (basicblock*) info->returnaddress();
    2227           0 :                 if (bptr)
    2228           0 :                         fprintf(file,"ret(L%03d)",bptr->nr);
    2229             :                 else
    2230           0 :                         fprintf(file,"primitive");
    2231           0 :         return;
    2232             :     }
    2233             : 
    2234           0 :     if (info->is_nulltype()) {
    2235           0 :         fprintf(file,"null");
    2236           0 :         return;
    2237             :     }
    2238             : 
    2239           0 :     if (info->is_newobject()) {
    2240           0 :         ins = (instruction *) info->newobject_instruction();
    2241           0 :         if (ins) {
    2242             :                         /*fprintf(file,"<ins %p>",ins);*/
    2243           0 :             fprintf(file,"NEW(%p):",(void*)ins);
    2244           0 :                         typeinfo_print_class(file,ins[-1].sx.val.c);
    2245             :         }
    2246             :         else
    2247           0 :             fprintf(file,"NEW(this)");
    2248           0 :         return;
    2249             :     }
    2250             : 
    2251           0 :     typeinfo_print_class(file,info->typeclass);
    2252             : 
    2253           0 :     if (info->merged) {
    2254           0 :         fprintf(file,"{");
    2255           0 :         for (i=0; i<info->merged->count; ++i) {
    2256           0 :             if (i) fprintf(file,",");
    2257           0 :                         typeinfo_print_class(file,info->merged->list[i]);
    2258             :         }
    2259           0 :         fprintf(file,"}");
    2260             :     }
    2261             : }
    2262             : 
    2263             : void
    2264           0 : typeinfo_print_type(FILE *file, int type, const typeinfo_t *info)
    2265             : {
    2266           0 :     switch (type) {
    2267           0 :       case TYPE_VOID: fprintf(file,"V"); break;
    2268           0 :       case TYPE_INT:  fprintf(file,"I"); break;
    2269           0 :       case TYPE_FLT:  fprintf(file,"F"); break;
    2270           0 :       case TYPE_DBL:  fprintf(file,"D"); break;
    2271           0 :       case TYPE_LNG:  fprintf(file,"J"); break;
    2272           0 :           case TYPE_RET:  fprintf(file,"R:"); /* FALLTHROUGH! */
    2273             :       case TYPE_ADR:
    2274           0 :                   typeinfo_print_short(file,info);
    2275           0 :           break;
    2276             :           
    2277             :       default:
    2278           0 :           fprintf(file,"!");
    2279             :     }
    2280           0 : }
    2281             : 
    2282             : void
    2283           0 : typedescriptor_print(FILE *file, const typedescriptor_t *td)
    2284             : {
    2285           0 :         typeinfo_print_type(file,td->type, &(td->typeinfo));
    2286           0 : }
    2287             : 
    2288             : void
    2289           0 : typevector_print(FILE *file, const varinfo *vec, int size)
    2290             : {
    2291             :     int i;
    2292             : 
    2293           0 :     for (i=0; i<size; ++i) {
    2294           0 :                 fprintf(file," %d=",i);
    2295           0 :         typeinfo_print_type(file, vec[i].type, &(vec[i].typeinfo));
    2296             :     }
    2297           0 : }
    2298             : 
    2299             : #endif /* TYPEINFO_DEBUG */
    2300             : 
    2301             : 
    2302             : /*
    2303             :  * These are local overrides for various environment variables in Emacs.
    2304             :  * Please do not remove this and leave it at the end of the file, where
    2305             :  * Emacs will automagically detect them.
    2306             :  * ---------------------------------------------------------------------
    2307             :  * Local variables:
    2308             :  * mode: c++
    2309             :  * indent-tabs-mode: t
    2310             :  * c-basic-offset: 4
    2311             :  * tab-width: 4
    2312             :  * End:
    2313             :  * vim:noexpandtab:sw=4:ts=4:
    2314             :  */

Generated by: LCOV version 1.11