added the typechecker (not yet complete)
authoredwin <none@none>
Sat, 6 Dec 2003 20:10:05 +0000 (20:10 +0000)
committeredwin <none@none>
Sat, 6 Dec 2003 20:10:05 +0000 (20:10 +0000)
29 files changed:
Makefile.am
builtin.c
builtin.h
global.h
jit/Makefile.am
jit/jit.c
jit/jit.h
jit/parse.c
jit/stack.c
jit/typecheck.c [new file with mode: 0644]
loader.c
loader.h
main.c
src/cacao/cacao.c
src/vm/builtin.c
src/vm/builtin.h
src/vm/global.h
src/vm/jit/Makefile.am
src/vm/jit/jit.c
src/vm/jit/jit.h
src/vm/jit/parse.c
src/vm/jit/stack.c
src/vm/jit/verify/typecheck.c [new file with mode: 0644]
src/vm/jit/verify/typeinfo.c
src/vm/jit/verify/typeinfo.h
src/vm/loader.c
src/vm/loader.h
typeinfo.c
typeinfo.h

index 2d268d5327670928573f4012856128b1042bef82..64dcb8748b5e8b0f1141d493a944f84552fb99ff 100644 (file)
@@ -1,6 +1,6 @@
 ## Process this file with automake to produce Makefile.in
 
-# $Id: Makefile.am 687 2003-12-04 22:29:54Z edwin $
+# $Id: Makefile.am 696 2003-12-06 20:10:05Z edwin $
 
 @SET_MAKE@
 
@@ -44,7 +44,8 @@ cacao_SOURCES = \
        tables.c \
        tables.h \
        unzip.c \
-       typeinfo.c
+       typeinfo.c \
+       typeinfo.h
 
 cacao_LDADD = \
        jit/libjit.a \
index 1610b83ef98cbfecb08dfb2f9ea6b31055d3a3b5..6b84b70b56a0bf703faba5ea06ddd373d6e1eece 100644 (file)
--- a/builtin.c
+++ b/builtin.c
@@ -34,7 +34,7 @@
    calls instead of machine instructions, using the C calling
    convention.
 
-   $Id: builtin.c 689 2003-12-05 18:03:47Z stefan $
+   $Id: builtin.c 696 2003-12-06 20:10:05Z edwin $
 
 */
 
