added uninitialized object typecheck
authoredwin <none@none>
Mon, 8 Dec 2003 14:26:05 +0000 (14:26 +0000)
committeredwin <none@none>
Mon, 8 Dec 2003 14:26:05 +0000 (14:26 +0000)
12 files changed:
global.h
jit/stack.c
jit/typecheck.c
loader.c
src/vm/global.h
src/vm/jit/stack.c
src/vm/jit/verify/typecheck.c
src/vm/jit/verify/typeinfo.c
src/vm/jit/verify/typeinfo.h
src/vm/loader.c
typeinfo.c
typeinfo.h

index efc7eda7282514a6eea7113c9bce81421f02b745..1c3430d3cb1e82ace0d74d21a2d4056f1c165e44 100644 (file)
--- a/global.h
+++ b/global.h
@@ -31,7 +31,7 @@
             Philipp Tomsich
                        Edwin Steiner
 
-   $Id: global.h 717 2003-12-07 22:02:19Z twisti $
+   $Id: global.h 719 2003-12-08 14:26:05Z edwin $
 
 */
 
@@ -747,6 +747,7 @@ extern classinfo *class_java_lang_ArrayStoreException;
 extern classinfo *class_java_lang_ThreadDeath;
 extern classinfo *pseudo_class_Arraystub;
 extern classinfo *pseudo_class_Null;
+extern classinfo *pseudo_class_New;
 extern vftbl *pseudo_class_Arraystub_vftbl;
 
 
index 4799a064a60dab5dbd623e5b6689848f75d408f6..e8ec5dc34dea49f587d884c565895ea8f73d14c8 100644 (file)
@@ -28,7 +28,7 @@
 
    Changes: Edwin Steiner
 
-   $Id: stack.c 696 2003-12-06 20:10:05Z edwin $
+   $Id: stack.c 719 2003-12-08 14:26:05Z edwin $
 
 */
 
@@ -1505,6 +1505,7 @@ void analyse_stack()
                                                        i = iptr->op1;
                                                        if (i > arguments_num)
                                                                arguments_num = i;
+                                                       /* XXX verify that there are enough arguments on the stack */
 #if defined(__X86_64__)
                                                        {
                                                                int iarg = 0;
index 98bd6cc445ed77e23e6226a9a03ed5a218960594..5ef48502f6a92a36652be5428e7e7a767b54d9c0 100644 (file)
@@ -26,7 +26,7 @@
 
    Authors: Edwin Steiner
 
-   $Id: typecheck.c 701 2003-12-07 16:26:58Z edwin $
+   $Id: typecheck.c 719 2003-12-08 14:26:05Z edwin $
 
 */
 
@@ -136,18 +136,18 @@ typeinfo_print_stack(FILE *file,stackptr stack)
 static
 void
 typeinfo_print_block(FILE *file,stackptr instack,
-                     u1 *vtype,typeinfo *vinfo,u1 *touched)
+                     int vnum,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);
+    typeinfo_print_locals(file,vtype,vinfo,touched,vnum);
 }
 
 
 static
 void
-typeinfo_print_blocks(FILE *file,u1 *vtype,typeinfo *vinfo)
+typeinfo_print_blocks(FILE *file,int vnum,u1 *vtype,typeinfo *vinfo)
 {
     int bi;
     /*    int j;*/
@@ -155,7 +155,7 @@ typeinfo_print_blocks(FILE *file,u1 *vtype,typeinfo *vinfo)
     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);
+                             vnum,vtype+vnum*bi,vinfo+vnum*bi,NULL);
         fprintf(file,"\n");
 
 /*         for (j=0; j<block[bi].icount; ++j) { */