@@ -314,20 +314,20 @@ static s4 builtin_descriptorscompatible(arraydescriptor *desc,arraydescriptor *t
                        
 *****************************************************************************/
 
-s4 builtin_checkarraycast(java_objectheader *o,arraydescriptor *target)
+s4 builtin_checkarraycast(java_objectheader *o,vftbl *target)
 {
        arraydescriptor *desc;
        
        if (!o) return 1;
        if ((desc = o->vftbl->arraydesc) == NULL) return 0;
 
-       return builtin_descriptorscompatible(desc,target);
+       return builtin_descriptorscompatible(desc,target->arraydesc);
 }
 
-s4 builtin_arrayinstanceof(java_objectheader *obj,arraydescriptor *desc)
+s4 builtin_arrayinstanceof(java_objectheader *obj,vftbl *target)
 {
        if (!obj) return 1;
-       return builtin_checkarraycast (obj, desc);
+       return builtin_checkarraycast (obj, target);
 }
 
 /************************** exception functions *******************************
index 98bb11cd92e5b50eeecb17656a6f91a9ba0ce782..68768d35422a8ca412ee4d87b5587532f59b0c02 100644 (file)
--- a/builtin.h
+++ b/builtin.h
@@ -30,12 +30,12 @@ s4 builtin_isanysubclass_vftbl (vftbl *sub, vftbl *super);
 s4 builtin_checkcast(java_objectheader *obj, classinfo *class);
 s4 asm_builtin_checkcast(java_objectheader *obj, classinfo *class);
 
-s4 builtin_arrayinstanceof(java_objectheader *obj, arraydescriptor *desc);
+s4 builtin_arrayinstanceof(java_objectheader *obj, vftbl *target);
 #ifdef __I386__
 s4 asm_builtin_arrayinstanceof(java_objectheader *obj, classinfo *class); /* XXX ? */
 #endif
-s4 builtin_checkarraycast(java_objectheader *obj, arraydescriptor *desc);
-s4 asm_builtin_checkarraycast(java_objectheader *obj, arraydescriptor *desc);
+s4 builtin_checkarraycast(java_objectheader *obj, vftbl *target);
+s4 asm_builtin_checkarraycast(java_objectheader *obj, vftbl *target);
 
 java_objectheader *builtin_throw_exception (java_objectheader *exception);
 java_objectheader *builtin_trace_exception (java_objectheader *exceptionptr,
index 07849fe28924ca3ad5d91872227bf8e661e0e1f9..611feb67da405c978eb14329cd2d7b95e5312a8d 100644 (file)
--- a/global.h
+++ b/global.h
@@ -31,7 +31,7 @@
             Philipp Tomsich
                        Edwin Steiner
 
-   $Id: global.h 687 2003-12-04 22:29:54Z edwin $
+   $Id: global.h 696 2003-12-06 20:10:05Z edwin $
 
 */
 
  */
 #define SIZE_FROM_CLASSINFO
 
+/*
+ * CACAO_TYPECHECK activates typechecking (part of bytecode verification)
+ */
+#define CACAO_TYPECHECK
+
+/*
+ * Macros for configuration of the typechecking code
+ *
+ * TYPEINFO_DEBUG activates debug checks and debug helpers in typeinfo.c
+ * TYPECHECK_DEBUG activates debug checks in typecheck.c
+ * TYPEINFO_DEBUG_TEST activates the typeinfo test at startup.
+ * TYPECHECK_VERBOSE_IMPORTANT activates important debug messages
+ * TYPECHECK_VERBOSE activates all debug messages
+ */
+#define TYPEINFO_DEBUG
+#define TYPECHECK_DEBUG
+/*#define TYPEINFO_DEBUG_TEST*/
+#define TYPECHECK_VERBOSE
+/*#define TYPECHECK_VERBOSE_IMPORTANT*/
+#if defined(TYPECHECK_VERBOSE) || defined(TYPECHECK_VERBOSE_IMPORTANT)
+#define TYPECHECK_VERBOSE_OPT
+#endif
+
 /* standard includes **********************************************************/
 
 #include <stdio.h>
@@ -749,6 +772,9 @@ extern bool verbose;
 extern bool opt_rt;             /* Rapid Type Analysis for better inlining CO-RT*/
 extern bool opt_xta;            /* X Type Analysis for better inlining    CO-XTA*/
 extern bool opt_vta;            /* Variable Type Analysis for better inlining    CO-VTA*/
+#ifdef TYPECHECK_VERBOSE_OPT
+extern bool typecheckverbose;
+#endif
 
 //extern int pClassHeir;
 //extern int pCallgraph;
index fab6134dc060ecf2c0fa7087db815c0933fc2322..7834c9ab118f343d076642b8a094669445540777 100644 (file)
@@ -1,6 +1,6 @@
 ## Process this file with automake to produce Makefile.in
 
-# $Id: Makefile.am 662 2003-11-21 18:06:25Z jowenn $
+# $Id: Makefile.am 696 2003-12-06 20:10:05Z edwin $
 
 
 SUBDIRS = . loop @ARCH_DIR@
@@ -20,7 +20,8 @@ EXTRA_DIST = \
        sets.h \
        parseRT.c \
        parseRTprint.h \
-       parseRTstats.c
+       parseRTstats.c \
+       typecheck.c
 
 noinst_HEADERS = \
        parse.h \
@@ -32,7 +33,7 @@ noinst_HEADERS = \
 
 noinst_LIBRARIES = libjit.a
 
-libjit_a_SOURCES = jit.c parse.c stack.c inline.c sets.c parseRT.c parseRTstats.c
+libjit_a_SOURCES = jit.c parse.c stack.c inline.c sets.c parseRT.c parseRTstats.c typecheck.c
 
 all-local:
        $(MAKE) $(AM_MAKEFLAGS) -C .. jit/@ARCH_DIR@/offsets.h
index aef4d5ae9170e5a95be72a81cfa02aeca6e2485c..efe81aa6a91e687907cc3dec1bb297d49f5840d7 100644 (file)
--- a/jit/jit.c
+++ b/jit/jit.c
@@ -27,7 +27,7 @@
    Authors: Andreas Krall
             Reinhard Grafl
 
-   $Id: jit.c 689 2003-12-05 18:03:47Z stefan $
+   $Id: jit.c 696 2003-12-06 20:10:05Z edwin $
 
 */
 
@@ -195,6 +195,8 @@ bool isleafmethod;              /* true if a method doesn't call subroutines  */
 
 basicblock *last_block;         /* points to the end of the BB list           */
 
+bool regs_ok;                   /* true if registers have been allocated      */
+
 /* list of all classes used by the compiled method which have to be           */
 /* initialised (if not already done) before execution of this method          */
 chain *uninitializedclasses;
@@ -1343,7 +1345,8 @@ methodptr jit_compile(methodinfo *m)
        count_methods++;
 
        intsDisable();      /* disable interrupts */
-       
+
+       regs_ok = false;
 
        /* mark start of dump memory area */
 
@@ -1427,6 +1430,10 @@ methodptr jit_compile(methodinfo *m)
        parse();
        analyse_stack();
    
+#ifdef CACAO_TYPECHECK
+       typecheck();
+#endif
+       
        if (opt_loops) {
                depthFirst();
                analyseGraph();
@@ -1438,6 +1445,7 @@ methodptr jit_compile(methodinfo *m)
 #endif
 
        regalloc();
+       regs_ok = true;
        codegen();
 
        /* intermediate and assembly code listings ********************************/
index 9a4dc6756be6a01c0d1117917cd745c12adde1db..a7fb78dda78e70319192e16d621041d37213665a 100644 (file)
--- a/jit/jit.h
+++ b/jit/jit.h
@@ -29,7 +29,7 @@
 
    Changes: Christian Thalinger
 
-   $Id: jit.h 665 2003-11-21 18:36:43Z jowenn $
+   $Id: jit.h 696 2003-12-06 20:10:05Z edwin $
 
 */
 
@@ -39,6 +39,7 @@
 
 #include "toolbox/chain.h"
 #include "global.h"
+#include "typeinfo.h"
 
 /**************************** resolve typedef-cycles **************************/
 
@@ -59,6 +60,7 @@ typedef varinfo *varinfoptr;
 
 /* slot types */
 
+/* XXX use TYPE_ADDRESS, ...? */
 #define TYPE_INT   0            /* the stack slot types must numbered in the  */
 #define TYPE_LNG   1            /* same order as the ICMD_Ixxx to ICMD_Axxx   */
 #define TYPE_FLT   2            /* instructions (LOAD and STORE)              */
@@ -88,6 +90,9 @@ typedef varinfo *varinfoptr;
 struct stackelement {
        stackptr prev;              /* pointer to next element towards bottom     */
        int type;                   /* slot type of stack element                 */
+#ifdef CACAO_TYPECHECK
+       typeinfo typeinfo;          /* info on reference types                    */
+#endif
        int flags;                  /* flags (SAVED, INMEMORY)                    */
        int varkind;                /* kind of variable or register               */
        int varnum;                 /* number of variable                         */
@@ -124,6 +129,8 @@ struct instruction {
 #define BBUNDEF    -1
 #define BBREACHED  0
 #define BBFINISHED 1
+#define BBTYPECHECK_UNDEF    2
+#define BBTYPECHECK_REACHED  3
 
 #define BBTYPE_STD 0            /* standard basic block type                  */
 #define BBTYPE_EXH 1            /* exception handler basic block type         */
@@ -948,6 +955,9 @@ extern bool isleafmethod;       /* true if a method doesn't call subroutines  */
 
 extern basicblock *last_block;  /* points to the end of the BB list           */
 
+extern bool regs_ok;            /* true if registers have been allocated      */
+
+
 /* list of all classes used by the compiled method which have to be           */
 /* initialised (if not already done) before execution of this method          */
 extern chain *uninitializedclasses;
@@ -968,6 +978,13 @@ u1 *createnativestub(functionptr f, methodinfo *m);
 void removecompilerstub(u1 *stub);
 void removenativestub(u1 *stub);
 
+/* debug helpers (in stack.c) */
+
+void icmd_print_stack(stackptr s);
+void show_icmd_block(basicblock *bptr);
+void show_icmd(instruction *iptr,bool deadcode);
+void show_icmd_method();
+
 #endif /* _JIT_H */
 
 
index e5866614c805d51a89c6fd34f424fcd189eed9c1..3e299b1a4850ede1e0eff81aeb73c598e02235c6 100644 (file)
@@ -27,8 +27,9 @@
    Author: Andreas Krall
 
    Changes: Carolyn Oates
+            Edwin Steiner
 
-   $Id: parse.c 689 2003-12-05 18:03:47Z stefan $
+   $Id: parse.c 696 2003-12-06 20:10:05Z edwin $
 
 */
 
@@ -1240,7 +1241,7 @@ void parse()
                                        classinfo *cls = (classinfo*)class_getconstant(class, i, CONSTANT_Class);
                                        if (cls->vftbl->arraydesc) {
                                                /* array type cast-check */
-                                               LOADCONST_A(cls->vftbl->arraydesc);
+                                               LOADCONST_A(cls->vftbl);
                                                s_count++;
                                                BUILTIN2((functionptr) asm_builtin_checkarraycast, TYPE_ADR);
                                        }
@@ -1263,7 +1264,7 @@ void parse()
                                        classinfo *cls = (classinfo*)class_getconstant(class, i, CONSTANT_Class);
                                        if (cls->vftbl->arraydesc) {
                                                /* array type cast-check */
-                                               LOADCONST_A(cls->vftbl->arraydesc);
+                                               LOADCONST_A(cls->vftbl);
                                                s_count++;
   #if defined(__I386__)
                                                BUILTIN2((functionptr) asm_builtin_arrayinstanceof, TYPE_INT);
index 676f3d7f79581ac3db336571ed9bf88c28207f2c..4799a064a60dab5dbd623e5b6689848f75d408f6 100644 (file)
@@ -26,7 +26,9 @@
 
    Authors: Andreas Krall
 
-   $Id: stack.c 665 2003-11-21 18:36:43Z jowenn $
+   Changes: Edwin Steiner
+
+   $Id: stack.c 696 2003-12-06 20:10:05Z edwin $
 
 */
 
@@ -1478,6 +1480,12 @@ void analyse_stack()
 
                                                iptr[0].target = (void *) tbptr;
 
+                                               /* XXX This is a dirty hack. The typechecker
+                                                * needs it because the OP1_0ANY below
+                                                * overwrites iptr->dst.
+                                                */
+                                               iptr->val.a = (void*) iptr->dst;
+
                                                tbptr->type=BBTYPE_SBR;
                                                MARKREACHED(tbptr, copy);
                                                OP1_0ANY;
@@ -1734,7 +1742,7 @@ void analyse_stack()
 }
 
 
-static void print_stack(stackptr s)
+void icmd_print_stack(stackptr s)
 {
        int i, j;
        stackptr t;
@@ -1751,15 +1759,17 @@ static void print_stack(stackptr s)
                printf("    ");
        while (s) {
                j--;
+               /* XXX remove */ /* printf("(%d)",s->flags); fflush(stdout); */
                if (s->flags & SAVEDVAR)
                        switch (s->varkind) {
                        case TEMPVAR:
                                if (s->flags & INMEMORY)
-                                       printf(" M%02d", s->regoff);
+                                       printf((regs_ok) ? " M%02d" : " M??", s->regoff);
                                else if ((s->type == TYPE_FLT) || (s->type == TYPE_DBL))
-                                       printf(" F%02d", s->regoff);
-                               else
-                                       printf(" %3s", regs[s->regoff]);
+                                       printf((regs_ok) ? " F%02d" : " F??", s->regoff);
+                               else {
+                                       if (regs_ok) printf(" %3s",regs[s->regoff]); else printf(" ???");
+                               }
                                break;
                        case STACKVAR:
                                printf(" I%02d", s->varnum);
@@ -1777,11 +1787,12 @@ static void print_stack(stackptr s)
                        switch (s->varkind) {
                        case TEMPVAR:
                                if (s->flags & INMEMORY)
-                                       printf(" m%02d", s->regoff);
+                                       printf((regs_ok) ? " m%02d" : " m??", s->regoff);
                                else if ((s->type == TYPE_FLT) || (s->type == TYPE_DBL))
-                                       printf(" f%02d", s->regoff);
-                               else
-                                       printf(" %3s", regs[s->regoff]);
+                                       printf((regs_ok) ? " f%02d" : " f??", s->regoff);
+                               else {
+                                       if (regs_ok) printf(" %3s",regs[s->regoff]); else printf(" ???");
+                               }
                                break;
                        case STACKVAR:
                                printf(" i%02d", s->varnum);
@@ -1851,7 +1862,7 @@ static void print_reg(stackptr s) {
 #endif
 
 
-static char *builtin_name(functionptr bptr)
+char *icmd_builtin_name(functionptr bptr)
 {
        builtin_descriptor *bdesc = builtin_desc;
        while ((bdesc->bptr != NULL) && (bdesc->bptr != bptr))
@@ -1902,11 +1913,12 @@ void show_icmd_method()
                        if (locals[i][j].type >= 0) {
                                printf("   (%s) ", jit_type[j]);
                                if (locals[i][j].flags & INMEMORY)
-                                       printf("m%2d", locals[i][j].regoff);
+                                       printf((regs_ok) ? "m%2d" : "m??", locals[i][j].regoff);
                                else if ((j == TYPE_FLT) || (j == TYPE_DBL))
-                                       printf("f%02d", locals[i][j].regoff);
-                               else
-                                       printf("%3s", regs[locals[i][j].regoff]);
+                                       printf((regs_ok) ? "f%02d" : "f??", locals[i][j].regoff);
+                               else {
+                                       if (regs_ok) printf("%3s",regs[locals[i][j].regoff]); else printf("???");
+                               }
                        }
                printf("\n");
        }
@@ -1923,19 +1935,21 @@ void show_icmd_method()
                                        printf("   (%s) ", jit_type[j]);
                                        if (interfaces[i][j].flags & SAVEDVAR) {
                                                if (interfaces[i][j].flags & INMEMORY)
-                                                       printf("M%2d", interfaces[i][j].regoff);
+                                                       printf((regs_ok) ? "M%2d" : "M??", interfaces[i][j].regoff);
                                                else if ((j == TYPE_FLT) || (j == TYPE_DBL))
-                                                       printf("F%02d", interfaces[i][j].regoff);
-                                               else
-                                                       printf("%3s", regs[interfaces[i][j].regoff]);
+                                                       printf((regs_ok) ? "F%02d" : "F??", interfaces[i][j].regoff);
+                                               else {
+                                                       if (regs_ok) printf("%3s",regs[interfaces[i][j].regoff]); else printf("???");
+                                               }
                                        }
                                        else {
                                                if (interfaces[i][j].flags & INMEMORY)
-                                                       printf("m%2d", interfaces[i][j].regoff);
+                                                       printf((regs_ok) ? "m%2d" : "m??", interfaces[i][j].regoff);
                                                else if ((j == TYPE_FLT) || (j == TYPE_DBL))
-                                                       printf("f%02d", interfaces[i][j].regoff);
-                                               else
-                                                       printf("%3s", regs[interfaces[i][j].regoff]);
+                                                       printf((regs_ok) ? "f%02d" : "f??", interfaces[i][j].regoff);
+                                               else {
+                                                       if (regs_ok) printf("%3s",regs[interfaces[i][j].regoff]); else printf("???");
+                                               }
                                        }
                                }
                        printf("\n");
@@ -1966,27 +1980,99 @@ void show_icmd_method()
 
        
        for (bptr = block; bptr != NULL; bptr = bptr->next) {
+               show_icmd_block(bptr);
+       }
+}
+
+void
+show_icmd_block(basicblock *bptr)
+{
+       int i, j;
+       int deadcode;
+       s4  *s4ptr;
+       instruction *iptr;
+
                if (bptr->flags != BBDELETED) {
                        deadcode = bptr->flags <= BBREACHED;
                        printf("[");
                        if (deadcode)
-                               for (j = maxstack; j > 0; j--)
+                               for (j = method->maxstack; j > 0; j--)
                                        printf(" ?  ");
                        else
-                               print_stack(bptr->instack);
-                       printf("] L%03d(%d - %d):\n", bptr->debug_nr, bptr->icount, bptr->pre_count);
+                               icmd_print_stack(bptr->instack);
+                       printf("] L%03d(%d - %d) flags=%d:\n", bptr->debug_nr, bptr->icount, bptr->pre_count,bptr->flags);
                        iptr = bptr->iinstr;
 
                        for (i=0; i < bptr->icount; i++, iptr++) {
                                printf("[");
                                if (deadcode) {
-                                       for (j = maxstack; j > 0; j--)
+                                       for (j = method->maxstack; j > 0; j--)
                                                printf(" ?  ");
                                }
                                else
-                                       print_stack(iptr->dst);
-                               printf("]     %4d  %s", i, icmd_names[iptr->opc]);
-                               switch ((int) iptr->opc) {
+                                       icmd_print_stack(iptr->dst);
+                               printf("]     %4d  ", i);
+                               /* XXX remove */ /*fflush(stdout);*/
+                               show_icmd(iptr,deadcode);
+                               printf("\n");
+                       }
+
+                       if (showdisassemble && (!deadcode)) {
+#if defined(__I386__) || defined(__X86_64__)
+                               u1 *u1ptr;
+                               int a;
+
+                               printf("\n");
+                               i = bptr->mpc;
+                               u1ptr = method->mcode + dseglen + i;
+
+                               if (bptr->next != NULL) {
+                                       for (; i < bptr->next->mpc; i++, u1ptr++) {
+                                               a = disassinstr(u1ptr, i);
+                                               i += a;
+                                               u1ptr += a;
+                                       }
+                                       printf("\n");
+
+                               } else {
+                                       for (; u1ptr < (u1 *) (method->mcode + method->mcodelength); i++, u1ptr++) {
+                                               a = disassinstr(u1ptr, i); 
+                                               i += a;
+                                               u1ptr += a;
+                                       }
+                                       printf("\n");
+                               }
+#else
+                               printf("\n");
+                               i = bptr->mpc;
+                               s4ptr = (s4 *) (method->mcode + dseglen + i);
+
+                               if (bptr->next != NULL) {
+                                       for (; i < bptr->next->mpc; i += 4, s4ptr++) {
+                                               disassinstr(*s4ptr, i); 
+                                   }
+                                       printf("\n");
+                           }
+                               else {
+                                       for (; s4ptr < (s4 *) (method->mcode + method->mcodelength); i += 4, s4ptr++) {
+                                               disassinstr(*s4ptr, i); 
+                                   }
+                                       printf("\n");
+                           }
+#endif
+                   }
+               }
+}
+
+void
+show_icmd(instruction *iptr,bool deadcode)
+{
+       int j;
+       s4  *s4ptr;
+       void **tptr;
+       
+       printf("%s",icmd_names[iptr->opc]);
+       switch ((int) iptr->opc) {
                                case ICMD_IADDCONST:
                                case ICMD_ISUBCONST:
                                case ICMD_IMULCONST:
@@ -2137,7 +2223,7 @@ void show_icmd_method()
                                case ICMD_BUILTIN3:
                                case ICMD_BUILTIN2:
                                case ICMD_BUILTIN1:
-                                       printf(" %s", builtin_name((functionptr) iptr->val.a));
+                                       printf(" %s", icmd_builtin_name((functionptr) iptr->val.a));
                                        break;
                                case ICMD_INVOKEVIRTUAL:
                                case ICMD_INVOKESPECIAL:
@@ -2156,7 +2242,10 @@ void show_icmd_method()
                                case ICMD_IFGE:
                                case ICMD_IFGT:
                                case ICMD_IFLE:
-                                       printf("(%d) L%03d", iptr->val.i, ((basicblock *) iptr->target)->debug_nr);
+                                       if (deadcode)
+                                               printf("(%d) op1=%d", iptr->val.i, iptr->op1);
+                                       else
+                                               printf("(%d) L%03d", iptr->val.i, ((basicblock *) iptr->target)->debug_nr);
                                        break;
                                case ICMD_IF_LEQ:
                                case ICMD_IF_LNE:
@@ -2164,7 +2253,10 @@ void show_icmd_method()
                                case ICMD_IF_LGE:
                                case ICMD_IF_LGT:
                                case ICMD_IF_LLE:
-                                       printf("(%lld) L%03d", iptr->val.l, ((basicblock *) iptr->target)->debug_nr);
+                                       if (deadcode)
+                                               printf("(%lld) op1=%d", iptr->val.l, iptr->op1);
+                                       else
+                                               printf("(%lld) L%03d", iptr->val.l, ((basicblock *) iptr->target)->debug_nr);
                                        break;
                                case ICMD_JSR:
                                case ICMD_GOTO:
@@ -2184,94 +2276,65 @@ void show_icmd_method()
                                case ICMD_IF_LCMPLE:
                                case ICMD_IF_ACMPEQ:
                                case ICMD_IF_ACMPNE:
-                                       printf(" L%03d", ((basicblock *) iptr->target)->debug_nr);
+                                       if (deadcode)
+                                               printf(" op1=%d", iptr->op1);
+                                       else
+                                               printf(" L%03d", ((basicblock *) iptr->target)->debug_nr);
                                        break;
                                case ICMD_TABLESWITCH:
 
                                        s4ptr = iptr->val.a;
-                                       tptr = (void **) iptr->target;
-
-                                       printf(" L%03d;", ((basicblock *) *tptr)->debug_nr); 
-                                       /* default */
 
-                                       s4ptr++;
-                                       tptr++;
+                                       if (deadcode) {
+                                               printf(" %d;", *s4ptr);
+                                       }
+                                       else {
+                                               tptr = (void **) iptr->target;
+                                               printf(" L%03d;", ((basicblock *) *tptr)->debug_nr); 
+                                               tptr++;
+                                       }
 
+                                       s4ptr++;         /* skip default */
                                        j = *s4ptr++;                               /* low     */
                                        j = *s4ptr++ - j;                           /* high    */
                                        while (j >= 0) {
-                                               printf(" L%03d", ((basicblock *) *tptr)->debug_nr);
-                                               tptr++;
+                                               if (deadcode)
+                                                       printf(" %d", *s4ptr++);
+                                               else {
+                                                       printf(" L%03d", ((basicblock *) *tptr)->debug_nr);
+                                                       tptr++;
+                                               }
                                                j--;
                                        }
                                        break;
                                case ICMD_LOOKUPSWITCH:
                                        s4ptr = iptr->val.a;
-                                       tptr = (void **) iptr->target;
-
-                                       printf(" L%03d", ((basicblock *) *tptr)->debug_nr); 
-                                       s4ptr++;                                         /* default */
-                                       j = *s4ptr;                                      /* count   */
-                                       tptr++;
 
-                                       while (--j >= 0) {
+                                       if (deadcode) {
+                                               printf(" %d;", *s4ptr);
+                                       }
+                                       else {
+                                               tptr = (void **) iptr->target;
                                                printf(" L%03d", ((basicblock *) *tptr)->debug_nr);
                                                tptr++;
                                        }
-                                       break;
-                               }
-                               printf("\n");
-                       }
-
-                       if (showdisassemble && (!deadcode)) {
-#if defined(__I386__) || defined(__X86_64__)
-                               u1 *u1ptr;
-                               int a;
-
-                               printf("\n");
-                               i = bptr->mpc;
-                               u1ptr = method->mcode + dseglen + i;
-
-                               if (bptr->next != NULL) {
-                                       for (; i < bptr->next->mpc; i++, u1ptr++) {
-                                               a = disassinstr(u1ptr, i);
-                                               i += a;
-                                               u1ptr += a;
-                                       }
-                                       printf("\n");
+                                       s4ptr++;                                         /* default */
+                                       j = *s4ptr++;                                    /* count   */
 
-                               } else {
-                                       for (; u1ptr < (u1 *) (method->mcode + method->mcodelength); i++, u1ptr++) {
-                                               a = disassinstr(u1ptr, i); 
-                                               i += a;
-                                               u1ptr += a;
+                                       while (--j >= 0) {
+                                               if (deadcode) {
+                                                       s4ptr++; /* skip value */
+                                                       printf(" %d",*s4ptr++);
+                                               }
+                                               else {
+                                                       printf(" L%03d", ((basicblock *) *tptr)->debug_nr);
+                                                       tptr++;
+                                               }
                                        }
-                                       printf("\n");
-                               }
-#else
-                               printf("\n");
-                               i = bptr->mpc;
-                               s4ptr = (s4 *) (method->mcode + dseglen + i);
-
-                               if (bptr->next != NULL) {
-                                       for (; i < bptr->next->mpc; i += 4, s4ptr++) {
-                                               disassinstr(*s4ptr, i); 
-                                   }
-                                       printf("\n");
-                           }
-                               else {
-                                       for (; s4ptr < (s4 *) (method->mcode + method->mcodelength); i += 4, s4ptr++) {
-                                               disassinstr(*s4ptr, i); 
-                                   }
-                                       printf("\n");
-                           }
-#endif
-                   }
-               }
+                                       break;
        }
 }
 
-
 /*
  * These are local overrides for various environment variables in Emacs.
  * Please do not remove this and leave it at the end of the file, where
diff --git a/jit/typecheck.c b/jit/typecheck.c
new file mode 100644 (file)
index 0000000..44ffacf
--- /dev/null
@@ -0,0 +1,1476 @@
+/* jit/typecheck.c - typechecking (part of bytecode verification)
+
+   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
+   R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser,
+   M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck,
+   P. Tomsich, J. Wenninger
+
+   This file is part of CACAO.
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2, or (at
+   your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+   02111-1307, USA.
+
+   Contact: cacao@complang.tuwien.ac.at
+
+   Authors: Edwin Steiner
+
+   $Id: typecheck.c 696 2003-12-06 20:10:05Z edwin $
+
+*/
+
+#include "global.h" /* must be here because of CACAO_TYPECHECK */
+
+#ifdef CACAO_TYPECHECK
+
+#include "jit.h"
+#include "builtin.h"
+#include "tables.h"
+#include "loader.h"
+#include "types.h"
+#include "toolbox/loging.h"
+#include "toolbox/memory.h"
+
+#define TOUCHED_YES    0x01
+#define TOUCHED_NO     0x02
+#define TOUCHED_MAYBE  (TOUCHED_YES | TOUCHED_NO)
+
+#define REACH_STD      0
+#define REACH_JSR      1
+#define REACH_RET      2
+
+/****************************************************************************/
+/* DEBUG HELPERS                                                            */
+/****************************************************************************/
+
+#ifdef TYPECHECK_VERBOSE_OPT
+bool typecheckverbose = false;
+#define DOLOG(action)  do { if (typecheckverbose) {action;} } while(0)
+#else
+#define DOLOG(action)
+#endif
+
+#ifdef TYPECHECK_VERBOSE
+#define TYPECHECK_VERBOSE_IMPORTANT
+#define LOG(str)           DOLOG(log_text(str))
+#define LOG1(str,a)        DOLOG(dolog(str,a))
+#define LOG2(str,a,b)      DOLOG(dolog(str,a,b))
+#define LOG3(str,a,b,c)    DOLOG(dolog(str,a,b,c))
+#define LOGIF(cond,str)    DOLOG(do {if (cond) log_text(str);} while(0))
+#define LOGINFO(info)      DOLOG(do {typeinfo_print_short(stdout,info);printf("\n");} while(0))
+#define LOGFLUSH           DOLOG(fflush(stdout))
+#define LOGNL              DOLOG(printf("\n"))
+#define LOGSTR(str)        DOLOG(printf(str))
+#define LOGSTR1(str,a)     DOLOG(printf(str,a))
+#define LOGSTR2(str,a,b)   DOLOG(printf(str,a,b))
+#define LOGSTR3(str,a,b,c) DOLOG(printf(str,a,b,c))
+#define LOGSTRu(utf)       DOLOG(utf_display(utf))
+#else
+#define LOG(str)
+#define LOG1(str,a)
+#define LOG2(str,a,b)
+#define LOG3(str,a,b,c)
+#define LOGIF(cond,str)
+#define LOGINFO(info)
+#define LOGFLUSH
+#define LOGNL
+#define LOGSTR(str)
+#define LOGSTR1(str,a)
+#define LOGSTR2(str,a,b)
+#define LOGSTR3(str,a,b,c)
+#endif
+
+#ifdef TYPECHECK_VERBOSE_IMPORTANT
+#define LOGimp(str)     DOLOG(log_text(str))
+#define LOGimpSTR(str)  DOLOG(printf(str))
+#define LOGimpSTRu(utf) DOLOG(utf_display(utf))
+#else
+#define LOGimp(str)
+#define LOGimpSTR(str)
+#define LOGimpSTRu(utf)
+#endif
+
+#if defined(TYPECHECK_VERBOSE) || defined(TYPECHECK_VERBOSE_IMPORTANT)
+
+static
+void
+typeinfo_print_locals(FILE *file,u1 *vtype,typeinfo *vinfo,u1 *touched,int num)
+{
+    int i;
+
+    for (i=0; i<num; ++i) {
+        if (touched)
+            fprintf(file," %d%s=",i,
+                    (touched[i]==TOUCHED_YES) ? "*"
+                    : ((touched[i]==TOUCHED_NO) ? "" : "~"));
+        else
+            fprintf(file," %d=",i);
+        typeinfo_print_type(file,vtype[i],vinfo+i);
+    }
+}
+
+static
+void
+typeinfo_print_stack(FILE *file,stackptr stack)
+{
+    while (stack) {
+        typeinfo_print_type(file,stack->type,&stack->typeinfo);
+        stack = stack->prev;
+        if (stack) fprintf(file," ");
+    }
+}
+
+static
+void
+typeinfo_print_block(FILE *file,stackptr instack,
+                     u1 *vtype,typeinfo *vinfo,u1 *touched)
+{
+    fprintf(file,"Stack: ");
+    typeinfo_print_stack(file,instack);
+    fprintf(file," Locals:");
+    typeinfo_print_locals(file,vtype,vinfo,touched,maxlocals);
+}
+
+
+static
+void
+typeinfo_print_blocks(FILE *file,u1 *vtype,typeinfo *vinfo)
+{
+    int bi;
+    /*    int j;*/
+
+    for (bi=0; bi<block_count; ++bi) {
+        fprintf(file,"%04d: (%3d) ",bi,block[bi].flags);
+        typeinfo_print_block(file,block[bi].instack,
+                             vtype+maxlocals*bi,vinfo+maxlocals*bi,NULL);
+        fprintf(file,"\n");
+
+/*         for (j=0; j<block[bi].icount; ++j) { */
+/*             fprintf(file,"\t%s\n",icmd_names[block[bi].iinstr[j].opc]); */
+/*         } */
+
+        show_icmd_block(block+bi);
+    }
+}
+
+#endif
+
+/****************************************************************************/
+/* INTERNAL DATA STRUCTURES                                                 */
+/****************************************************************************/
+
+typedef struct jsr_record jsr_record;
+
+/*
+ * For each basic block we store the chain of JSR instructions which
+ * were used to reach the block (usually zero or one). For more
+ * details on verifying JSR and RET instructions see the Java VM
+ * Specification.
+ *
+ * CAUTION: The fields starting with sbr_ are only valid for the
+ * jsr_record of the first block of the subroutine.
+ */
+struct jsr_record {
+    basicblock *target;      /* target of the JSR instruction (first block of subroutine) */
+    jsr_record *next;        /* for chaining in nested try ... finally */ /* XXX make it sbr_next? */
+    u1         *sbr_touched; /* specifies which variables the subroutine touches */
+    u1         *sbr_vtype;   /* Types of local variables after RET */
+    typeinfo   *sbr_vinfo;   /* Types of local variables after RET */
+    u1          touched[1];  /* touched flags for local variables */
+};
+
+/****************************************************************************/
+/* MACROS USED INTERNALLY IN typecheck()                                    */
+/****************************************************************************/
+
+#define TOUCH_VARIABLE(num) do {if (jsrchain) touched[num] = TOUCHED_YES;} while (0)
+#define TOUCH_TWOWORD(num)  do {TOUCH_VARIABLE(num);TOUCH_VARIABLE((num)+1);} while (0)
+
+/* XXX should check num in range? */
+/* XXX invalidate two word variables on store in second half! */
+#define STORE_TYPE(num,type)       do {vtype[(num)] = (type); TOUCH_VARIABLE(num);} while(0)
+#define STORE_INVALID(num)         STORE_TYPE((num),TYPE_VOID)
+#define STORE_PRIMITIVE(num,type)  STORE_TYPE((num),(type))
+#define STORE_TWOWORD(num,type)    {STORE_PRIMITIVE((num),(type));STORE_INVALID((num)+1);}
+
+#define CHECKVARTYPE(num,type)  \
+            {if (vtype[(num)] != (type)) panic("Variable type mismatch"); TOUCH_VARIABLE(num);}
+
+/* XXX maybe it's faster to copy always */
+#define COPYTYPE(source,dest)   \
+            {if ((source)->type == TYPE_ADR) \
+                 TYPEINFO_COPY((source)->typeinfo,(dest)->typeinfo);}
+
+#define ISBUILTIN(v)   (iptr->val.a == (functionptr)(v))
+
+/* TYPECHECK_COPYVARS: copy the types and typeinfos of the current local
+ *     variables to the local variables of the target block.
+ * Input:
+ *     vtype......current local variable types
+ *     vinfo......current local variable typeinfos
+ *     ttype......local variable types of target block
+ *     tinfo......local variable typeinfos of target block
+ *     maxlocals..number of local variables
+ * Used:
+ *     macro_i
+ */
+#define TYPECHECK_COPYVARS                                      \
+    LOG("TYPECHECK_COPYVARS");                                  \
+    for (macro_i=0; macro_i<maxlocals; ++macro_i) {             \
+        if ((ttype[macro_i] = vtype[macro_i]) == TYPE_ADR)      \
+            TYPEINFO_CLONE(vinfo[macro_i],tinfo[macro_i]);      \
+    }
+
+/* TYPECHECK_MERGEVARS: merge the local variables of the target block
+ *     with the current local variables.
+ * Input:
+ *     vtype......current local variable types
+ *     vinfo......current local variable typeinfos
+ *     ttype......local variable types of target block
+ *     tinfo......local variable typeinfos of target block
+ *     maxlocals..number of local variables
+ * Ouput:
+ *     changed....set to true if any typeinfo has changed
+ * Used:
+ *     macro_i
+ */
+#define TYPECHECK_MERGEVARS                                             \
+    LOG("TYPECHECK_MERGEVARS");                                         \
+    for (macro_i=0; macro_i<maxlocals; ++macro_i) {                     \
+        if ((ttype[macro_i] != TYPE_VOID) && (vtype[macro_i] != ttype[macro_i])) { \
+            LOG3("var %d: type %d + type %d = void",macro_i,ttype[macro_i],vtype[macro_i]); \
+            ttype[macro_i] = TYPE_VOID;                                 \
+            changed = true;                                             \
+        } else if (ttype[macro_i] == TYPE_ADR) {                        \
+            if ( ((TYPEINFO_IS_PRIMITIVE(tinfo[macro_i])) ? 1 : 0)      \
+                 ^                                                      \
+                 ((TYPEINFO_IS_PRIMITIVE(vinfo[macro_i])) ? 1 : 0)) {   \
+                LOG1("var %d: primitive + reference merge",macro_i);    \
+                ttype[macro_i] = TYPE_VOID;                             \
+                changed = true;                                         \
+            }                                                           \
+            else {                                                      \
+                LOG1("var %d:",macro_i);                                \
+                LOGINFO(tinfo+macro_i);                                 \
+                LOGINFO(vinfo+macro_i);                                 \
+                changed |= typeinfo_merge(tinfo+macro_i,vinfo+macro_i); \
+                LOGINFO(tinfo+macro_i);                                 \
+                LOGIF(changed,"vars have changed");                     \
+            }                                                           \
+        };                                                              \
+    }
+
+/* TYPECHECK_MERGEJSR:
+ *
+ * Input:
+ * Ouput:
+ *     tbptr......target block
+ *     changed....set to true if any typeinfo has changed
+ *     maxlocals..number of local variables
+ *     touched....current touched flags of local variables
+ * Used:
+ *     macro_i, jsrtemp, jsrtemp2
+ */
+#define TYPECHECK_MERGEJSR                                              \
+    do {                                                                \
+        LOG("TYPECHECK_MERGEJSR");                                      \
+    jsrtemp = jsrbuffer[tbptr-block];                                   \
+    jsrtemp2 = jsrchain;                                                \
+    while (jsrtemp || jsrtemp2) {                                       \
+        if (!jsrtemp || !jsrtemp2)                                      \
+            panic("Merging JSR subroutines of different depth");        \
+        if (jsrtemp->target != jsrtemp2->target)                        \
+            panic("Merging different JSR subroutines");                 \
+        jsrtemp = jsrtemp->next;                                        \
+        jsrtemp2 = jsrtemp2->next;                                      \
+    }                                                                   \
+    jsrtemp = jsrbuffer[tbptr-block];                                   \
+    if (jsrtemp)                                                        \
+        for (macro_i=0; macro_i<maxlocals; ++macro_i) {                 \
+            jsrtemp->touched[i] |= touched[i];                          \
+    } } while (0)
+
+/* TYPECHECK_COPYSTACK: copy the typeinfos of the current stack to
+ *     the input stack of the target block.
+ * Input:
+ *     srcstack...current stack
+ *     dststack...input stack of target block
+ */
+#define TYPECHECK_COPYSTACK                                             \
+    LOG("TYPECHECK_COPYSTACK");                                         \
+    while (srcstack) {                                                  \
+        LOG1("copy %d",srcstack->type);                                 \
+        if (!dststack) panic("Stack depth mismatch");                   \
+        if (srcstack->type != dststack->type)                           \
+            panic("Type mismatch on stack");                            \
+        if (srcstack->type == TYPE_ADR) {                               \
+            TYPEINFO_CLONE(srcstack->typeinfo,dststack->typeinfo);      \
+        }                                                               \
+        dststack = dststack->prev;                                      \
+        srcstack = srcstack->prev;                                      \
+    }                                                                   \
+    if (dststack) panic("Stack depth mismatch");
+
+/* TYPECHECK_MERGESTACK: merge the input stack of the target block
+ *     with the current stack.
+ * Input:
+ *     srcstack...current stack
+ *     dststack...input stack of target block
+ * Ouput:
+ *     changed....set to true if any typeinfo has changed
+ */
+#define TYPECHECK_MERGESTACK                                            \
+    LOG("TYPECHECK_MERGESTACK");                                        \
+    while (srcstack) {                                                  \
+        if (!dststack) panic("Stack depth mismatch");                   \
+        if (srcstack->type != dststack->type)                           \
+            panic("Type mismatch on stack");                            \
+        if (srcstack->type == TYPE_ADR) {                               \
+            LOGINFO(&dststack->typeinfo);                               \
+            LOGINFO(&srcstack->typeinfo);  LOGFLUSH;                    \
+            changed |= typeinfo_merge(&dststack->typeinfo,              \
+                                      &srcstack->typeinfo);             \
+            LOGINFO(&dststack->typeinfo);                               \
+            LOG((changed)?"CHANGED!\n":"not changed.\n");               \
+        }                                                               \
+        dststack = dststack->prev;                                      \
+        srcstack = srcstack->prev;                                      \
+    }                                                                   \
+    if (dststack) panic("Stack depth mismatch");
+
+
+/* TYPECHECK_CHECK_JSR_CHAIN: checks if the target block is reached by
+ *     the same JSR targets on all control paths.
+ *
+ * Input:
+ *     tbptr......target block
+ *     jsrchain...current JSR target chain
+ *     jsrbuffer..JSR target chain for each basic block
+ * Output:
+ *     panic if the JSR target chains don't match
+ * Used:
+ *     jsrtemp, jsrtemp2
+ */
+#define TYPECHECK_CHECK_JSR_CHAIN                                       \
+    do {                                                                \
+    jsrtemp = jsrbuffer[tbptr-block];                                   \
+    if (!jsrtemp) panic("non-subroutine called by JSR");                \
+    if (jsrtemp->target != tbptr)                                       \
+        panic("Merging different JSR subroutines");                     \
+    jsrtemp = jsrtemp->next;                                            \
+    jsrtemp2 = jsrchain;                                                \
+    while (jsrtemp || jsrtemp2) {                                       \
+        if (!jsrtemp || !jsrtemp2)                                      \
+            panic("Merging JSR subroutines of different depth");        \
+        if (jsrtemp->target != jsrtemp2->target)                        \
+            panic("Merging different JSR subroutines");                 \
+        jsrtemp = jsrtemp->next;                                        \
+        jsrtemp2 = jsrtemp2->next;                                      \
+    } } while (0)
+
+/* TYPECHECK_ADD_JSR: add a JSR target to the current JSR target chain
+ *     and store the resulting chain in the target block.
+ *
+ * Input:
+ *     jsrchain...current JSR target chain
+ *     tbptr.....the basic block targeted by the JSR
+ *     maxlocals..number of local variables
+ *     jsrbuffer..JSR target chain for each basic block
+ * Used:
+ *     jsrtemp
+ */
+#define TYPECHECK_ADD_JSR                                               \
+    do {                                                                \
+        LOG1("adding JSR to block %04d",(tbptr)-block);                 \
+    jsrtemp = (jsr_record *) dump_alloc(sizeof(jsr_record)+(maxlocals-1)*sizeof(u1)); \
+    jsrtemp->target = (tbptr);                                          \
+    jsrtemp->next = jsrchain;                                           \
+    jsrtemp->sbr_touched = NULL;                                        \
+    memset(&jsrtemp->touched,TOUCHED_NO,sizeof(u1)*maxlocals);          \
+    jsrbuffer[tbptr-block] = jsrtemp;                                   \
+    } while (0)
+
+/* TYPECHECK_COPYJSR: copy the current JSR chain to the target block.
+ *
+ * Input:
+ *     chain......current JSR target chain
+ *     tbptr.....the basic block targeted by the JSR
+ *     maxlocals..number of local variables
+ *     jsrbuffer..JSR target chain for each basic block
+ *     touched....current touched flags of local variables
+ * Used:
+ *     jsrtemp
+ */
+#define TYPECHECK_COPYJSR(chain)                                        \
+    do {                                                                \
+        LOG("TYPECHECK_COPYJSR");                                       \
+        if (chain) {                                                    \
+            jsrtemp = (jsr_record *) dump_alloc(sizeof(jsr_record)+(maxlocals-1)*sizeof(u1)); \
+            jsrtemp->target = (chain)->target;                          \
+            jsrtemp->next = (chain)->next;                              \
+            jsrtemp->sbr_touched = NULL;                                \
+            memcpy(&jsrtemp->touched,touched,sizeof(u1)*maxlocals);     \
+            jsrbuffer[tbptr-block] = jsrtemp;                           \
+        }                                                               \
+        else                                                            \
+            jsrbuffer[tbptr-block] = NULL;                              \
+    } while (0)
+
+/* TYPECHECK_REACH: executed, when the target block (tbptr) can be reached
+ *     from the current block (bptr). The types of local variables and
+ *     stack slots are propagated to the target block.
+ * Input:
+ *     bptr.......current block
+ *     tbptr......target block
+ *     dst........current output stack pointer
+ *     vtype......current local variable types
+ *     vinfo......current local variable typeinfos
+ *     jsrchain...current JSR target chain
+ *     jsrbuffer..JSR target chain for each basic block
+ *     way........in which way the block is reached (REACH_ constant)
+ *     touched....current touched flags of local variables
+ * Output:
+ *     repeat.....changed to true if a block before the current
+ *                block has changed
+ * Used:
+ *     ttype, tinfo, srcstack, dststack, changed, macro_i
+ */
+#define TYPECHECK_REACH(way)                                            \
+    LOG1("reaching block %04d",tbptr-block);                            \
+    srcstack = dst;                                                     \
+    dststack = tbptr->instack;                                          \
+    ttype = vartype + maxlocals*(tbptr-block);                          \
+    tinfo = vartypeinfo + maxlocals*(tbptr-block);                      \
+    if (tbptr->flags == BBTYPECHECK_UNDEF) {                            \
+        /* This block is reached for the first time */                  \
+        if (way == REACH_JSR) {                                         \
+            TYPECHECK_ADD_JSR;                                          \
+            TYPECHECK_COPYVARS;                                         \
+        }                                                               \
+        else {                                                          \
+            TYPECHECK_COPYJSR(jsrchain);                                \
+            TYPECHECK_COPYVARS;                                         \
+        }                                                               \
+        TYPECHECK_COPYSTACK;                                            \
+        changed = true;                                                 \
+    } else {                                                            \
+        /* This block has been reached before */                        \
+        changed = false;                                                \
+        if (way == REACH_JSR)                                           \
+            TYPECHECK_CHECK_JSR_CHAIN;                                  \
+        else                                                            \
+            TYPECHECK_MERGEJSR;                                         \
+        LOGIF(changed,"changed jsr");                                   \
+        TYPECHECK_MERGEVARS;                                            \
+        LOGIF(changed,"changed vars");                                  \
+        TYPECHECK_MERGESTACK;                                           \
+        LOGIF(changed,"changed stack");                                 \
+    }                                                                   \
+    if (changed) {                                                      \
+        LOG("REACHED!");                                                \
+        tbptr->flags = BBTYPECHECK_REACHED;                             \
+        if (tbptr <= bptr) {repeat = true; LOG("MUST REPEAT!");}        \
+    } LOG("done.");
+
+/****************************************************************************/
+/* typecheck()                                                              */
+/****************************************************************************/
+
+#define MAXPARAMS 255
+
+/* typecheck is called directly after analyse_stack */
+void
+typecheck()
+{
+    int b_count, b_index;
+    stackptr curstack;      /* input stack top for current instruction */
+    stackptr srcstack;       /* source stack for copying and merging */
+    stackptr dststack;       /* target stack for copying and merging */
+    int opcode, macro_i, len, i;
+    bool superblockend;        /* true if no fallthrough to next block */
+    bool repeat;            /* if true, blocks are iterated over again */
+    bool changed;
+    instruction *iptr = instr;       /* pointer to current instruction */
+    basicblock *bptr;                /* pointer to current basic block */
+    basicblock *tbptr;
+    u1 *vartype;            /* type of each local for each basic block */
+    typeinfo *vartypeinfo;  /* type of each local for each basic block */
+    u1 *vtype;           /* type of each local for current instruction */
+    typeinfo *vinfo;     /* type of each local for current instruction */
+    u1 *ttype;                                    /* temporary pointer */
+    typeinfo *tinfo;                              /* temporary pointer */
+    typeinfo tempinfo;                                    /* temporary */
+    int returntype;                   /* return type of current method */
+    typeinfo returntypeinfo;               /* typeinfo for return type */
+    u1 *ptype;                     /* parameter types of called method */
+    typeinfo *pinfo;           /* parameter typeinfos of called method */
+    int rtype;                         /* return type of called method */
+    typeinfo rinfo;       /* typeinfo for return type of called method */
+    stackptr dst;               /* output stack of current instruction */
+    int changeddepth;          /* depth to which the stack has changed */ /* XXX */
+    bool fulltypecheck;           /* false == check only changed types */ /* XXX */
+    basicblock **tptr;    /* pointer into target list of switch instructions */
+    jsr_record **jsrbuffer;   /* JSR target chain for each basic block */
+    jsr_record *jsrchain;               /* JSR chain for current block */
+    jsr_record *jsrtemp,*jsrtemp2,*jsrold;      /* temporary variables */
+    jsr_record *subroutine;    /* jsr_record of the current subroutine */
+    u1 *touched;                  /* touched flags for local variables */
+
+    LOGSTR("\n==============================================================================\n");
+    DOLOG(show_icmd_method());
+    LOGSTR("\n==============================================================================\n");
+    LOGimpSTR("Entering typecheck: ");
+    LOGimpSTRu(method->name);
+    LOGimpSTR("    ");
+    LOGimpSTRu(method->descriptor);
+    LOGimpSTR("    (class ");
+    LOGimpSTRu(method->class->name);
+    LOGimpSTR(")\n");
+
+    /* XXX allocate buffers for method arguments */
+    ptype = DMNEW(u1,MAXPARAMS);
+    pinfo = DMNEW(typeinfo,MAXPARAMS);
+    
+    LOG("Buffer allocated.\n");
+
+    /* reset all BBFINISHED blocks to BBTYPECHECK_UNDEF. */
+    b_count = block_count;
+    bptr = block;
+    while (--b_count >= 0) {
+#ifdef TYPECHECK_DEBUG
+        if (bptr->flags != BBFINISHED && bptr->flags != BBDELETED
+            && bptr->flags != BBUNDEF)
+        {
+            show_icmd_method();
+            LOGSTR1("block flags: %d\n",bptr->flags); LOGFLUSH;
+            panic("Internal error: Unexpected block flags in typecheck()");
+        }
+#endif
+        if (bptr->flags >= BBFINISHED) {
+            bptr->flags = BBTYPECHECK_UNDEF;
+        }
+        bptr++;
+    }
+
+    /* The first block is always reached */
+    if (block_count && block[0].flags == BBTYPECHECK_UNDEF)
+        block[0].flags = BBTYPECHECK_REACHED;
+
+    LOG("Blocks reset.\n");
+
+    /* allocate the buffers for local variables */
+    vartype = DMNEW(u1,maxlocals * (block_count+1));
+    vartypeinfo = DMNEW(typeinfo,maxlocals * (block_count+1));
+    touched = DMNEW(u1,maxlocals);
+    vtype = vartype + maxlocals * block_count;
+    vinfo = vartypeinfo + maxlocals * block_count;
+    memset(vartype,TYPE_VOID,maxlocals * (block_count+1) * sizeof(typeinfo));
+    memset(vartypeinfo,0,maxlocals * (block_count+1) * sizeof(typeinfo));
+
+    LOG("Variable buffer initialized.\n");
+
+    /* allocate the buffer for storing JSR target chains */
+    jsrbuffer = DMNEW(jsr_record*,block_count);
+    memset(jsrbuffer,0,block_count * sizeof(jsr_record*));
+    jsrchain = NULL;
+    
+    LOG("jsrbuffer initialized.\n");
+
+    /* initialize the variable types of the first block */
+    /* to the types of the arguments */
+    ttype = vartype;
+    tinfo = vartypeinfo;
+
+    /* if this is an instance method initialize the "this" ref type */
+    if (!(method->flags & ACC_STATIC)) {
+        *ttype++ = TYPE_ADDRESS;
+        TYPEINFO_INIT_CLASSINFO(*tinfo,class);
+        tinfo++;
+    }
+
+    LOG("'this' argument set.\n");
+
+    /* the rest of the arguments and the return type */
+    typeinfo_init_from_method_args(method->descriptor,ttype,tinfo,
+                                   maxlocals - (tinfo-vartypeinfo),
+                                   true, /* two word types use two slots */
+                                   &returntype,&returntypeinfo);
+
+    LOG("Arguments set.\n");
+
+    /* loop while there are still blocks to be checked */
+    fulltypecheck = true; /* XXX */
+    do {
+
+        repeat = false;
+        
+        b_count = block_count;
+        bptr = block;
+
+        while (--b_count >= 0) {
+            LOGSTR1("---- BLOCK %04d, ",bptr-block);
+            LOGSTR1("blockflags: %d\n",bptr->flags);
+            LOGFLUSH;
+                
+            if (bptr->flags == BBTYPECHECK_REACHED) {
+                LOGSTR1("\n---- BLOCK %04d ------------------------------------------------\n",bptr-block);
+                LOGFLUSH;
+                
+                superblockend = false;
+                bptr->flags = BBFINISHED;
+                b_index = bptr - block;
+
+                /* init stack at the start of this block */
+                curstack = bptr->instack;
+                                       
+                /* init variable types at the start of this block */
+                for (i=0; i<maxlocals; ++i) {
+                    vtype[i] = vartype[maxlocals*b_index + i];
+                    TYPEINFO_COPY(vartypeinfo[maxlocals*b_index + i],vinfo[i]);
+                }
+
+                /* init JSR target chain */
+                if ((jsrchain = jsrbuffer[b_index]) != NULL) {
+#ifdef TYPECHECK_VERBOSE
+                    if (typecheckverbose) {
+                        LOGSTR("jsr chain:");
+                        jsrtemp = jsrchain;
+                        while (jsrtemp) {
+                            LOGSTR1(" L%03d",jsrtemp->target->debug_nr);
+                            jsrtemp = jsrtemp->next;
+                        }
+                        LOGNL;
+                        LOGFLUSH;
+                    }
+#endif
+
+                    subroutine = jsrbuffer[jsrchain->target - block];
+                    memcpy(touched,jsrchain->touched,sizeof(u1)*maxlocals);
+                }
+                else
+                    subroutine = NULL;
+#ifdef TYPECHECK_VERBOSE
+                if (typecheckverbose) {
+                    if (subroutine) {LOGSTR1("subroutine L%03d\n",subroutine->target->debug_nr);LOGFLUSH;}
+                    typeinfo_print_block(stdout,curstack,vtype,vinfo,(jsrchain) ? touched : NULL);
+                    LOGNL; LOGFLUSH;
+                }
+#endif
+                                       
+                /* loop over the instructions */
+                len = bptr->icount;
+                iptr = bptr->iinstr;
+                while (--len >= 0)  {
+                    DOLOG(show_icmd(iptr,false));
+                    LOGNL;
+                    LOGFLUSH;
+                        
+                    opcode = iptr->opc;
+                    dst = iptr->dst;
+                                               
+                    switch (opcode) {
+
+                        /****************************************/
+                        /* STACK MANIPULATIONS                  */
+
+                        /* We just need to copy the typeinfo */
+                        /* for slots containing addresses.   */
+
+                      case ICMD_DUP:
+                          COPYTYPE(curstack,dst);
+                          break;
+                                                         
+                      case ICMD_DUP_X1:
+                          COPYTYPE(curstack,dst);
+                          COPYTYPE(curstack,dst-2);
+                          COPYTYPE(curstack->prev,dst-1);
+                          break;
+                                                         
+                      case ICMD_DUP_X2:
+                          COPYTYPE(curstack,dst);
+                          COPYTYPE(curstack,dst-3);
+                          COPYTYPE(curstack->prev,dst-1);
+                          COPYTYPE(curstack->prev->prev,dst-2);
+                          break;
+                                                         
+                      case ICMD_DUP2:
+                          COPYTYPE(curstack,dst);
+                          COPYTYPE(curstack->prev,dst-1);
+                          break;
+
+                      case ICMD_DUP2_X1:
+                          COPYTYPE(curstack,dst);
+                          COPYTYPE(curstack->prev,dst-1);
+                          COPYTYPE(curstack,dst-3);
+                          COPYTYPE(curstack->prev,dst-4);
+                          COPYTYPE(curstack->prev->prev,dst-2);
+                          break;
+                                                         
+                      case ICMD_DUP2_X2:
+                          COPYTYPE(curstack,dst);
+                          COPYTYPE(curstack->prev,dst-1);
+                          COPYTYPE(curstack,dst-4);
+                          COPYTYPE(curstack->prev,dst-5);
+                          COPYTYPE(curstack->prev->prev,dst-2);
+                          COPYTYPE(curstack->prev->prev->prev,dst-3);
+                          break;
+                                                         
+                      case ICMD_SWAP:
+                          COPYTYPE(curstack,dst-1);
+                          COPYTYPE(curstack->prev,dst);
+                          break;
+
+                          /* XXX only add these cases in debug mode? */
+                      case ICMD_POP:
+                          break;
+                                                       
+                      case ICMD_POP2:
+                          break;
+
+                          /****************************************/
+                          /* LOADING ADDRESS FROM VARIABLE        */
+
+                      case ICMD_ALOAD:
+                          CHECKVARTYPE(iptr->op1,TYPE_ADR);
+                          
+                          /* loading a returnAddress is not allowed */
+                          if (TYPEINFO_IS_PRIMITIVE(vinfo[iptr->op1]))
+                              panic("illegal instruction: ALOAD loading returnAddress");
+
+                          TYPEINFO_COPY(vinfo[iptr->op1],dst->typeinfo);
+                          break;
+                                                       
+                          /****************************************/
+                          /* STORING ADDRESS TO VARIABLE          */
+
+                      case ICMD_ASTORE:
+                          /* TYPE_ADR has already been checked. */
+                          STORE_TYPE(iptr->op1,TYPE_ADDRESS);
+                          TYPEINFO_COPY(curstack->typeinfo,vinfo[iptr->op1]);
+                          break;
+                          
+                          /****************************************/
+                          /* LOADING ADDRESS FROM ARRAY           */
+
+                      case ICMD_AALOAD:
+                          if (!TYPEINFO_MAYBE_ARRAY_OF_REFS(curstack->prev->typeinfo))
+                              panic("illegal instruction: AALOAD on non-reference array");
+
+                          typeinfo_init_component(&curstack->prev->typeinfo,&dst->typeinfo);
+                          break;
+                                                         
+                          /****************************************/
+                          /* STORING ADDRESS TO ARRAY             */
+
+                      case ICMD_AASTORE:
+                          /* XXX also handled by builtin3 */
+                          if (!TYPEINFO_MAYBE_ARRAY_OF_REFS(curstack->prev->prev->typeinfo))
+                              panic("illegal instruction: AASTORE to non-reference array");
+
+                          /* XXX optimize */
+                          /*
+                            typeinfo_init_component(&curstack->prev->prev->typeinfo,&tempinfo);
+                            if (!typeinfo_is_assignable(&curstack->typeinfo,&tempinfo))
+                            panic("illegal instruction: AASTORE to incompatible type");
+                          */
+                          break;
+
+                          /****************************************/
+                          /* FIELD ACCESS                         */
+
+                      case ICMD_PUTFIELD:
+                          if (!TYPEINFO_IS_REFERENCE(curstack->prev->typeinfo))
+                              panic("illegal instruction: PUTFIELD on non-reference");
+                          if (TYPEINFO_IS_ARRAY(curstack->prev->typeinfo)) /* XXX arraystub */
+                              panic("illegal instruction: PUTFIELD on array");
+
+                          
+                          /* XXX */
+                          break;
+
+                      case ICMD_PUTSTATIC:
+                          /* XXX */
+                          break;
+
+                      case ICMD_GETFIELD:
+                          if (!TYPEINFO_IS_REFERENCE(curstack->typeinfo))
+                              panic("illegal instruction: GETFIELD on non-reference");
+                          if (TYPEINFO_IS_ARRAY(curstack->typeinfo))
+                              panic("illegal instruction: GETFIELD on array");
+                          
+                          {
+                              fieldinfo *fi = (fieldinfo *)(iptr->val.a);
+                              /* XXX check non-static? */
+                              if (dst->type == TYPE_ADR) {
+                                  TYPEINFO_INIT_FROM_FIELDINFO(dst->typeinfo,fi);
+                              }
+                              else {
+                                  TYPEINFO_INIT_PRIMITIVE(dst->typeinfo);
+                              }
+                          }
+                          break;
+
+                      case ICMD_GETSTATIC:
+                          {
+                              fieldinfo *fi = (fieldinfo *)(iptr->val.a);
+                              /* XXX check static? */
+                              if (dst->type == TYPE_ADR) {
+                                  TYPEINFO_INIT_FROM_FIELDINFO(dst->typeinfo,fi);
+                              }
+                              else {
+                                  TYPEINFO_INIT_PRIMITIVE(dst->typeinfo);
+                              }
+                          }
+                          break;
+
+                          /****************************************/
+                          /* PRIMITIVE ARRAY ACCESS               */
+
+                      case ICMD_ARRAYLENGTH:
+                          /* XXX should this also work on arraystubs? */
+                          if (!TYPEINFO_MAYBE_ARRAY(curstack->typeinfo))
+                              panic("illegal instruction: ARRAYLENGTH on non-array");
+                          break;
+                                                         
+                      case ICMD_BALOAD:
+                          if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(curstack->prev->typeinfo,ARRAYTYPE_BOOLEAN)
+                              && !TYPEINFO_MAYBE_PRIMITIVE_ARRAY(curstack->prev->typeinfo,ARRAYTYPE_BYTE))
+                              panic("Array type mismatch");
+                          break;
+                      case ICMD_CALOAD:
+                          if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(curstack->prev->typeinfo,ARRAYTYPE_CHAR))
+                              panic("Array type mismatch");
+                          break;
+                      case ICMD_DALOAD:
+                          if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(curstack->prev->typeinfo,ARRAYTYPE_DOUBLE))
+                              panic("Array type mismatch");
+                          break;
+                      case ICMD_FALOAD:
+                          if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(curstack->prev->typeinfo,ARRAYTYPE_FLOAT))
+                              panic("Array type mismatch");
+                          break;
+                      case ICMD_IALOAD:
+                          if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(curstack->prev->typeinfo,ARRAYTYPE_INT))
+                              panic("Array type mismatch");
+                          break;
+                      case ICMD_SALOAD:
+                          if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(curstack->prev->typeinfo,ARRAYTYPE_SHORT))
+                              panic("Array type mismatch");
+                          break;
+                      case ICMD_LALOAD:
+                          if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(curstack->prev->typeinfo,ARRAYTYPE_LONG))
+                              panic("Array type mismatch");
+                          break;
+
+                      case ICMD_BASTORE:
+                          if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(curstack->prev->prev->typeinfo,ARRAYTYPE_BOOLEAN)
+                              && !TYPEINFO_MAYBE_PRIMITIVE_ARRAY(curstack->prev->prev->typeinfo,ARRAYTYPE_BYTE))
+                              panic("Array type mismatch");
+                          break;
+                      case ICMD_CASTORE:
+                          if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(curstack->prev->prev->typeinfo,ARRAYTYPE_CHAR))
+                              panic("Array type mismatch");
+                          break;
+                      case ICMD_DASTORE:
+                          if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(curstack->prev->prev->typeinfo,ARRAYTYPE_DOUBLE))
+                              panic("Array type mismatch");
+                          break;
+                      case ICMD_FASTORE:
+                          if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(curstack->prev->prev->typeinfo,ARRAYTYPE_FLOAT))
+                              panic("Array type mismatch");
+                          break;
+                      case ICMD_IASTORE:
+                          if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(curstack->prev->prev->typeinfo,ARRAYTYPE_INT))
+                              panic("Array type mismatch");
+                          break;
+                      case ICMD_SASTORE:
+                          if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(curstack->prev->prev->typeinfo,ARRAYTYPE_SHORT))
+                              panic("Array type mismatch");
+                          break;
+                      case ICMD_LASTORE:
+                          if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(curstack->prev->prev->typeinfo,ARRAYTYPE_LONG))
+                              panic("Array type mismatch");
+                          break;
+
+                          /****************************************/
+                          /* OPERATIONS WITH UNCHECKED INPUT      */
+
+                      case ICMD_CHECKCAST:
+                          /* returnAddress is not allowed */
+                          if (!TYPEINFO_IS_REFERENCE(curstack->typeinfo))
+                              panic("Illegal instruction: INSTANCEOF on non-reference");
+
+                          /* XXX check if the cast can be done statically */
+                          TYPEINFO_INIT_CLASSINFO(dst->typeinfo,(classinfo *)iptr[0].val.a);
+                          /* XXX */
+                          break;
+
+                      case ICMD_INSTANCEOF:
+                          /* returnAddress is not allowed */
+                          if (!TYPEINFO_IS_REFERENCE(curstack->typeinfo))
+                              panic("Illegal instruction: INSTANCEOF on non-reference");
+                          
+                          /* XXX */
+                          break;
+                          
+                      case ICMD_ACONST:
+                          if (iptr->val.a == NULL)
+                              TYPEINFO_INIT_NULLTYPE(dst->typeinfo)
+                          else
+                              /* XXX constants for builtin functions */
+                              /* string constants */
+                              TYPEINFO_INIT_CLASSINFO(dst->typeinfo,class_java_lang_String);
+                          break;
+
+                          /****************************************/
+                          /* BRANCH INSTRUCTIONS                  */
+
+                      case ICMD_GOTO:
+                          superblockend = true;
+                          /* FALLTHROUGH! */
+                      case ICMD_IFNULL:
+                      case ICMD_IFNONNULL:
+                      case ICMD_IFEQ:
+                      case ICMD_IFNE:
+                      case ICMD_IFLT:
+                      case ICMD_IFGE:
+                      case ICMD_IFGT:
+                      case ICMD_IFLE:
+                      case ICMD_IF_ICMPEQ:
+                      case ICMD_IF_ICMPNE:
+                      case ICMD_IF_ICMPLT:
+                      case ICMD_IF_ICMPGE:
+                      case ICMD_IF_ICMPGT:
+                      case ICMD_IF_ICMPLE:
+                      case ICMD_IF_ACMPEQ:
+                      case ICMD_IF_ACMPNE:
+                      case ICMD_IF_LEQ:
+                      case ICMD_IF_LNE:
+                      case ICMD_IF_LLT:
+                      case ICMD_IF_LGE:
+                      case ICMD_IF_LGT:
+                      case ICMD_IF_LLE:
+                      case ICMD_IF_LCMPEQ:
+                      case ICMD_IF_LCMPNE:
+                      case ICMD_IF_LCMPLT:
+                      case ICMD_IF_LCMPGE:
+                      case ICMD_IF_LCMPGT:
+                      case ICMD_IF_LCMPLE:
+                          tbptr = (basicblock *) iptr->target;
+
+                          /* propagate stack and variables to the target block */
+                          TYPECHECK_REACH(REACH_STD);
+                          /* XXX */
+                          break;
+
+                          /****************************************/
+                          /* SWITCHES                             */
+                          
+                      case ICMD_TABLESWITCH:
+                          {
+                              s4 *s4ptr = iptr->val.a;
+                              s4ptr++; /* skip default */
+                              i = *s4ptr++; /* low */
+                              i = *s4ptr++ - i + 2; /* +1 for default target */
+                          }
+                          goto switch_instruction_tail;
+                          
+                      case ICMD_LOOKUPSWITCH:
+                          {
+                              s4 *s4ptr = iptr->val.a;
+                              s4ptr++; /* skip default */
+                              i = *s4ptr++ + 1; /* count +1 for default target */
+                          }
+                    switch_instruction_tail:
+                          tptr = (basicblock **)iptr->target;
+                          
+                          while (--i >= 0) {
+                              tbptr = *tptr++;
+                              LOG2("target %d is block %04d",(tptr-(basicblock **)iptr->target)-1,tbptr-block);
+                              TYPECHECK_REACH(REACH_STD);
+                          }
+                          LOG("switch done");
+                          superblockend = true;
+                          break;
+
+                          /****************************************/
+                          /* RETURNS AND THROW                    */
+
+                      case ICMD_ATHROW:
+                          TYPEINFO_INIT_CLASSINFO(tempinfo,class_java_lang_Throwable);
+                          if (!typeinfo_is_assignable(&curstack->typeinfo,&tempinfo))
+                              panic("illegal instruction: ATHROW on non-Throwable");
+                          superblockend = true;
+                          break;
+
+                      case ICMD_ARETURN:
+                          if (!TYPEINFO_IS_REFERENCE(curstack->typeinfo))
+                              panic("illegal instruction: ARETURN on non-reference");
+
+                          if (returntype != TYPE_ADDRESS
+                              || !typeinfo_is_assignable(&curstack->typeinfo,&returntypeinfo))
+                              panic("Return type mismatch");
+                                                         
+                          superblockend = true;
+                          break;
+
+                      case ICMD_IRETURN:
+                          if (returntype != TYPE_INT)
+                              panic("Return type mismatch");
+                          superblockend = true;
+                          break;                           
+                      case ICMD_LRETURN:
+                          if (returntype != TYPE_LONG)
+                              panic("Return type mismatch");
+                          superblockend = true;
+                          break;
+                      case ICMD_FRETURN:
+                          if (returntype != TYPE_FLOAT)
+                              panic("Return type mismatch");
+                          superblockend = true;
+                          break;
+                      case ICMD_DRETURN:
+                          if (returntype != TYPE_DOUBLE)
+                              panic("Return type mismatch");
+                          superblockend = true;
+                          break;
+                      case ICMD_RETURN:
+                          if (returntype != TYPE_VOID)
+                              panic("Return type mismatch");
+                          superblockend = true;
+                          break;
+                                                    
+                          /****************************************/
+                          /* SUBROUTINE INSTRUCTIONS              */
+
+                      case ICMD_JSR:
+                          LOG("jsr");
+
+                          /* XXX This is a dirty hack. It is needed
+                           * because of the special handling of ICMD_JSR in stack.c
+                           */
+                          dst = (stackptr) iptr->val.a;
+                          
+                          /* push return address */
+                          TYPEINFO_INIT_PRIMITIVE(dst->typeinfo);
+
+                          LOG("reaching block...");
+                          
+                          /* add the target to the JSR target chain and */
+                          /* propagate stack and variables to the target block */
+                          tbptr = (basicblock *) iptr->target;
+                          TYPECHECK_REACH(REACH_JSR);
+
+                          /* set dst to the stack after the subroutine execution */
+                          /* XXX We assume (as in stack.c) that the
+                           * subroutine returns the stack as it was
+                           * before the JSR instruction. Is this
+                           * correct?
+                           */
+                          dst = iptr->dst;
+
+                          /* Find the jsr_record of the called subroutine */
+                          jsrtemp = jsrbuffer[tbptr - block];
+
+                          /* Check if we already calculated (at least
+                           * for one RET) which variables the
+                           * subroutine touches.
+                           */
+                          if (jsrtemp->sbr_touched) {
+                              /* Calculate the local variables after the subroutine call */
+                              for (i=0; i<maxlocals; ++i)
+                                  if (jsrtemp->sbr_touched[i] != TOUCHED_NO) {
+                                      TOUCH_VARIABLE(i);
+                                      if ((vtype[i] = jsrtemp->sbr_vtype[i]) == TYPE_ADR)
+                                          TYPEINFO_CLONE(jsrtemp->sbr_vinfo[i],vinfo[i]);
+                                  }
+
+                              /* continue after the JSR call */
+                              superblockend = false;
+                          }
+                          else {
+                              /* We cannot proceed until the subroutine has been typechecked. */
+                              /* XXX actually we would not have to check this block again */
+                              bptr->flags = BBTYPECHECK_REACHED;
+                              repeat = true;
+                              superblockend = true;
+                          }
+                          break;
+                          
+                      case ICMD_RET:
+                          /* check returnAddress variable */
+                          CHECKVARTYPE(iptr->op1,TYPE_ADR);
+                          
+                          if (!TYPEINFO_IS_PRIMITIVE(vinfo[iptr->op1]))
+                              panic("illegal instruction: RET using non-returnAddress variable");
+
+                          /* check if we are inside a subroutine */
+                          if (!subroutine)
+                              panic("RET outside of subroutine");
+
+                          /* determine which variables are touched by this subroutine */
+                          /* and their types */
+                          if (subroutine->sbr_touched) {
+                              for (i=0; i<maxlocals; ++i)
+                                  subroutine->sbr_touched[i] |= touched[i];
+                              ttype = subroutine->sbr_vtype;
+                              tinfo = subroutine->sbr_vinfo;
+                              TYPECHECK_MERGEVARS;
+                          }
+                          else {
+                              subroutine->sbr_touched = DMNEW(u1,maxlocals);
+                              memcpy(subroutine->sbr_touched,touched,sizeof(u1)*maxlocals);
+                              subroutine->sbr_vtype = DMNEW(u1,maxlocals);
+                              memcpy(subroutine->sbr_vtype,vtype,sizeof(u1)*maxlocals);
+                              subroutine->sbr_vinfo = DMNEW(typeinfo,maxlocals);
+                              for (i=0; i<maxlocals; ++i)
+                                  if (vtype[i] == TYPE_ADR)
+                                      TYPEINFO_CLONE(vinfo[i],subroutine->sbr_vinfo[i]);
+                          }
+
+                          LOGSTR("subroutine touches:");
+                          DOLOG(typeinfo_print_locals(stdout,subroutine->sbr_vtype,subroutine->sbr_vinfo,
+                                                      subroutine->sbr_touched,maxlocals));
+                          LOGNL; LOGFLUSH;
+
+                          /* reach blocks after JSR statements */
+                          for (i=0; i<block_count; ++i) {
+                              tbptr = block + i;
+                              if (tbptr->iinstr[tbptr->icount - 1].opc != ICMD_JSR)
+                                  continue;
+                              if ((basicblock*) tbptr->iinstr[tbptr->icount - 1].target != jsrold->target)
+                                  continue;
+                              tbptr++;
+
+                              LOG1("RET reaches block %04d",tbptr-block);
+
+                              /*TYPECHECK_REACH(REACH_RET);*/
+                          }
+                          
+                          superblockend = true;
+                          break;
+                                                         
+                          /****************************************/
+                          /* INVOKATIONS                          */
+
+                      case ICMD_INVOKEVIRTUAL:
+                      case ICMD_INVOKESPECIAL:
+                      case ICMD_INVOKESTATIC:
+                      case ICMD_INVOKEINTERFACE:
+                          {
+                              /* XXX check access rights */
+                              
+                              methodinfo *mi = (methodinfo*) iptr->val.a;
+                              /* XXX might use dst->typeinfo directly if non void */
+                              typeinfo_init_from_method_args(mi->descriptor,ptype,pinfo,MAXPARAMS,false,
+                                                             &rtype,&rinfo);
+
+                              /* XXX compare rtype and dst->type? */
+                              if (rtype != TYPE_VOID) {
+                                  TYPEINFO_COPY(rinfo,dst->typeinfo);
+                              }
+                          }
+                          break;
+                          
+                      case ICMD_MULTIANEWARRAY:
+                          /* check the array lengths on the stack */
+                          i = iptr[0].op1;
+                          if (i<1) panic("MULTIANEWARRAY with dimensions < 1");
+                          srcstack = curstack;
+                          while (i--) {
+                              if (!srcstack)
+                                  panic("MULTIANEWARRAY missing array length");
+                              if (srcstack->type != TYPE_INT)
+                                  panic("MULTIANEWARRAY using non-int as array length");
+                              srcstack = srcstack->prev;
+                          }
+                          
+                          /* set the array type of the result */
+                          TYPEINFO_INIT_CLASSINFO(dst->typeinfo,((vftbl *)iptr[0].val.a)->class);
+                          break;
+                          
+                      case ICMD_BUILTIN3:
+                          if (ISBUILTIN(asm_builtin_aastore)) {
+                              /* XXX also handled by ICMD_AASTORE */
+                              if (!TYPEINFO_MAYBE_ARRAY_OF_REFS(curstack->prev->prev->typeinfo))
+                                  panic("illegal instruction: AASTORE to non-reference array");
+
+                              /* XXX optimize */
+                              /*
+                                typeinfo_init_component(&curstack->prev->prev->typeinfo,&tempinfo);
+                                if (!typeinfo_is_assignable(&curstack->typeinfo,&tempinfo))
+                                panic("illegal instruction: AASTORE to incompatible type");
+                              */
+                          }
+                          /* XXX check for missed builtins in debug mode? */
+                          break;
+                          
+                      case ICMD_BUILTIN2:
+                          if (
+#if defined(__I386__)
+                              ISBUILTIN(asm_builtin_newarray)
+#else
+                              ISBUILTIN(builtin_newarray)
+#endif
+                              )
+                          {
+                              if (iptr[-1].opc != ICMD_ACONST)
+                                  panic("illegal instruction: builtin_newarray without classinfo");
+                              TYPEINFO_INIT_CLASSINFO(dst->typeinfo,((vftbl *)iptr[-1].val.a)->class);
+                          }
+                          else if (ISBUILTIN(asm_builtin_checkarraycast)) {
+                              if (iptr[-1].opc != ICMD_ACONST)
+                                  panic("illegal instruction: asm_builtin_checkarraycast without classinfo");
+                              TYPEINFO_INIT_CLASSINFO(dst->typeinfo,((vftbl *)iptr[-1].val.a)->class);
+                          }
+                          /* XXX check for missed builtins in debug mode? */
+                          break;
+                          
+                      case ICMD_BUILTIN1:
+                          if (ISBUILTIN(builtin_new)) {
+                              if (iptr[-1].opc != ICMD_ACONST)
+                                  panic("illegal instruction: builtin_new without classinfo");
+                              TYPEINFO_INIT_CLASSINFO(dst->typeinfo,(classinfo *)iptr[-1].val.a);
+                          }
+                          else if (ISBUILTIN(builtin_newarray_boolean)) {
+                              TYPEINFO_INIT_PRIMITIVE_ARRAY(dst->typeinfo,ARRAYTYPE_BOOLEAN);
+                          }
+                          else if (ISBUILTIN(builtin_newarray_char)) {
+                              TYPEINFO_INIT_PRIMITIVE_ARRAY(dst->typeinfo,ARRAYTYPE_CHAR);
+                          }
+                          else if (ISBUILTIN(builtin_newarray_float)) {
+                              TYPEINFO_INIT_PRIMITIVE_ARRAY(dst->typeinfo,ARRAYTYPE_FLOAT);
+                          }
+                          else if (ISBUILTIN(builtin_newarray_double)) {
+                              TYPEINFO_INIT_PRIMITIVE_ARRAY(dst->typeinfo,ARRAYTYPE_DOUBLE);
+                          }
+                          else if (ISBUILTIN(builtin_newarray_byte)) {
+                              TYPEINFO_INIT_PRIMITIVE_ARRAY(dst->typeinfo,ARRAYTYPE_BYTE);
+                          }
+                          else if (ISBUILTIN(builtin_newarray_short)) {
+                              TYPEINFO_INIT_PRIMITIVE_ARRAY(dst->typeinfo,ARRAYTYPE_SHORT);
+                          }
+                          else if (ISBUILTIN(builtin_newarray_int)) {
+                              TYPEINFO_INIT_PRIMITIVE_ARRAY(dst->typeinfo,ARRAYTYPE_INT);
+                          }
+                          else if (ISBUILTIN(builtin_newarray_long)) {
+                              TYPEINFO_INIT_PRIMITIVE_ARRAY(dst->typeinfo,ARRAYTYPE_LONG);
+                          }
+                          /* XXX check for missed builtins in debug mode? */
+                          break;
+                                                     
+                          /****************************************/
+                          /* PRIMITIVE VARIABLE ACCESS            */
+
+                      case ICMD_ILOAD: CHECKVARTYPE(iptr->op1,TYPE_INT); break;
+                      case ICMD_LLOAD: CHECKVARTYPE(iptr->op1,TYPE_LONG); break;
+                      case ICMD_FLOAD: CHECKVARTYPE(iptr->op1,TYPE_FLOAT); break;
+                      case ICMD_DLOAD: CHECKVARTYPE(iptr->op1,TYPE_DOUBLE); break;
+                      case ICMD_IINC:  CHECKVARTYPE(iptr->op1,TYPE_INT); /*TOUCH_VARIABLE(iptr->op1);*/ break;
+                          
+                      case ICMD_FSTORE: STORE_PRIMITIVE(iptr->op1,TYPE_FLOAT); break;
+                      case ICMD_ISTORE: STORE_PRIMITIVE(iptr->op1,TYPE_INT); break;                           
+                      case ICMD_LSTORE: STORE_TWOWORD(iptr->op1,TYPE_LONG); break;
+                      case ICMD_DSTORE: STORE_TWOWORD(iptr->op1,TYPE_DOUBLE); break;
+                          
+                          /****************************************/
+                          /* INSTRUCTIONS WHICH SHOULD HAVE BEEN  */
+                          /* REPLACED BY BUILTIN CALLS            */
+
+                      case ICMD_NEW:
+                      case ICMD_NEWARRAY:
+                      case ICMD_ANEWARRAY:
+                      case ICMD_MONITORENTER:
+                      case ICMD_MONITOREXIT:
+                          /* XXX only check this in debug mode? */
+                          LOGSTR2("ICMD %d at %d\n", iptr->opc, (int)(iptr-instr));
+                          panic("Internal error: unexpected instruction encountered");
+                          break;
+                                                     
+                          /****************************************/
+                          /* UNCHECKED OPERATIONS                 */
+
+                          /* These ops have no input or output to be checked */
+                          /* (apart from the checks done in analyse_stack).  */
+                                                /* XXX only add cases for them in debug mode? */
+
+                      case ICMD_NOP:
+                      case ICMD_CHECKASIZE: /* XXX ? */
+                      case ICMD_NULLCHECKPOP: /* XXX ? */
+                      case ICMD_READONLY_ARG: /* XXX ? */
+                      case ICMD_CLEAR_ARGREN: /* XXX ? */
+                          break;
+
+                          /****************************************/
+                          /* ARITHMETIC AND CONVERSION            */
+
+                          /* These instructions are typechecked in analyse_stack. */
+                                                /* XXX only add cases for them in debug mode? */
+
+                      case ICMD_IADD:
+                      case ICMD_ISUB:
+                      case ICMD_IMUL:
+                      case ICMD_IDIV:
+                      case ICMD_IREM:
+                      case ICMD_INEG:
+                      case ICMD_IAND:
+                      case ICMD_IOR:
+                      case ICMD_IXOR:
+                      case ICMD_ISHL:
+                      case ICMD_ISHR:
+                      case ICMD_IUSHR:
+                      case ICMD_LADD:
+                      case ICMD_LSUB:
+                      case ICMD_LMUL:
+                      case ICMD_LDIV:
+                      case ICMD_LREM:
+                      case ICMD_LNEG:
+                      case ICMD_LAND:
+                      case ICMD_LOR:
+                      case ICMD_LXOR:
+                      case ICMD_LSHL:
+                      case ICMD_LSHR:
+                      case ICMD_LUSHR:
+                      case ICMD_IREM0X10001:
+                      case ICMD_LREM0X10001:
+                      case ICMD_IDIVPOW2:
+                      case ICMD_LDIVPOW2:
+                      case ICMD_IADDCONST:
+                      case ICMD_ISUBCONST:
+                      case ICMD_IMULCONST:
+                      case ICMD_IANDCONST:
+                      case ICMD_IORCONST:
+                      case ICMD_IXORCONST:
+                      case ICMD_ISHLCONST:
+                      case ICMD_ISHRCONST:
+                      case ICMD_IUSHRCONST:
+                      case ICMD_IREMPOW2:
+                      case ICMD_LADDCONST:
+                      case ICMD_LSUBCONST:
+                      case ICMD_LMULCONST:
+                      case ICMD_LANDCONST:
+                      case ICMD_LORCONST:
+                      case ICMD_LXORCONST:
+                      case ICMD_LSHLCONST:
+                      case ICMD_LSHRCONST:
+                      case ICMD_LUSHRCONST:
+                      case ICMD_LREMPOW2:
+                          
+                      case ICMD_LCMP:
+                      case ICMD_LCMPCONST:
+                      case ICMD_FCMPL:
+                      case ICMD_FCMPG:
+                      case ICMD_DCMPL:
+                      case ICMD_DCMPG:
+                          
+                      case ICMD_FADD:
+                      case ICMD_DADD:
+                      case ICMD_FSUB:
+                      case ICMD_DSUB:
+                      case ICMD_FMUL:
+                      case ICMD_DMUL:
+                      case ICMD_FDIV:
+                      case ICMD_DDIV:
+                      case ICMD_FREM:
+                      case ICMD_DREM:
+                      case ICMD_FNEG:
+                      case ICMD_DNEG:
+
+                      case ICMD_I2L:
+                      case ICMD_I2F:
+                      case ICMD_I2D:
+                      case ICMD_L2I:
+                      case ICMD_L2F:
+                      case ICMD_L2D:
+                      case ICMD_F2I:
+                      case ICMD_F2L:
+                      case ICMD_F2D:
+                      case ICMD_D2I:
+                      case ICMD_D2L:
+                      case ICMD_D2F:
+                      case ICMD_INT2BYTE:
+                      case ICMD_INT2CHAR:
+                      case ICMD_INT2SHORT:
+
+                      case ICMD_ICONST:
+                      case ICMD_LCONST:
+                      case ICMD_FCONST:
+                      case ICMD_DCONST:
+
+                      case ICMD_IFEQ_ICONST:
+                      case ICMD_IFNE_ICONST:
+                      case ICMD_IFLT_ICONST:
+                      case ICMD_IFGE_ICONST:
+                      case ICMD_IFGT_ICONST:
+                      case ICMD_IFLE_ICONST:
+                      case ICMD_ELSE_ICONST:
+
+                          break;
+                          
+                          /****************************************/
+
+                      default:
+                          LOGSTR2("ICMD %d at %d\n", iptr->opc, (int)(iptr-instr));
+                          panic("Missing ICMD code during typecheck");
+                    }
+                    
+                    /* the output of this instruction becomes the current stack */
+                    curstack = dst;
+                    
+                    iptr++;
+                } /* while instructions */
+
+                LOG("instructions done");
+                LOGSTR("RESULT=> ");
+                DOLOG(typeinfo_print_block(stdout,curstack,vtype,vinfo,(jsrchain) ? touched : NULL));
+                LOGNL; LOGFLUSH;
+                
+                /* propagate stack and variables to the following block */
+                if (!superblockend) {
+                    LOG("reaching following block");
+                    tbptr = bptr + 1;
+                    while (tbptr->flags == BBDELETED) {
+                        tbptr++;
+#ifdef TYPECHECK_DEBUG
+                        if ((tbptr-block) >= block_count)
+                            panic("Control flow falls off the last block");
+#endif
+                    }
+                    TYPECHECK_REACH(REACH_STD);
+                }
+                
+            } /* if block has to be checked */
+            bptr++;
+        } /* while blocks */
+        
+        /* the following iterations only check if any types changed */
+        fulltypecheck = false; /* XXX */
+
+        LOGIF(repeat,"repeat=true");
+    } while (repeat);
+
+    /* XXX reset BB... to BBFINISHED */
+    
+    /* XXX free vartype */
+    /* XXX free vartypeinfo */
+            /* XXX free buffers for method arguments. */
+
+    /* XXX add debug check if all non-dead blocks have been checked */
+
+    LOGimp("exiting typecheck");
+}
+
+#undef COPYTYPE
+
+#endif /* CACAO_TYPECHECK */
index 03e2a1601749f9910c7eabd0e35a9faa3e8a74d8..945d41aaf5417154b9962079552e9a76af5d2d4e 100644 (file)
--- a/loader.c
+++ b/loader.c
@@ -28,8 +28,9 @@
    Changes: Andreas Krall
             Roman Obermaiser
             Mark Probst
+                       Edwin Steiner
 
-   $Id: loader.c 693 2003-12-05 19:00:58Z jowenn $
+   $Id: loader.c 696 2003-12-06 20:10:05Z edwin $
 
 */
 
@@ -888,6 +889,7 @@ static void method_load (methodinfo *m, classinfo *c)
        m -> flags = suck_u2 ();
        m -> name =  class_getconstant (c, suck_u2(), CONSTANT_Utf8);
        m -> descriptor = class_getconstant (c, suck_u2(), CONSTANT_Utf8);
+       checkmethoddescriptor(m->descriptor);
        
        m -> jcode = NULL;
        m -> exceptiontable = NULL;
@@ -1599,6 +1601,8 @@ class_new_array(classinfo *c)
        methodinfo *clone;
        int namelen;
 
+       /* XXX remove */ /* dolog("class_new_array: %s",c->name->text); */
+
        /* Array classes are not loaded from classfiles. */
        list_remove (&unloadedclasses, c);
 
@@ -1626,12 +1630,12 @@ class_new_array(classinfo *c)
        c->super = class_java_lang_Object;
 
     c->interfacescount = 2;
-    c->interfaces = MNEW(classinfo*,2);
+    c->interfaces = MNEW(classinfo*,2); /* XXX use GC? */
     c->interfaces[0] = class_java_lang_Cloneable;
     c->interfaces[1] = class_java_io_Serializable;
 
        c->methodscount = 1;