@@ -223,14 +223,14 @@ struct jsr_record {
  *     vinfo......current local variable typeinfos
  *     ttype......local variable types of target block
  *     tinfo......local variable typeinfos of target block
- *     maxlocals..number of local variables
+ *     numlocals..number of local variables
  * Used:
  *     macro_i
  */
 #define TYPECHECK_COPYVARS                                      \
     do {                                                        \
     LOG("TYPECHECK_COPYVARS");                                  \
-    for (macro_i=0; macro_i<maxlocals; ++macro_i) {             \
+    for (macro_i=0; macro_i<numlocals; ++macro_i) {             \
         if ((ttype[macro_i] = vtype[macro_i]) == TYPE_ADR)      \
             TYPEINFO_CLONE(vinfo[macro_i],tinfo[macro_i]);      \
     } } while(0)
@@ -242,7 +242,7 @@ struct jsr_record {
  *     vinfo......current local variable typeinfos
  *     ttype......local variable types of target block
  *     tinfo......local variable typeinfos of target block
- *     maxlocals..number of local variables
+ *     numlocals..number of local variables
  * Ouput:
  *     changed....set to true if any typeinfo has changed
  * Used:
@@ -251,7 +251,7 @@ struct jsr_record {
 #define TYPECHECK_MERGEVARS                                             \
     do {                                                                \
     LOG("TYPECHECK_MERGEVARS");                                         \
-    for (macro_i=0; macro_i<maxlocals; ++macro_i) {                     \
+    for (macro_i=0; macro_i<numlocals; ++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;                                 \
@@ -281,7 +281,7 @@ struct jsr_record {
  * Ouput:
  *     tbptr......target block
  *     changed....set to true if any typeinfo has changed
- *     maxlocals..number of local variables
+ *     numlocals..number of local variables
  *     touched....current touched flags of local variables
  * Used:
  *     macro_i, jsrtemp, jsrtemp2
@@ -301,7 +301,7 @@ struct jsr_record {
     }                                                                   \
     jsrtemp = jsrbuffer[tbptr-block];                                   \
     if (jsrtemp)                                                        \
-        for (macro_i=0; macro_i<maxlocals; ++macro_i) {                 \
+        for (macro_i=0; macro_i<numlocals; ++macro_i) {                 \
             jsrtemp->touched[i] |= touched[i];                          \
     } } while (0)
 
@@ -393,7 +393,7 @@ struct jsr_record {
  * Input:
  *     jsrchain...current JSR target chain
  *     tbptr.....the basic block targeted by the JSR
- *     maxlocals..number of local variables
+ *     numlocals..number of local variables
  *     jsrbuffer..JSR target chain for each basic block
  * Used:
  *     jsrtemp
@@ -401,11 +401,11 @@ struct jsr_record {
 #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 = (jsr_record *) dump_alloc(sizeof(jsr_record)+(numlocals-1)*sizeof(u1)); \
     jsrtemp->target = (tbptr);                                          \
     jsrtemp->next = jsrchain;                                           \
     jsrtemp->sbr_touched = NULL;                                        \
-    memset(&jsrtemp->touched,TOUCHED_NO,sizeof(u1)*maxlocals);          \
+    memset(&jsrtemp->touched,TOUCHED_NO,sizeof(u1)*numlocals);          \
     jsrbuffer[tbptr-block] = jsrtemp;                                   \
     } while (0)
 
@@ -414,7 +414,7 @@ struct jsr_record {
  * Input:
  *     chain......current JSR target chain
  *     tbptr.....the basic block targeted by the JSR
- *     maxlocals..number of local variables
+ *     numlocals..number of local variables
  *     jsrbuffer..JSR target chain for each basic block
  *     touched....current touched flags of local variables
  * Used:
@@ -424,17 +424,43 @@ struct jsr_record {
     do {                                                                \
         LOG("TYPECHECK_COPYJSR");                                       \
         if (chain) {                                                    \
-            jsrtemp = (jsr_record *) dump_alloc(sizeof(jsr_record)+(maxlocals-1)*sizeof(u1)); \
+            jsrtemp = (jsr_record *) dump_alloc(sizeof(jsr_record)+(numlocals-1)*sizeof(u1)); \
             jsrtemp->target = (chain)->target;                          \
             jsrtemp->next = (chain)->next;                              \
             jsrtemp->sbr_touched = NULL;                                \
-            memcpy(&jsrtemp->touched,touched,sizeof(u1)*maxlocals);     \
+            memcpy(&jsrtemp->touched,touched,sizeof(u1)*numlocals);     \
             jsrbuffer[tbptr-block] = jsrtemp;                           \
         }                                                               \
         else                                                            \
             jsrbuffer[tbptr-block] = NULL;                              \
     } while (0)
 
+/* TYPECHECK_BRANCH_BACKWARDS: executed when control flow moves
+ *     backwards. Checks if there are uninitialized objects on the
+ *     stack or in local variables.
+ * Input:
+ *     dst........current output stack pointer (not needed for REACH_THROW)
+ *     vtype......current local variable types
+ *     vinfo......current local variable typeinfos
+ * Used:
+ *     srcstack, macro_i
+ */
+#define TYPECHECK_BRANCH_BACKWARDS                                      \
+    do {                                                                \
+        LOG("BACKWARDS!");                                              \
+        srcstack = dst;                                                 \
+        while (srcstack) {                                              \
+            if (srcstack->type == TYPE_ADR &&                           \
+                TYPEINFO_IS_NEWOBJECT(srcstack->typeinfo))              \
+                panic("Branching backwards with uninitialized object on stack"); \
+            srcstack = srcstack->prev;                                  \
+        }                                                               \
+        for (macro_i=0; macro_i<numlocals; ++macro_i)                   \
+            if (vtype[macro_i] == TYPE_ADR &&                           \
+                TYPEINFO_IS_NEWOBJECT(vinfo[macro_i]))                  \
+                panic("Branching backwards with uninitialized object in local variable"); \
+    } 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.
@@ -442,6 +468,7 @@ struct jsr_record {
  *     bptr.......current block
  *     tbptr......target block
  *     dst........current output stack pointer (not needed for REACH_THROW)
+ *     numlocals..number of local variables
  *     vtype......current local variable types
  *     vinfo......current local variable typeinfos
  *     jsrchain...current JSR target chain
@@ -457,10 +484,12 @@ struct jsr_record {
 #define TYPECHECK_REACH(way)                                            \
     do {                                                                \
     LOG2("reaching block %04d (%d)",tbptr-block,way);                   \
+    if (tbptr <= bptr && way != REACH_THROW)                            \
+        TYPECHECK_BRANCH_BACKWARDS;                                     \
     srcstack = dst;                                                     \
     dststack = tbptr->instack;                                          \
-    ttype = vartype + maxlocals*(tbptr-block);                          \
-    tinfo = vartypeinfo + maxlocals*(tbptr-block);                      \
+    ttype = vartype + numlocals*(tbptr-block);                          \
+    tinfo = vartypeinfo + numlocals*(tbptr-block);                      \
     if (tbptr->flags == BBTYPECHECK_UNDEF) {                            \
         /* This block is reached for the first time */                  \
         if (way == REACH_JSR) {                                         \
@@ -486,11 +515,29 @@ struct jsr_record {
     if (changed) {                                                      \
         LOG("REACHED!");                                                \
         tbptr->flags = BBTYPECHECK_REACHED;                             \
-        if (tbptr <= bptr) {repeat = true; LOG("MUST REPEAT!");}        \
+        if (tbptr <= bptr) {repeat = true; LOG("REPEAT!");}             \
     }                                                                   \
     LOG("done.");                                                       \
     } while (0)
 
+/* TYPECHECK_LEAVE: executed when the method is exited non-abruptly
+ * Input:
+ *     class........class of the current method
+ *     numlocals....number of local variables
+ *     vtype........current local variable types
+ *     vinfo........current local variable typeinfos
+ *     initmethod...true if this is an <init> method
+ */
+#define TYPECHECK_LEAVE                                                 \
+    do {                                                                \
+        if (initmethod && class != class_java_lang_Object) {            \
+            /* check the marker variable */                             \
+            LOG("Checking <init> marker");                              \
+            if (vtype[numlocals-1] == TYPE_VOID)                        \
+                panic("<init> method does not initialize 'this'");      \
+        }                                                               \
+    } while (0)
+
 /****************************************************************************/
 /* typecheck()                                                              */
 /****************************************************************************/
@@ -514,6 +561,7 @@ typecheck()
     instruction *iptr;               /* pointer to current instruction */
     basicblock *bptr;                /* pointer to current basic block */
     basicblock *tbptr;                   /* temporary for target block */
+    int numlocals;                        /* number of local variables */
     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 */
@@ -537,6 +585,8 @@ typecheck()
     xtable **handlers;                    /* active exception handlers */
     classinfo *cls;                                       /* temporary */
     bool maythrow;               /* true if this instruction may throw */
+    utf *name_init;                                        /* "<init>" */
+    bool initmethod;             /* true if this is an "<init>" method */
 
     LOGSTR("\n==============================================================================\n");
     DOLOG(show_icmd_method());
@@ -549,6 +599,9 @@ typecheck()
     LOGimpSTRu(method->class->name);
     LOGimpSTR(")\n");
 
+    name_init = utf_new_char("<init>");
+    initmethod = (method->name == name_init);
+
     /* XXX allocate buffers for method arguments */
     ptype = DMNEW(u1,MAXPARAMS);
     pinfo = DMNEW(typeinfo,MAXPARAMS);
@@ -580,14 +633,21 @@ typecheck()
 
     LOG("Blocks reset.\n");
 
+    /* number of local variables */
+    
+    /* In <init> methods we use an extra local variable to signal if
+     * the 'this' reference has been initialized. */
+    numlocals = maxlocals;
+    if (initmethod) numlocals++;
+
     /* 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));
+    vartype = DMNEW(u1,numlocals * (block_count+1));
+    vartypeinfo = DMNEW(typeinfo,numlocals * (block_count+1));
+    touched = DMNEW(u1,numlocals);
+    vtype = vartype + numlocals * block_count;
+    vinfo = vartypeinfo + numlocals * block_count;
+    memset(vartype,TYPE_VOID,numlocals * (block_count+1) * sizeof(typeinfo));
+    memset(vartypeinfo,0,numlocals * (block_count+1) * sizeof(typeinfo));
 
     LOG("Variable buffer initialized.\n");
 
@@ -609,7 +669,10 @@ typecheck()
     /* if this is an instance method initialize the "this" ref type */
     if (!(method->flags & ACC_STATIC)) {
         *ttype++ = TYPE_ADDRESS;
-        TYPEINFO_INIT_CLASSINFO(*tinfo,class);
+        if (initmethod)
+            TYPEINFO_INIT_NEWOBJECT(*tinfo,NULL);
+        else
+            TYPEINFO_INIT_CLASSINFO(*tinfo,class);
         tinfo++;
     }
 
@@ -617,7 +680,7 @@ typecheck()
 
     /* the rest of the arguments and the return type */
     typeinfo_init_from_method_args(method->descriptor,ttype,tinfo,
-                                   maxlocals - (tinfo-vartypeinfo),
+                                   numlocals - (tinfo-vartypeinfo),
                                    true, /* two word types use two slots */
                                    &returntype,&returntypeinfo);
 
@@ -657,10 +720,26 @@ typecheck()
                 /* init stack at the start of this block */
                 curstack = bptr->instack;
                                        
+                /* determine the active exception handlers for this block */
+                /* XXX could use a faster algorithm with sorted lists or
+                 * something? */
+                len = 0;
+                for (i=0; i<method->exceptiontablelength; ++i) {
+                    if ((extable[i].start <= bptr) && (extable[i].end > bptr)) {
+                        LOG1("active handler L%03d",extable[i].handler->debug_nr);
+                        handlers[len++] = extable + i;
+                    }
+                }
+                handlers[len] = NULL;
+                                       
                 /* 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]);
+                for (i=0; i<numlocals; ++i) {
+                    vtype[i] = vartype[numlocals*b_index + i];
+                    TYPEINFO_COPY(vartypeinfo[numlocals*b_index + i],vinfo[i]);
+
+                    if (handlers[0] &&
+                        vtype[i] == TYPE_ADR && TYPEINFO_IS_NEWOBJECT(vinfo[i]))
+                        panic("Uninitialized object in local variable inside try block");
                 }
 
                 /* init JSR target chain */
@@ -679,30 +758,18 @@ typecheck()
 #endif
 
                     subroutine = jsrbuffer[jsrchain->target - block];
-                    memcpy(touched,jsrchain->touched,sizeof(u1)*maxlocals);
+                    memcpy(touched,jsrchain->touched,sizeof(u1)*numlocals);
                 }
                 else
                     subroutine = NULL;
 #ifdef TYPECHECK_VERBOSE
                 if (typecheckverbose) {
                     if (subroutine) {LOGSTR1("subroutine L%03d\n",subroutine->target->debug_nr);LOGFLUSH;}
-                    typeinfo_print_block(get_logfile(),curstack,vtype,vinfo,(jsrchain) ? touched : NULL);
+                    typeinfo_print_block(get_logfile(),curstack,numlocals,vtype,vinfo,(jsrchain) ? touched : NULL);
                     LOGNL; LOGFLUSH;
                 }
 #endif
 
-                /* determine the active exception handlers for this block */
-                /* XXX could use a faster algorithm with sorted lists or
-                 * something? */
-                len = 0;
-                for (i=0; i<method->exceptiontablelength; ++i) {
-                    if ((extable[i].start <= bptr) && (extable[i].end > bptr)) {
-                        LOG1("active handler L%03d",extable[i].handler->debug_nr);
-                        handlers[len++] = extable + i;
-                    }
-                }
-                handlers[len] = NULL;
-                                       
                 /* loop over the instructions */
                 len = bptr->icount;
                 iptr = bptr->iinstr;
@@ -723,6 +790,12 @@ typecheck()
                         /* We just need to copy the typeinfo */
                         /* for slots containing addresses.   */
 
+                        /* XXX We assume that the destination stack
+                         * slots were continuously allocated in
+                         * memory.  (The current implementation in
+                         * stack.c)
+                         */
+
                       case ICMD_DUP:
                           COPYTYPE(curstack,dst);
                           break;
@@ -792,6 +865,11 @@ typecheck()
 
                       case ICMD_ASTORE:
                           /* TYPE_ADR has already been checked. */
+                          
+                          if (handlers[0] &&
+                              TYPEINFO_IS_NEWOBJECT(curstack->typeinfo))
+                              panic("Storing uninitialized object in local variable inside try block");
+                          
                           STORE_TYPE(iptr->op1,TYPE_ADDRESS);
                           TYPEINFO_COPY(curstack->typeinfo,vinfo[iptr->op1]);
                           break;
@@ -841,7 +919,7 @@ typecheck()
 
                       case ICMD_PUTSTATIC:
                           /* XXX */
-                          maythrow = true; /* XXX ? */
+                          maythrow = true;
                           break;
 
                       case ICMD_GETFIELD:
@@ -876,7 +954,7 @@ typecheck()
                                   TYPEINFO_INIT_PRIMITIVE(dst->typeinfo);
                               }
                           }
-                          /* XXX may throw? */
+                          maythrow = true;
                           break;
 
                           /****************************************/
@@ -987,7 +1065,7 @@ typecheck()
                           
                       case ICMD_ACONST:
                           if (iptr->val.a == NULL)
-                              TYPEINFO_INIT_NULLTYPE(dst->typeinfo)
+                              TYPEINFO_INIT_NULLTYPE(dst->typeinfo);
                           else
                               /* XXX constants for builtin functions */
                               /* string constants */
@@ -1068,6 +1146,8 @@ typecheck()
                           /****************************************/
                           /* RETURNS AND THROW                    */
 
+                          /* XXX returns may throw */
+
                       case ICMD_ATHROW:
                           TYPEINFO_INIT_CLASSINFO(tempinfo,class_java_lang_Throwable);
                           if (!typeinfo_is_assignable(&curstack->typeinfo,&tempinfo))
@@ -1083,33 +1163,39 @@ typecheck()
                           if (returntype != TYPE_ADDRESS
                               || !typeinfo_is_assignable(&curstack->typeinfo,&returntypeinfo))
                               panic("Return type mismatch");
-                                                         
+
+                          TYPECHECK_LEAVE;
                           superblockend = true;
                           break;
 
                       case ICMD_IRETURN:
                           if (returntype != TYPE_INT)
                               panic("Return type mismatch");
+                          TYPECHECK_LEAVE;
                           superblockend = true;
                           break;                           
                       case ICMD_LRETURN:
                           if (returntype != TYPE_LONG)
                               panic("Return type mismatch");
+                          TYPECHECK_LEAVE;
                           superblockend = true;
                           break;
                       case ICMD_FRETURN:
                           if (returntype != TYPE_FLOAT)
                               panic("Return type mismatch");
+                          TYPECHECK_LEAVE;
                           superblockend = true;
                           break;
                       case ICMD_DRETURN:
                           if (returntype != TYPE_DOUBLE)
                               panic("Return type mismatch");
+                          TYPECHECK_LEAVE;
                           superblockend = true;
                           break;
                       case ICMD_RETURN:
                           if (returntype != TYPE_VOID)
                               panic("Return type mismatch");
+                          TYPECHECK_LEAVE;
                           superblockend = true;
                           break;
                                                     
@@ -1151,7 +1237,7 @@ typecheck()
                            */
                           if (jsrtemp->sbr_touched) {
                               /* Calculate the local variables after the subroutine call */
-                              for (i=0; i<maxlocals; ++i)
+                              for (i=0; i<numlocals; ++i)
                                   if (jsrtemp->sbr_touched[i] != TOUCHED_NO) {
                                       TOUCH_VARIABLE(i);
                                       if ((vtype[i] = jsrtemp->sbr_vtype[i]) == TYPE_ADR)
@@ -1185,19 +1271,19 @@ typecheck()
                           /* determine which variables are touched by this subroutine */
                           /* and their types */
                           if (subroutine->sbr_touched) {
-                              for (i=0; i<maxlocals; ++i)
+                              for (i=0; i<numlocals; ++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)
+                              subroutine->sbr_touched = DMNEW(u1,numlocals);
+                              memcpy(subroutine->sbr_touched,touched,sizeof(u1)*numlocals);
+                              subroutine->sbr_vtype = DMNEW(u1,numlocals);
+                              memcpy(subroutine->sbr_vtype,vtype,sizeof(u1)*numlocals);
+                              subroutine->sbr_vinfo = DMNEW(typeinfo,numlocals);
+                              for (i=0; i<numlocals; ++i)
                                   if (vtype[i] == TYPE_ADR)
                                       TYPEINFO_CLONE(vinfo[i],subroutine->sbr_vinfo[i]);
                           }
@@ -1205,7 +1291,7 @@ typecheck()
 
                           LOGSTR("subroutine touches:");
                           DOLOG(typeinfo_print_locals(get_logfile(),subroutine->sbr_vtype,subroutine->sbr_vinfo,
-                                                      subroutine->sbr_touched,maxlocals));
+                                                      subroutine->sbr_touched,numlocals));
                           LOGNL; LOGFLUSH;
 
                           /* reach blocks after JSR statements */
@@ -1238,6 +1324,9 @@ typecheck()
                               /* XXX check access rights */
                               
                               methodinfo *mi = (methodinfo*) iptr->val.a;
+                              bool callinginit = (opcode == ICMD_INVOKESPECIAL && mi->name == name_init);
+                              instruction *ins;
+                              classinfo *initclass;
 
                               /* XXX for INVOKESPECIAL: check if the invokation is done at all */
 
@@ -1263,8 +1352,24 @@ typecheck()
                                   if (srcstack->type == TYPE_ADR) {
                                       LOGINFO(&(srcstack->typeinfo));
                                       LOGINFO(pinfo + i);
-                                      if (!typeinfo_is_assignable(&(srcstack->typeinfo),pinfo+i))
-                                          panic("Parameter reference type mismatch in method invocation");
+                                      if (i==0 && callinginit)
+                                      {
+                                          /* first argument to <init> method */
+                                          if (!TYPEINFO_IS_NEWOBJECT(srcstack->typeinfo))
+                                              panic("Calling <init> on initialized object");
+                                          
+                                          /* get the address of the NEW instruction */
+                                          LOGINFO(&(srcstack->typeinfo));
+                                          ins = (instruction*)TYPEINFO_NEWOBJECT_INSTRUCTION(srcstack->typeinfo);
+                                          initclass = (ins) ? (classinfo*)ins[-1].val.a : method->class;
+                                          LOGSTR("class: "); LOGSTRu(initclass->name); LOGNL;
+
+                                          /* XXX check type */
+                                      }
+                                      else {
+                                          if (!typeinfo_is_assignable(&(srcstack->typeinfo),pinfo+i))
+                                              panic("Parameter reference type mismatch in method invocation");
+                                      }
                                   }
                                   LOG("ok");
 
@@ -1276,6 +1381,38 @@ typecheck()
                                       panic("Return type mismatch in method invocation");
                                   TYPEINFO_COPY(rinfo,dst->typeinfo);
                               }
+
+                              if (callinginit) {
+                                  /* replace uninitialized object type on stack */
+                                  srcstack = dst;
+                                  while (srcstack) {
+                                      if (srcstack->type == TYPE_ADR
+                                          && TYPEINFO_IS_NEWOBJECT(srcstack->typeinfo)
+                                          && TYPEINFO_NEWOBJECT_INSTRUCTION(srcstack->typeinfo) == ins)
+                                      {
+                                          LOG("replacing uninitialized type on stack");
+                                          TYPEINFO_INIT_CLASSINFO(srcstack->typeinfo,initclass);
+                                      }
+                                      srcstack = srcstack->prev;
+                                  }
+                                  /* replace uninitialized object type in locals */
+                                  for (i=0; i<numlocals; ++i) {
+                                      if (vtype[i] == TYPE_ADR
+                                          && TYPEINFO_IS_NEWOBJECT(vinfo[i])
+                                          && TYPEINFO_NEWOBJECT_INSTRUCTION(vinfo[i]) == ins)
+                                      {
+                                          LOG1("replacing uninitialized type in local %d",i);
+                                          TYPEINFO_INIT_CLASSINFO(vinfo[i],initclass);
+                                      }
+                                  }
+
+                                  /* initializing the 'this' reference? */
+                                  if (initmethod && !ins) {
+                                      /* set our marker variable to type int */
+                                      LOG("setting <init> marker");
+                                      STORE_PRIMITIVE(numlocals-1,TYPE_INT);
+                                  }
+                              }
                           }
                           maythrow = true;
                           break;
@@ -1341,7 +1478,7 @@ typecheck()
                           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);
+                              TYPEINFO_INIT_NEWOBJECT(dst->typeinfo,iptr);
                           }
                           else if (ISBUILTIN(builtin_newarray_boolean)) {
                               TYPEINFO_INIT_PRIMITIVE_ARRAY(dst->typeinfo,ARRAYTYPE_BOOLEAN);
@@ -1418,15 +1555,37 @@ typecheck()
 
                           /****************************************/
                           /* ARITHMETIC AND CONVERSION            */
+                          /* (These instructions are typechecked in analyse_stack.) */
 
-                          /* These instructions are typechecked in analyse_stack. */
-                                                /* XXX only add cases for them in debug mode? */
+                          /* The following instructions may throw a runtime exception: */
+                          
+                      case ICMD_IDIV:
+                      case ICMD_IREM:
+                      case ICMD_LDIV:
+                      case ICMD_LREM:
+                          
+                          maythrow = true;
+                          break;
+                          
+                          /* The following instructions never throw a runtime exception: */
+                          /* XXX only add cases for them in debug mode? */
+                          
+                      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:
 
                       case ICMD_IADD:
                       case ICMD_ISUB:
                       case ICMD_IMUL:
-                      case ICMD_IDIV:
-                      case ICMD_IREM:
                       case ICMD_INEG:
                       case ICMD_IAND:
                       case ICMD_IOR:
@@ -1437,8 +1596,6 @@ typecheck()
                       case ICMD_LADD:
                       case ICMD_LSUB:
                       case ICMD_LMUL:
-                      case ICMD_LDIV:
-                      case ICMD_LREM:
                       case ICMD_LNEG:
                       case ICMD_LAND:
                       case ICMD_LOR:
@@ -1471,6 +1628,22 @@ typecheck()
                       case ICMD_LUSHRCONST:
                       case ICMD_LREMPOW2:
                           
+                      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_LCMP:
                       case ICMD_LCMPCONST:
                       case ICMD_FCMPL:
@@ -1491,44 +1664,12 @@ typecheck()
                       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:
-
-                          maythrow = true; /* XXX be more selective here */
-                          break;
-                          
-                      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));
+                          LOG2("ICMD %d at %d\n", iptr->opc, (int)(iptr-instr));
                           panic("Missing ICMD code during typecheck");
                     }
 
@@ -1545,13 +1686,18 @@ typecheck()
                             i++;
                         }
                     }
+
+                    /*
+                      DOLOG(typeinfo_print_block(get_logfile(),curstack,numlocals,vtype,vinfo,(jsrchain) ? touched : NULL));
+                      LOGNL; LOGFLUSH;
+                    */
                     
                     iptr++;
                 } /* while instructions */
 
                 LOG("instructions done");
                 LOGSTR("RESULT=> ");
-                DOLOG(typeinfo_print_block(get_logfile(),curstack,vtype,vinfo,(jsrchain) ? touched : NULL));
+                DOLOG(typeinfo_print_block(get_logfile(),curstack,numlocals,vtype,vinfo,(jsrchain) ? touched : NULL));
                 LOGNL; LOGFLUSH;
                 
                 /* propagate stack and variables to the following block */
index 945d41aaf5417154b9962079552e9a76af5d2d4e..4aaf84dffa297f15e09661cdad2e602c757ba8fc 100644 (file)
--- a/loader.c
+++ b/loader.c
@@ -30,7 +30,7 @@
             Mark Probst
                        Edwin Steiner
 
-   $Id: loader.c 696 2003-12-06 20:10:05Z edwin $
+   $Id: loader.c 719 2003-12-08 14:26:05Z edwin $
 
 */
 
@@ -128,6 +128,7 @@ classinfo *class_java_io_Serializable;
 /* Pseudo classes for the typechecker */
 classinfo *pseudo_class_Arraystub = NULL;
 classinfo *pseudo_class_Null = NULL;
+classinfo *pseudo_class_New = NULL;
 vftbl *pseudo_class_Arraystub_vftbl = NULL;
 
 /* stefan */
@@ -2940,6 +2941,16 @@ create_pseudo_classes()
 
     list_addlast(&unlinkedclasses,pseudo_class_Null);
     class_link(pseudo_class_Null);     
+
+    /* pseudo class representing new uninitialized objects */
+    
+    pseudo_class_New = class_new( utf_new_char("$NEW$") );
+    list_remove(&unloadedclasses,pseudo_class_New);
+
+    pseudo_class_New->super = class_java_lang_Object;
+
+    list_addlast(&unlinkedclasses,pseudo_class_New);
+    class_link(pseudo_class_New);      
 }
 
 /********************** Function: loader_init **********************************
index efc7eda7282514a6eea7113c9bce81421f02b745..1c3430d3cb1e82ace0d74d21a2d4056f1c165e44 100644 (file)
@@ -31,7 +31,7 @@
             Philipp Tomsich
                        Edwin Steiner
 
-   $Id: global.h 717 2003-12-07 22:02:19Z twisti $
+   $Id: global.h 719 2003-12-08 14:26:05Z edwin $
 
 */
 
@@ -747,6 +747,7 @@ extern classinfo *class_java_lang_ArrayStoreException;
 extern classinfo *class_java_lang_ThreadDeath;
 extern classinfo *pseudo_class_Arraystub;
 extern classinfo *pseudo_class_Null;
+extern classinfo *pseudo_class_New;
 extern vftbl *pseudo_class_Arraystub_vftbl;
 
 
index 4799a064a60dab5dbd623e5b6689848f75d408f6..e8ec5dc34dea49f587d884c565895ea8f73d14c8 100644 (file)
@@ -28,7 +28,7 @@
 
    Changes: Edwin Steiner
 
-   $Id: stack.c 696 2003-12-06 20:10:05Z edwin $
+   $Id: stack.c 719 2003-12-08 14:26:05Z edwin $
 
 */
 
@@ -1505,6 +1505,7 @@ void analyse_stack()
                                                        i = iptr->op1;
                                                        if (i > arguments_num)
                                                                arguments_num = i;
+                                                       /* XXX verify that there are enough arguments on the stack */
 #if defined(__X86_64__)
                                                        {
                                                                int iarg = 0;
index 98bd6cc445ed77e23e6226a9a03ed5a218960594..5ef48502f6a92a36652be5428e7e7a767b54d9c0 100644 (file)
@@ -26,7 +26,7 @@
 
    Authors: Edwin Steiner
 
-   $Id: typecheck.c 701 2003-12-07 16:26:58Z edwin $
+   $Id: typecheck.c 719 2003-12-08 14:26:05Z edwin $
 
 */
 
@@ -136,18 +136,18 @@ typeinfo_print_stack(FILE *file,stackptr stack)
 static
 void
 typeinfo_print_block(FILE *file,stackptr instack,
-                     u1 *vtype,typeinfo *vinfo,u1 *touched)
+                     int vnum,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);
+    typeinfo_print_locals(file,vtype,vinfo,touched,vnum);
 }
 
 
 static
 void
-typeinfo_print_blocks(FILE *file,u1 *vtype,typeinfo *vinfo)
+typeinfo_print_blocks(FILE *file,int vnum,u1 *vtype,typeinfo *vinfo)
 {
     int bi;
     /*    int j;*/
@@ -155,7 +155,7 @@ typeinfo_print_blocks(FILE *file,u1 *vtype,typeinfo *vinfo)
     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);
+                             vnum,vtype+vnum*bi,vinfo+vnum*bi,NULL);
         fprintf(file,"\n");
 
 /*         for (j=0; j<block[bi].icount; ++j) { */
@@ -223,14 +223,14 @@ struct jsr_record {
  *     vinfo......current local variable typeinfos
  *     ttype......local variable types of target block
  *     tinfo......local variable typeinfos of target block
- *     maxlocals..number of local variables
+ *     numlocals..number of local variables
  * Used:
  *     macro_i
  */
 #define TYPECHECK_COPYVARS                                      \
     do {                                                        \
     LOG("TYPECHECK_COPYVARS");                                  \
-    for (macro_i=0; macro_i<maxlocals; ++macro_i) {             \
+    for (macro_i=0; macro_i<numlocals; ++macro_i) {             \
         if ((ttype[macro_i] = vtype[macro_i]) == TYPE_ADR)      \
             TYPEINFO_CLONE(vinfo[macro_i],tinfo[macro_i]);      \
     } } while(0)
@@ -242,7 +242,7 @@ struct jsr_record {
  *     vinfo......current local variable typeinfos
  *     ttype......local variable types of target block
  *     tinfo......local variable typeinfos of target block
- *     maxlocals..number of local variables
+ *     numlocals..number of local variables
  * Ouput:
  *     changed....set to true if any typeinfo has changed
  * Used:
@@ -251,7 +251,7 @@ struct jsr_record {
 #define TYPECHECK_MERGEVARS                                             \
     do {                                                                \
     LOG("TYPECHECK_MERGEVARS");                                         \
-    for (macro_i=0; macro_i<maxlocals; ++macro_i) {                     \
+    for (macro_i=0; macro_i<numlocals; ++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;                                 \
@@ -281,7 +281,7 @@ struct jsr_record {
  * Ouput:
  *     tbptr......target block
  *     changed....set to true if any typeinfo has changed
- *     maxlocals..number of local variables
+ *     numlocals..number of local variables
  *     touched....current touched flags of local variables
  * Used:
  *     macro_i, jsrtemp, jsrtemp2
@@ -301,7 +301,7 @@ struct jsr_record {
     }                                                                   \
     jsrtemp = jsrbuffer[tbptr-block];                                   \
     if (jsrtemp)                                                        \
-        for (macro_i=0; macro_i<maxlocals; ++macro_i) {                 \
+        for (macro_i=0; macro_i<numlocals; ++macro_i) {                 \
             jsrtemp->touched[i] |= touched[i];                          \
     } } while (0)
 
@@ -393,7 +393,7 @@ struct jsr_record {
  * Input:
  *     jsrchain...current JSR target chain
  *     tbptr.....the basic block targeted by the JSR
- *     maxlocals..number of local variables
+ *     numlocals..number of local variables
  *     jsrbuffer..JSR target chain for each basic block
  * Used:
  *     jsrtemp
@@ -401,11 +401,11 @@ struct jsr_record {
 #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 = (jsr_record *) dump_alloc(sizeof(jsr_record)+(numlocals-1)*sizeof(u1)); \
     jsrtemp->target = (tbptr);                                          \
     jsrtemp->next = jsrchain;                                           \
     jsrtemp->sbr_touched = NULL;                                        \
-    memset(&jsrtemp->touched,TOUCHED_NO,sizeof(u1)*maxlocals);          \
+    memset(&jsrtemp->touched,TOUCHED_NO,sizeof(u1)*numlocals);          \
     jsrbuffer[tbptr-block] = jsrtemp;                                   \
     } while (0)
 
@@ -414,7 +414,7 @@ struct jsr_record {
  * Input:
  *     chain......current JSR target chain
  *     tbptr.....the basic block targeted by the JSR
- *     maxlocals..number of local variables
+ *     numlocals..number of local variables
  *     jsrbuffer..JSR target chain for each basic block
  *     touched....current touched flags of local variables
  * Used:
@@ -424,17 +424,43 @@ struct jsr_record {
     do {                                                                \
         LOG("TYPECHECK_COPYJSR");                                       \
         if (chain) {                                                    \
-            jsrtemp = (jsr_record *) dump_alloc(sizeof(jsr_record)+(maxlocals-1)*sizeof(u1)); \
+            jsrtemp = (jsr_record *) dump_alloc(sizeof(jsr_record)+(numlocals-1)*sizeof(u1)); \
             jsrtemp->target = (chain)->target;                          \
             jsrtemp->next = (chain)->next;                              \
             jsrtemp->sbr_touched = NULL;                                \
-            memcpy(&jsrtemp->touched,touched,sizeof(u1)*maxlocals);     \
+            memcpy(&jsrtemp->touched,touched,sizeof(u1)*numlocals);     \
             jsrbuffer[tbptr-block] = jsrtemp;                           \
         }                                                               \
         else                                                            \
             jsrbuffer[tbptr-block] = NULL;                              \
     } while (0)
 
+/* TYPECHECK_BRANCH_BACKWARDS: executed when control flow moves
+ *     backwards. Checks if there are uninitialized objects on the
+ *     stack or in local variables.
+ * Input:
+ *     dst........current output stack pointer (not needed for REACH_THROW)
+ *     vtype......current local variable types
+ *     vinfo......current local variable typeinfos
+ * Used:
+ *     srcstack, macro_i
+ */
+#define TYPECHECK_BRANCH_BACKWARDS                                      \
+    do {                                                                \
+        LOG("BACKWARDS!");                                              \
+        srcstack = dst;                                                 \
+        while (srcstack) {                                              \
+            if (srcstack->type == TYPE_ADR &&                           \
+                TYPEINFO_IS_NEWOBJECT(srcstack->typeinfo))              \
+                panic("Branching backwards with uninitialized object on stack"); \
+            srcstack = srcstack->prev;                                  \
+        }                                                               \
+        for (macro_i=0; macro_i<numlocals; ++macro_i)                   \
+            if (vtype[macro_i] == TYPE_ADR &&                           \
+                TYPEINFO_IS_NEWOBJECT(vinfo[macro_i]))                  \
+                panic("Branching backwards with uninitialized object in local variable"); \
+    } 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.
@@ -442,6 +468,7 @@ struct jsr_record {
  *     bptr.......current block
  *     tbptr......target block
  *     dst........current output stack pointer (not needed for REACH_THROW)
+ *     numlocals..number of local variables
  *     vtype......current local variable types
  *     vinfo......current local variable typeinfos
  *     jsrchain...current JSR target chain
@@ -457,10 +484,12 @@ struct jsr_record {
 #define TYPECHECK_REACH(way)                                            \
     do {                                                                \
     LOG2("reaching block %04d (%d)",tbptr-block,way);                   \
+    if (tbptr <= bptr && way != REACH_THROW)                            \
+        TYPECHECK_BRANCH_BACKWARDS;                                     \
     srcstack = dst;                                                     \
     dststack = tbptr->instack;                                          \
-    ttype = vartype + maxlocals*(tbptr-block);                          \
-    tinfo = vartypeinfo + maxlocals*(tbptr-block);                      \
+    ttype = vartype + numlocals*(tbptr-block);                          \
+    tinfo = vartypeinfo + numlocals*(tbptr-block);                      \
     if (tbptr->flags == BBTYPECHECK_UNDEF) {                            \
         /* This block is reached for the first time */                  \
         if (way == REACH_JSR) {                                         \
@@ -486,11 +515,29 @@ struct jsr_record {
     if (changed) {                                                      \
         LOG("REACHED!");                                                \
         tbptr->flags = BBTYPECHECK_REACHED;                             \
-        if (tbptr <= bptr) {repeat = true; LOG("MUST REPEAT!");}        \
+        if (tbptr <= bptr) {repeat = true; LOG("REPEAT!");}             \
     }                                                                   \
     LOG("done.");                                                       \
     } while (0)
 
+/* TYPECHECK_LEAVE: executed when the method is exited non-abruptly
+ * Input:
+ *     class........class of the current method
+ *     numlocals....number of local variables
+ *     vtype........current local variable types
+ *     vinfo........current local variable typeinfos
+ *     initmethod...true if this is an <init> method
+ */
+#define TYPECHECK_LEAVE                                                 \
+    do {                                                                \
+        if (initmethod && class != class_java_lang_Object) {            \
+            /* check the marker variable */                             \
+            LOG("Checking <init> marker");                              \
+            if (vtype[numlocals-1] == TYPE_VOID)                        \
+                panic("<init> method does not initialize 'this'");      \
+        }                                                               \
+    } while (0)
+
 /****************************************************************************/
 /* typecheck()                                                              */
 /****************************************************************************/
@@ -514,6 +561,7 @@ typecheck()
     instruction *iptr;               /* pointer to current instruction */
     basicblock *bptr;                /* pointer to current basic block */
     basicblock *tbptr;                   /* temporary for target block */
+    int numlocals;                        /* number of local variables */
     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 */
@@ -537,6 +585,8 @@ typecheck()
     xtable **handlers;                    /* active exception handlers */
     classinfo *cls;                                       /* temporary */
     bool maythrow;               /* true if this instruction may throw */
+    utf *name_init;                                        /* "<init>" */
+    bool initmethod;             /* true if this is an "<init>" method */
 
     LOGSTR("\n==============================================================================\n");
     DOLOG(show_icmd_method());
@@ -549,6 +599,9 @@ typecheck()
     LOGimpSTRu(method->class->name);
     LOGimpSTR(")\n");
 
+    name_init = utf_new_char("<init>");
+    initmethod = (method->name == name_init);
+
     /* XXX allocate buffers for method arguments */
     ptype = DMNEW(u1,MAXPARAMS);
     pinfo = DMNEW(typeinfo,MAXPARAMS);
@@ -580,14 +633,21 @@ typecheck()
 
     LOG("Blocks reset.\n");
 
+    /* number of local variables */
+    
+    /* In <init> methods we use an extra local variable to signal if
+     * the 'this' reference has been initialized. */
+    numlocals = maxlocals;
+    if (initmethod) numlocals++;
+
     /* 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));
+    vartype = DMNEW(u1,numlocals * (block_count+1));
+    vartypeinfo = DMNEW(typeinfo,numlocals * (block_count+1));
+    touched = DMNEW(u1,numlocals);
+    vtype = vartype + numlocals * block_count;
+    vinfo = vartypeinfo + numlocals * block_count;
+    memset(vartype,TYPE_VOID,numlocals * (block_count+1) * sizeof(typeinfo));
+    memset(vartypeinfo,0,numlocals * (block_count+1) * sizeof(typeinfo));
 
     LOG("Variable buffer initialized.\n");
 
@@ -609,7 +669,10 @@ typecheck()
     /* if this is an instance method initialize the "this" ref type */
     if (!(method->flags & ACC_STATIC)) {
         *ttype++ = TYPE_ADDRESS;
-        TYPEINFO_INIT_CLASSINFO(*tinfo,class);
+        if (initmethod)
+            TYPEINFO_INIT_NEWOBJECT(*tinfo,NULL);
+        else
+            TYPEINFO_INIT_CLASSINFO(*tinfo,class);
         tinfo++;
     }
 
@@ -617,7 +680,7 @@ typecheck()
 
     /* the rest of the arguments and the return type */
     typeinfo_init_from_method_args(method->descriptor,ttype,tinfo,
-                                   maxlocals - (tinfo-vartypeinfo),
+                                   numlocals - (tinfo-vartypeinfo),
                                    true, /* two word types use two slots */
                                    &returntype,&returntypeinfo);
 
@@ -657,10 +720,26 @@ typecheck()
                 /* init stack at the start of this block */
                 curstack = bptr->instack;
                                        
+                /* determine the active exception handlers for this block */
+                /* XXX could use a faster algorithm with sorted lists or
+                 * something? */
+                len = 0;
+                for (i=0; i<method->exceptiontablelength; ++i) {
+                    if ((extable[i].start <= bptr) && (extable[i].end > bptr)) {
+                        LOG1("active handler L%03d",extable[i].handler->debug_nr);
+                        handlers[len++] = extable + i;
+                    }
+                }
+                handlers[len] = NULL;
+                                       
                 /* 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]);
+                for (i=0; i<numlocals; ++i) {
+                    vtype[i] = vartype[numlocals*b_index + i];
+                    TYPEINFO_COPY(vartypeinfo[numlocals*b_index + i],vinfo[i]);
+
+                    if (handlers[0] &&
+                        vtype[i] == TYPE_ADR && TYPEINFO_IS_NEWOBJECT(vinfo[i]))
+                        panic("Uninitialized object in local variable inside try block");
                 }
 
                 /* init JSR target chain */
@@ -679,30 +758,18 @@ typecheck()
 #endif
 
                     subroutine = jsrbuffer[jsrchain->target - block];
-                    memcpy(touched,jsrchain->touched,sizeof(u1)*maxlocals);
+                    memcpy(touched,jsrchain->touched,sizeof(u1)*numlocals);
                 }
                 else
                     subroutine = NULL;
 #ifdef TYPECHECK_VERBOSE
                 if (typecheckverbose) {
                     if (subroutine) {LOGSTR1("subroutine L%03d\n",subroutine->target->debug_nr);LOGFLUSH;}
-                    typeinfo_print_block(get_logfile(),curstack,vtype,vinfo,(jsrchain) ? touched : NULL);
+                    typeinfo_print_block(get_logfile(),curstack,numlocals,vtype,vinfo,(jsrchain) ? touched : NULL);
                     LOGNL; LOGFLUSH;
                 }
 #endif
 
-                /* determine the active exception handlers for this block */
-                /* XXX could use a faster algorithm with sorted lists or
-                 * something? */
-                len = 0;
-                for (i=0; i<method->exceptiontablelength; ++i) {
-                    if ((extable[i].start <= bptr) && (extable[i].end > bptr)) {
-                        LOG1("active handler L%03d",extable[i].handler->debug_nr);
-                        handlers[len++] = extable + i;
-                    }
-                }
-                handlers[len] = NULL;
-                                       
                 /* loop over the instructions */
                 len = bptr->icount;
                 iptr = bptr->iinstr;
@@ -723,6 +790,12 @@ typecheck()
                         /* We just need to copy the typeinfo */
                         /* for slots containing addresses.   */
 
+                        /* XXX We assume that the destination stack
+                         * slots were continuously allocated in
+                         * memory.  (The current implementation in
+                         * stack.c)
+                         */
+
                       case ICMD_DUP:
                           COPYTYPE(curstack,dst);
                           break;
@@ -792,6 +865,11 @@ typecheck()
 
                       case ICMD_ASTORE:
                           /* TYPE_ADR has already been checked. */
+                          
+                          if (handlers[0] &&
+                              TYPEINFO_IS_NEWOBJECT(curstack->typeinfo))
+                              panic("Storing uninitialized object in local variable inside try block");
+                          
                           STORE_TYPE(iptr->op1,TYPE_ADDRESS);
                           TYPEINFO_COPY(curstack->typeinfo,vinfo[iptr->op1]);
                           break;
@@ -841,7 +919,7 @@ typecheck()
 
                       case ICMD_PUTSTATIC:
                           /* XXX */
-                          maythrow = true; /* XXX ? */
+                          maythrow = true;
                           break;
 
                       case ICMD_GETFIELD:
@@ -876,7 +954,7 @@ typecheck()
                                   TYPEINFO_INIT_PRIMITIVE(dst->typeinfo);
                               }
                           }
-                          /* XXX may throw? */
+                          maythrow = true;
                           break;
 
                           /****************************************/
@@ -987,7 +1065,7 @@ typecheck()
                           
                       case ICMD_ACONST:
                           if (iptr->val.a == NULL)
-                              TYPEINFO_INIT_NULLTYPE(dst->typeinfo)
+                              TYPEINFO_INIT_NULLTYPE(dst->typeinfo);
                           else
                               /* XXX constants for builtin functions */
                               /* string constants */
@@ -1068,6 +1146,8 @@ typecheck()
                           /****************************************/
                           /* RETURNS AND THROW                    */
 
+                          /* XXX returns may throw */
+
                       case ICMD_ATHROW:
                           TYPEINFO_INIT_CLASSINFO(tempinfo,class_java_lang_Throwable);
                           if (!typeinfo_is_assignable(&curstack->typeinfo,&tempinfo))
@@ -1083,33 +1163,39 @@ typecheck()
                           if (returntype != TYPE_ADDRESS
                               || !typeinfo_is_assignable(&curstack->typeinfo,&returntypeinfo))
                               panic("Return type mismatch");
-                                                         
+
+                          TYPECHECK_LEAVE;
                           superblockend = true;
                           break;
 
                       case ICMD_IRETURN:
                           if (returntype != TYPE_INT)
                               panic("Return type mismatch");
+                          TYPECHECK_LEAVE;
                           superblockend = true;
                           break;                           
                       case ICMD_LRETURN:
                           if (returntype != TYPE_LONG)
                               panic("Return type mismatch");
+                          TYPECHECK_LEAVE;
                           superblockend = true;
                           break;
                       case ICMD_FRETURN:
                           if (returntype != TYPE_FLOAT)
                               panic("Return type mismatch");
+                          TYPECHECK_LEAVE;
                           superblockend = true;
                           break;
                       case ICMD_DRETURN:
                           if (returntype != TYPE_DOUBLE)
                               panic("Return type mismatch");
+                          TYPECHECK_LEAVE;
                           superblockend = true;
                           break;
                       case ICMD_RETURN:
                           if (returntype != TYPE_VOID)
                               panic("Return type mismatch");
+                          TYPECHECK_LEAVE;
                           superblockend = true;
                           break;
                                                     
@@ -1151,7 +1237,7 @@ typecheck()
                            */
                           if (jsrtemp->sbr_touched) {
                               /* Calculate the local variables after the subroutine call */
-                              for (i=0; i<maxlocals; ++i)
+                              for (i=0; i<numlocals; ++i)
                                   if (jsrtemp->sbr_touched[i] != TOUCHED_NO) {
                                       TOUCH_VARIABLE(i);
                                       if ((vtype[i] = jsrtemp->sbr_vtype[i]) == TYPE_ADR)
@@ -1185,19 +1271,19 @@ typecheck()
                           /* determine which variables are touched by this subroutine */
                           /* and their types */
                           if (subroutine->sbr_touched) {
-                              for (i=0; i<maxlocals; ++i)
+                              for (i=0; i<numlocals; ++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)
+                              subroutine->sbr_touched = DMNEW(u1,numlocals);
+                              memcpy(subroutine->sbr_touched,touched,sizeof(u1)*numlocals);
+                              subroutine->sbr_vtype = DMNEW(u1,numlocals);
+                              memcpy(subroutine->sbr_vtype,vtype,sizeof(u1)*numlocals);
+                              subroutine->sbr_vinfo = DMNEW(typeinfo,numlocals);
+                              for (i=0; i<numlocals; ++i)
                                   if (vtype[i] == TYPE_ADR)
                                       TYPEINFO_CLONE(vinfo[i],subroutine->sbr_vinfo[i]);
                           }
@@ -1205,7 +1291,7 @@ typecheck()
 
                           LOGSTR("subroutine touches:");
                           DOLOG(typeinfo_print_locals(get_logfile(),subroutine->sbr_vtype,subroutine->sbr_vinfo,
-                                                      subroutine->sbr_touched,maxlocals));
+                                                      subroutine->sbr_touched,numlocals));
                           LOGNL; LOGFLUSH;
 
                           /* reach blocks after JSR statements */
@@ -1238,6 +1324,9 @@ typecheck()
                               /* XXX check access rights */
                               
                               methodinfo *mi = (methodinfo*) iptr->val.a;
+                              bool callinginit = (opcode == ICMD_INVOKESPECIAL && mi->name == name_init);
+                              instruction *ins;
+                              classinfo *initclass;
 
                               /* XXX for INVOKESPECIAL: check if the invokation is done at all */
 
@@ -1263,8 +1352,24 @@ typecheck()
                                   if (srcstack->type == TYPE_ADR) {
                                       LOGINFO(&(srcstack->typeinfo));
                                       LOGINFO(pinfo + i);
-                                      if (!typeinfo_is_assignable(&(srcstack->typeinfo),pinfo+i))
-                                          panic("Parameter reference type mismatch in method invocation");
+                                      if (i==0 && callinginit)
+                                      {
+                                          /* first argument to <init> method */
+                                          if (!TYPEINFO_IS_NEWOBJECT(srcstack->typeinfo))
+                                              panic("Calling <init> on initialized object");
+                                          
+                                          /* get the address of the NEW instruction */
+                                          LOGINFO(&(srcstack->typeinfo));
+                                          ins = (instruction*)TYPEINFO_NEWOBJECT_INSTRUCTION(srcstack->typeinfo);
+                                          initclass = (ins) ? (classinfo*)ins[-1].val.a : method->class;
+                                          LOGSTR("class: "); LOGSTRu(initclass->name); LOGNL;
+
+                                          /* XXX check type */
+                                      }
+                                      else {
+                                          if (!typeinfo_is_assignable(&(srcstack->typeinfo),pinfo+i))
+                                              panic("Parameter reference type mismatch in method invocation");
+                                      }
                                   }
                                   LOG("ok");
 
@@ -1276,6 +1381,38 @@ typecheck()
                                       panic("Return type mismatch in method invocation");
                                   TYPEINFO_COPY(rinfo,dst->typeinfo);
                               }
+
+                              if (callinginit) {
+                                  /* replace uninitialized object type on stack */
+                                  srcstack = dst;
+                                  while (srcstack) {
+                                      if (srcstack->type == TYPE_ADR
+                                          && TYPEINFO_IS_NEWOBJECT(srcstack->typeinfo)
+                                          && TYPEINFO_NEWOBJECT_INSTRUCTION(srcstack->typeinfo) == ins)
+                                      {
+                                          LOG("replacing uninitialized type on stack");
+                                          TYPEINFO_INIT_CLASSINFO(srcstack->typeinfo,initclass);
+                                      }
+                                      srcstack = srcstack->prev;
+                                  }
+                                  /* replace uninitialized object type in locals */
+                                  for (i=0; i<numlocals; ++i) {
+                                      if (vtype[i] == TYPE_ADR
+                                          && TYPEINFO_IS_NEWOBJECT(vinfo[i])
+                                          && TYPEINFO_NEWOBJECT_INSTRUCTION(vinfo[i]) == ins)
+                                      {
+                                          LOG1("replacing uninitialized type in local %d",i);
+                                          TYPEINFO_INIT_CLASSINFO(vinfo[i],initclass);
+                                      }
+                                  }
+
+                                  /* initializing the 'this' reference? */
+                                  if (initmethod && !ins) {
+                                      /* set our marker variable to type int */
+                                      LOG("setting <init> marker");
+                                      STORE_PRIMITIVE(numlocals-1,TYPE_INT);
+                                  }
+                              }
                           }
                           maythrow = true;
                           break;
@@ -1341,7 +1478,7 @@ typecheck()
                           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);
+                              TYPEINFO_INIT_NEWOBJECT(dst->typeinfo,iptr);
                           }
                           else if (ISBUILTIN(builtin_newarray_boolean)) {
                               TYPEINFO_INIT_PRIMITIVE_ARRAY(dst->typeinfo,ARRAYTYPE_BOOLEAN);
@@ -1418,15 +1555,37 @@ typecheck()
 
                           /****************************************/
                           /* ARITHMETIC AND CONVERSION            */
+                          /* (These instructions are typechecked in analyse_stack.) */
 
-                          /* These instructions are typechecked in analyse_stack. */
-                                                /* XXX only add cases for them in debug mode? */
+                          /* The following instructions may throw a runtime exception: */
+                          
+                      case ICMD_IDIV:
+                      case ICMD_IREM:
+                      case ICMD_LDIV:
+                      case ICMD_LREM:
+                          
+                          maythrow = true;
+                          break;
+                          
+                          /* The following instructions never throw a runtime exception: */
+                          /* XXX only add cases for them in debug mode? */
+                          
+                      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:
 
                       case ICMD_IADD:
                       case ICMD_ISUB:
                       case ICMD_IMUL:
-                      case ICMD_IDIV:
-                      case ICMD_IREM:
                       case ICMD_INEG:
                       case ICMD_IAND:
                       case ICMD_IOR:
@@ -1437,8 +1596,6 @@ typecheck()
                       case ICMD_LADD:
                       case ICMD_LSUB:
                       case ICMD_LMUL:
-                      case ICMD_LDIV:
-                      case ICMD_LREM:
                       case ICMD_LNEG:
                       case ICMD_LAND:
                       case ICMD_LOR:
@@ -1471,6 +1628,22 @@ typecheck()
                       case ICMD_LUSHRCONST:
                       case ICMD_LREMPOW2:
                           
+                      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_LCMP:
                       case ICMD_LCMPCONST:
                       case ICMD_FCMPL:
@@ -1491,44 +1664,12 @@ typecheck()
                       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:
-
-                          maythrow = true; /* XXX be more selective here */
-                          break;
-                          
-                      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));
+                          LOG2("ICMD %d at %d\n", iptr->opc, (int)(iptr-instr));
                           panic("Missing ICMD code during typecheck");
                     }
 
@@ -1545,13 +1686,18 @@ typecheck()
                             i++;
                         }
                     }
+
+                    /*
+                      DOLOG(typeinfo_print_block(get_logfile(),curstack,numlocals,vtype,vinfo,(jsrchain) ? touched : NULL));
+                      LOGNL; LOGFLUSH;
+                    */
                     
                     iptr++;
                 } /* while instructions */
 
                 LOG("instructions done");
                 LOGSTR("RESULT=> ");
-                DOLOG(typeinfo_print_block(get_logfile(),curstack,vtype,vinfo,(jsrchain) ? touched : NULL));
+                DOLOG(typeinfo_print_block(get_logfile(),curstack,numlocals,vtype,vinfo,(jsrchain) ? touched : NULL));
                 LOGNL; LOGFLUSH;
                 
                 /* propagate stack and variables to the following block */
index 2260a10c2a06e8e6da3ecf22cd9a5c11966f5933..eb1559d4c4dfa9d65310e6bc6ad41f108a8592f2 100644 (file)
@@ -26,7 +26,7 @@
 
    Authors: Edwin Steiner
 
-   $Id: typeinfo.c 707 2003-12-07 17:29:08Z twisti $
+   $Id: typeinfo.c 719 2003-12-08 14:26:05Z edwin $
 
 */
 
@@ -40,8 +40,6 @@
 #include "toolbox/memory.h"
 
 
-#define TYPEINFO_REUSE_MERGED
-
 #define CLASS_IMPLEMENTS_INTERFACE(cls,index)                   \
     ( ((index) < (cls)->vftbl->interfacetablelength)            \
       && (VFTBLINTERFACETABLE((cls)->vftbl,(index)) != NULL) )
@@ -174,6 +172,10 @@ typeinfo_is_assignable(typeinfo *value,typeinfo *dest)
     if (TYPEINFO_IS_NULLTYPE(*value))
         return true;
 
+    /* uninitialized objects are not assignable */
+    if (TYPEINFO_IS_NEWOBJECT(*value))
+        return false;
+
     if (dest->typeclass->flags & ACC_INTERFACE) {
         /* We are assigning to an interface type. */
         return merged_implements_interface(cls,value->merged,
@@ -250,6 +252,8 @@ typeinfo_init_from_descriptor(typeinfo *info,char *utf_ptr,char *end_ptr)
 {
     classinfo *cls;
     char *end;
+
+    /* XXX simplify */
     cls = class_from_descriptor(utf_ptr,end_ptr,&end,CLASSLOAD_NEW);
 
     if (!cls)
@@ -270,6 +274,7 @@ typeinfo_init_from_descriptor(typeinfo *info,char *utf_ptr,char *end_ptr)
     if (end!=end_ptr) panic ("descriptor has exceeding chars");
 }
 
+/* XXX delete or use SKIP_FIELDDESCRIPTOR_SAFE */
 int
 typeinfo_count_method_args(utf *d,bool twoword)
 {
@@ -366,6 +371,7 @@ typeinfo_init_from_method_args(utf *desc,u1 *typebuf,typeinfo *infobuf,
 
     /* check arguments */
     while ((c = *utf_ptr) != ')') {
+        /* XXX simplify */
         cls = class_from_descriptor(utf_ptr,end_pos,&utf_ptr,CLASSLOAD_NEW);
         if (!cls)
             panic("Invalid method descriptor.");
@@ -546,7 +552,8 @@ typeinfo_clone(typeinfo *src,typeinfo *dest)
 void
 typeinfo_free(typeinfo *info)
 {
-    TYPEINFO_FREE(*info);
+    TYPEINFO_FREEMERGED_IF_ANY(info->merged);
+    info->merged = NULL;
 }
 
 /**********************************************************************/
@@ -935,6 +942,17 @@ typeinfo_merge(typeinfo *dest,typeinfo* y)
         typeinfo_merge_error("Trying to merge unlinked class(es).",dest,y);
 #endif
 
+    /* handle uninitialized object types */
+    /* XXX is there a way we could put this after the common case? */
+    if (TYPEINFO_IS_NEWOBJECT(*dest) || TYPEINFO_IS_NEWOBJECT(*y)) {
+        if (!TYPEINFO_IS_NEWOBJECT(*dest) || !TYPEINFO_IS_NEWOBJECT(*y))
+            typeinfo_merge_error("Trying to merge uninitialized object type.",dest,y);
+        if (TYPEINFO_NEWOBJECT_INSTRUCTION(*dest)
+            != TYPEINFO_NEWOBJECT_INSTRUCTION(*y))
+            typeinfo_merge_error("Trying to merge different uninitialized objects.",dest,y);
+        return false;
+    }
+    
     /* XXX remove */ /* log_text("Testing common case"); */
 
     /* Common case: class dest == class y */
@@ -944,7 +962,7 @@ typeinfo_merge(typeinfo *dest,typeinfo* y)
     /* XXX count this case for statistics */
     if ((dest->typeclass == y->typeclass) && (!dest->merged || !y->merged)) {
         changed = (dest->merged != NULL);
-        TYPEINFO_FREEMERGED_IF_ANY(dest->merged); /* XXX unify if */
+        TYPEINFO_FREEMERGED_IF_ANY(dest->merged); /* XXX unify if? */
         dest->merged = NULL;
         /* XXX remove */ /* log_text("common case handled"); */
         return changed;
@@ -1073,6 +1091,9 @@ typeinfo_merge(typeinfo *dest,typeinfo* y)
 
 #include "tables.h"
 #include "loader.h"
+#include "jit/jit.h"
+
+extern instruction *instr;
 
 static int
 typeinfo_test_compare(classinfo **a,classinfo **b)
@@ -1130,6 +1151,12 @@ typeinfo_equal(typeinfo *x,typeinfo *y)
         if (x->elementclass != y->elementclass) return false;
         if (x->elementtype != y->elementtype) return false;
     }
+
+    if (TYPEINFO_IS_NEWOBJECT(*x))
+        if (TYPEINFO_NEWOBJECT_INSTRUCTION(*x)
+            != TYPEINFO_NEWOBJECT_INSTRUCTION(*y))
+            return false;
+
     if (x->merged || y->merged) {
         if (!(x->merged && y->merged)) return false;
         if (x->merged->count != y->merged->count) return false;
@@ -1248,21 +1275,6 @@ typeinfo_testrun(char *filename)
 void
 typeinfo_test()
 {
-/*     typeinfo i1,i2,i3,i4,i5,i6,i7,i8; */
-        
-/*     typeinfo_init_from_fielddescriptor(&i1,"[Ljava/lang/Integer;"); */
-/*     typeinfo_init_from_fielddescriptor(&i2,"[[Ljava/lang/String;"); */
-/*     typeinfo_init_from_fielddescriptor(&i3,"[Ljava/lang/Cloneable;"); */
-/*     typeinfo_init_from_fielddescriptor(&i3,"[[Ljava/lang/String;"); */
-/*     TYPEINFO_INIT_NULLTYPE(i1); */
-/*     typeinfo_print_short(stdout,&i1); printf("\n"); */
-/*     typeinfo_print_short(stdout,&i2); printf("\n"); */
-/*     typeinfo_merge(&i1,&i2); */
-/*     typeinfo_print_short(stdout,&i1); printf("\n"); */
-/*     typeinfo_print_short(stdout,&i3); printf("\n"); */
-/*     typeinfo_merge(&i1,&i3); */
-/*     typeinfo_print_short(stdout,&i1); printf("\n"); */
-
     log_text("Running typeinfo test file...");
     typeinfo_testrun("typeinfo.tst");
     log_text("Finished typeinfo test file.");
@@ -1281,6 +1293,7 @@ typeinfo_print(FILE *file,typeinfo *info,int indent)
 {
     int i;
     char ind[TYPEINFO_MAXINDENT + 1];
+    instruction *ins;
 
     if (indent > TYPEINFO_MAXINDENT) indent = TYPEINFO_MAXINDENT;
     
@@ -1297,7 +1310,20 @@ typeinfo_print(FILE *file,typeinfo *info,int indent)
         fprintf(file,"%snull\n",ind);
         return;
     }
-    
+
+    if (TYPEINFO_IS_NEWOBJECT(*info)) {
+        ins = (instruction *)TYPEINFO_NEWOBJECT_INSTRUCTION(*info);
+        if (ins) {
+            fprintf(file,"%sNEW(%d):",ind,ins-instr);
+            utf_fprint(file,((classinfo *)ins[-1].val.a)->name);
+            fprintf(file,"\n");
+        }
+        else {
+            fprintf(file,"%sNEW(this)",ind);
+        }
+        return;
+    }
+
     fprintf(file,"%sClass:      ",ind);
     utf_fprint(file,info->typeclass->name);
     fprintf(file,"\n");
@@ -1340,6 +1366,7 @@ void
 typeinfo_print_short(FILE *file,typeinfo *info)
 {
     int i;
+    instruction *ins;
 
     if (TYPEINFO_IS_PRIMITIVE(*info)) {
         fprintf(file,"primitive");
@@ -1351,6 +1378,17 @@ typeinfo_print_short(FILE *file,typeinfo *info)
         return;
     }
     
+    if (TYPEINFO_IS_NEWOBJECT(*info)) {
+        ins = (instruction *)TYPEINFO_NEWOBJECT_INSTRUCTION(*info);
+        if (ins) {
+            fprintf(file,"NEW(%d):",ins-instr);
+            utf_fprint(file,((classinfo *)ins[-1].val.a)->name);
+        }
+        else
+            fprintf(file,"NEW(this)");
+        return;
+    }
+
     utf_fprint(file,info->typeclass->name);
 
     if (info->merged) {
index 58b677b08d91e385d955209463d95c8f2130882e..2d3cedec37ef195b6bb43afb5031a26452d3c1f6 100644 (file)
@@ -26,7 +26,7 @@
 
    Authors: Edwin Steiner
 
-   $Id: typeinfo.h 706 2003-12-07 17:28:29Z twisti $
+   $Id: typeinfo.h 719 2003-12-08 14:26:05Z edwin $
 
 */
 
@@ -151,8 +151,6 @@ 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.
  */
@@ -161,9 +159,9 @@ struct typeinfo_mergedlist {
 
 /* internal, don't use this explicitly! */
 #define TYPEINFO_ALLOCMERGED(mergedlist,count)                  \
-            {(mergedlist) = (typeinfo_mergedlist*)dump_alloc(   \
-                sizeof(typeinfo_mergedlist)                     \
-                + ((count)-1)*sizeof(classinfo*));}
+    do {(mergedlist) = (typeinfo_mergedlist*)dump_alloc(        \
+            sizeof(typeinfo_mergedlist)                         \
+            + ((count)-1)*sizeof(classinfo*));} while(0)
 
 /* internal, don't use this explicitly! */
 #define TYPEINFO_FREEMERGED(mergedlist)
@@ -182,6 +180,13 @@ struct typeinfo_mergedlist {
 #define TYPEINFO_IS_NULLTYPE(info)                              \
             ((info).typeclass == pseudo_class_Null)
 
+#define TYPEINFO_IS_NEWOBJECT(info)                             \
+            ((info).typeclass == pseudo_class_New)
+
+/* only use this if TYPEINFO_IS_NEWOBJECT returned true! */
+#define TYPEINFO_NEWOBJECT_INSTRUCTION(info)                    \
+            ((void *)(info).elementclass)
+
 /* macros for array type queries ********************************************/
 
 #define TYPEINFO_IS_ARRAY(info)                                 \
@@ -211,7 +216,7 @@ struct typeinfo_mergedlist {
             ( TYPEINFO_IS_ARRAY(info)                           \
               && TYPEINFO_IS_ARRAY_OF_REFS_NOCHECK(info) )
 
-/* queries allowing null types **********************************************/
+/* queries allowing the null type ********************************************/
 
 #define TYPEINFO_MAYBE_ARRAY(info)                              \
     (TYPEINFO_IS_ARRAY(info) || TYPEINFO_IS_NULLTYPE(info))
@@ -222,88 +227,91 @@ struct typeinfo_mergedlist {
 #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)                           \
-            {(info).typeclass = NULL;                           \
+         do {(info).typeclass = NULL;                           \
              (info).elementclass = NULL;                        \
              (info).merged = NULL;                              \
              (info).dimension = 0;                              \
-             (info).elementtype = 0;}
+             (info).elementtype = 0;} while(0)
 
 #define TYPEINFO_INIT_NON_ARRAY_CLASSINFO(info,cinfo)   \
-            {(info).typeclass = (cinfo);                \
+         do {(info).typeclass = (cinfo);                \
              (info).elementclass = NULL;                \
              (info).merged = NULL;                      \
              (info).dimension = 0;                      \
-             (info).elementtype = 0;}
+             (info).elementtype = 0;} while(0)
 
 #define TYPEINFO_INIT_NULLTYPE(info)                            \
             TYPEINFO_INIT_CLASSINFO(info,pseudo_class_Null)
 
+#define TYPEINFO_INIT_NEWOBJECT(info,instr)             \
+         do {(info).typeclass = pseudo_class_New;       \
+             (info).elementclass = (classinfo*) (instr);\
+             (info).merged = NULL;                      \
+             (info).dimension = 0;                      \
+             (info).elementtype = 0;} while(0)
+
 #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)                \
+        do {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;                             \
                 (info).dimension = 0;                                   \
                 (info).elementtype = 0;                                 \
             }                                                           \
-            (info).merged = NULL;}
+            (info).merged = NULL;} while(0)
 
 #define TYPEINFO_INIT_FROM_FIELDINFO(info,fi)                   \
             typeinfo_init_from_descriptor(&(info),              \
                 (fi)->descriptor->text,utf_end((fi)->descriptor));
 
-/* macros for freeing typeinfo structures ***********************************/
-
-#define TYPEINFO_FREE(info)                                     \
-            {TYPEINFO_FREEMERGED_IF_ANY((info).merged);         \
-             (info).merged = NULL;}
-
 /* macros for writing types (destination must have been initialized) ********/
 /* XXX delete them? */
+#if 0
 
 #define TYPEINFO_PUT_NULLTYPE(info)                             \
-            {(info).typeclass = pseudo_class_Null;}
+    do {(info).typeclass = pseudo_class_Null;} while(0)
 
 #define TYPEINFO_PUT_NON_ARRAY_CLASSINFO(info,cinfo)            \
-            {(info).typeclass = (cinfo);}
+    do {(info).typeclass = (cinfo);} while(0)
 
 #define TYPEINFO_PUT_CLASSINFO(info,cls)                                \
-        {if (((info).typeclass = (cls))->vftbl->arraydesc) {              \
+    do {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; \
-            }}
+        }} while(0)
 
 /* srcarray must be an array (not checked) */
 #define TYPEINFO_PUT_COMPONENT(srcarray,dst)                    \
-            {typeinfo_put_component(&(srcarray),&(dst));}
+    do {typeinfo_put_component(&(srcarray),&(dst));} while(0)
+
+#endif
 
 /* macros for copying types (destinition is not checked or freed) ***********/
 
 /* TYPEINFO_COPY makes a shallow copy, the merged pointer is simply copied. */
 #define TYPEINFO_COPY(src,dst)                                  \
-            {(dst) = (src);}
+    do {(dst) = (src);} while(0)
 
 /* TYPEINFO_CLONE makes a deep copy, the merged list (if any) is duplicated
  * into a newly allocated array.
  */
 #define TYPEINFO_CLONE(src,dst)                                 \
-            {(dst) = (src);                                     \
-             if ((dst).merged) typeinfo_clone(&(src),&(dst));}
+    do {(dst) = (src);                                          \
+        if ((dst).merged) typeinfo_clone(&(src),&(dst));} while(0)
 
 /****************************************************************************/
 /* FUNCTIONS                                                                */
index 945d41aaf5417154b9962079552e9a76af5d2d4e..4aaf84dffa297f15e09661cdad2e602c757ba8fc 100644 (file)
@@ -30,7 +30,7 @@
             Mark Probst
                        Edwin Steiner
 
-   $Id: loader.c 696 2003-12-06 20:10:05Z edwin $
+   $Id: loader.c 719 2003-12-08 14:26:05Z edwin $
 
 */
 
@@ -128,6 +128,7 @@ classinfo *class_java_io_Serializable;
 /* Pseudo classes for the typechecker */
 classinfo *pseudo_class_Arraystub = NULL;
 classinfo *pseudo_class_Null = NULL;
+classinfo *pseudo_class_New = NULL;
 vftbl *pseudo_class_Arraystub_vftbl = NULL;
 
 /* stefan */
@@ -2940,6 +2941,16 @@ create_pseudo_classes()
 
     list_addlast(&unlinkedclasses,pseudo_class_Null);
     class_link(pseudo_class_Null);     
+
+    /* pseudo class representing new uninitialized objects */
+    
+    pseudo_class_New = class_new( utf_new_char("$NEW$") );
+    list_remove(&unloadedclasses,pseudo_class_New);
+
+    pseudo_class_New->super = class_java_lang_Object;
+
+    list_addlast(&unlinkedclasses,pseudo_class_New);
+    class_link(pseudo_class_New);      
 }
 
 /********************** Function: loader_init **********************************
index 2260a10c2a06e8e6da3ecf22cd9a5c11966f5933..eb1559d4c4dfa9d65310e6bc6ad41f108a8592f2 100644 (file)
@@ -26,7 +26,7 @@
 
    Authors: Edwin Steiner
 
-   $Id: typeinfo.c 707 2003-12-07 17:29:08Z twisti $
+   $Id: typeinfo.c 719 2003-12-08 14:26:05Z edwin $
 
 */
 
@@ -40,8 +40,6 @@
 #include "toolbox/memory.h"
 
 
-#define TYPEINFO_REUSE_MERGED
-
 #define CLASS_IMPLEMENTS_INTERFACE(cls,index)                   \
     ( ((index) < (cls)->vftbl->interfacetablelength)            \
       && (VFTBLINTERFACETABLE((cls)->vftbl,(index)) != NULL) )
@@ -174,6 +172,10 @@ typeinfo_is_assignable(typeinfo *value,typeinfo *dest)
     if (TYPEINFO_IS_NULLTYPE(*value))
         return true;
 
+    /* uninitialized objects are not assignable */
+    if (TYPEINFO_IS_NEWOBJECT(*value))
+        return false;
+
     if (dest->typeclass->flags & ACC_INTERFACE) {
         /* We are assigning to an interface type. */
         return merged_implements_interface(cls,value->merged,
@@ -250,6 +252,8 @@ typeinfo_init_from_descriptor(typeinfo *info,char *utf_ptr,char *end_ptr)
 {
     classinfo *cls;
     char *end;
+
+    /* XXX simplify */
     cls = class_from_descriptor(utf_ptr,end_ptr,&end,CLASSLOAD_NEW);
 
     if (!cls)
@@ -270,6 +274,7 @@ typeinfo_init_from_descriptor(typeinfo *info,char *utf_ptr,char *end_ptr)
     if (end!=end_ptr) panic ("descriptor has exceeding chars");
 }
 
+/* XXX delete or use SKIP_FIELDDESCRIPTOR_SAFE */
 int
 typeinfo_count_method_args(utf *d,bool twoword)
 {
@@ -366,6 +371,7 @@ typeinfo_init_from_method_args(utf *desc,u1 *typebuf,typeinfo *infobuf,
 
     /* check arguments */
     while ((c = *utf_ptr) != ')') {
+        /* XXX simplify */
         cls = class_from_descriptor(utf_ptr,end_pos,&utf_ptr,CLASSLOAD_NEW);
         if (!cls)
             panic("Invalid method descriptor.");
@@ -546,7 +552,8 @@ typeinfo_clone(typeinfo *src,typeinfo *dest)
 void
 typeinfo_free(typeinfo *info)
 {
-    TYPEINFO_FREE(*info);
+    TYPEINFO_FREEMERGED_IF_ANY(info->merged);
+    info->merged = NULL;
 }
 
 /**********************************************************************/
@@ -935,6 +942,17 @@ typeinfo_merge(typeinfo *dest,typeinfo* y)
         typeinfo_merge_error("Trying to merge unlinked class(es).",dest,y);
 #endif
 
+    /* handle uninitialized object types */
+    /* XXX is there a way we could put this after the common case? */
+    if (TYPEINFO_IS_NEWOBJECT(*dest) || TYPEINFO_IS_NEWOBJECT(*y)) {
+        if (!TYPEINFO_IS_NEWOBJECT(*dest) || !TYPEINFO_IS_NEWOBJECT(*y))
+            typeinfo_merge_error("Trying to merge uninitialized object type.",dest,y);
+        if (TYPEINFO_NEWOBJECT_INSTRUCTION(*dest)
+            != TYPEINFO_NEWOBJECT_INSTRUCTION(*y))
+            typeinfo_merge_error("Trying to merge different uninitialized objects.",dest,y);
+        return false;
+    }
+    
     /* XXX remove */ /* log_text("Testing common case"); */
 
     /* Common case: class dest == class y */
@@ -944,7 +962,7 @@ typeinfo_merge(typeinfo *dest,typeinfo* y)
     /* XXX count this case for statistics */
     if ((dest->typeclass == y->typeclass) && (!dest->merged || !y->merged)) {
         changed = (dest->merged != NULL);
-        TYPEINFO_FREEMERGED_IF_ANY(dest->merged); /* XXX unify if */
+        TYPEINFO_FREEMERGED_IF_ANY(dest->merged); /* XXX unify if? */
         dest->merged = NULL;
         /* XXX remove */ /* log_text("common case handled"); */
         return changed;
@@ -1073,6 +1091,9 @@ typeinfo_merge(typeinfo *dest,typeinfo* y)
 
 #include "tables.h"
 #include "loader.h"
+#include "jit/jit.h"
+
+extern instruction *instr;
 
 static int
 typeinfo_test_compare(classinfo **a,classinfo **b)
@@ -1130,6 +1151,12 @@ typeinfo_equal(typeinfo *x,typeinfo *y)
         if (x->elementclass != y->elementclass) return false;
         if (x->elementtype != y->elementtype) return false;
     }
+
+    if (TYPEINFO_IS_NEWOBJECT(*x))
+        if (TYPEINFO_NEWOBJECT_INSTRUCTION(*x)
+            != TYPEINFO_NEWOBJECT_INSTRUCTION(*y))
+            return false;
+
     if (x->merged || y->merged) {
         if (!(x->merged && y->merged)) return false;
         if (x->merged->count != y->merged->count) return false;
@@ -1248,21 +1275,6 @@ typeinfo_testrun(char *filename)
 void
 typeinfo_test()
 {
-/*     typeinfo i1,i2,i3,i4,i5,i6,i7,i8; */
-        
-/*     typeinfo_init_from_fielddescriptor(&i1,"[Ljava/lang/Integer;"); */
-/*     typeinfo_init_from_fielddescriptor(&i2,"[[Ljava/lang/String;"); */
-/*     typeinfo_init_from_fielddescriptor(&i3,"[Ljava/lang/Cloneable;"); */
-/*     typeinfo_init_from_fielddescriptor(&i3,"[[Ljava/lang/String;"); */
-/*     TYPEINFO_INIT_NULLTYPE(i1); */
-/*     typeinfo_print_short(stdout,&i1); printf("\n"); */
-/*     typeinfo_print_short(stdout,&i2); printf("\n"); */
-/*     typeinfo_merge(&i1,&i2); */
-/*     typeinfo_print_short(stdout,&i1); printf("\n"); */
-/*     typeinfo_print_short(stdout,&i3); printf("\n"); */
-/*     typeinfo_merge(&i1,&i3); */
-/*     typeinfo_print_short(stdout,&i1); printf("\n"); */
-
     log_text("Running typeinfo test file...");
     typeinfo_testrun("typeinfo.tst");
     log_text("Finished typeinfo test file.");
@@ -1281,6 +1293,7 @@ typeinfo_print(FILE *file,typeinfo *info,int indent)
 {
     int i;
     char ind[TYPEINFO_MAXINDENT + 1];
+    instruction *ins;
 
     if (indent > TYPEINFO_MAXINDENT) indent = TYPEINFO_MAXINDENT;
     
@@ -1297,7 +1310,20 @@ typeinfo_print(FILE *file,typeinfo *info,int indent)
         fprintf(file,"%snull\n",ind);
         return;
     }
-    
+
+    if (TYPEINFO_IS_NEWOBJECT(*info)) {
+        ins = (instruction *)TYPEINFO_NEWOBJECT_INSTRUCTION(*info);
+        if (ins) {
+            fprintf(file,"%sNEW(%d):",ind,ins-instr);
+            utf_fprint(file,((classinfo *)ins[-1].val.a)->name);
+            fprintf(file,"\n");
+        }
+        else {
+            fprintf(file,"%sNEW(this)",ind);
+        }
+        return;
+    }
+
     fprintf(file,"%sClass:      ",ind);
     utf_fprint(file,info->typeclass->name);
     fprintf(file,"\n");
@@ -1340,6 +1366,7 @@ void
 typeinfo_print_short(FILE *file,typeinfo *info)
 {
     int i;
+    instruction *ins;
 
     if (TYPEINFO_IS_PRIMITIVE(*info)) {
         fprintf(file,"primitive");
@@ -1351,6 +1378,17 @@ typeinfo_print_short(FILE *file,typeinfo *info)
         return;
     }
     
+    if (TYPEINFO_IS_NEWOBJECT(*info)) {
+        ins = (instruction *)TYPEINFO_NEWOBJECT_INSTRUCTION(*info);
+        if (ins) {
+            fprintf(file,"NEW(%d):",ins-instr);
+            utf_fprint(file,((classinfo *)ins[-1].val.a)->name);
+        }
+        else
+            fprintf(file,"NEW(this)");
+        return;
+    }
+
     utf_fprint(file,info->typeclass->name);
 
     if (info->merged) {
index 58b677b08d91e385d955209463d95c8f2130882e..2d3cedec37ef195b6bb43afb5031a26452d3c1f6 100644 (file)
@@ -26,7 +26,7 @@
 
    Authors: Edwin Steiner
 
-   $Id: typeinfo.h 706 2003-12-07 17:28:29Z twisti $
+   $Id: typeinfo.h 719 2003-12-08 14:26:05Z edwin $
 
 */
 
@@ -151,8 +151,6 @@ 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.
  */
@@ -161,9 +159,9 @@ struct typeinfo_mergedlist {
 
 /* internal, don't use this explicitly! */
 #define TYPEINFO_ALLOCMERGED(mergedlist,count)                  \
-            {(mergedlist) = (typeinfo_mergedlist*)dump_alloc(   \
-                sizeof(typeinfo_mergedlist)                     \
-                + ((count)-1)*sizeof(classinfo*));}
+    do {(mergedlist) = (typeinfo_mergedlist*)dump_alloc(        \
+            sizeof(typeinfo_mergedlist)                         \
+            + ((count)-1)*sizeof(classinfo*));} while(0)
 
 /* internal, don't use this explicitly! */
 #define TYPEINFO_FREEMERGED(mergedlist)
@@ -182,6 +180,13 @@ struct typeinfo_mergedlist {
 #define TYPEINFO_IS_NULLTYPE(info)                              \
             ((info).typeclass == pseudo_class_Null)
 
+#define TYPEINFO_IS_NEWOBJECT(info)                             \
+            ((info).typeclass == pseudo_class_New)
+
+/* only use this if TYPEINFO_IS_NEWOBJECT returned true! */
+#define TYPEINFO_NEWOBJECT_INSTRUCTION(info)                    \
+            ((void *)(info).elementclass)
+
 /* macros for array type queries ********************************************/
 
 #define TYPEINFO_IS_ARRAY(info)                                 \
@@ -211,7 +216,7 @@ struct typeinfo_mergedlist {
             ( TYPEINFO_IS_ARRAY(info)                           \
               && TYPEINFO_IS_ARRAY_OF_REFS_NOCHECK(info) )
 
-/* queries allowing null types **********************************************/
+/* queries allowing the null type ********************************************/
 
 #define TYPEINFO_MAYBE_ARRAY(info)                              \
     (TYPEINFO_IS_ARRAY(info) || TYPEINFO_IS_NULLTYPE(info))
@@ -222,88 +227,91 @@ struct typeinfo_mergedlist {
 #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)                           \
-            {(info).typeclass = NULL;                           \
+         do {(info).typeclass = NULL;                           \
              (info).elementclass = NULL;                        \
              (info).merged = NULL;                              \
              (info).dimension = 0;                              \
-             (info).elementtype = 0;}
+             (info).elementtype = 0;} while(0)
 
 #define TYPEINFO_INIT_NON_ARRAY_CLASSINFO(info,cinfo)   \
-            {(info).typeclass = (cinfo);                \
+         do {(info).typeclass = (cinfo);                \
              (info).elementclass = NULL;                \
              (info).merged = NULL;                      \
              (info).dimension = 0;                      \
-             (info).elementtype = 0;}
+             (info).elementtype = 0;} while(0)
 
 #define TYPEINFO_INIT_NULLTYPE(info)                            \
             TYPEINFO_INIT_CLASSINFO(info,pseudo_class_Null)
 
+#define TYPEINFO_INIT_NEWOBJECT(info,instr)             \
+         do {(info).typeclass = pseudo_class_New;       \
+             (info).elementclass = (classinfo*) (instr);\
+             (info).merged = NULL;                      \
+             (info).dimension = 0;                      \
+             (info).elementtype = 0;} while(0)
+
 #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)                \
+        do {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;                             \
                 (info).dimension = 0;                                   \
                 (info).elementtype = 0;                                 \
             }                                                           \
-            (info).merged = NULL;}
+            (info).merged = NULL;} while(0)
 
 #define TYPEINFO_INIT_FROM_FIELDINFO(info,fi)                   \
             typeinfo_init_from_descriptor(&(info),              \
                 (fi)->descriptor->text,utf_end((fi)->descriptor));
 
-/* macros for freeing typeinfo structures ***********************************/
-
-#define TYPEINFO_FREE(info)                                     \
-            {TYPEINFO_FREEMERGED_IF_ANY((info).merged);         \
-             (info).merged = NULL;}
-
 /* macros for writing types (destination must have been initialized) ********/
 /* XXX delete them? */
+#if 0
 
 #define TYPEINFO_PUT_NULLTYPE(info)                             \
-            {(info).typeclass = pseudo_class_Null;}
+    do {(info).typeclass = pseudo_class_Null;} while(0)
 
 #define TYPEINFO_PUT_NON_ARRAY_CLASSINFO(info,cinfo)            \
-            {(info).typeclass = (cinfo);}
+    do {(info).typeclass = (cinfo);} while(0)
 
 #define TYPEINFO_PUT_CLASSINFO(info,cls)                                \
-        {if (((info).typeclass = (cls))->vftbl->arraydesc) {              \
+    do {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; \
-            }}
+        }} while(0)
 
 /* srcarray must be an array (not checked) */
 #define TYPEINFO_PUT_COMPONENT(srcarray,dst)                    \
-            {typeinfo_put_component(&(srcarray),&(dst));}
+    do {typeinfo_put_component(&(srcarray),&(dst));} while(0)
+
+#endif
 
 /* macros for copying types (destinition is not checked or freed) ***********/
 
 /* TYPEINFO_COPY makes a shallow copy, the merged pointer is simply copied. */
 #define TYPEINFO_COPY(src,dst)                                  \
-            {(dst) = (src);}
+    do {(dst) = (src);} while(0)
 
 /* TYPEINFO_CLONE makes a deep copy, the merged list (if any) is duplicated
  * into a newly allocated array.
  */
 #define TYPEINFO_CLONE(src,dst)                                 \
-            {(dst) = (src);                                     \
-             if ((dst).merged) typeinfo_clone(&(src),&(dst));}
+    do {(dst) = (src);                                          \
+        if ((dst).merged) typeinfo_clone(&(src),&(dst));} while(0)
 
 /****************************************************************************/
 /* FUNCTIONS                                                                */