-       c->methods = MNEW (methodinfo, c->methodscount);
+       c->methods = MNEW (methodinfo, c->methodscount); /* XXX use GC? */
 
        clone = c->methods;
        memset(clone,0,sizeof(methodinfo));
@@ -2881,7 +2885,7 @@ classinfo *class_from_descriptor(char *utf_ptr,char *end_ptr,char **next,int mod
        char *start = utf_ptr;
        bool error = false;
        utf *name;
-       
+
        SKIP_FIELDDESCRIPTOR_SAFE(utf_ptr,end_ptr,error);
        if (error) return NULL;
        if (next) *next = utf_ptr;
index 35cd9bafc6125e0194689fe3429d2deb3b6fb6c9..3885630b254eaa3b0ca9f8af1abe3bf95f7331df 100644 (file)
--- a/loader.h
+++ b/loader.h
@@ -1,4 +1,4 @@
-/* loader.c - class loader header
+/* loader.h - class loader header
 
    Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
    R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser,
@@ -26,7 +26,7 @@
 
    Authors: Reinhard Grafl
 
-   $Id: loader.h 669 2003-11-23 14:04:20Z edwin $
+   $Id: loader.h 696 2003-12-06 20:10:05Z edwin $
 */
 
 
@@ -106,6 +106,18 @@ classinfo *class_primitive_from_sig(char sig);
 #define CLASSLOAD_SKIP  0
 #define CLASSLOAD_NEW   1
 #define CLASSLOAD_LOAD  2
+
+#if 0
+#define CLASSLOAD_NEW       0x0000 /* default */
+#define CLASSLOAD_LOAD      0x0001
+#define CLASSLOAD_SKIP      0x0002
+#define CLASSLOAD_PANIC     0x0000 /* default */
+#define CLASSLOAD_NOPANIC   0x0010
+#define CLASSLOAD_PRIMITIVE 0x0000 /* default */
+#define CLASSLOAD_VOID      0x0000 /* default */
+#define CLASSLOAD_NOVOID    0x0020
+#endif
+
 classinfo *class_from_descriptor(char *utf_ptr,char *end_ptr,char **next,int mode);
 
 /* (used by class_new, don't use directly) */
diff --git a/main.c b/main.c
index 98649a13f5ec642f8496a1047043ae751e529fea..c01cf4e8cf109063195dfeaf6ef46472019e8d6f 100644 (file)
--- a/main.c
+++ b/main.c
@@ -37,7 +37,7 @@
      - Calling the class loader
      - Running the main method
 
-   $Id: main.c 689 2003-12-05 18:03:47Z stefan $
+   $Id: main.c 696 2003-12-06 20:10:05Z edwin $
 
 */
 
@@ -108,7 +108,8 @@ void **stackbottom = 0;
 #define OPT_INLINING   25
 #define OPT_RT          26
 #define OPT_XTA         27 
-#define OPT_VTA         28 
+#define OPT_VTA         28
+#define OPT_VERBOSETC   29
 
 
 struct {char *name; bool arg; int value;} opts[] = {
@@ -124,6 +125,9 @@ struct {char *name; bool arg; int value;} opts[] = {
        {"verbose",     false,  OPT_VERBOSE},
        {"verbosegc",   false,  OPT_VERBOSEGC},
        {"verbosecall", false,  OPT_VERBOSECALL},
+#ifdef TYPECHECK_VERBOSE
+       {"verbosetc",   false,  OPT_VERBOSETC},
+#endif
 #if defined(__ALPHA__)
        {"noieee",      false,  OPT_NOIEEE},
 #endif
@@ -213,6 +217,9 @@ static void print_usage()
        printf("          -verbose ............. write more information\n");
        printf("          -verbosegc ........... write message for each GC\n");
        printf("          -verbosecall ......... write message for each call\n");
+#ifdef TYPECHECK_VERBOSE
+       printf("          -verbosetc ........... write debug messages while typechecking\n");
+#endif
 #if defined(__ALPHA__)
        printf("          -noieee .............. don't use ieee compliant arithmetic\n");
 #endif
@@ -609,6 +616,12 @@ int main(int argc, char **argv)
                case OPT_VERBOSEGC:
                        collectverbose = true;
                        break;
+
+#ifdef TYPECHECK_VERBOSE
+               case OPT_VERBOSETC:
+                       typecheckverbose = true;
+                       break;
+#endif
                                
                case OPT_VERBOSECALL:
                        runverbose = true;
@@ -835,8 +848,9 @@ int main(int argc, char **argv)
                        a->data[i - opt_ind] = javastring_new(utf_new_char(argv[i]));
                }
 
-#ifdef DEBUG_TYPES
-               typeinfo_test(); /* XXX remove debug */
+#ifdef TYPEINFO_DEBUG_TEST
+               /* test the typeinfo system */
+               typeinfo_test();
 #endif
                /*class_showmethods(currentThread->group->header.vftbl->class); */
        
index 5f5019b7bb2019ab6729e45d1b81fd779c18fa15..dcd1832f047269173306366f78296685673dd36c 100644 (file)
@@ -37,7 +37,7 @@
      - Calling the class loader
      - Running the main method
 
-   $Id: cacao.c 689 2003-12-05 18:03:47Z stefan $
+   $Id: cacao.c 696 2003-12-06 20:10:05Z edwin $
 
 */
 
@@ -108,7 +108,8 @@ void **stackbottom = 0;
 #define OPT_INLINING   25
 #define OPT_RT          26
 #define OPT_XTA         27 
-#define OPT_VTA         28 
+#define OPT_VTA         28
+#define OPT_VERBOSETC   29
 
 
 struct {char *name; bool arg; int value;} opts[] = {
@@ -124,6 +125,9 @@ struct {char *name; bool arg; int value;} opts[] = {
        {"verbose",     false,  OPT_VERBOSE},
        {"verbosegc",   false,  OPT_VERBOSEGC},
        {"verbosecall", false,  OPT_VERBOSECALL},
+#ifdef TYPECHECK_VERBOSE
+       {"verbosetc",   false,  OPT_VERBOSETC},
+#endif
 #if defined(__ALPHA__)
        {"noieee",      false,  OPT_NOIEEE},
 #endif
@@ -213,6 +217,9 @@ static void print_usage()
        printf("          -verbose ............. write more information\n");
        printf("          -verbosegc ........... write message for each GC\n");
        printf("          -verbosecall ......... write message for each call\n");
+#ifdef TYPECHECK_VERBOSE
+       printf("          -verbosetc ........... write debug messages while typechecking\n");
+#endif
 #if defined(__ALPHA__)
        printf("          -noieee .............. don't use ieee compliant arithmetic\n");
 #endif
@@ -609,6 +616,12 @@ int main(int argc, char **argv)
                case OPT_VERBOSEGC:
                        collectverbose = true;
                        break;
+
+#ifdef TYPECHECK_VERBOSE
+               case OPT_VERBOSETC:
+                       typecheckverbose = true;
+                       break;
+#endif
                                
                case OPT_VERBOSECALL:
                        runverbose = true;
@@ -835,8 +848,9 @@ int main(int argc, char **argv)
                        a->data[i - opt_ind] = javastring_new(utf_new_char(argv[i]));
                }
 
-#ifdef DEBUG_TYPES
-               typeinfo_test(); /* XXX remove debug */
+#ifdef TYPEINFO_DEBUG_TEST
+               /* test the typeinfo system */
+               typeinfo_test();
 #endif
                /*class_showmethods(currentThread->group->header.vftbl->class); */
        
index 1610b83ef98cbfecb08dfb2f9ea6b31055d3a3b5..6b84b70b56a0bf703faba5ea06ddd373d6e1eece 100644 (file)
@@ -34,7 +34,7 @@
    calls instead of machine instructions, using the C calling
    convention.
 
-   $Id: builtin.c 689 2003-12-05 18:03:47Z stefan $
+   $Id: builtin.c 696 2003-12-06 20:10:05Z edwin $
 
 */
 
@@ -314,20 +314,20 @@ static s4 builtin_descriptorscompatible(arraydescriptor *desc,arraydescriptor *t
                        
 *****************************************************************************/
 
-s4 builtin_checkarraycast(java_objectheader *o,arraydescriptor *target)
+s4 builtin_checkarraycast(java_objectheader *o,vftbl *target)
 {
        arraydescriptor *desc;
        
        if (!o) return 1;
        if ((desc = o->vftbl->arraydesc) == NULL) return 0;
 
-       return builtin_descriptorscompatible(desc,target);
+       return builtin_descriptorscompatible(desc,target->arraydesc);
 }
 
-s4 builtin_arrayinstanceof(java_objectheader *obj,arraydescriptor *desc)
+s4 builtin_arrayinstanceof(java_objectheader *obj,vftbl *target)
 {
        if (!obj) return 1;
-       return builtin_checkarraycast (obj, desc);
+       return builtin_checkarraycast (obj, target);
 }
 
 /************************** exception functions *******************************
index 98bb11cd92e5b50eeecb17656a6f91a9ba0ce782..68768d35422a8ca412ee4d87b5587532f59b0c02 100644 (file)
@@ -30,12 +30,12 @@ s4 builtin_isanysubclass_vftbl (vftbl *sub, vftbl *super);
 s4 builtin_checkcast(java_objectheader *obj, classinfo *class);
 s4 asm_builtin_checkcast(java_objectheader *obj, classinfo *class);
 
-s4 builtin_arrayinstanceof(java_objectheader *obj, arraydescriptor *desc);
+s4 builtin_arrayinstanceof(java_objectheader *obj, vftbl *target);
 #ifdef __I386__
 s4 asm_builtin_arrayinstanceof(java_objectheader *obj, classinfo *class); /* XXX ? */
 #endif
-s4 builtin_checkarraycast(java_objectheader *obj, arraydescriptor *desc);
-s4 asm_builtin_checkarraycast(java_objectheader *obj, arraydescriptor *desc);
+s4 builtin_checkarraycast(java_objectheader *obj, vftbl *target);
+s4 asm_builtin_checkarraycast(java_objectheader *obj, vftbl *target);
 
 java_objectheader *builtin_throw_exception (java_objectheader *exception);
 java_objectheader *builtin_trace_exception (java_objectheader *exceptionptr,
index 07849fe28924ca3ad5d91872227bf8e661e0e1f9..611feb67da405c978eb14329cd2d7b95e5312a8d 100644 (file)
@@ -31,7 +31,7 @@
             Philipp Tomsich
                        Edwin Steiner
 
-   $Id: global.h 687 2003-12-04 22:29:54Z edwin $
+   $Id: global.h 696 2003-12-06 20:10:05Z edwin $
 
 */
 
  */
 #define SIZE_FROM_CLASSINFO
 
+/*
+ * CACAO_TYPECHECK activates typechecking (part of bytecode verification)
+ */
+#define CACAO_TYPECHECK
+
+/*
+ * Macros for configuration of the typechecking code
+ *
+ * TYPEINFO_DEBUG activates debug checks and debug helpers in typeinfo.c
+ * TYPECHECK_DEBUG activates debug checks in typecheck.c
+ * TYPEINFO_DEBUG_TEST activates the typeinfo test at startup.
+ * TYPECHECK_VERBOSE_IMPORTANT activates important debug messages
+ * TYPECHECK_VERBOSE activates all debug messages
+ */
+#define TYPEINFO_DEBUG
+#define TYPECHECK_DEBUG
+/*#define TYPEINFO_DEBUG_TEST*/
+#define TYPECHECK_VERBOSE
+/*#define TYPECHECK_VERBOSE_IMPORTANT*/
+#if defined(TYPECHECK_VERBOSE) || defined(TYPECHECK_VERBOSE_IMPORTANT)
+#define TYPECHECK_VERBOSE_OPT
+#endif
+
 /* standard includes **********************************************************/
 
 #include <stdio.h>
@@ -749,6 +772,9 @@ extern bool verbose;
 extern bool opt_rt;             /* Rapid Type Analysis for better inlining CO-RT*/
 extern bool opt_xta;            /* X Type Analysis for better inlining    CO-XTA*/
 extern bool opt_vta;            /* Variable Type Analysis for better inlining    CO-VTA*/
+#ifdef TYPECHECK_VERBOSE_OPT
+extern bool typecheckverbose;
+#endif
 
 //extern int pClassHeir;
 //extern int pCallgraph;
index fab6134dc060ecf2c0fa7087db815c0933fc2322..7834c9ab118f343d076642b8a094669445540777 100644 (file)
@@ -1,6 +1,6 @@
 ## Process this file with automake to produce Makefile.in
 
-# $Id: Makefile.am 662 2003-11-21 18:06:25Z jowenn $
+# $Id: Makefile.am 696 2003-12-06 20:10:05Z edwin $
 
 
 SUBDIRS = . loop @ARCH_DIR@
@@ -20,7 +20,8 @@ EXTRA_DIST = \
        sets.h \
        parseRT.c \
        parseRTprint.h \
-       parseRTstats.c
+       parseRTstats.c \
+       typecheck.c
 
 noinst_HEADERS = \
        parse.h \
@@ -32,7 +33,7 @@ noinst_HEADERS = \
 
 noinst_LIBRARIES = libjit.a
 
-libjit_a_SOURCES = jit.c parse.c stack.c inline.c sets.c parseRT.c parseRTstats.c
+libjit_a_SOURCES = jit.c parse.c stack.c inline.c sets.c parseRT.c parseRTstats.c typecheck.c
 
 all-local:
        $(MAKE) $(AM_MAKEFLAGS) -C .. jit/@ARCH_DIR@/offsets.h
index aef4d5ae9170e5a95be72a81cfa02aeca6e2485c..efe81aa6a91e687907cc3dec1bb297d49f5840d7 100644 (file)
@@ -27,7 +27,7 @@
    Authors: Andreas Krall
             Reinhard Grafl
 
-   $Id: jit.c 689 2003-12-05 18:03:47Z stefan $
+   $Id: jit.c 696 2003-12-06 20:10:05Z edwin $
 
 */
 
@@ -195,6 +195,8 @@ bool isleafmethod;              /* true if a method doesn't call subroutines  */
 
 basicblock *last_block;         /* points to the end of the BB list           */
 
+bool regs_ok;                   /* true if registers have been allocated      */
+
 /* list of all classes used by the compiled method which have to be           */
 /* initialised (if not already done) before execution of this method          */
 chain *uninitializedclasses;
@@ -1343,7 +1345,8 @@ methodptr jit_compile(methodinfo *m)
        count_methods++;
 
        intsDisable();      /* disable interrupts */
-       
+
+       regs_ok = false;
 
        /* mark start of dump memory area */
 
@@ -1427,6 +1430,10 @@ methodptr jit_compile(methodinfo *m)
        parse();
        analyse_stack();
    
+#ifdef CACAO_TYPECHECK
+       typecheck();
+#endif
+       
        if (opt_loops) {
                depthFirst();
                analyseGraph();
@@ -1438,6 +1445,7 @@ methodptr jit_compile(methodinfo *m)
 #endif
 
        regalloc();
+       regs_ok = true;
        codegen();
 
        /* intermediate and assembly code listings ********************************/
index 9a4dc6756be6a01c0d1117917cd745c12adde1db..a7fb78dda78e70319192e16d621041d37213665a 100644 (file)
@@ -29,7 +29,7 @@
 
    Changes: Christian Thalinger
 
-   $Id: jit.h 665 2003-11-21 18:36:43Z jowenn $
+   $Id: jit.h 696 2003-12-06 20:10:05Z edwin $
 
 */
 
@@ -39,6 +39,7 @@
 
 #include "toolbox/chain.h"
 #include "global.h"
+#include "typeinfo.h"
 
 /**************************** resolve typedef-cycles **************************/
 
@@ -59,6 +60,7 @@ typedef varinfo *varinfoptr;
 
 /* slot types */
 
+/* XXX use TYPE_ADDRESS, ...? */
 #define TYPE_INT   0            /* the stack slot types must numbered in the  */
 #define TYPE_LNG   1            /* same order as the ICMD_Ixxx to ICMD_Axxx   */
 #define TYPE_FLT   2            /* instructions (LOAD and STORE)              */
@@ -88,6 +90,9 @@ typedef varinfo *varinfoptr;
 struct stackelement {
        stackptr prev;              /* pointer to next element towards bottom     */
        int type;                   /* slot type of stack element                 */
+#ifdef CACAO_TYPECHECK
+       typeinfo typeinfo;          /* info on reference types                    */
+#endif
        int flags;                  /* flags (SAVED, INMEMORY)                    */
        int varkind;                /* kind of variable or register               */
        int varnum;                 /* number of variable                         */
@@ -124,6 +129,8 @@ struct instruction {
 #define BBUNDEF    -1
 #define BBREACHED  0
 #define BBFINISHED 1
+#define BBTYPECHECK_UNDEF    2
+#define BBTYPECHECK_REACHED  3
 
 #define BBTYPE_STD 0            /* standard basic block type                  */
 #define BBTYPE_EXH 1            /* exception handler basic block type         */
@@ -948,6 +955,9 @@ extern bool isleafmethod;       /* true if a method doesn't call subroutines  */
 
 extern basicblock *last_block;  /* points to the end of the BB list           */
 
+extern bool regs_ok;            /* true if registers have been allocated      */
+
+
 /* list of all classes used by the compiled method which have to be           */
 /* initialised (if not already done) before execution of this method          */
 extern chain *uninitializedclasses;
@@ -968,6 +978,13 @@ u1 *createnativestub(functionptr f, methodinfo *m);
 void removecompilerstub(u1 *stub);
 void removenativestub(u1 *stub);
 
+/* debug helpers (in stack.c) */
+
+void icmd_print_stack(stackptr s);
+void show_icmd_block(basicblock *bptr);
+void show_icmd(instruction *iptr,bool deadcode);
+void show_icmd_method();
+
 #endif /* _JIT_H */
 
 
index e5866614c805d51a89c6fd34f424fcd189eed9c1..3e299b1a4850ede1e0eff81aeb73c598e02235c6 100644 (file)
@@ -27,8 +27,9 @@
    Author: Andreas Krall
 
    Changes: Carolyn Oates
+            Edwin Steiner
 
-   $Id: parse.c 689 2003-12-05 18:03:47Z stefan $
+   $Id: parse.c 696 2003-12-06 20:10:05Z edwin $
 
 */
 
@@ -1240,7 +1241,7 @@ void parse()
                                        classinfo *cls = (classinfo*)class_getconstant(class, i, CONSTANT_Class);
                                        if (cls->vftbl->arraydesc) {
                                                /* array type cast-check */
-                                               LOADCONST_A(cls->vftbl->arraydesc);
+                                               LOADCONST_A(cls->vftbl);
                                                s_count++;
                                                BUILTIN2((functionptr) asm_builtin_checkarraycast, TYPE_ADR);
                                        }
@@ -1263,7 +1264,7 @@ void parse()
                                        classinfo *cls = (classinfo*)class_getconstant(class, i, CONSTANT_Class);
                                        if (cls->vftbl->arraydesc) {
                                                /* array type cast-check */
-                                               LOADCONST_A(cls->vftbl->arraydesc);
+                                               LOADCONST_A(cls->vftbl);
                                                s_count++;
   #if defined(__I386__)
                                                BUILTIN2((functionptr) asm_builtin_arrayinstanceof, TYPE_INT);
index 676f3d7f79581ac3db336571ed9bf88c28207f2c..4799a064a60dab5dbd623e5b6689848f75d408f6 100644 (file)
@@ -26,7 +26,9 @@
 
    Authors: Andreas Krall
 
-   $Id: stack.c 665 2003-11-21 18:36:43Z jowenn $
+   Changes: Edwin Steiner
+
+   $Id: stack.c 696 2003-12-06 20:10:05Z edwin $
 
 */
 
@@ -1478,6 +1480,12 @@ void analyse_stack()
 
                                                iptr[0].target = (void *) tbptr;
 
+                                               /* XXX This is a dirty hack. The typechecker
+                                                * needs it because the OP1_0ANY below
+                                                * overwrites iptr->dst.
+                                                */
+                                               iptr->val.a = (void*) iptr->dst;
+
                                                tbptr->type=BBTYPE_SBR;
                                                MARKREACHED(tbptr, copy);
                                                OP1_0ANY;
@@ -1734,7 +1742,7 @@ void analyse_stack()
 }
 
 
-static void print_stack(stackptr s)
+void icmd_print_stack(stackptr s)
 {
        int i, j;
        stackptr t;
@@ -1751,15 +1759,17 @@ static void print_stack(stackptr s)
                printf("    ");
        while (s) {
                j--;
+               /* XXX remove */ /* printf("(%d)",s->flags); fflush(stdout); */
                if (s->flags & SAVEDVAR)
                        switch (s->varkind) {
                        case TEMPVAR:
                                if (s->flags & INMEMORY)
-                                       printf(" M%02d", s->regoff);
+                                       printf((regs_ok) ? " M%02d" : " M??", s->regoff);
                                else if ((s->type == TYPE_FLT) || (s->type == TYPE_DBL))
-                                       printf(" F%02d", s->regoff);
-                               else
-                                       printf(" %3s", regs[s->regoff]);
+                                       printf((regs_ok) ? " F%02d" : " F??", s->regoff);
+                               else {
+                                       if (regs_ok) printf(" %3s",regs[s->regoff]); else printf(" ???");
+                               }
                                break;
                        case STACKVAR:
                                printf(" I%02d", s->varnum);
@@ -1777,11 +1787,12 @@ static void print_stack(stackptr s)
                        switch (s->varkind) {
                        case TEMPVAR:
                                if (s->flags & INMEMORY)
-                                       printf(" m%02d", s->regoff);
+                                       printf((regs_ok) ? " m%02d" : " m??", s->regoff);
                                else if ((s->type == TYPE_FLT) || (s->type == TYPE_DBL))
-                                       printf(" f%02d", s->regoff);
-                               else
-                                       printf(" %3s", regs[s->regoff]);
+                                       printf((regs_ok) ? " f%02d" : " f??", s->regoff);
+                               else {
+                                       if (regs_ok) printf(" %3s",regs[s->regoff]); else printf(" ???");
+                               }
                                break;
                        case STACKVAR:
                                printf(" i%02d", s->varnum);
@@ -1851,7 +1862,7 @@ static void print_reg(stackptr s) {
 #endif
 
 
-static char *builtin_name(functionptr bptr)
+char *icmd_builtin_name(functionptr bptr)
 {
        builtin_descriptor *bdesc = builtin_desc;
        while ((bdesc->bptr != NULL) && (bdesc->bptr != bptr))
@@ -1902,11 +1913,12 @@ void show_icmd_method()
                        if (locals[i][j].type >= 0) {
                                printf("   (%s) ", jit_type[j]);
                                if (locals[i][j].flags & INMEMORY)
-                                       printf("m%2d", locals[i][j].regoff);
+                                       printf((regs_ok) ? "m%2d" : "m??", locals[i][j].regoff);
                                else if ((j == TYPE_FLT) || (j == TYPE_DBL))
-                                       printf("f%02d", locals[i][j].regoff);
-                               else
-                                       printf("%3s", regs[locals[i][j].regoff]);
+                                       printf((regs_ok) ? "f%02d" : "f??", locals[i][j].regoff);
+                               else {
+                                       if (regs_ok) printf("%3s",regs[locals[i][j].regoff]); else printf("???");
+                               }
                        }
                printf("\n");
        }
@@ -1923,19 +1935,21 @@ void show_icmd_method()
                                        printf("   (%s) ", jit_type[j]);
                                        if (interfaces[i][j].flags & SAVEDVAR) {
                                                if (interfaces[i][j].flags & INMEMORY)
-                                                       printf("M%2d", interfaces[i][j].regoff);
+                                                       printf((regs_ok) ? "M%2d" : "M??", interfaces[i][j].regoff);
                                                else if ((j == TYPE_FLT) || (j == TYPE_DBL))
-                                                       printf("F%02d", interfaces[i][j].regoff);
-                                               else
-                                                       printf("%3s", regs[interfaces[i][j].regoff]);
+                                                       printf((regs_ok) ? "F%02d" : "F??", interfaces[i][j].regoff);
+                                               else {
+                                                       if (regs_ok) printf("%3s",regs[interfaces[i][j].regoff]); else printf("???");
+                                               }
                                        }
                                        else {
                                                if (interfaces[i][j].flags & INMEMORY)
-                                                       printf("m%2d", interfaces[i][j].regoff);
+                                                       printf((regs_ok) ? "m%2d" : "m??", interfaces[i][j].regoff);
                                                else if ((j == TYPE_FLT) || (j == TYPE_DBL))
-                                                       printf("f%02d", interfaces[i][j].regoff);
-                                               else
-                                                       printf("%3s", regs[interfaces[i][j].regoff]);
+                                                       printf((regs_ok) ? "f%02d" : "f??", interfaces[i][j].regoff);
+                                               else {
+                                                       if (regs_ok) printf("%3s",regs[interfaces[i][j].regoff]); else printf("???");
+                                               }
                                        }
                                }
                        printf("\n");
@@ -1966,27 +1980,99 @@ void show_icmd_method()
 
        
        for (bptr = block; bptr != NULL; bptr = bptr->next) {
+               show_icmd_block(bptr);
+       }
+}
+
+void
+show_icmd_block(basicblock *bptr)
+{
+       int i, j;
+       int deadcode;
+       s4  *s4ptr;
+       instruction *iptr;
+
                if (bptr->flags != BBDELETED) {
                        deadcode = bptr->flags <= BBREACHED;
                        printf("[");
                        if (deadcode)
-                               for (j = maxstack; j > 0; j--)
+                               for (j = method->maxstack; j > 0; j--)
                                        printf(" ?  ");
                        else
-                               print_stack(bptr->instack);
-                       printf("] L%03d(%d - %d):\n", bptr->debug_nr, bptr->icount, bptr->pre_count);
+                               icmd_print_stack(bptr->instack);
+                       printf("] L%03d(%d - %d) flags=%d:\n", bptr->debug_nr, bptr->icount, bptr->pre_count,bptr->flags);
                        iptr = bptr->iinstr;
 
                        for (i=0; i < bptr->icount; i++, iptr++) {
                                printf("[");
                                if (deadcode) {
-                                       for (j = maxstack; j > 0; j--)
+                                       for (j = method->maxstack; j > 0; j--)
                                                printf(" ?  ");
                                }
                                else
-                                       print_stack(iptr->dst);
-                               printf("]     %4d  %s", i, icmd_names[iptr->opc]);
-                               switch ((int) iptr->opc) {
+                                       icmd_print_stack(iptr->dst);
+                               printf("]     %4d  ", i);
+                               /* XXX remove */ /*fflush(stdout);*/
+                               show_icmd(iptr,deadcode);
+                               printf("\n");
+                       }
+
+                       if (showdisassemble && (!deadcode)) {
+#if defined(__I386__) || defined(__X86_64__)
+                               u1 *u1ptr;
+                               int a;
+
+                               printf("\n");
+                               i = bptr->mpc;
+                               u1ptr = method->mcode + dseglen + i;
+
+                               if (bptr->next != NULL) {
+                                       for (; i < bptr->next->mpc; i++, u1ptr++) {
+                                               a = disassinstr(u1ptr, i);
+                                               i += a;
+                                               u1ptr += a;
+                                       }
+                                       printf("\n");
+
+                               } else {
+                                       for (; u1ptr < (u1 *) (method->mcode + method->mcodelength); i++, u1ptr++) {
+                                               a = disassinstr(u1ptr, i); 
+                                               i += a;
+                                               u1ptr += a;
+                                       }
+                                       printf("\n");
+                               }
+#else
+                               printf("\n");
+                               i = bptr->mpc;
+                               s4ptr = (s4 *) (method->mcode + dseglen + i);
+
+                               if (bptr->next != NULL) {
+                                       for (; i < bptr->next->mpc; i += 4, s4ptr++) {
+                                               disassinstr(*s4ptr, i); 
+                                   }
+                                       printf("\n");
+                           }
+                               else {
+                                       for (; s4ptr < (s4 *) (method->mcode + method->mcodelength); i += 4, s4ptr++) {
+                                               disassinstr(*s4ptr, i); 
+                                   }
+                                       printf("\n");
+                           }
+#endif
+                   }
+               }
+}
+
+void
+show_icmd(instruction *iptr,bool deadcode)
+{
+       int j;
+       s4  *s4ptr;
+       void **tptr;
+       
+       printf("%s",icmd_names[iptr->opc]);
+       switch ((int) iptr->opc) {
                                case ICMD_IADDCONST:
                                case ICMD_ISUBCONST:
                                case ICMD_IMULCONST:
@@ -2137,7 +2223,7 @@ void show_icmd_method()
                                case ICMD_BUILTIN3:
                                case ICMD_BUILTIN2:
                                case ICMD_BUILTIN1:
-                                       printf(" %s", builtin_name((functionptr) iptr->val.a));
+                                       printf(" %s", icmd_builtin_name((functionptr) iptr->val.a));
                                        break;
                                case ICMD_INVOKEVIRTUAL:
                                case ICMD_INVOKESPECIAL:
@@ -2156,7 +2242,10 @@ void show_icmd_method()
                                case ICMD_IFGE:
                                case ICMD_IFGT:
                                case ICMD_IFLE:
-                                       printf("(%d) L%03d", iptr->val.i, ((basicblock *) iptr->target)->debug_nr);
+                                       if (deadcode)
+                                               printf("(%d) op1=%d", iptr->val.i, iptr->op1);
+                                       else
+                                               printf("(%d) L%03d", iptr->val.i, ((basicblock *) iptr->target)->debug_nr);
                                        break;
                                case ICMD_IF_LEQ:
                                case ICMD_IF_LNE:
@@ -2164,7 +2253,10 @@ void show_icmd_method()
                                case ICMD_IF_LGE:
                                case ICMD_IF_LGT:
                                case ICMD_IF_LLE:
-                                       printf("(%lld) L%03d", iptr->val.l, ((basicblock *) iptr->target)->debug_nr);
+                                       if (deadcode)
+                                               printf("(%lld) op1=%d", iptr->val.l, iptr->op1);
+                                       else
+                                               printf("(%lld) L%03d", iptr->val.l, ((basicblock *) iptr->target)->debug_nr);
                                        break;
                                case ICMD_JSR:
                                case ICMD_GOTO:
@@ -2184,94 +2276,65 @@ void show_icmd_method()
                                case ICMD_IF_LCMPLE:
                                case ICMD_IF_ACMPEQ:
                                case ICMD_IF_ACMPNE:
-                                       printf(" L%03d", ((basicblock *) iptr->target)->debug_nr);
+                                       if (deadcode)
+                                               printf(" op1=%d", iptr->op1);
+                                       else
+                                               printf(" L%03d", ((basicblock *) iptr->target)->debug_nr);
                                        break;
                                case ICMD_TABLESWITCH:
 
                                        s4ptr = iptr->val.a;
-                                       tptr = (void **) iptr->target;
-
-                                       printf(" L%03d;", ((basicblock *) *tptr)->debug_nr); 
-                                       /* default */
 
-                                       s4ptr++;
-                                       tptr++;
+                                       if (deadcode) {
+                                               printf(" %d;", *s4ptr);
+                                       }
+                                       else {
+                                               tptr = (void **) iptr->target;
+                                               printf(" L%03d;", ((basicblock *) *tptr)->debug_nr); 
+                                               tptr++;
+                                       }
 
+                                       s4ptr++;         /* skip default */
                                        j = *s4ptr++;                               /* low     */
                                        j = *s4ptr++ - j;                           /* high    */
                                        while (j >= 0) {
-                                               printf(" L%03d", ((basicblock *) *tptr)->debug_nr);
-                                               tptr++;
+                                               if (deadcode)
+                                                       printf(" %d", *s4ptr++);
+                                               else {
+                                                       printf(" L%03d", ((basicblock *) *tptr)->debug_nr);
+                                                       tptr++;
+                                               }
                                                j--;
                                        }
                                        break;
                                case ICMD_LOOKUPSWITCH:
                                        s4ptr = iptr->val.a;
-                                       tptr = (void **) iptr->target;
-
-                                       printf(" L%03d", ((basicblock *) *tptr)->debug_nr); 
-                                       s4ptr++;                                         /* default */
-                                       j = *s4ptr;                                      /* count   */
-                                       tptr++;
 
-                                       while (--j >= 0) {
+                                       if (deadcode) {
+                                               printf(" %d;", *s4ptr);
+                                       }
+                                       else {
+                                               tptr = (void **) iptr->target;
                                                printf(" L%03d", ((basicblock *) *tptr)->debug_nr);
                                                tptr++;
                                        }
-                                       break;
-                               }
-                               printf("\n");
-                       }
-
-                       if (showdisassemble && (!deadcode)) {
-#if defined(__I386__) || defined(__X86_64__)
-                               u1 *u1ptr;
-                               int a;
-
-                               printf("\n");
-                               i = bptr->mpc;
-                               u1ptr = method->mcode + dseglen + i;
-
-                               if (bptr->next != NULL) {
-                                       for (; i < bptr->next->mpc; i++, u1ptr++) {
-                                               a = disassinstr(u1ptr, i);
-                                               i += a;
-                                               u1ptr += a;
-                                       }
-                                       printf("\n");
+                                       s4ptr++;                                         /* default */
+                                       j = *s4ptr++;                                    /* count   */
 
-                               } else {
-                                       for (; u1ptr < (u1 *) (method->mcode + method->mcodelength); i++, u1ptr++) {
-                                               a = disassinstr(u1ptr, i); 
-                                               i += a;
-                                               u1ptr += a;
+                                       while (--j >= 0) {
+                                               if (deadcode) {
+                                                       s4ptr++; /* skip value */
+                                                       printf(" %d",*s4ptr++);
+                                               }
+                                               else {
+                                                       printf(" L%03d", ((basicblock *) *tptr)->debug_nr);
+                                                       tptr++;
+                                               }
                                        }
-                                       printf("\n");
-                               }
-#else
-                               printf("\n");
-                               i = bptr->mpc;
-                               s4ptr = (s4 *) (method->mcode + dseglen + i);
-
-                               if (bptr->next != NULL) {
-                                       for (; i < bptr->next->mpc; i += 4, s4ptr++) {
-                                               disassinstr(*s4ptr, i); 
-                                   }
-                                       printf("\n");
-                           }
-                               else {
-                                       for (; s4ptr < (s4 *) (method->mcode + method->mcodelength); i += 4, s4ptr++) {
-                                               disassinstr(*s4ptr, i); 
-                                   }
-                                       printf("\n");
-                           }
-#endif
-                   }
-               }
+                                       break;
        }
 }
 
-
 /*
  * These are local overrides for various environment variables in Emacs.
  * Please do not remove this and leave it at the end of the file, where
diff --git a/src/vm/jit/verify/typecheck.c b/src/vm/jit/verify/typecheck.c
new file mode 100644 (file)
index 0000000..44ffacf
--- /dev/null
@@ -0,0 +1,1476 @@
+/* jit/typecheck.c - typechecking (part of bytecode verification)
+
+   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
+   R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser,
+   M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck,
+   P. Tomsich, J. Wenninger
+
+   This file is part of CACAO.
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2, or (at
+   your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+   02111-1307, USA.
+
+   Contact: cacao@complang.tuwien.ac.at
+
+   Authors: Edwin Steiner
+
+   $Id: typecheck.c 696 2003-12-06 20:10:05Z edwin $
+
+*/
+
+#include "global.h" /* must be here because of CACAO_TYPECHECK */
+
+#ifdef CACAO_TYPECHECK
+
+#include "jit.h"
+#include "builtin.h"
+#include "tables.h"
+#include "loader.h"
+#include "types.h"
+#include "toolbox/loging.h"
+#include "toolbox/memory.h"
+
+#define TOUCHED_YES    0x01
+#define TOUCHED_NO     0x02
+#define TOUCHED_MAYBE  (TOUCHED_YES | TOUCHED_NO)
+
+#define REACH_STD      0
+#define REACH_JSR      1
+#define REACH_RET      2
+
+/****************************************************************************/
+/* DEBUG HELPERS                                                            */
+/****************************************************************************/
+
+#ifdef TYPECHECK_VERBOSE_OPT
+bool typecheckverbose = false;
+#define DOLOG(action)  do { if (typecheckverbose) {action;} } while(0)
+#else
+#define DOLOG(action)
+#endif
+
+#ifdef TYPECHECK_VERBOSE
+#define TYPECHECK_VERBOSE_IMPORTANT
+#define LOG(str)           DOLOG(log_text(str))
+#define LOG1(str,a)        DOLOG(dolog(str,a))
+#define LOG2(str,a,b)      DOLOG(dolog(str,a,b))
+#define LOG3(str,a,b,c)    DOLOG(dolog(str,a,b,c))
+#define LOGIF(cond,str)    DOLOG(do {if (cond) log_text(str);} while(0))
+#define LOGINFO(info)      DOLOG(do {typeinfo_print_short(stdout,info);printf("\n");} while(0))
+#define LOGFLUSH           DOLOG(fflush(stdout))
+#define LOGNL              DOLOG(printf("\n"))
+#define LOGSTR(str)        DOLOG(printf(str))
+#define LOGSTR1(str,a)     DOLOG(printf(str,a))
+#define LOGSTR2(str,a,b)   DOLOG(printf(str,a,b))
+#define LOGSTR3(str,a,b,c) DOLOG(printf(str,a,b,c))
+#define LOGSTRu(utf)       DOLOG(utf_display(utf))
+#else
+#define LOG(str)
+#define LOG1(str,a)
+#define LOG2(str,a,b)
+#define LOG3(str,a,b,c)
+#define LOGIF(cond,str)
+#define LOGINFO(info)
+#define LOGFLUSH
+#define LOGNL
+#define LOGSTR(str)
+#define LOGSTR1(str,a)
+#define LOGSTR2(str,a,b)
+#define LOGSTR3(str,a,b,c)
+#endif
+
+#ifdef TYPECHECK_VERBOSE_IMPORTANT
+#define LOGimp(str)     DOLOG(log_text(str))
+#define LOGimpSTR(str)  DOLOG(printf(str))
+#define LOGimpSTRu(utf) DOLOG(utf_display(utf))
+#else
+#define LOGimp(str)
+#define LOGimpSTR(str)
+#define LOGimpSTRu(utf)
+#endif
+
+#if defined(TYPECHECK_VERBOSE) || defined(TYPECHECK_VERBOSE_IMPORTANT)
+
+static
+void
+typeinfo_print_locals(FILE *file,u1 *vtype,typeinfo *vinfo,u1 *touched,int num)
+{
+    int i;
+
+    for (i=0; i<num; ++i) {
+        if (touched)
+            fprintf(file," %d%s=",i,
+                    (touched[i]==TOUCHED_YES) ? "*"
+                    : ((touched[i]==TOUCHED_NO) ? "" : "~"));
+        else
+            fprintf(file," %d=",i);
+        typeinfo_print_type(file,vtype[i],vinfo+i);
+    }
+}
+
+static
+void
+typeinfo_print_stack(FILE *file,stackptr stack)
+{
+    while (stack) {
+        typeinfo_print_type(file,stack->type,&stack->typeinfo);
+        stack = stack->prev;
+        if (stack) fprintf(file," ");
+    }
+}
+
+static
+void
+typeinfo_print_block(FILE *file,stackptr instack,
+                     u1 *vtype,typeinfo *vinfo,u1 *touched)
+{
+    fprintf(file,"Stack: ");
+    typeinfo_print_stack(file,instack);
+    fprintf(file," Locals:");
+    typeinfo_print_locals(file,vtype,vinfo,touched,maxlocals);
+}
+
+
+static
+void
+typeinfo_print_blocks(FILE *file,u1 *vtype,typeinfo *vinfo)
+{
+    int bi;
+    /*    int j;*/
+
+    for (bi=0; bi<block_count; ++bi) {
+        fprintf(file,"%04d: (%3d) ",bi,block[bi].flags);
+        typeinfo_print_block(file,block[bi].instack,
+                             vtype+maxlocals*bi,vinfo+maxlocals*bi,NULL);
+        fprintf(file,"\n");
+
+/*         for (j=0; j<block[bi].icount; ++j) { */
+/*             fprintf(file,"\t%s\n",icmd_names[block[bi].iinstr[j].opc]); */
+/*         } */
+
+        show_icmd_block(block+bi);
+    }
+}
+
+#endif
+
+/****************************************************************************/
+/* INTERNAL DATA STRUCTURES                                                 */
+/****************************************************************************/
+
+typedef struct jsr_record jsr_record;
+
+/*
+ * For each basic block we store the chain of JSR instructions which
+ * were used to reach the block (usually zero or one). For more
+ * details on verifying JSR and RET instructions see the Java VM
+ * Specification.
+ *
+ * CAUTION: The fields starting with sbr_ are only valid for the
+ * jsr_record of the first block of the subroutine.
+ */
+struct jsr_record {
+    basicblock *target;      /* target of the JSR instruction (first block of subroutine) */
+    jsr_record *next;        /* for chaining in nested try ... finally */ /* XXX make it sbr_next? */
+    u1         *sbr_touched; /* specifies which variables the subroutine touches */
+    u1         *sbr_vtype;   /* Types of local variables after RET */
+    typeinfo   *sbr_vinfo;   /* Types of local variables after RET */
+    u1          touched[1];  /* touched flags for local variables */
+};
+
+/****************************************************************************/
+/* MACROS USED INTERNALLY IN typecheck()                                    */
+/****************************************************************************/
+
+#define TOUCH_VARIABLE(num) do {if (jsrchain) touched[num] = TOUCHED_YES;} while (0)
+#define TOUCH_TWOWORD(num)  do {TOUCH_VARIABLE(num);TOUCH_VARIABLE((num)+1);} while (0)
+
+/* XXX should check num in range? */
+/* XXX invalidate two word variables on store in second half! */
+#define STORE_TYPE(num,type)       do {vtype[(num)] = (type); TOUCH_VARIABLE(num);} while(0)
+#define STORE_INVALID(num)         STORE_TYPE((num),TYPE_VOID)
+#define STORE_PRIMITIVE(num,type)  STORE_TYPE((num),(type))
+#define STORE_TWOWORD(num,type)    {STORE_PRIMITIVE((num),(type));STORE_INVALID((num)+1);}
+
+#define CHECKVARTYPE(num,type)  \
+            {if (vtype[(num)] != (type)) panic("Variable type mismatch"); TOUCH_VARIABLE(num);}
+
+/* XXX maybe it's faster to copy always */
+#define COPYTYPE(source,dest)   \
+            {if ((source)->type == TYPE_ADR) \
+                 TYPEINFO_COPY((source)->typeinfo,(dest)->typeinfo);}
+
+#define ISBUILTIN(v)   (iptr->val.a == (functionptr)(v))
+
+/* TYPECHECK_COPYVARS: copy the types and typeinfos of the current local
+ *     variables to the local variables of the target block.
+ * Input:
+ *     vtype......current local variable types
+ *     vinfo......current local variable typeinfos
+ *     ttype......local variable types of target block
+ *     tinfo......local variable typeinfos of target block
+ *     maxlocals..number of local variables
+ * Used:
+ *     macro_i
+ */
+#define TYPECHECK_COPYVARS                                      \
+    LOG("TYPECHECK_COPYVARS");                                  \
+    for (macro_i=0; macro_i<maxlocals; ++macro_i) {             \
+        if ((ttype[macro_i] = vtype[macro_i]) == TYPE_ADR)      \
+            TYPEINFO_CLONE(vinfo[macro_i],tinfo[macro_i]);      \
+    }
+
+/* TYPECHECK_MERGEVARS: merge the local variables of the target block
+ *     with the current local variables.
+ * Input:
+ *     vtype......current local variable types
+ *     vinfo......current local variable typeinfos
+ *     ttype......local variable types of target block
+ *     tinfo......local variable typeinfos of target block
+ *     maxlocals..number of local variables
+ * Ouput:
+ *     changed....set to true if any typeinfo has changed
+ * Used:
+ *     macro_i
+ */
+#define TYPECHECK_MERGEVARS                                             \
+    LOG("TYPECHECK_MERGEVARS");                                         \
+    for (macro_i=0; macro_i<maxlocals; ++macro_i) {                     \
+        if ((ttype[macro_i] != TYPE_VOID) && (vtype[macro_i] != ttype[macro_i])) { \
+            LOG3("var %d: type %d + type %d = void",macro_i,ttype[macro_i],vtype[macro_i]); \
+            ttype[macro_i] = TYPE_VOID;                                 \
+            changed = true;                                             \
+        } else if (ttype[macro_i] == TYPE_ADR) {                        \
+            if ( ((TYPEINFO_IS_PRIMITIVE(tinfo[macro_i])) ? 1 : 0)      \
+                 ^                                                      \
+                 ((TYPEINFO_IS_PRIMITIVE(vinfo[macro_i])) ? 1 : 0)) {   \
+                LOG1("var %d: primitive + reference merge",macro_i);    \
+                ttype[macro_i] = TYPE_VOID;                             \
+                changed = true;                                         \
+            }                                                           \
+            else {                                                      \
+                LOG1("var %d:",macro_i);                                \
+                LOGINFO(tinfo+macro_i);                                 \
+                LOGINFO(vinfo+macro_i);                                 \
+                changed |= typeinfo_merge(tinfo+macro_i,vinfo+macro_i); \
+                LOGINFO(tinfo+macro_i);                                 \
+                LOGIF(changed,"vars have changed");                     \
+            }                                                           \
+        };                                                              \
+    }
+
+/* TYPECHECK_MERGEJSR:
+ *
+ * Input:
+ * Ouput:
+ *     tbptr......target block
+ *     changed....set to true if any typeinfo has changed
+ *     maxlocals..number of local variables
+ *     touched....current touched flags of local variables
+ * Used:
+ *     macro_i, jsrtemp, jsrtemp2
+ */
+#define TYPECHECK_MERGEJSR                                              \
+    do {                                                                \
+        LOG("TYPECHECK_MERGEJSR");                                      \
+    jsrtemp = jsrbuffer[tbptr-block];                                   \
+    jsrtemp2 = jsrchain;                                                \
+    while (jsrtemp || jsrtemp2) {                                       \
+        if (!jsrtemp || !jsrtemp2)                                      \
+            panic("Merging JSR subroutines of different depth");        \
+        if (jsrtemp->target != jsrtemp2->target)                        \
+            panic("Merging different JSR subroutines");                 \
+        jsrtemp = jsrtemp->next;                                        \
+        jsrtemp2 = jsrtemp2->next;                                      \
+    }                                                                   \
+    jsrtemp = jsrbuffer[tbptr-block];                                   \
+    if (jsrtemp)                                                        \
+        for (macro_i=0; macro_i<maxlocals; ++macro_i) {                 \
+            jsrtemp->touched[i] |= touched[i];                          \
+    } } while (0)
+
+/* TYPECHECK_COPYSTACK: copy the typeinfos of the current stack to
+ *     the input stack of the target block.
+ * Input:
+ *     srcstack...current stack
+ *     dststack...input stack of target block
+ */
+#define TYPECHECK_COPYSTACK                                             \
+    LOG("TYPECHECK_COPYSTACK");                                         \
+    while (srcstack) {                                                  \
+        LOG1("copy %d",srcstack->type);                                 \
+        if (!dststack) panic("Stack depth mismatch");                   \
+        if (srcstack->type != dststack->type)                           \
+            panic("Type mismatch on stack");                            \
+        if (srcstack->type == TYPE_ADR) {                               \
+            TYPEINFO_CLONE(srcstack->typeinfo,dststack->typeinfo);      \
+        }                                                               \
+        dststack = dststack->prev;                                      \
+        srcstack = srcstack->prev;                                      \
+    }                                                                   \
+    if (dststack) panic("Stack depth mismatch");
+
+/* TYPECHECK_MERGESTACK: merge the input stack of the target block
+ *     with the current stack.
+ * Input:
+ *     srcstack...current stack
+ *     dststack...input stack of target block
+ * Ouput:
+ *     changed....set to true if any typeinfo has changed
+ */
+#define TYPECHECK_MERGESTACK                                            \
+    LOG("TYPECHECK_MERGESTACK");                                        \
+    while (srcstack) {                                                  \
+        if (!dststack) panic("Stack depth mismatch");                   \
+        if (srcstack->type != dststack->type)                           \
+            panic("Type mismatch on stack");                            \
+        if (srcstack->type == TYPE_ADR) {                               \
+            LOGINFO(&dststack->typeinfo);                               \
+            LOGINFO(&srcstack->typeinfo);  LOGFLUSH;                    \
+            changed |= typeinfo_merge(&dststack->typeinfo,              \
+                                      &srcstack->typeinfo);             \
+            LOGINFO(&dststack->typeinfo);                               \
+            LOG((changed)?"CHANGED!\n":"not changed.\n");               \
+        }                                                               \
+        dststack = dststack->prev;                                      \
+        srcstack = srcstack->prev;                                      \
+    }                                                                   \
+    if (dststack) panic("Stack depth mismatch");
+
+
+/* TYPECHECK_CHECK_JSR_CHAIN: checks if the target block is reached by
+ *     the same JSR targets on all control paths.
+ *
+ * Input:
+ *     tbptr......target block
+ *     jsrchain...current JSR target chain
+ *     jsrbuffer..JSR target chain for each basic block
+ * Output:
+ *     panic if the JSR target chains don't match
+ * Used:
+ *     jsrtemp, jsrtemp2
+ */
+#define TYPECHECK_CHECK_JSR_CHAIN                                       \
+    do {                                                                \
+    jsrtemp = jsrbuffer[tbptr-block];                                   \
+    if (!jsrtemp) panic("non-subroutine called by JSR");                \
+    if (jsrtemp->target != tbptr)                                       \
+        panic("Merging different JSR subroutines");                     \
+    jsrtemp = jsrtemp->next;                                            \
+    jsrtemp2 = jsrchain;                                                \
+    while (jsrtemp || jsrtemp2) {                                       \
+        if (!jsrtemp || !jsrtemp2)                                      \
+            panic("Merging JSR subroutines of different depth");        \
+        if (jsrtemp->target != jsrtemp2->target)                        \
+            panic("Merging different JSR subroutines");                 \
+        jsrtemp = jsrtemp->next;                                        \
+        jsrtemp2 = jsrtemp2->next;                                      \
+    } } while (0)
+
+/* TYPECHECK_ADD_JSR: add a JSR target to the current JSR target chain
+ *     and store the resulting chain in the target block.
+ *
+ * Input:
+ *     jsrchain...current JSR target chain
+ *     tbptr.....the basic block targeted by the JSR
+ *     maxlocals..number of local variables
+ *     jsrbuffer..JSR target chain for each basic block
+ * Used:
+ *     jsrtemp
+ */
+#define TYPECHECK_ADD_JSR                                               \
+    do {                                                                \
+        LOG1("adding JSR to block %04d",(tbptr)-block);                 \
+    jsrtemp = (jsr_record *) dump_alloc(sizeof(jsr_record)+(maxlocals-1)*sizeof(u1)); \
+    jsrtemp->target = (tbptr);                                          \
+    jsrtemp->next = jsrchain;                                           \
+    jsrtemp->sbr_touched = NULL;                                        \
+    memset(&jsrtemp->touched,TOUCHED_NO,sizeof(u1)*maxlocals);          \
+    jsrbuffer[tbptr-block] = jsrtemp;                                   \
+    } while (0)
+
+/* TYPECHECK_COPYJSR: copy the current JSR chain to the target block.
+ *
+ * Input:
+ *     chain......current JSR target chain
+ *     tbptr.....the basic block targeted by the JSR
+ *     maxlocals..number of local variables
+ *     jsrbuffer..JSR target chain for each basic block
+ *     touched....current touched flags of local variables
+ * Used:
+ *     jsrtemp
+ */
+#define TYPECHECK_COPYJSR(chain)                                        \
+    do {                                                                \
+        LOG("TYPECHECK_COPYJSR");                                       \
+        if (chain) {                                                    \
+            jsrtemp = (jsr_record *) dump_alloc(sizeof(jsr_record)+(maxlocals-1)*sizeof(u1)); \
+            jsrtemp->target = (chain)->target;                          \
+            jsrtemp->next = (chain)->next;                              \
+            jsrtemp->sbr_touched = NULL;                                \
+            memcpy(&jsrtemp->touched,touched,sizeof(u1)*maxlocals);     \
+            jsrbuffer[tbptr-block] = jsrtemp;                           \
+        }                                                               \
+        else                                                            \
+            jsrbuffer[tbptr-block] = NULL;                              \
+    } while (0)
+
+/* TYPECHECK_REACH: executed, when the target block (tbptr) can be reached
+ *     from the current block (bptr). The types of local variables and
+ *     stack slots are propagated to the target block.
+ * Input:
+ *     bptr.......current block
+ *     tbptr......target block
+ *     dst........current output stack pointer
+ *     vtype......current local variable types
+ *     vinfo......current local variable typeinfos
+ *     jsrchain...current JSR target chain
+ *     jsrbuffer..JSR target chain for each basic block
+ *     way........in which way the block is reached (REACH_ constant)
+ *     touched....current touched flags of local variables
+ * Output:
+ *     repeat.....changed to true if a block before the current
+ *                block has changed
+ * Used:
+ *     ttype, tinfo, srcstack, dststack, changed, macro_i
+ */
+#define TYPECHECK_REACH(way)                                            \
+    LOG1("reaching block %04d",tbptr-block);                            \
+    srcstack = dst;                                                     \
+    dststack = tbptr->instack;                                          \
+    ttype = vartype + maxlocals*(tbptr-block);                          \
+    tinfo = vartypeinfo + maxlocals*(tbptr-block);                      \
+    if (tbptr->flags == BBTYPECHECK_UNDEF) {                            \
+        /* This block is reached for the first time */                  \
+        if (way == REACH_JSR) {                                         \
+            TYPECHECK_ADD_JSR;                                          \
+            TYPECHECK_COPYVARS;                                         \
+        }                                                               \
+        else {                                                          \
+            TYPECHECK_COPYJSR(jsrchain);                                \
+            TYPECHECK_COPYVARS;                                         \
+        }                                                               \
+        TYPECHECK_COPYSTACK;                                            \
+        changed = true;                                                 \
+    } else {                                                            \
+        /* This block has been reached before */                        \
+        changed = false;                                                \
+        if (way == REACH_JSR)                                           \
+            TYPECHECK_CHECK_JSR_CHAIN;                                  \
+        else                                                            \
+            TYPECHECK_MERGEJSR;                                         \
+        LOGIF(changed,"changed jsr");                                   \
+        TYPECHECK_MERGEVARS;                                            \
+        LOGIF(changed,"changed vars");                                  \
+        TYPECHECK_MERGESTACK;                                           \
+        LOGIF(changed,"changed stack");                                 \
+    }                                                                   \
+    if (changed) {                                                      \
+        LOG("REACHED!");                                                \
+        tbptr->flags = BBTYPECHECK_REACHED;                             \
+        if (tbptr <= bptr) {repeat = true; LOG("MUST REPEAT!");}        \
+    } LOG("done.");
+
+/****************************************************************************/
+/* typecheck()                                                              */
+/****************************************************************************/
+
+#define MAXPARAMS 255
+
+/* typecheck is called directly after analyse_stack */
+void
+typecheck()
+{
+    int b_count, b_index;
+    stackptr curstack;      /* input stack top for current instruction */
+    stackptr srcstack;       /* source stack for copying and merging */
+    stackptr dststack;       /* target stack for copying and merging */
+    int opcode, macro_i, len, i;
+    bool superblockend;        /* true if no fallthrough to next block */
+    bool repeat;            /* if true, blocks are iterated over again */
+    bool changed;
+    instruction *iptr = instr;       /* pointer to current instruction */
+    basicblock *bptr;                /* pointer to current basic block */
+    basicblock *tbptr;
+    u1 *vartype;            /* type of each local for each basic block */
+    typeinfo *vartypeinfo;  /* type of each local for each basic block */
+    u1 *vtype;           /* type of each local for current instruction */
+    typeinfo *vinfo;     /* type of each local for current instruction */
+    u1 *ttype;                                    /* temporary pointer */
+    typeinfo *tinfo;                              /* temporary pointer */
+    typeinfo tempinfo;                                    /* temporary */
+    int returntype;                   /* return type of current method */
+    typeinfo returntypeinfo;               /* typeinfo for return type */
+    u1 *ptype;                     /* parameter types of called method */
+    typeinfo *pinfo;           /* parameter typeinfos of called method */
+    int rtype;                         /* return type of called method */
+    typeinfo rinfo;       /* typeinfo for return type of called method */
+    stackptr dst;               /* output stack of current instruction */
+    int changeddepth;          /* depth to which the stack has changed */ /* XXX */
+    bool fulltypecheck;           /* false == check only changed types */ /* XXX */
+    basicblock **tptr;    /* pointer into target list of switch instructions */
+    jsr_record **jsrbuffer;   /* JSR target chain for each basic block */
+    jsr_record *jsrchain;               /* JSR chain for current block */
+    jsr_record *jsrtemp,*jsrtemp2,*jsrold;      /* temporary variables */
+    jsr_record *subroutine;    /* jsr_record of the current subroutine */
+    u1 *touched;                  /* touched flags for local variables */
+
+    LOGSTR("\n==============================================================================\n");
+    DOLOG(show_icmd_method());
+    LOGSTR("\n==============================================================================\n");
+    LOGimpSTR("Entering typecheck: ");
+    LOGimpSTRu(method->name);
+    LOGimpSTR("    ");
+    LOGimpSTRu(method->descriptor);
+    LOGimpSTR("    (class ");
+    LOGimpSTRu(method->class->name);
+    LOGimpSTR(")\n");
+
+    /* XXX allocate buffers for method arguments */
+    ptype = DMNEW(u1,MAXPARAMS);
+    pinfo = DMNEW(typeinfo,MAXPARAMS);
+    
+    LOG("Buffer allocated.\n");
+
+    /* reset all BBFINISHED blocks to BBTYPECHECK_UNDEF. */
+    b_count = block_count;
+    bptr = block;
+    while (--b_count >= 0) {
+#ifdef TYPECHECK_DEBUG
+        if (bptr->flags != BBFINISHED && bptr->flags != BBDELETED
+            && bptr->flags != BBUNDEF)
+        {
+            show_icmd_method();
+            LOGSTR1("block flags: %d\n",bptr->flags); LOGFLUSH;
+            panic("Internal error: Unexpected block flags in typecheck()");
+        }
+#endif
+        if (bptr->flags >= BBFINISHED) {
+            bptr->flags = BBTYPECHECK_UNDEF;
+        }
+        bptr++;
+    }
+
+    /* The first block is always reached */
+    if (block_count && block[0].flags == BBTYPECHECK_UNDEF)
+        block[0].flags = BBTYPECHECK_REACHED;
+
+    LOG("Blocks reset.\n");
+
+    /* allocate the buffers for local variables */
+    vartype = DMNEW(u1,maxlocals * (block_count+1));
+    vartypeinfo = DMNEW(typeinfo,maxlocals * (block_count+1));
+    touched = DMNEW(u1,maxlocals);
+    vtype = vartype + maxlocals * block_count;
+    vinfo = vartypeinfo + maxlocals * block_count;
+    memset(vartype,TYPE_VOID,maxlocals * (block_count+1) * sizeof(typeinfo));
+    memset(vartypeinfo,0,maxlocals * (block_count+1) * sizeof(typeinfo));
+
+    LOG("Variable buffer initialized.\n");
+
+    /* allocate the buffer for storing JSR target chains */
+    jsrbuffer = DMNEW(jsr_record*,block_count);
+    memset(jsrbuffer,0,block_count * sizeof(jsr_record*));
+    jsrchain = NULL;
+    
+    LOG("jsrbuffer initialized.\n");
+
+    /* initialize the variable types of the first block */
+    /* to the types of the arguments */
+    ttype = vartype;
+    tinfo = vartypeinfo;
+
+    /* if this is an instance method initialize the "this" ref type */
+    if (!(method->flags & ACC_STATIC)) {
+        *ttype++ = TYPE_ADDRESS;
+        TYPEINFO_INIT_CLASSINFO(*tinfo,class);
+        tinfo++;
+    }
+
+    LOG("'this' argument set.\n");
+
+    /* the rest of the arguments and the return type */
+    typeinfo_init_from_method_args(method->descriptor,ttype,tinfo,
+                                   maxlocals - (tinfo-vartypeinfo),
+                                   true, /* two word types use two slots */
+                                   &returntype,&returntypeinfo);
+
+    LOG("Arguments set.\n");
+
+    /* loop while there are still blocks to be checked */
+    fulltypecheck = true; /* XXX */
+    do {
+
+        repeat = false;
+        
+        b_count = block_count;
+        bptr = block;
+
+        while (--b_count >= 0) {
+            LOGSTR1("---- BLOCK %04d, ",bptr-block);
+            LOGSTR1("blockflags: %d\n",bptr->flags);
+            LOGFLUSH;
+                
+            if (bptr->flags == BBTYPECHECK_REACHED) {
+                LOGSTR1("\n---- BLOCK %04d ------------------------------------------------\n",bptr-block);
+                LOGFLUSH;
+                
+                superblockend = false;
+                bptr->flags = BBFINISHED;
+                b_index = bptr - block;
+
+                /* init stack at the start of this block */
+                curstack = bptr->instack;
+                                       
+                /* init variable types at the start of this block */
+                for (i=0; i<maxlocals; ++i) {
+                    vtype[i] = vartype[maxlocals*b_index + i];
+                    TYPEINFO_COPY(vartypeinfo[maxlocals*b_index + i],vinfo[i]);
+                }
+
+                /* init JSR target chain */
+                if ((jsrchain = jsrbuffer[b_index]) != NULL) {
+#ifdef TYPECHECK_VERBOSE
+                    if (typecheckverbose) {
+                        LOGSTR("jsr chain:");
+                        jsrtemp = jsrchain;
+                        while (jsrtemp) {
+                            LOGSTR1(" L%03d",jsrtemp->target->debug_nr);
+                            jsrtemp = jsrtemp->next;
+                        }
+                        LOGNL;
+                        LOGFLUSH;
+                    }
+#endif
+
+                    subroutine = jsrbuffer[jsrchain->target - block];
+                    memcpy(touched,jsrchain->touched,sizeof(u1)*maxlocals);
+                }
+                else
+                    subroutine = NULL;
+#ifdef TYPECHECK_VERBOSE
+                if (typecheckverbose) {
+                    if (subroutine) {LOGSTR1("subroutine L%03d\n",subroutine->target->debug_nr);LOGFLUSH;}
+                    typeinfo_print_block(stdout,curstack,vtype,vinfo,(jsrchain) ? touched : NULL);
+                    LOGNL; LOGFLUSH;
+                }
+#endif
+                                       
+                /* loop over the instructions */
+                len = bptr->icount;
+                iptr = bptr->iinstr;
+                while (--len >= 0)  {
+                    DOLOG(show_icmd(iptr,false));
+                    LOGNL;
+                    LOGFLUSH;
+                        
+                    opcode = iptr->opc;
+                    dst = iptr->dst;
+                                               
+                    switch (opcode) {
+
+                        /****************************************/
+                        /* STACK MANIPULATIONS                  */
+
+                        /* We just need to copy the typeinfo */
+                        /* for slots containing addresses.   */
+
+                      case ICMD_DUP:
+                          COPYTYPE(curstack,dst);
+                          break;
+                                                         
+                      case ICMD_DUP_X1:
+                          COPYTYPE(curstack,dst);
+                          COPYTYPE(curstack,dst-2);
+                          COPYTYPE(curstack->prev,dst-1);
+                          break;
+                                                         
+                      case ICMD_DUP_X2:
+                          COPYTYPE(curstack,dst);
+                          COPYTYPE(curstack,dst-3);
+                          COPYTYPE(curstack->prev,dst-1);
+                          COPYTYPE(curstack->prev->prev,dst-2);
+                          break;
+                                                         
+                      case ICMD_DUP2:
+                          COPYTYPE(curstack,dst);
+                          COPYTYPE(curstack->prev,dst-1);
+                          break;
+
+                      case ICMD_DUP2_X1:
+                          COPYTYPE(curstack,dst);
+                          COPYTYPE(curstack->prev,dst-1);
+                          COPYTYPE(curstack,dst-3);
+                          COPYTYPE(curstack->prev,dst-4);
+                          COPYTYPE(curstack->prev->prev,dst-2);
+                          break;
+                                                         
+                      case ICMD_DUP2_X2:
+                          COPYTYPE(curstack,dst);
+                          COPYTYPE(curstack->prev,dst-1);
+                          COPYTYPE(curstack,dst-4);
+                          COPYTYPE(curstack->prev,dst-5);
+                          COPYTYPE(curstack->prev->prev,dst-2);
+                          COPYTYPE(curstack->prev->prev->prev,dst-3);
+                          break;
+                                                         
+                      case ICMD_SWAP:
+                          COPYTYPE(curstack,dst-1);
+                          COPYTYPE(curstack->prev,dst);
+                          break;
+
+                          /* XXX only add these cases in debug mode? */
+                      case ICMD_POP:
+                          break;
+                                                       
+                      case ICMD_POP2:
+                          break;
+
+                          /****************************************/
+                          /* LOADING ADDRESS FROM VARIABLE        */
+
+                      case ICMD_ALOAD:
+                          CHECKVARTYPE(iptr->op1,TYPE_ADR);
+                          
+                          /* loading a returnAddress is not allowed */
+                          if (TYPEINFO_IS_PRIMITIVE(vinfo[iptr->op1]))
+                              panic("illegal instruction: ALOAD loading returnAddress");
+
+                          TYPEINFO_COPY(vinfo[iptr->op1],dst->typeinfo);
+                          break;
+                                                       
+                          /****************************************/
+                          /* STORING ADDRESS TO VARIABLE          */
+
+                      case ICMD_ASTORE:
+                          /* TYPE_ADR has already been checked. */
+                          STORE_TYPE(iptr->op1,TYPE_ADDRESS);
+                          TYPEINFO_COPY(curstack->typeinfo,vinfo[iptr->op1]);
+                          break;
+                          
+                          /****************************************/
+                          /* LOADING ADDRESS FROM ARRAY           */
+
+                      case ICMD_AALOAD:
+                          if (!TYPEINFO_MAYBE_ARRAY_OF_REFS(curstack->prev->typeinfo))
+                              panic("illegal instruction: AALOAD on non-reference array");
+
+                          typeinfo_init_component(&curstack->prev->typeinfo,&dst->typeinfo);
+                          break;
+                                                         
+                          /****************************************/
+                          /* STORING ADDRESS TO ARRAY             */
+
+                      case ICMD_AASTORE:
+                          /* XXX also handled by builtin3 */
+                          if (!TYPEINFO_MAYBE_ARRAY_OF_REFS(curstack->prev->prev->typeinfo))
+                              panic("illegal instruction: AASTORE to non-reference array");
+
+                          /* XXX optimize */
+                          /*
+                            typeinfo_init_component(&curstack->prev->prev->typeinfo,&tempinfo);
+                            if (!typeinfo_is_assignable(&curstack->typeinfo,&tempinfo))
+                            panic("illegal instruction: AASTORE to incompatible type");
+                          */
+                          break;
+
+                          /****************************************/
+                          /* FIELD ACCESS                         */
+
+                      case ICMD_PUTFIELD:
+                          if (!TYPEINFO_IS_REFERENCE(curstack->prev->typeinfo))
+                              panic("illegal instruction: PUTFIELD on non-reference");
+                          if (TYPEINFO_IS_ARRAY(curstack->prev->typeinfo)) /* XXX arraystub */
+                              panic("illegal instruction: PUTFIELD on array");
+
+                          
+                          /* XXX */
+                          break;
+
+                      case ICMD_PUTSTATIC:
+                          /* XXX */
+                          break;
+
+                      case ICMD_GETFIELD:
+                          if (!TYPEINFO_IS_REFERENCE(curstack->typeinfo))
+                              panic("illegal instruction: GETFIELD on non-reference");
+                          if (TYPEINFO_IS_ARRAY(curstack->typeinfo))
+                              panic("illegal instruction: GETFIELD on array");
+                          
+                          {
+                              fieldinfo *fi = (fieldinfo *)(iptr->val.a);
+                              /* XXX check non-static? */
+                              if (dst->type == TYPE_ADR) {
+                                  TYPEINFO_INIT_FROM_FIELDINFO(dst->typeinfo,fi);
+                              }
+                              else {
+                                  TYPEINFO_INIT_PRIMITIVE(dst->typeinfo);
+                              }
+                          }
+                          break;
+
+                      case ICMD_GETSTATIC:
+                          {
+                              fieldinfo *fi = (fieldinfo *)(iptr->val.a);
+                              /* XXX check static? */
+                              if (dst->type == TYPE_ADR) {
+                                  TYPEINFO_INIT_FROM_FIELDINFO(dst->typeinfo,fi);
+                              }
+                              else {
+                                  TYPEINFO_INIT_PRIMITIVE(dst->typeinfo);
+                              }
+                          }
+                          break;
+
+                          /****************************************/
+                          /* PRIMITIVE ARRAY ACCESS               */
+
+                      case ICMD_ARRAYLENGTH:
+                          /* XXX should this also work on arraystubs? */
+                          if (!TYPEINFO_MAYBE_ARRAY(curstack->typeinfo))
+                              panic("illegal instruction: ARRAYLENGTH on non-array");
+                          break;
+                                                         
+                      case ICMD_BALOAD:
+                          if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(curstack->prev->typeinfo,ARRAYTYPE_BOOLEAN)
+                              && !TYPEINFO_MAYBE_PRIMITIVE_ARRAY(curstack->prev->typeinfo,ARRAYTYPE_BYTE))
+                              panic("Array type mismatch");
+                          break;
+                      case ICMD_CALOAD:
+                          if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(curstack->prev->typeinfo,ARRAYTYPE_CHAR))
+                              panic("Array type mismatch");
+                          break;
+                      case ICMD_DALOAD:
+                          if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(curstack->prev->typeinfo,ARRAYTYPE_DOUBLE))
+                              panic("Array type mismatch");
+                          break;
+                      case ICMD_FALOAD:
+                          if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(curstack->prev->typeinfo,ARRAYTYPE_FLOAT))
+                              panic("Array type mismatch");
+                          break;
+                      case ICMD_IALOAD:
+                          if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(curstack->prev->typeinfo,ARRAYTYPE_INT))
+                              panic("Array type mismatch");
+                          break;
+                      case ICMD_SALOAD:
+                          if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(curstack->prev->typeinfo,ARRAYTYPE_SHORT))
+                              panic("Array type mismatch");
+                          break;
+                      case ICMD_LALOAD:
+                          if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(curstack->prev->typeinfo,ARRAYTYPE_LONG))
+                              panic("Array type mismatch");
+                          break;
+
+                      case ICMD_BASTORE:
+                          if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(curstack->prev->prev->typeinfo,ARRAYTYPE_BOOLEAN)
+                              && !TYPEINFO_MAYBE_PRIMITIVE_ARRAY(curstack->prev->prev->typeinfo,ARRAYTYPE_BYTE))
+                              panic("Array type mismatch");
+                          break;
+                      case ICMD_CASTORE:
+                          if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(curstack->prev->prev->typeinfo,ARRAYTYPE_CHAR))
+                              panic("Array type mismatch");
+                          break;
+                      case ICMD_DASTORE:
+                          if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(curstack->prev->prev->typeinfo,ARRAYTYPE_DOUBLE))
+                              panic("Array type mismatch");
+                          break;
+                      case ICMD_FASTORE:
+                          if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(curstack->prev->prev->typeinfo,ARRAYTYPE_FLOAT))
+                              panic("Array type mismatch");
+                          break;
+                      case ICMD_IASTORE:
+                          if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(curstack->prev->prev->typeinfo,ARRAYTYPE_INT))
+                              panic("Array type mismatch");
+                          break;
+                      case ICMD_SASTORE:
+                          if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(curstack->prev->prev->typeinfo,ARRAYTYPE_SHORT))
+                              panic("Array type mismatch");
+                          break;
+                      case ICMD_LASTORE:
+                          if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(curstack->prev->prev->typeinfo,ARRAYTYPE_LONG))
+                              panic("Array type mismatch");
+                          break;
+
+                          /****************************************/
+                          /* OPERATIONS WITH UNCHECKED INPUT      */
+
+                      case ICMD_CHECKCAST:
+                          /* returnAddress is not allowed */
+                          if (!TYPEINFO_IS_REFERENCE(curstack->typeinfo))
+                              panic("Illegal instruction: INSTANCEOF on non-reference");
+
+                          /* XXX check if the cast can be done statically */
+                          TYPEINFO_INIT_CLASSINFO(dst->typeinfo,(classinfo *)iptr[0].val.a);
+                          /* XXX */
+                          break;
+
+                      case ICMD_INSTANCEOF:
+                          /* returnAddress is not allowed */
+                          if (!TYPEINFO_IS_REFERENCE(curstack->typeinfo))
+                              panic("Illegal instruction: INSTANCEOF on non-reference");
+                          
+                          /* XXX */
+                          break;
+                          
+                      case ICMD_ACONST:
+                          if (iptr->val.a == NULL)
+                              TYPEINFO_INIT_NULLTYPE(dst->typeinfo)
+                          else
+                              /* XXX constants for builtin functions */
+                              /* string constants */
+                              TYPEINFO_INIT_CLASSINFO(dst->typeinfo,class_java_lang_String);
+                          break;
+
+                          /****************************************/
+                          /* BRANCH INSTRUCTIONS                  */
+
+                      case ICMD_GOTO:
+                          superblockend = true;
+                          /* FALLTHROUGH! */
+                      case ICMD_IFNULL:
+                      case ICMD_IFNONNULL:
+                      case ICMD_IFEQ:
+                      case ICMD_IFNE:
+                      case ICMD_IFLT:
+                      case ICMD_IFGE:
+                      case ICMD_IFGT:
+                      case ICMD_IFLE:
+                      case ICMD_IF_ICMPEQ:
+                      case ICMD_IF_ICMPNE:
+                      case ICMD_IF_ICMPLT:
+                      case ICMD_IF_ICMPGE:
+                      case ICMD_IF_ICMPGT:
+                      case ICMD_IF_ICMPLE:
+                      case ICMD_IF_ACMPEQ:
+                      case ICMD_IF_ACMPNE:
+                      case ICMD_IF_LEQ:
+                      case ICMD_IF_LNE:
+                      case ICMD_IF_LLT:
+                      case ICMD_IF_LGE:
+                      case ICMD_IF_LGT:
+                      case ICMD_IF_LLE:
+                      case ICMD_IF_LCMPEQ:
+                      case ICMD_IF_LCMPNE:
+                      case ICMD_IF_LCMPLT:
+                      case ICMD_IF_LCMPGE:
+                      case ICMD_IF_LCMPGT:
+                      case ICMD_IF_LCMPLE:
+                          tbptr = (basicblock *) iptr->target;
+
+                          /* propagate stack and variables to the target block */
+                          TYPECHECK_REACH(REACH_STD);
+                          /* XXX */
+                          break;
+
+                          /****************************************/
+                          /* SWITCHES                             */
+                          
+                      case ICMD_TABLESWITCH:
+                          {
+                              s4 *s4ptr = iptr->val.a;
+                              s4ptr++; /* skip default */
+                              i = *s4ptr++; /* low */
+                              i = *s4ptr++ - i + 2; /* +1 for default target */
+                          }
+                          goto switch_instruction_tail;
+                          
+                      case ICMD_LOOKUPSWITCH:
+                          {
+                              s4 *s4ptr = iptr->val.a;
+                              s4ptr++; /* skip default */
+                              i = *s4ptr++ + 1; /* count +1 for default target */
+                          }
+                    switch_instruction_tail:
+                          tptr = (basicblock **)iptr->target;
+                          
+                          while (--i >= 0) {
+                              tbptr = *tptr++;
+                              LOG2("target %d is block %04d",(tptr-(basicblock **)iptr->target)-1,tbptr-block);
+                              TYPECHECK_REACH(REACH_STD);
+                          }
+                          LOG("switch done");
+                          superblockend = true;
+                          break;
+
+                          /****************************************/
+                          /* RETURNS AND THROW                    */
+
+                      case ICMD_ATHROW:
+                          TYPEINFO_INIT_CLASSINFO(tempinfo,class_java_lang_Throwable);
+                          if (!typeinfo_is_assignable(&curstack->typeinfo,&tempinfo))
+                              panic("illegal instruction: ATHROW on non-Throwable");
+                          superblockend = true;
+                          break;
+
+                      case ICMD_ARETURN:
+                          if (!TYPEINFO_IS_REFERENCE(curstack->typeinfo))
+                              panic("illegal instruction: ARETURN on non-reference");
+
+                          if (returntype != TYPE_ADDRESS
+                              || !typeinfo_is_assignable(&curstack->typeinfo,&returntypeinfo))
+                              panic("Return type mismatch");
+                                                         
+                          superblockend = true;
+                          break;
+
+                      case ICMD_IRETURN:
+                          if (returntype != TYPE_INT)
+                              panic("Return type mismatch");
+                          superblockend = true;
+                          break;                           
+                      case ICMD_LRETURN:
+                          if (returntype != TYPE_LONG)
+                              panic("Return type mismatch");
+                          superblockend = true;
+                          break;
+                      case ICMD_FRETURN:
+                          if (returntype != TYPE_FLOAT)
+                              panic("Return type mismatch");
+                          superblockend = true;
+                          break;
+                      case ICMD_DRETURN:
+                          if (returntype != TYPE_DOUBLE)
+                              panic("Return type mismatch");
+                          superblockend = true;
+                          break;
+                      case ICMD_RETURN:
+                          if (returntype != TYPE_VOID)
+                              panic("Return type mismatch");
+                          superblockend = true;
+                          break;
+                                                    
+                          /****************************************/
+                          /* SUBROUTINE INSTRUCTIONS              */
+
+                      case ICMD_JSR:
+                          LOG("jsr");
+
+                          /* XXX This is a dirty hack. It is needed
+                           * because of the special handling of ICMD_JSR in stack.c
+                           */
+                          dst = (stackptr) iptr->val.a;
+                          
+                          /* push return address */
+                          TYPEINFO_INIT_PRIMITIVE(dst->typeinfo);
+
+                          LOG("reaching block...");
+                          
+                          /* add the target to the JSR target chain and */
+                          /* propagate stack and variables to the target block */
+                          tbptr = (basicblock *) iptr->target;
+                          TYPECHECK_REACH(REACH_JSR);
+
+                          /* set dst to the stack after the subroutine execution */
+                          /* XXX We assume (as in stack.c) that the
+                           * subroutine returns the stack as it was
+                           * before the JSR instruction. Is this
+                           * correct?
+                           */
+                          dst = iptr->dst;
+
+                          /* Find the jsr_record of the called subroutine */
+                          jsrtemp = jsrbuffer[tbptr - block];
+
+                          /* Check if we already calculated (at least
+                           * for one RET) which variables the
+                           * subroutine touches.
+                           */
+                          if (jsrtemp->sbr_touched) {
+                              /* Calculate the local variables after the subroutine call */
+                              for (i=0; i<maxlocals; ++i)
+                                  if (jsrtemp->sbr_touched[i] != TOUCHED_NO) {
+                                      TOUCH_VARIABLE(i);
+                                      if ((vtype[i] = jsrtemp->sbr_vtype[i]) == TYPE_ADR)
+                                          TYPEINFO_CLONE(jsrtemp->sbr_vinfo[i],vinfo[i]);
+                                  }
+
+                              /* continue after the JSR call */
+                              superblockend = false;
+                          }
+                          else {
+                              /* We cannot proceed until the subroutine has been typechecked. */
+                              /* XXX actually we would not have to check this block again */
+                              bptr->flags = BBTYPECHECK_REACHED;
+                              repeat = true;
+                              superblockend = true;
+                          }
+                          break;
+                          
+                      case ICMD_RET:
+                          /* check returnAddress variable */
+                          CHECKVARTYPE(iptr->op1,TYPE_ADR);
+                          
+                          if (!TYPEINFO_IS_PRIMITIVE(vinfo[iptr->op1]))
+                              panic("illegal instruction: RET using non-returnAddress variable");
+
+                          /* check if we are inside a subroutine */
+                          if (!subroutine)
+                              panic("RET outside of subroutine");
+
+                          /* determine which variables are touched by this subroutine */
+                          /* and their types */
+                          if (subroutine->sbr_touched) {
+                              for (i=0; i<maxlocals; ++i)
+                                  subroutine->sbr_touched[i] |= touched[i];
+                              ttype = subroutine->sbr_vtype;
+                              tinfo = subroutine->sbr_vinfo;
+                              TYPECHECK_MERGEVARS;
+                          }
+                          else {
+                              subroutine->sbr_touched = DMNEW(u1,maxlocals);
+                              memcpy(subroutine->sbr_touched,touched,sizeof(u1)*maxlocals);
+                              subroutine->sbr_vtype = DMNEW(u1,maxlocals);
+                              memcpy(subroutine->sbr_vtype,vtype,sizeof(u1)*maxlocals);
+                              subroutine->sbr_vinfo = DMNEW(typeinfo,maxlocals);
+                              for (i=0; i<maxlocals; ++i)
+                                  if (vtype[i] == TYPE_ADR)
+                                      TYPEINFO_CLONE(vinfo[i],subroutine->sbr_vinfo[i]);
+                          }
+
+                          LOGSTR("subroutine touches:");
+                          DOLOG(typeinfo_print_locals(stdout,subroutine->sbr_vtype,subroutine->sbr_vinfo,
+                                                      subroutine->sbr_touched,maxlocals));
+                          LOGNL; LOGFLUSH;
+
+                          /* reach blocks after JSR statements */
+                          for (i=0; i<block_count; ++i) {
+                              tbptr = block + i;
+                              if (tbptr->iinstr[tbptr->icount - 1].opc != ICMD_JSR)
+                                  continue;
+                              if ((basicblock*) tbptr->iinstr[tbptr->icount - 1].target != jsrold->target)
+                                  continue;
+                              tbptr++;
+
+                              LOG1("RET reaches block %04d",tbptr-block);
+
+                              /*TYPECHECK_REACH(REACH_RET);*/
+                          }
+                          
+                          superblockend = true;
+                          break;
+                                                         
+                          /****************************************/
+                          /* INVOKATIONS                          */
+
+                      case ICMD_INVOKEVIRTUAL:
+                      case ICMD_INVOKESPECIAL:
+                      case ICMD_INVOKESTATIC:
+                      case ICMD_INVOKEINTERFACE:
+                          {
+                              /* XXX check access rights */
+                              
+                              methodinfo *mi = (methodinfo*) iptr->val.a;
+                              /* XXX might use dst->typeinfo directly if non void */
+                              typeinfo_init_from_method_args(mi->descriptor,ptype,pinfo,MAXPARAMS,false,
+                                                             &rtype,&rinfo);
+
+                              /* XXX compare rtype and dst->type? */
+                              if (rtype != TYPE_VOID) {
+                                  TYPEINFO_COPY(rinfo,dst->typeinfo);
+                              }
+                          }
+                          break;
+                          
+                      case ICMD_MULTIANEWARRAY:
+                          /* check the array lengths on the stack */
+                          i = iptr[0].op1;
+                          if (i<1) panic("MULTIANEWARRAY with dimensions < 1");
+                          srcstack = curstack;
+                          while (i--) {
+                              if (!srcstack)
+                                  panic("MULTIANEWARRAY missing array length");
+                              if (srcstack->type != TYPE_INT)
+                                  panic("MULTIANEWARRAY using non-int as array length");
+                              srcstack = srcstack->prev;
+                          }
+                          
+                          /* set the array type of the result */
+                          TYPEINFO_INIT_CLASSINFO(dst->typeinfo,((vftbl *)iptr[0].val.a)->class);
+                          break;
+                          
+                      case ICMD_BUILTIN3:
+                          if (ISBUILTIN(asm_builtin_aastore)) {
+                              /* XXX also handled by ICMD_AASTORE */
+                              if (!TYPEINFO_MAYBE_ARRAY_OF_REFS(curstack->prev->prev->typeinfo))
+                                  panic("illegal instruction: AASTORE to non-reference array");
+
+                              /* XXX optimize */
+                              /*
+                                typeinfo_init_component(&curstack->prev->prev->typeinfo,&tempinfo);
+                                if (!typeinfo_is_assignable(&curstack->typeinfo,&tempinfo))
+                                panic("illegal instruction: AASTORE to incompatible type");
+                              */
+                          }
+                          /* XXX check for missed builtins in debug mode? */
+                          break;
+                          
+                      case ICMD_BUILTIN2:
+                          if (
+#if defined(__I386__)
+                              ISBUILTIN(asm_builtin_newarray)
+#else
+                              ISBUILTIN(builtin_newarray)
+#endif
+                              )
+                          {
+                              if (iptr[-1].opc != ICMD_ACONST)
+                                  panic("illegal instruction: builtin_newarray without classinfo");
+                              TYPEINFO_INIT_CLASSINFO(dst->typeinfo,((vftbl *)iptr[-1].val.a)->class);
+                          }
+                          else if (ISBUILTIN(asm_builtin_checkarraycast)) {
+                              if (iptr[-1].opc != ICMD_ACONST)
+                                  panic("illegal instruction: asm_builtin_checkarraycast without classinfo");
+                              TYPEINFO_INIT_CLASSINFO(dst->typeinfo,((vftbl *)iptr[-1].val.a)->class);
+                          }
+                          /* XXX check for missed builtins in debug mode? */
+                          break;
+                          
+                      case ICMD_BUILTIN1:
+                          if (ISBUILTIN(builtin_new)) {
+                              if (iptr[-1].opc != ICMD_ACONST)
+                                  panic("illegal instruction: builtin_new without classinfo");
+                              TYPEINFO_INIT_CLASSINFO(dst->typeinfo,(classinfo *)iptr[-1].val.a);
+                          }
+                          else if (ISBUILTIN(builtin_newarray_boolean)) {
+                              TYPEINFO_INIT_PRIMITIVE_ARRAY(dst->typeinfo,ARRAYTYPE_BOOLEAN);
+                          }
+                          else if (ISBUILTIN(builtin_newarray_char)) {
+                              TYPEINFO_INIT_PRIMITIVE_ARRAY(dst->typeinfo,ARRAYTYPE_CHAR);
+                          }
+                          else if (ISBUILTIN(builtin_newarray_float)) {
+                              TYPEINFO_INIT_PRIMITIVE_ARRAY(dst->typeinfo,ARRAYTYPE_FLOAT);
+                          }
+                          else if (ISBUILTIN(builtin_newarray_double)) {
+                              TYPEINFO_INIT_PRIMITIVE_ARRAY(dst->typeinfo,ARRAYTYPE_DOUBLE);
+                          }
+                          else if (ISBUILTIN(builtin_newarray_byte)) {
+                              TYPEINFO_INIT_PRIMITIVE_ARRAY(dst->typeinfo,ARRAYTYPE_BYTE);
+                          }
+                          else if (ISBUILTIN(builtin_newarray_short)) {
+                              TYPEINFO_INIT_PRIMITIVE_ARRAY(dst->typeinfo,ARRAYTYPE_SHORT);
+                          }
+                          else if (ISBUILTIN(builtin_newarray_int)) {
+                              TYPEINFO_INIT_PRIMITIVE_ARRAY(dst->typeinfo,ARRAYTYPE_INT);
+                          }
+                          else if (ISBUILTIN(builtin_newarray_long)) {
+                              TYPEINFO_INIT_PRIMITIVE_ARRAY(dst->typeinfo,ARRAYTYPE_LONG);
+                          }
+                          /* XXX check for missed builtins in debug mode? */
+                          break;
+                                                     
+                          /****************************************/
+                          /* PRIMITIVE VARIABLE ACCESS            */
+
+                      case ICMD_ILOAD: CHECKVARTYPE(iptr->op1,TYPE_INT); break;
+                      case ICMD_LLOAD: CHECKVARTYPE(iptr->op1,TYPE_LONG); break;
+                      case ICMD_FLOAD: CHECKVARTYPE(iptr->op1,TYPE_FLOAT); break;
+                      case ICMD_DLOAD: CHECKVARTYPE(iptr->op1,TYPE_DOUBLE); break;
+                      case ICMD_IINC:  CHECKVARTYPE(iptr->op1,TYPE_INT); /*TOUCH_VARIABLE(iptr->op1);*/ break;
+                          
+                      case ICMD_FSTORE: STORE_PRIMITIVE(iptr->op1,TYPE_FLOAT); break;
+                      case ICMD_ISTORE: STORE_PRIMITIVE(iptr->op1,TYPE_INT); break;                           
+                      case ICMD_LSTORE: STORE_TWOWORD(iptr->op1,TYPE_LONG); break;
+                      case ICMD_DSTORE: STORE_TWOWORD(iptr->op1,TYPE_DOUBLE); break;
+                          
+                          /****************************************/
+                          /* INSTRUCTIONS WHICH SHOULD HAVE BEEN  */
+                          /* REPLACED BY BUILTIN CALLS            */
+
+                      case ICMD_NEW:
+                      case ICMD_NEWARRAY:
+                      case ICMD_ANEWARRAY:
+                      case ICMD_MONITORENTER:
+                      case ICMD_MONITOREXIT:
+                          /* XXX only check this in debug mode? */
+                          LOGSTR2("ICMD %d at %d\n", iptr->opc, (int)(iptr-instr));
+                          panic("Internal error: unexpected instruction encountered");
+                          break;
+                                                     
+                          /****************************************/
+                          /* UNCHECKED OPERATIONS                 */
+
+                          /* These ops have no input or output to be checked */
+                          /* (apart from the checks done in analyse_stack).  */
+                                                /* XXX only add cases for them in debug mode? */
+
+                      case ICMD_NOP:
+                      case ICMD_CHECKASIZE: /* XXX ? */
+                      case ICMD_NULLCHECKPOP: /* XXX ? */
+                      case ICMD_READONLY_ARG: /* XXX ? */
+                      case ICMD_CLEAR_ARGREN: /* XXX ? */
+                          break;
+
+                          /****************************************/
+                          /* ARITHMETIC AND CONVERSION            */
+
+                          /* These instructions are typechecked in analyse_stack. */
+                                                /* XXX only add cases for them in debug mode? */
+
+                      case ICMD_IADD:
+                      case ICMD_ISUB:
+                      case ICMD_IMUL:
+                      case ICMD_IDIV:
+                      case ICMD_IREM:
+                      case ICMD_INEG:
+                      case ICMD_IAND:
+                      case ICMD_IOR:
+                      case ICMD_IXOR:
+                      case ICMD_ISHL:
+                      case ICMD_ISHR:
+                      case ICMD_IUSHR:
+                      case ICMD_LADD:
+                      case ICMD_LSUB:
+                      case ICMD_LMUL:
+                      case ICMD_LDIV:
+                      case ICMD_LREM:
+                      case ICMD_LNEG:
+                      case ICMD_LAND:
+                      case ICMD_LOR:
+                      case ICMD_LXOR:
+                      case ICMD_LSHL:
+                      case ICMD_LSHR:
+                      case ICMD_LUSHR:
+                      case ICMD_IREM0X10001:
+                      case ICMD_LREM0X10001:
+                      case ICMD_IDIVPOW2:
+                      case ICMD_LDIVPOW2:
+                      case ICMD_IADDCONST:
+                      case ICMD_ISUBCONST:
+                      case ICMD_IMULCONST:
+                      case ICMD_IANDCONST:
+                      case ICMD_IORCONST:
+                      case ICMD_IXORCONST:
+                      case ICMD_ISHLCONST:
+                      case ICMD_ISHRCONST:
+                      case ICMD_IUSHRCONST:
+                      case ICMD_IREMPOW2:
+                      case ICMD_LADDCONST:
+                      case ICMD_LSUBCONST:
+                      case ICMD_LMULCONST:
+                      case ICMD_LANDCONST:
+                      case ICMD_LORCONST:
+                      case ICMD_LXORCONST:
+                      case ICMD_LSHLCONST:
+                      case ICMD_LSHRCONST:
+                      case ICMD_LUSHRCONST:
+                      case ICMD_LREMPOW2:
+                          
+                      case ICMD_LCMP:
+                      case ICMD_LCMPCONST:
+                      case ICMD_FCMPL:
+                      case ICMD_FCMPG:
+                      case ICMD_DCMPL:
+                      case ICMD_DCMPG:
+                          
+                      case ICMD_FADD:
+                      case ICMD_DADD:
+                      case ICMD_FSUB:
+                      case ICMD_DSUB:
+                      case ICMD_FMUL:
+                      case ICMD_DMUL:
+                      case ICMD_FDIV:
+                      case ICMD_DDIV:
+                      case ICMD_FREM:
+                      case ICMD_DREM:
+                      case ICMD_FNEG:
+                      case ICMD_DNEG:
+
+                      case ICMD_I2L:
+                      case ICMD_I2F:
+                      case ICMD_I2D:
+                      case ICMD_L2I:
+                      case ICMD_L2F:
+                      case ICMD_L2D:
+                      case ICMD_F2I:
+                      case ICMD_F2L:
+                      case ICMD_F2D:
+                      case ICMD_D2I:
+                      case ICMD_D2L:
+                      case ICMD_D2F:
+                      case ICMD_INT2BYTE:
+                      case ICMD_INT2CHAR:
+                      case ICMD_INT2SHORT:
+
+                      case ICMD_ICONST:
+                      case ICMD_LCONST:
+                      case ICMD_FCONST:
+                      case ICMD_DCONST:
+
+                      case ICMD_IFEQ_ICONST:
+                      case ICMD_IFNE_ICONST:
+                      case ICMD_IFLT_ICONST:
+                      case ICMD_IFGE_ICONST:
+                      case ICMD_IFGT_ICONST:
+                      case ICMD_IFLE_ICONST:
+                      case ICMD_ELSE_ICONST:
+
+                          break;
+                          
+                          /****************************************/
+
+                      default:
+                          LOGSTR2("ICMD %d at %d\n", iptr->opc, (int)(iptr-instr));
+                          panic("Missing ICMD code during typecheck");
+                    }
+                    
+                    /* the output of this instruction becomes the current stack */
+                    curstack = dst;
+                    
+                    iptr++;
+                } /* while instructions */
+
+                LOG("instructions done");
+                LOGSTR("RESULT=> ");
+                DOLOG(typeinfo_print_block(stdout,curstack,vtype,vinfo,(jsrchain) ? touched : NULL));
+                LOGNL; LOGFLUSH;
+                
+                /* propagate stack and variables to the following block */
+                if (!superblockend) {
+                    LOG("reaching following block");
+                    tbptr = bptr + 1;
+                    while (tbptr->flags == BBDELETED) {
+                        tbptr++;
+#ifdef TYPECHECK_DEBUG
+                        if ((tbptr-block) >= block_count)
+                            panic("Control flow falls off the last block");
+#endif
+                    }
+                    TYPECHECK_REACH(REACH_STD);
+                }
+                
+            } /* if block has to be checked */
+            bptr++;
+        } /* while blocks */
+        
+        /* the following iterations only check if any types changed */
+        fulltypecheck = false; /* XXX */
+
+        LOGIF(repeat,"repeat=true");
+    } while (repeat);
+
+    /* XXX reset BB... to BBFINISHED */
+    
+    /* XXX free vartype */
+    /* XXX free vartypeinfo */
+            /* XXX free buffers for method arguments. */
+
+    /* XXX add debug check if all non-dead blocks have been checked */
+
+    LOGimp("exiting typecheck");
+}
+
+#undef COPYTYPE
+
+#endif /* CACAO_TYPECHECK */
index 0c896177dcc5a495e5851cf4c81d78b4789b4ffa..80e718fa6c69bfb11d34c03bba9fd4e29178f745 100644 (file)
@@ -1,16 +1,34 @@
-/********************************* typeinfo.c *********************************
+/* typeinfo.c - type system used by the type checker
 
-       Copyright (c) 2003 ? XXX
+   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
+   R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser,
+   M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck,
+   P. Tomsich, J. Wenninger
 
-       See file COPYRIGHT for information on usage and disclaimer of warranties
+   This file is part of CACAO.
 
-       functions for the compiler's type system
-       
-       Authors: Edwin Steiner
-                  
-       Last Change:
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2, or (at
+   your option) any later version.
 
-*******************************************************************************/
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+   02111-1307, USA.
+
+   Contact: cacao@complang.tuwien.ac.at
+
+   Authors: Edwin Steiner
+
+   $Id: typeinfo.c 696 2003-12-06 20:10:05Z edwin $
+
+*/
 
 #include "typeinfo.h"
 #include "tables.h"
@@ -133,7 +151,7 @@ typeinfo_is_assignable(typeinfo *value,typeinfo *dest)
     cls = value->typeclass;
 
     /* DEBUG CHECK: dest must not have a merged list. */
-#ifdef DEBUG_TYPES
+#ifdef TYPEINFO_DEBUG
     if (dest->merged)
         panic("Internal error: typeinfo_is_assignable on merged destination.");
 #endif
@@ -221,35 +239,6 @@ typeinfo_is_assignable(typeinfo *value,typeinfo *dest)
 /* The following functions fill in uninitialized typeinfo structures. */
 /**********************************************************************/
 
-/* XXX delete */
-#if 0
-void
-typeinfo_init_from_arraydescriptor(typeinfo *info,
-                                   constant_arraydescriptor *desc)
-{
-    int dim = 1;
-    
-    /* Arrays are instances of the pseudo class Array. */
-    info->typeclass = pseudo_class_Array; /* XXX */
-    info->merged = NULL;
-
-    /* Handle multidimensional arrays */
-    while (desc->arraytype == ARRAYTYPE_ARRAY) {
-        dim++;
-        desc = desc->elementdescriptor;
-    }
-
-    info->dimension = dim;
-
-    if ((info->elementtype = desc->arraytype) == ARRAYTYPE_OBJECT) {
-        info->elementclass = desc->objectclass;
-    }
-    else {
-        info->elementclass = NULL;
-    }
-}
-#endif
-
 void
 typeinfo_init_from_descriptor(typeinfo *info,char *utf_ptr,char *end_ptr)
 {
@@ -374,7 +363,7 @@ typeinfo_init_from_method_args(utf *desc,u1 *typebuf,typeinfo *infobuf,
         cls = class_from_descriptor(utf_ptr,end_pos,&utf_ptr,CLASSLOAD_NEW);
         if (!cls)
             panic("Invalid method descriptor.");
-        
+
         switch (c) {
           case 'B':
           case 'C':
@@ -403,6 +392,8 @@ typeinfo_init_from_method_args(utf *desc,u1 *typebuf,typeinfo *infobuf,
               if (twoword) {
                   if (++args > buflen)
                       panic("Buffer too small for method arguments.");
+                  if (typebuf)
+                      *typebuf++ = TYPE_VOID;
                   TYPEINFO_INIT_PRIMITIVE(*infobuf);
                   infobuf++;
               }
@@ -418,7 +409,6 @@ typeinfo_init_from_method_args(utf *desc,u1 *typebuf,typeinfo *infobuf,
                   *typebuf++ = TYPE_ADDRESS;
               
               TYPEINFO_INIT_CLASSINFO(*infobuf,cls);
-              /* XXX remove */ /* utf_display(cls->name); */
               infobuf++;
               break;
           
@@ -485,6 +475,11 @@ void
 typeinfo_init_component(typeinfo *srcarray,typeinfo *dst)
 {
     vftbl *comp = NULL;
+
+    if (TYPEINFO_IS_NULLTYPE(*srcarray)) {
+        TYPEINFO_INIT_NULLTYPE(*dst);
+        return;
+    }
     
     /* XXX find component class */
     if (!TYPEINFO_IS_ARRAY(*srcarray))
@@ -522,7 +517,7 @@ typeinfo_clone(typeinfo *src,typeinfo *dest)
     int count;
     classinfo **srclist,**destlist;
 
-#ifdef DEBUG_TYPES
+#ifdef TYPEINFO_DEBUG
     if (src == dest)
         panic("Internal error: typeinfo_clone with src==dest");
 #endif
@@ -561,7 +556,7 @@ typeinfo_free(typeinfo *info)
 static
 void
 typeinfo_merge_error(char *str,typeinfo *x,typeinfo *y) {
-#ifdef DEBUG_TYPES
+#ifdef TYPEINFO_DEBUG
     fprintf(stderr,"Error in typeinfo_merge: %s\n",str);
     fprintf(stderr,"Typeinfo x:\n");
     typeinfo_print(stderr,x,1);
@@ -581,7 +576,7 @@ typeinfo_merge_two(typeinfo *dest,classinfo *clsx,classinfo *clsy)
     TYPEINFO_ALLOCMERGED(dest->merged,2);
     dest->merged->count = 2;
 
-#ifdef DEBUG_TYPES
+#ifdef TYPEINFO_DEBUG
     if (clsx == clsy)
         panic("Internal error: typeinfo_merge_two called with clsx==clsy.");
 #endif
@@ -693,7 +688,7 @@ typeinfo_merge_mergedlists(typeinfo *dest,typeinfo_mergedlist *x,
 
     /* {The new mergedlist will have count entries.} */
 
-    if (y->count == count) {
+    if ((x->count != count) && (y->count == count)) {
         temp = x; x = y; y = temp;
     }
     /* {If one of x,y is already the result it is x.} */
@@ -770,7 +765,7 @@ typeinfo_merge_nonarrays(typeinfo *dest,
 
     /* XXX remove */
     /*
-#ifdef DEBUG_TYPES
+#ifdef TYPEINFO_DEBUG
     typeinfo dbgx,dbgy;
     printf("typeinfo_merge_nonarrays:\n");
     TYPEINFO_INIT_CLASSINFO(dbgx,clsx);
@@ -875,8 +870,6 @@ typeinfo_merge_nonarrays(typeinfo *dest,
 
     /* {common == nearest common anchestor of clsx and clsy.} */
 
-    /* XXX remove */ /* printf("common: "); utf_display(common->name); printf("\n"); */
-
     /* If clsx==common and x is a whole class (not a merge of subclasses)
      * then the result of the merge is clsx.
      */
@@ -916,17 +909,21 @@ typeinfo_merge(typeinfo *dest,typeinfo* y)
 
     /* XXX remove */
     /*
-#ifdef DEBUG_TYPES
+#ifdef TYPEINFO_DEBUG
     typeinfo_print(stdout,dest,4);
     typeinfo_print(stdout,y,4);
 #endif
     */ 
 
-    /* This function cannot be used to merge primitive types. */
+    /* Merging two returnAddress types is ok. */
+    if (!dest->typeclass && !y->typeclass)
+        return false;
+    
+    /* Primitive types cannot be merged with reference types */
     if (!dest->typeclass || !y->typeclass)
         typeinfo_merge_error("Trying to merge primitive types.",dest,y);
 
-#ifdef DEBUG_TYPES
+#ifdef TYPEINFO_DEBUG
     if (dest == y)
         panic("Internal error: typeinfo_merge with dest==y");
     
@@ -1069,7 +1066,7 @@ typeinfo_merge(typeinfo *dest,typeinfo* y)
 /* DEBUGGING HELPERS                                                  */
 /**********************************************************************/
 
-#ifdef DEBUG_TYPES
+#ifdef TYPEINFO_DEBUG
 
 #include "tables.h"
 #include "loader.h"
@@ -1144,6 +1141,7 @@ static void
 typeinfo_testmerge(typeinfo *a,typeinfo *b,typeinfo *result,int *failed)
 {
     typeinfo dest;
+    bool changed,changed_should_be;
 
     TYPEINFO_CLONE(*a,dest);
     
@@ -1153,12 +1151,19 @@ typeinfo_testmerge(typeinfo *a,typeinfo *b,typeinfo *result,int *failed)
     typeinfo_print_short(stdout,b);
     printf("\n");
 
-    typeinfo_merge(&dest,b);
+    changed = (typeinfo_merge(&dest,b)) ? 1 : 0;
+    changed_should_be = (!typeinfo_equal(&dest,a)) ? 1 : 0;
+
+    printf("          %s\n",(changed) ? "changed" : "=");
 
     if (typeinfo_equal(&dest,result)) {
         printf("OK        ");
         typeinfo_print_short(stdout,&dest);
         printf("\n");
+        if (changed != changed_should_be) {
+            printf("WRONG RETURN VALUE!\n");
+            (*failed)++;
+        }
     }
     else {
         printf("RESULT    ");
@@ -1190,7 +1195,7 @@ typeinfo_testrun(char *filename)
     char bufa[TYPEINFO_TEST_BUFLEN];
     char bufb[TYPEINFO_TEST_BUFLEN];
     char bufc[TYPEINFO_TEST_BUFLEN];
-    typeinfo a,b,c,a2,b2;
+    typeinfo a,b,c;
     int maxdim;
     int failed = 0;
     FILE *file = fopen(filename,"rt");
@@ -1345,32 +1350,6 @@ typeinfo_print_short(FILE *file,typeinfo *info)
     
     utf_fprint(file,info->typeclass->name);
 
-    /* XXX remove */
-#if 0
-    if (TYPEINFO_IS_ARRAY(*info)) {
-        fprintf(file,"[%d]",info->dimension);
-        switch (info->elementtype) {
-            case ARRAYTYPE_INT     : fprintf(file,"int"); break;
-            case ARRAYTYPE_LONG    : fprintf(file,"long"); break;
-            case ARRAYTYPE_FLOAT   : fprintf(file,"float"); break;
-            case ARRAYTYPE_DOUBLE  : fprintf(file,"double"); break;
-            case ARRAYTYPE_BYTE    : fprintf(file,"byte"); break;
-            case ARRAYTYPE_CHAR    : fprintf(file,"char"); break;
-            case ARRAYTYPE_SHORT   : fprintf(file,"short"); break;
-            case ARRAYTYPE_BOOLEAN : fprintf(file,"boolean"); break;
-
-            case ARRAYTYPE_OBJECT:
-                fprintf(file,"object(");
-                utf_fprint(file,info->elementclass->name);
-                fprintf(file,")");
-                break;
-                
-            default:
-                fprintf(file,"INVALID ARRAYTYPE!");
-        }
-    }
-#endif
-    
     if (info->merged) {
         fprintf(file,"{");
         for (i=0; i<info->merged->count; ++i) {
@@ -1394,9 +1373,7 @@ typeinfo_print_type(FILE *file,int type,typeinfo *info)
           if (TYPEINFO_IS_PRIMITIVE(*info))
               fprintf(file,"R"); /* returnAddress */
           else {
-              fprintf(file,"L");
               typeinfo_print_short(file,info);
-              fprintf(file,";");
           }
           break;
           
@@ -1405,4 +1382,4 @@ typeinfo_print_type(FILE *file,int type,typeinfo *info)
     }
 }
 
-#endif // DEBUG_TYPES
+#endif // TYPEINFO_DEBUG
index 06c6828b09dc4b457c0edfd013ee8f9a4ec1a378..e779da73483752ab570b6525bc0836044659832a 100644 (file)
@@ -1,22 +1,38 @@
-/********************************* typeinfo.h **********************************
+/* typeinfo.h - type system used by the type checker
 
-       Copyright (c) 2003 ? XXX
+   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
+   R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser,
+   M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck,
+   P. Tomsich, J. Wenninger
 
-       See file COPYRIGHT for information on usage and disclaimer of warranties
+   This file is part of CACAO.
 
-       defininitions for the compiler's type system
-       
-       Authors: Edwin Steiner
-                  
-       Last Change:
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2, or (at
+   your option) any later version.
 
-*******************************************************************************/
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+   02111-1307, USA.
+
+   Contact: cacao@complang.tuwien.ac.at
+
+   Authors: Edwin Steiner
+
+   $Id: typeinfo.h 696 2003-12-06 20:10:05Z edwin $
+
+*/
 
 #ifndef __typeinfo_h_
 #define __typeinfo_h_
 
-/* #define DEBUG_TYPES */ /* XXX */
-
 #include "global.h"
 
 /* resolve typedef cycles *****************************************************/
@@ -41,12 +57,6 @@ typedef struct typeinfo_mergedlist typeinfo_mergedlist;
  *     and java.io.Serializable. This pseudo class is used internally
  *     to represent such results. (They are *not* considered arrays!)
  *
- * pseudo_class_Array                          XXX delete?
- *     (extends pseudo_class_Arraystub)
- *
- *     This pseudo class is used internally as the class of all arrays
- *     to distinguish them from arbitrary Objects.
- *
  * pseudo_class_Null
  *
  *     This pseudo class is used internally to represent the
@@ -139,6 +149,8 @@ struct typeinfo_mergedlist {
 /* MACROS                                                                   */
 /****************************************************************************/
 
+/* XXX wrap macro blocks in do { } while(0) */
+
 /* NOTE: These macros take typeinfo *structs* not pointers as arguments.
  *       You have to dereference any pointers.
  */
@@ -146,24 +158,16 @@ struct typeinfo_mergedlist {
 /* internally used macros ***************************************************/
 
 /* internal, don't use this explicitly! */
-/* XXX change to GC? */
 #define TYPEINFO_ALLOCMERGED(mergedlist,count)                  \
             {(mergedlist) = (typeinfo_mergedlist*)dump_alloc(   \
                 sizeof(typeinfo_mergedlist)                     \
                 + ((count)-1)*sizeof(classinfo*));}
 
 /* internal, don't use this explicitly! */
-/* XXX change to GC? */
-#if 0
-#define TYPEINFO_FREEMERGED(mergedlist)                         \
-            {mem_free((mergedlist),sizeof(typeinfo_mergedlist)  \
-                + ((mergedlist)->count - 1)*sizeof(classinfo*));}
-#endif
 #define TYPEINFO_FREEMERGED(mergedlist)
 
 /* internal, don't use this explicitly! */
-#define TYPEINFO_FREEMERGED_IF_ANY(mergedlist)                  \
-            {if (mergedlist) TYPEINFO_FREEMERGED(mergedlist);}
+#define TYPEINFO_FREEMERGED_IF_ANY(mergedlist)
 
 /* macros for type queries **************************************************/
 
@@ -205,6 +209,18 @@ struct typeinfo_mergedlist {
             ( TYPEINFO_IS_ARRAY(info)                           \
               && TYPEINFO_IS_ARRAY_OF_REFS_NOCHECK(info) )
 
+/* queries allowing null types **********************************************/
+
+#define TYPEINFO_MAYBE_ARRAY(info)                              \
+    (TYPEINFO_IS_ARRAY(info) || TYPEINFO_IS_NULLTYPE(info))
+
+#define TYPEINFO_MAYBE_PRIMITIVE_ARRAY(info,at)                 \
+    (TYPEINFO_IS_PRIMITIVE_ARRAY(info,at) || TYPEINFO_IS_NULLTYPE(info))
+
+#define TYPEINFO_MAYBE_ARRAY_OF_REFS(info)                      \
+    (TYPEINFO_IS_ARRAY_OF_REFS(info) || TYPEINFO_IS_NULLTYPE(info))
+
+
 /* macros for initializing typeinfo structures ******************************/
 
 #define TYPEINFO_INIT_PRIMITIVE(info)                           \
@@ -224,35 +240,17 @@ struct typeinfo_mergedlist {
 #define TYPEINFO_INIT_NULLTYPE(info)                            \
             TYPEINFO_INIT_CLASSINFO(info,pseudo_class_Null)
 
-/* XXX delete */
-#if 0
-#define TYPEINFO_INIT_ARRAY(info,dim,elmtype,elmcinfo)        \
-            {(info).typeclass = pseudo_class_Array;             \
-             (info).elementclass = (elmcinfo);                  \
-             (info).merged = NULL;                              \
-             (info).dimension = (dim);                          \
-             (info).elementtype = (elmtype);}
-#endif
-
-/* XXX delete? */
-#define TYPEINFO_INIT_ARRAY(info,cls)                                   \
-            {(info).typeclass = cls;                                    \
-             if (cls->vftbl->arraydesc->elementvftbl)                   \
-                 (info).elementclass = cls->vftbl->arraydesc->elementvftbl->class; \
-             else                                                       \
-                 (info).elementclass = NULL;                            \
-             (info).merged = NULL;                                      \
-             (info).dimension = cls->vftbl->arraydesc->dimension;       \
-             (info).elementtype = cls->vftbl->arraydesc->elementtype;}
+#define TYPEINFO_INIT_PRIMITIVE_ARRAY(info,arraytype)                   \
+    TYPEINFO_INIT_CLASSINFO(info,primitivetype_table[arraytype].arrayclass);
 
 #define TYPEINFO_INIT_CLASSINFO(info,cls)                               \
-        {if (((info).typeclass = cls)->vftbl->arraydesc) {              \
-                if (cls->vftbl->arraydesc->elementvftbl)                \
-                    (info).elementclass = cls->vftbl->arraydesc->elementvftbl->class; \
+        {if (((info).typeclass = (cls))->vftbl->arraydesc) {              \
+                if ((cls)->vftbl->arraydesc->elementvftbl)                \
+                    (info).elementclass = (cls)->vftbl->arraydesc->elementvftbl->class; \
                 else                                                    \
                     (info).elementclass = NULL;                         \
-                (info).dimension = cls->vftbl->arraydesc->dimension;    \
-                (info).elementtype = cls->vftbl->arraydesc->elementtype;\
+                (info).dimension = (cls)->vftbl->arraydesc->dimension;    \
+                (info).elementtype = (cls)->vftbl->arraydesc->elementtype;\
             }                                                           \
             else {                                                      \
                 (info).elementclass = NULL;                             \
@@ -261,10 +259,6 @@ struct typeinfo_mergedlist {
             }                                                           \
             (info).merged = NULL;}
 
-/* XXX */
-#define TYPEINFO_INC_DIMENSION(info)                            \
-             (info).dimension++
-
 #define TYPEINFO_INIT_FROM_FIELDINFO(info,fi)                   \
             typeinfo_init_from_descriptor(&(info),              \
                 (fi)->descriptor->text,utf_end((fi)->descriptor));
@@ -284,37 +278,14 @@ struct typeinfo_mergedlist {
 #define TYPEINFO_PUT_NON_ARRAY_CLASSINFO(info,cinfo)            \
             {(info).typeclass = (cinfo);}
 
-/* XXX delete */
-#if 0
-#define TYPEINFO_PUT_ARRAY(info,dim,elmtype)                    \
-            {(info).typeclass = pseudo_class_Array;             \
-             (info).dimension = (dim);                          \
-             (info).elementtype = (elmtype);}
-#endif
-
-/* XXX delete? */
-#define TYPEINFO_PUT_ARRAY(info,cls)                                    \
-            {(info).typeclass = cls;                                    \
-             if (cls->vftbl->arraydesc->elementvftbl)                \
-                 (info).elementclass = cls->vftbl->arraydesc->elementvftbl->class; \
-             (info).dimension = cls->vftbl->arraydesc->dimension;       \
-             (info).elementtype = cls->vftbl->arraydesc->elementtype;}
-
 #define TYPEINFO_PUT_CLASSINFO(info,cls)                                \
-        {if (((info).typeclass = cls)->vftbl->arraydesc) {              \
-                if (cls->vftbl->arraydesc->elementvftbl)                \
-                    (info).elementclass = cls->vftbl->arraydesc->elementvftbl->class; \
-                (info).dimension = cls->vftbl->arraydesc->dimension;    \
-                (info).elementtype = cls->vftbl->arraydesc->elementtype; \
+        {if (((info).typeclass = (cls))->vftbl->arraydesc) {              \
+                if ((cls)->vftbl->arraydesc->elementvftbl)                \
+                    (info).elementclass = (cls)->vftbl->arraydesc->elementvftbl->class; \
+                (info).dimension = (cls)->vftbl->arraydesc->dimension;    \
+                (info).elementtype = (cls)->vftbl->arraydesc->elementtype; \
             }}
 
-/* XXX delete */
-#if 0
-#define TYPEINFO_PUT_OBJECT_ARRAY(info,dim,elmcinfo)            \
-            {TYPEINFO_PUT_ARRAY(info,dim,ARRAYTYPE_OBJECT);     \
-             (info).elementclass = (elmcinfo);}
-#endif
-
 /* srcarray must be an array (not checked) */
 #define TYPEINFO_PUT_COMPONENT(srcarray,dst)                    \
             {typeinfo_put_component(&(srcarray),&(dst));}
@@ -366,7 +337,7 @@ bool typeinfo_merge(typeinfo *dest,typeinfo* y);
 
 /* debugging helpers ********************************************************/
 
-#ifdef DEBUG_TYPES
+#ifdef TYPEINFO_DEBUG
 
 void typeinfo_test();
 void typeinfo_init_from_fielddescriptor(typeinfo *info,char *desc);
@@ -374,6 +345,6 @@ void typeinfo_print(FILE *file,typeinfo *info,int indent);
 void typeinfo_print_short(FILE *file,typeinfo *info);
 void typeinfo_print_type(FILE *file,int type,typeinfo *info);
 
-#endif // DEBUG_TYPES
+#endif // TYPEINFO_DEBUG
 
 #endif
index 03e2a1601749f9910c7eabd0e35a9faa3e8a74d8..945d41aaf5417154b9962079552e9a76af5d2d4e 100644 (file)
@@ -28,8 +28,9 @@
    Changes: Andreas Krall
             Roman Obermaiser
             Mark Probst
+                       Edwin Steiner
 
-   $Id: loader.c 693 2003-12-05 19:00:58Z jowenn $
+   $Id: loader.c 696 2003-12-06 20:10:05Z edwin $
 
 */
 
@@ -888,6 +889,7 @@ static void method_load (methodinfo *m, classinfo *c)
        m -> flags = suck_u2 ();
        m -> name =  class_getconstant (c, suck_u2(), CONSTANT_Utf8);
        m -> descriptor = class_getconstant (c, suck_u2(), CONSTANT_Utf8);
+       checkmethoddescriptor(m->descriptor);
        
        m -> jcode = NULL;
        m -> exceptiontable = NULL;
@@ -1599,6 +1601,8 @@ class_new_array(classinfo *c)
        methodinfo *clone;
        int namelen;
 
+       /* XXX remove */ /* dolog("class_new_array: %s",c->name->text); */
+
        /* Array classes are not loaded from classfiles. */
        list_remove (&unloadedclasses, c);
 
@@ -1626,12 +1630,12 @@ class_new_array(classinfo *c)
        c->super = class_java_lang_Object;
 
     c->interfacescount = 2;
-    c->interfaces = MNEW(classinfo*,2);
+    c->interfaces = MNEW(classinfo*,2); /* XXX use GC? */
     c->interfaces[0] = class_java_lang_Cloneable;
     c->interfaces[1] = class_java_io_Serializable;
 
        c->methodscount = 1;
-       c->methods = MNEW (methodinfo, c->methodscount);
+       c->methods = MNEW (methodinfo, c->methodscount); /* XXX use GC? */
 
        clone = c->methods;
        memset(clone,0,sizeof(methodinfo));
@@ -2881,7 +2885,7 @@ classinfo *class_from_descriptor(char *utf_ptr,char *end_ptr,char **next,int mod
        char *start = utf_ptr;
        bool error = false;
        utf *name;
-       
+
        SKIP_FIELDDESCRIPTOR_SAFE(utf_ptr,end_ptr,error);
        if (error) return NULL;
        if (next) *next = utf_ptr;
index 35cd9bafc6125e0194689fe3429d2deb3b6fb6c9..3885630b254eaa3b0ca9f8af1abe3bf95f7331df 100644 (file)
@@ -1,4 +1,4 @@
-/* loader.c - class loader header
+/* loader.h - class loader header
 
    Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
    R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser,
@@ -26,7 +26,7 @@
 
    Authors: Reinhard Grafl
 
-   $Id: loader.h 669 2003-11-23 14:04:20Z edwin $
+   $Id: loader.h 696 2003-12-06 20:10:05Z edwin $
 */
 
 
@@ -106,6 +106,18 @@ classinfo *class_primitive_from_sig(char sig);
 #define CLASSLOAD_SKIP  0
 #define CLASSLOAD_NEW   1
 #define CLASSLOAD_LOAD  2
+
+#if 0
+#define CLASSLOAD_NEW       0x0000 /* default */
+#define CLASSLOAD_LOAD      0x0001
+#define CLASSLOAD_SKIP      0x0002
+#define CLASSLOAD_PANIC     0x0000 /* default */
+#define CLASSLOAD_NOPANIC   0x0010
+#define CLASSLOAD_PRIMITIVE 0x0000 /* default */
+#define CLASSLOAD_VOID      0x0000 /* default */
+#define CLASSLOAD_NOVOID    0x0020
+#endif
+
 classinfo *class_from_descriptor(char *utf_ptr,char *end_ptr,char **next,int mode);
 
 /* (used by class_new, don't use directly) */
index 0c896177dcc5a495e5851cf4c81d78b4789b4ffa..80e718fa6c69bfb11d34c03bba9fd4e29178f745 100644 (file)
@@ -1,16 +1,34 @@
-/********************************* typeinfo.c *********************************
+/* typeinfo.c - type system used by the type checker
 
-       Copyright (c) 2003 ? XXX
+   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
+   R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser,
+   M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck,
+   P. Tomsich, J. Wenninger
 
-       See file COPYRIGHT for information on usage and disclaimer of warranties
+   This file is part of CACAO.
 
-       functions for the compiler's type system
-       
-       Authors: Edwin Steiner
-                  
-       Last Change:
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2, or (at
+   your option) any later version.
 
-*******************************************************************************/
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+   02111-1307, USA.
+
+   Contact: cacao@complang.tuwien.ac.at
+
+   Authors: Edwin Steiner
+
+   $Id: typeinfo.c 696 2003-12-06 20:10:05Z edwin $
+
+*/
 
 #include "typeinfo.h"
 #include "tables.h"
@@ -133,7 +151,7 @@ typeinfo_is_assignable(typeinfo *value,typeinfo *dest)
     cls = value->typeclass;
 
     /* DEBUG CHECK: dest must not have a merged list. */
-#ifdef DEBUG_TYPES
+#ifdef TYPEINFO_DEBUG
     if (dest->merged)
         panic("Internal error: typeinfo_is_assignable on merged destination.");
 #endif
@@ -221,35 +239,6 @@ typeinfo_is_assignable(typeinfo *value,typeinfo *dest)
 /* The following functions fill in uninitialized typeinfo structures. */
 /**********************************************************************/
 
-/* XXX delete */
-#if 0
-void
-typeinfo_init_from_arraydescriptor(typeinfo *info,
-                                   constant_arraydescriptor *desc)
-{
-    int dim = 1;
-    
-    /* Arrays are instances of the pseudo class Array. */
-    info->typeclass = pseudo_class_Array; /* XXX */
-    info->merged = NULL;
-
-    /* Handle multidimensional arrays */
-    while (desc->arraytype == ARRAYTYPE_ARRAY) {
-        dim++;
-        desc = desc->elementdescriptor;
-    }
-
-    info->dimension = dim;
-
-    if ((info->elementtype = desc->arraytype) == ARRAYTYPE_OBJECT) {
-        info->elementclass = desc->objectclass;
-    }
-    else {
-        info->elementclass = NULL;
-    }
-}
-#endif
-
 void
 typeinfo_init_from_descriptor(typeinfo *info,char *utf_ptr,char *end_ptr)
 {
@@ -374,7 +363,7 @@ typeinfo_init_from_method_args(utf *desc,u1 *typebuf,typeinfo *infobuf,
         cls = class_from_descriptor(utf_ptr,end_pos,&utf_ptr,CLASSLOAD_NEW);
         if (!cls)
             panic("Invalid method descriptor.");
-        
+
         switch (c) {
           case 'B':
           case 'C':
@@ -403,6 +392,8 @@ typeinfo_init_from_method_args(utf *desc,u1 *typebuf,typeinfo *infobuf,
               if (twoword) {
                   if (++args > buflen)
                       panic("Buffer too small for method arguments.");
+                  if (typebuf)
+                      *typebuf++ = TYPE_VOID;
                   TYPEINFO_INIT_PRIMITIVE(*infobuf);
                   infobuf++;
               }
@@ -418,7 +409,6 @@ typeinfo_init_from_method_args(utf *desc,u1 *typebuf,typeinfo *infobuf,
                   *typebuf++ = TYPE_ADDRESS;
               
               TYPEINFO_INIT_CLASSINFO(*infobuf,cls);
-              /* XXX remove */ /* utf_display(cls->name); */
               infobuf++;
               break;
           
@@ -485,6 +475,11 @@ void
 typeinfo_init_component(typeinfo *srcarray,typeinfo *dst)
 {
     vftbl *comp = NULL;
+
+    if (TYPEINFO_IS_NULLTYPE(*srcarray)) {
+        TYPEINFO_INIT_NULLTYPE(*dst);
+        return;
+    }
     
     /* XXX find component class */
     if (!TYPEINFO_IS_ARRAY(*srcarray))
@@ -522,7 +517,7 @@ typeinfo_clone(typeinfo *src,typeinfo *dest)
     int count;
     classinfo **srclist,**destlist;
 
-#ifdef DEBUG_TYPES
+#ifdef TYPEINFO_DEBUG
     if (src == dest)
         panic("Internal error: typeinfo_clone with src==dest");
 #endif
@@ -561,7 +556,7 @@ typeinfo_free(typeinfo *info)
 static
 void
 typeinfo_merge_error(char *str,typeinfo *x,typeinfo *y) {
-#ifdef DEBUG_TYPES
+#ifdef TYPEINFO_DEBUG
     fprintf(stderr,"Error in typeinfo_merge: %s\n",str);
     fprintf(stderr,"Typeinfo x:\n");
     typeinfo_print(stderr,x,1);
@@ -581,7 +576,7 @@ typeinfo_merge_two(typeinfo *dest,classinfo *clsx,classinfo *clsy)
     TYPEINFO_ALLOCMERGED(dest->merged,2);
     dest->merged->count = 2;
 
-#ifdef DEBUG_TYPES
+#ifdef TYPEINFO_DEBUG
     if (clsx == clsy)
         panic("Internal error: typeinfo_merge_two called with clsx==clsy.");
 #endif
@@ -693,7 +688,7 @@ typeinfo_merge_mergedlists(typeinfo *dest,typeinfo_mergedlist *x,
 
     /* {The new mergedlist will have count entries.} */
 
-    if (y->count == count) {
+    if ((x->count != count) && (y->count == count)) {
         temp = x; x = y; y = temp;
     }
     /* {If one of x,y is already the result it is x.} */
@@ -770,7 +765,7 @@ typeinfo_merge_nonarrays(typeinfo *dest,
 
     /* XXX remove */
     /*
-#ifdef DEBUG_TYPES
+#ifdef TYPEINFO_DEBUG
     typeinfo dbgx,dbgy;
     printf("typeinfo_merge_nonarrays:\n");
     TYPEINFO_INIT_CLASSINFO(dbgx,clsx);
@@ -875,8 +870,6 @@ typeinfo_merge_nonarrays(typeinfo *dest,
 
     /* {common == nearest common anchestor of clsx and clsy.} */
 
-    /* XXX remove */ /* printf("common: "); utf_display(common->name); printf("\n"); */
-
     /* If clsx==common and x is a whole class (not a merge of subclasses)
      * then the result of the merge is clsx.
      */
@@ -916,17 +909,21 @@ typeinfo_merge(typeinfo *dest,typeinfo* y)
 
     /* XXX remove */
     /*
-#ifdef DEBUG_TYPES
+#ifdef TYPEINFO_DEBUG
     typeinfo_print(stdout,dest,4);
     typeinfo_print(stdout,y,4);
 #endif
     */ 
 
-    /* This function cannot be used to merge primitive types. */
+    /* Merging two returnAddress types is ok. */
+    if (!dest->typeclass && !y->typeclass)
+        return false;
+    
+    /* Primitive types cannot be merged with reference types */
     if (!dest->typeclass || !y->typeclass)
         typeinfo_merge_error("Trying to merge primitive types.",dest,y);
 
-#ifdef DEBUG_TYPES
+#ifdef TYPEINFO_DEBUG
     if (dest == y)
         panic("Internal error: typeinfo_merge with dest==y");
     
@@ -1069,7 +1066,7 @@ typeinfo_merge(typeinfo *dest,typeinfo* y)
 /* DEBUGGING HELPERS                                                  */
 /**********************************************************************/
 
-#ifdef DEBUG_TYPES
+#ifdef TYPEINFO_DEBUG
 
 #include "tables.h"
 #include "loader.h"
@@ -1144,6 +1141,7 @@ static void
 typeinfo_testmerge(typeinfo *a,typeinfo *b,typeinfo *result,int *failed)
 {
     typeinfo dest;
+    bool changed,changed_should_be;
 
     TYPEINFO_CLONE(*a,dest);
     
@@ -1153,12 +1151,19 @@ typeinfo_testmerge(typeinfo *a,typeinfo *b,typeinfo *result,int *failed)
     typeinfo_print_short(stdout,b);
     printf("\n");
 
-    typeinfo_merge(&dest,b);
+    changed = (typeinfo_merge(&dest,b)) ? 1 : 0;
+    changed_should_be = (!typeinfo_equal(&dest,a)) ? 1 : 0;
+
+    printf("          %s\n",(changed) ? "changed" : "=");
 
     if (typeinfo_equal(&dest,result)) {
         printf("OK        ");
         typeinfo_print_short(stdout,&dest);
         printf("\n");
+        if (changed != changed_should_be) {
+            printf("WRONG RETURN VALUE!\n");
+            (*failed)++;
+        }
     }
     else {
         printf("RESULT    ");
@@ -1190,7 +1195,7 @@ typeinfo_testrun(char *filename)
     char bufa[TYPEINFO_TEST_BUFLEN];
     char bufb[TYPEINFO_TEST_BUFLEN];
     char bufc[TYPEINFO_TEST_BUFLEN];
-    typeinfo a,b,c,a2,b2;
+    typeinfo a,b,c;
     int maxdim;
     int failed = 0;
     FILE *file = fopen(filename,"rt");
@@ -1345,32 +1350,6 @@ typeinfo_print_short(FILE *file,typeinfo *info)
     
     utf_fprint(file,info->typeclass->name);
 
-    /* XXX remove */
-#if 0
-    if (TYPEINFO_IS_ARRAY(*info)) {
-        fprintf(file,"[%d]",info->dimension);
-        switch (info->elementtype) {
-            case ARRAYTYPE_INT     : fprintf(file,"int"); break;
-            case ARRAYTYPE_LONG    : fprintf(file,"long"); break;
-            case ARRAYTYPE_FLOAT   : fprintf(file,"float"); break;
-            case ARRAYTYPE_DOUBLE  : fprintf(file,"double"); break;
-            case ARRAYTYPE_BYTE    : fprintf(file,"byte"); break;
-            case ARRAYTYPE_CHAR    : fprintf(file,"char"); break;
-            case ARRAYTYPE_SHORT   : fprintf(file,"short"); break;
-            case ARRAYTYPE_BOOLEAN : fprintf(file,"boolean"); break;
-
-            case ARRAYTYPE_OBJECT:
-                fprintf(file,"object(");
-                utf_fprint(file,info->elementclass->name);
-                fprintf(file,")");
-                break;
-                
-            default:
-                fprintf(file,"INVALID ARRAYTYPE!");
-        }
-    }
-#endif
-    
     if (info->merged) {
         fprintf(file,"{");
         for (i=0; i<info->merged->count; ++i) {
@@ -1394,9 +1373,7 @@ typeinfo_print_type(FILE *file,int type,typeinfo *info)
           if (TYPEINFO_IS_PRIMITIVE(*info))
               fprintf(file,"R"); /* returnAddress */
           else {
-              fprintf(file,"L");
               typeinfo_print_short(file,info);
-              fprintf(file,";");
           }
           break;
           
@@ -1405,4 +1382,4 @@ typeinfo_print_type(FILE *file,int type,typeinfo *info)
     }
 }
 
-#endif // DEBUG_TYPES
+#endif // TYPEINFO_DEBUG
index 06c6828b09dc4b457c0edfd013ee8f9a4ec1a378..e779da73483752ab570b6525bc0836044659832a 100644 (file)
@@ -1,22 +1,38 @@
-/********************************* typeinfo.h **********************************
+/* typeinfo.h - type system used by the type checker
 
-       Copyright (c) 2003 ? XXX
+   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
+   R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser,
+   M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck,
+   P. Tomsich, J. Wenninger
 
-       See file COPYRIGHT for information on usage and disclaimer of warranties
+   This file is part of CACAO.
 
-       defininitions for the compiler's type system
-       
-       Authors: Edwin Steiner
-                  
-       Last Change:
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2, or (at
+   your option) any later version.
 
-*******************************************************************************/
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+   02111-1307, USA.
+
+   Contact: cacao@complang.tuwien.ac.at
+
+   Authors: Edwin Steiner
+
+   $Id: typeinfo.h 696 2003-12-06 20:10:05Z edwin $
+
+*/
 
 #ifndef __typeinfo_h_
 #define __typeinfo_h_
 
-/* #define DEBUG_TYPES */ /* XXX */
-
 #include "global.h"
 
 /* resolve typedef cycles *****************************************************/
@@ -41,12 +57,6 @@ typedef struct typeinfo_mergedlist typeinfo_mergedlist;
  *     and java.io.Serializable. This pseudo class is used internally
  *     to represent such results. (They are *not* considered arrays!)
  *
- * pseudo_class_Array                          XXX delete?
- *     (extends pseudo_class_Arraystub)
- *
- *     This pseudo class is used internally as the class of all arrays
- *     to distinguish them from arbitrary Objects.
- *
  * pseudo_class_Null
  *
  *     This pseudo class is used internally to represent the
@@ -139,6 +149,8 @@ struct typeinfo_mergedlist {
 /* MACROS                                                                   */
 /****************************************************************************/
 
+/* XXX wrap macro blocks in do { } while(0) */
+
 /* NOTE: These macros take typeinfo *structs* not pointers as arguments.
  *       You have to dereference any pointers.
  */
@@ -146,24 +158,16 @@ struct typeinfo_mergedlist {
 /* internally used macros ***************************************************/
 
 /* internal, don't use this explicitly! */
-/* XXX change to GC? */
 #define TYPEINFO_ALLOCMERGED(mergedlist,count)                  \
             {(mergedlist) = (typeinfo_mergedlist*)dump_alloc(   \
                 sizeof(typeinfo_mergedlist)                     \
                 + ((count)-1)*sizeof(classinfo*));}
 
 /* internal, don't use this explicitly! */
-/* XXX change to GC? */
-#if 0
-#define TYPEINFO_FREEMERGED(mergedlist)                         \
-            {mem_free((mergedlist),sizeof(typeinfo_mergedlist)  \
-                + ((mergedlist)->count - 1)*sizeof(classinfo*));}
-#endif
 #define TYPEINFO_FREEMERGED(mergedlist)
 
 /* internal, don't use this explicitly! */
-#define TYPEINFO_FREEMERGED_IF_ANY(mergedlist)                  \
-            {if (mergedlist) TYPEINFO_FREEMERGED(mergedlist);}
+#define TYPEINFO_FREEMERGED_IF_ANY(mergedlist)
 
 /* macros for type queries **************************************************/
 
@@ -205,6 +209,18 @@ struct typeinfo_mergedlist {
             ( TYPEINFO_IS_ARRAY(info)                           \
               && TYPEINFO_IS_ARRAY_OF_REFS_NOCHECK(info) )
 
+/* queries allowing null types **********************************************/
+
+#define TYPEINFO_MAYBE_ARRAY(info)                              \
+    (TYPEINFO_IS_ARRAY(info) || TYPEINFO_IS_NULLTYPE(info))
+
+#define TYPEINFO_MAYBE_PRIMITIVE_ARRAY(info,at)                 \
+    (TYPEINFO_IS_PRIMITIVE_ARRAY(info,at) || TYPEINFO_IS_NULLTYPE(info))
+
+#define TYPEINFO_MAYBE_ARRAY_OF_REFS(info)                      \
+    (TYPEINFO_IS_ARRAY_OF_REFS(info) || TYPEINFO_IS_NULLTYPE(info))
+
+
 /* macros for initializing typeinfo structures ******************************/
 
 #define TYPEINFO_INIT_PRIMITIVE(info)                           \
@@ -224,35 +240,17 @@ struct typeinfo_mergedlist {
 #define TYPEINFO_INIT_NULLTYPE(info)                            \
             TYPEINFO_INIT_CLASSINFO(info,pseudo_class_Null)
 
-/* XXX delete */
-#if 0
-#define TYPEINFO_INIT_ARRAY(info,dim,elmtype,elmcinfo)        \
-            {(info).typeclass = pseudo_class_Array;             \
-             (info).elementclass = (elmcinfo);                  \
-             (info).merged = NULL;                              \
-             (info).dimension = (dim);                          \
-             (info).elementtype = (elmtype);}
-#endif
-
-/* XXX delete? */
-#define TYPEINFO_INIT_ARRAY(info,cls)                                   \
-            {(info).typeclass = cls;                                    \
-             if (cls->vftbl->arraydesc->elementvftbl)                   \
-                 (info).elementclass = cls->vftbl->arraydesc->elementvftbl->class; \
-             else                                                       \
-                 (info).elementclass = NULL;                            \
-             (info).merged = NULL;                                      \
-             (info).dimension = cls->vftbl->arraydesc->dimension;       \
-             (info).elementtype = cls->vftbl->arraydesc->elementtype;}
+#define TYPEINFO_INIT_PRIMITIVE_ARRAY(info,arraytype)                   \
+    TYPEINFO_INIT_CLASSINFO(info,primitivetype_table[arraytype].arrayclass);
 
 #define TYPEINFO_INIT_CLASSINFO(info,cls)                               \
-        {if (((info).typeclass = cls)->vftbl->arraydesc) {              \
-                if (cls->vftbl->arraydesc->elementvftbl)                \
-                    (info).elementclass = cls->vftbl->arraydesc->elementvftbl->class; \
+        {if (((info).typeclass = (cls))->vftbl->arraydesc) {              \
+                if ((cls)->vftbl->arraydesc->elementvftbl)                \
+                    (info).elementclass = (cls)->vftbl->arraydesc->elementvftbl->class; \
                 else                                                    \
                     (info).elementclass = NULL;                         \
-                (info).dimension = cls->vftbl->arraydesc->dimension;    \
-                (info).elementtype = cls->vftbl->arraydesc->elementtype;\
+                (info).dimension = (cls)->vftbl->arraydesc->dimension;    \
+                (info).elementtype = (cls)->vftbl->arraydesc->elementtype;\
             }                                                           \
             else {                                                      \
                 (info).elementclass = NULL;                             \
@@ -261,10 +259,6 @@ struct typeinfo_mergedlist {
             }                                                           \
             (info).merged = NULL;}
 
-/* XXX */
-#define TYPEINFO_INC_DIMENSION(info)                            \
-             (info).dimension++
-
 #define TYPEINFO_INIT_FROM_FIELDINFO(info,fi)                   \
             typeinfo_init_from_descriptor(&(info),              \
                 (fi)->descriptor->text,utf_end((fi)->descriptor));
@@ -284,37 +278,14 @@ struct typeinfo_mergedlist {
 #define TYPEINFO_PUT_NON_ARRAY_CLASSINFO(info,cinfo)            \
             {(info).typeclass = (cinfo);}
 
-/* XXX delete */
-#if 0
-#define TYPEINFO_PUT_ARRAY(info,dim,elmtype)                    \
-            {(info).typeclass = pseudo_class_Array;             \
-             (info).dimension = (dim);                          \
-             (info).elementtype = (elmtype);}
-#endif
-
-/* XXX delete? */
-#define TYPEINFO_PUT_ARRAY(info,cls)                                    \
-            {(info).typeclass = cls;                                    \
-             if (cls->vftbl->arraydesc->elementvftbl)                \
-                 (info).elementclass = cls->vftbl->arraydesc->elementvftbl->class; \
-             (info).dimension = cls->vftbl->arraydesc->dimension;       \
-             (info).elementtype = cls->vftbl->arraydesc->elementtype;}
-
 #define TYPEINFO_PUT_CLASSINFO(info,cls)                                \
-        {if (((info).typeclass = cls)->vftbl->arraydesc) {              \
-                if (cls->vftbl->arraydesc->elementvftbl)                \
-                    (info).elementclass = cls->vftbl->arraydesc->elementvftbl->class; \
-                (info).dimension = cls->vftbl->arraydesc->dimension;    \
-                (info).elementtype = cls->vftbl->arraydesc->elementtype; \
+        {if (((info).typeclass = (cls))->vftbl->arraydesc) {              \
+                if ((cls)->vftbl->arraydesc->elementvftbl)                \
+                    (info).elementclass = (cls)->vftbl->arraydesc->elementvftbl->class; \
+                (info).dimension = (cls)->vftbl->arraydesc->dimension;    \
+                (info).elementtype = (cls)->vftbl->arraydesc->elementtype; \
             }}
 
-/* XXX delete */
-#if 0
-#define TYPEINFO_PUT_OBJECT_ARRAY(info,dim,elmcinfo)            \
-            {TYPEINFO_PUT_ARRAY(info,dim,ARRAYTYPE_OBJECT);     \
-             (info).elementclass = (elmcinfo);}
-#endif
-
 /* srcarray must be an array (not checked) */
 #define TYPEINFO_PUT_COMPONENT(srcarray,dst)                    \
             {typeinfo_put_component(&(srcarray),&(dst));}
@@ -366,7 +337,7 @@ bool typeinfo_merge(typeinfo *dest,typeinfo* y);
 
 /* debugging helpers ********************************************************/
 
-#ifdef DEBUG_TYPES
+#ifdef TYPEINFO_DEBUG
 
 void typeinfo_test();
 void typeinfo_init_from_fielddescriptor(typeinfo *info,char *desc);
@@ -374,6 +345,6 @@ void typeinfo_print(FILE *file,typeinfo *info,int indent);
 void typeinfo_print_short(FILE *file,typeinfo *info);
 void typeinfo_print_type(FILE *file,int type,typeinfo *info);
 
-#endif // DEBUG_TYPES
+#endif // TYPEINFO_DEBUG
 
 #endif