* src/vm/jit/parse.c (CHECKCAST): Set check-flag.
[cacao.git] / src / vm / jit / parse.c
index 67f28475a78152e031fb322e1aa4c07cfce4d2ac..9a8e4e4cb99e0ae78203f079c29ec375a326fb9e 100644 (file)
 
    Contact: cacao@cacaojvm.org
 
-   Author: Andreas Krall
-
-   Changes: Carolyn Oates
+   Authors: Andreas Krall
+            Carolyn Oates
             Edwin Steiner
             Joseph Wenninger
             Christian Thalinger
 
-   $Id: parse.c 5721 2006-10-08 11:39:41Z edwin $
+   $Id: parse.c 6173 2006-12-11 19:55:31Z twisti $
 
 */
 
@@ -141,6 +140,7 @@ static instruction *parse_realloc_instructions(parsedata_t *pd, s4 ipc, s4 n)
 
        pd->instructions = DMREALLOC(pd->instructions, instruction, ipc,
                                                                 pd->instructionslength);
+       MZERO(pd->instructions + ipc, instruction, (pd->instructionslength - ipc));
 
        /* return the iptr */
 
@@ -148,83 +148,179 @@ static instruction *parse_realloc_instructions(parsedata_t *pd, s4 ipc, s4 n)
 }
 
 
-/*******************************************************************************
+/* parse_mark_exception_boundaries *********************************************
 
-       function 'parse' scans the JavaVM code and generates intermediate code
+   Mark exception handlers and the boundaries of the handled regions as
+   basic block boundaries.
 
-       During parsing the block index table is used to store at bit pos 0
-       a flag which marks basic block starts and at position 1 to 31 the
-       intermediate instruction index. After parsing the block index table
-       is scanned, for marked positions a block is generated and the block
-       number is stored in the block index table.
+   IN:
+       jd...............current jitdata
+
+   RETURN VALUE:
+       >= 0.............the number of new basic blocks marked
+          -1...............an exception has been thrown
 
 *******************************************************************************/
 
-static exceptiontable * fillextable(
-                                                                       jitdata *jd,
-                                                                       methodinfo *m, 
-                                                                       exceptiontable *extable, 
-                                                                       exceptiontable *raw_extable, 
-                                                               int exceptiontablelength, 
-                                                                       int *block_count)
+static int parse_mark_exception_boundaries(jitdata *jd)
 {
-       int b_count, p, src;
+       s4                   b_count;
+       s4                   pc;
+       s4                   i;
+       s4                   len;
+       raw_exception_entry *rex;
+       methodinfo          *m;
+
+       m = jd->m;
        
-       if (exceptiontablelength == 0) 
-               return extable;
+       len = m->rawexceptiontablelength;
 
-       b_count = *block_count;
+       if (len == 0)
+               return 0;
+
+       b_count = 0;
+       rex = m->rawexceptiontable;
+
+       for (i = 0; i < len; ++i, ++rex) {
 
-       for (src = exceptiontablelength-1; src >=0; src--) {
                /* the start of the handled region becomes a basic block start */
-               p = raw_extable[src].startpc;
-               CHECK_BYTECODE_INDEX(p);
-               extable->startpc = p;
-               MARK_BASICBLOCK(p);
+
+               pc = rex->startpc;
+               CHECK_BYTECODE_INDEX(pc);
+               MARK_BASICBLOCK(pc);
                
-               p = raw_extable[src].endpc; /* see JVM Spec 4.7.3 */
-               CHECK_BYTECODE_INDEX_EXCLUSIVE(p);
+               pc = rex->endpc; /* see JVM Spec 4.7.3 */
+               CHECK_BYTECODE_INDEX_EXCLUSIVE(pc);
+
+               /* check that the range is valid */
 
 #if defined(ENABLE_VERIFIER)
-               if (p <= raw_extable[src].startpc) {
+               if (pc <= rex->startpc) {
                        exceptions_throw_verifyerror(m,
                                "Invalid exception handler range");
-                       return NULL;
+                       return -1;
                }
 #endif
-               extable->endpc = p;
                
                /* end of handled region becomes a basic block boundary  */
                /* (If it is the bytecode end, we'll use the special     */
                /* end block that is created anyway.)                    */
-               if (p < m->jcodelength) 
-                       MARK_BASICBLOCK(p);
+
+               if (pc < m->jcodelength)
+                       MARK_BASICBLOCK(pc);
+               else
+                       jd->branchtoend = true;
 
                /* the start of the handler becomes a basic block start  */
-               p = raw_extable[src].handlerpc;
-               CHECK_BYTECODE_INDEX(p);
-               extable->handlerpc = p;
-               MARK_BASICBLOCK(p);
-
-               extable->catchtype = raw_extable[src].catchtype;
-               extable->next = NULL;
-               extable->down = &extable[1];
-               extable--;
+
+               pc = rex->handlerpc;
+               CHECK_BYTECODE_INDEX(pc);
+               MARK_BASICBLOCK(pc);
        }
 
-       *block_count = b_count;
-       
        /* everything ok */
-       return extable;
+
+       return b_count;
 
 #if defined(ENABLE_VERIFIER)
 throw_invalid_bytecode_index:
        exceptions_throw_verifyerror(m,
                                                                 "Illegal bytecode index in exception table");
-       return NULL;
+       return -1;
 #endif
 }
 
+
+/* parse_resolve_exception_table ***********************************************
+
+   Enter the exception handlers and their ranges, resolved to basicblock *s,
+   in the jitdata.
+
+   IN:
+       jd...............current jitdata
+
+   RETURN VALUE:
+          true.............everything ok
+          false............an exception has been thrown
+
+*******************************************************************************/
+
+static bool parse_resolve_exception_table(jitdata *jd)
+{
+       methodinfo          *m;
+       raw_exception_entry *rex;
+       exception_entry     *ex;
+       s4                   i;
+       s4                   len;
+       classinfo           *exclass;
+
+       m = jd->m;
+
+       len = m->rawexceptiontablelength;
+
+       /* common case: no handler entries */
+
+       if (len == 0)
+               return true;
+
+       /* allocate the exception table */
+
+       jd->exceptiontablelength = len;
+       jd->exceptiontable = DMNEW(exception_entry, len + 1); /* XXX why +1? */
+
+       /* copy and resolve the entries */
+
+       ex = jd->exceptiontable;
+       rex = m->rawexceptiontable;
+
+       for (i = 0; i < len; ++i, ++rex, ++ex) {
+               /* resolve instruction indices to basic blocks */
+
+               ex->start   = BLOCK_OF(rex->startpc);
+               ex->end     = BLOCK_OF(rex->endpc);
+               ex->handler = BLOCK_OF(rex->handlerpc);
+
+               /* lazily resolve the catchtype */
+
+               if (rex->catchtype.any != NULL) {
+                       if (!resolve_classref_or_classinfo(m,
+                                                                                          rex->catchtype,
+                                                                                          resolveLazy, true, false,
+                                                                                          &exclass))
+                               return false;
+
+                       /* if resolved, enter the result of resolution in the table */
+
+                       if (exclass != NULL)
+                               rex->catchtype.cls = exclass;
+               }
+
+               ex->catchtype = rex->catchtype;
+               ex->next = NULL;   /* set by loop analysis */
+               ex->down = ex + 1; /* link to next exception entry */
+       }
+
+       /* terminate the ->down linked list */
+
+       assert(ex != jd->exceptiontable);
+       ex[-1].down = NULL;
+
+       return true;
+}
+
+
+/*******************************************************************************
+
+       function 'parse' scans the JavaVM code and generates intermediate code
+
+       During parsing the block index table is used to store at bit pos 0
+       a flag which marks basic block starts and at position 1 to 31 the
+       intermediate instruction index. After parsing the block index table
+       is scanned, for marked positions a block is generated and the block
+       number is stored in the block index table.
+
+*******************************************************************************/
+
 /*** macro for checking the length of the bytecode ***/
 
 #if defined(ENABLE_VERIFIER)
@@ -240,8 +336,6 @@ throw_invalid_bytecode_index:
 bool parse(jitdata *jd)
 {
        methodinfo  *m;                     /* method being parsed                */
-       codeinfo    *code;
-       codegendata *cd;
        parsedata_t  pd;
        instruction *iptr;                  /* current ptr into instruction array */
        s4           ipc;                   /* intermediate instruction counter   */
@@ -250,7 +344,7 @@ bool parse(jitdata *jd)
        s4           opcode;                /* java opcode                        */
        s4           i;
        s4           j;
-       int  b_count = 0;           /* basic block counter                      */
+       int  b_count;               /* basic block counter                      */
        int  s_count = 0;           /* stack element counter                    */
        bool blockend = false;      /* true if basic block end has been reached */
        bool iswide = false;        /* true if last instruction was a wide      */
@@ -273,12 +367,10 @@ bool parse(jitdata *jd)
        /* get required compiler data */
 
        m    = jd->m;
-       code = jd->code;
-       cd   = jd->cd;
 
        /* allocate buffers for local variable renaming */
-       local_map = DMNEW(int, cd->maxlocals * 5);
-       for (i = 0; i < cd->maxlocals; i++) {
+       local_map = DMNEW(int, m->maxlocals * 5);
+       for (i = 0; i < m->maxlocals; i++) {
                local_map[i * 5 + 0] = 0;
                local_map[i * 5 + 1] = 0;
                local_map[i * 5 + 2] = 0;
@@ -295,23 +387,15 @@ bool parse(jitdata *jd)
        iptr = pd.instructions;
        ipc  = 0;
   
-       /* compute branch targets of exception table */
+       /* mark basic block boundaries for exception table */
 
-       if (!fillextable(jd, m,
-                       &(cd->exceptiontable[cd->exceptiontablelength-1]),
-                       m->exceptiontable,
-                       m->exceptiontablelength,
-                       &b_count))
-       {
+       b_count = parse_mark_exception_boundaries(jd);
+       if (b_count < 0)
                return false;
-       }
 
-       s_count = 1 + m->exceptiontablelength; /* initialize stack element counter   */
+       /* initialize stack element counter */
 
-#if defined(ENABLE_THREADS)
-       if (checksync && (m->flags & ACC_SYNCHRONIZED))
-               jd->isleafmethod = false;
-#endif
+       s_count = 1 + m->rawexceptiontablelength;
 
        /* setup line number info */
 
@@ -874,7 +958,7 @@ jsr_tail:
                                s4 prevvalue = 0;
 #endif
                                blockend = true;
-                               nextp = ALIGN((p + 1), 4);
+                               nextp = MEMORY_ALIGN((p + 1), 4);
 
                                CHECK_END_OF_BYTECODE(nextp + 8);
 
@@ -942,7 +1026,7 @@ jsr_tail:
                                branch_target_t *table;
 
                                blockend = true;
-                               nextp = ALIGN((p + 1), 4);
+                               nextp = MEMORY_ALIGN((p + 1), 4);
 
                                CHECK_END_OF_BYTECODE(nextp + 12);
 
@@ -981,7 +1065,7 @@ jsr_tail:
                                /* create the intermediate code table */
                                /* the first entry is the default target */
 
-                               table = MNEW(branch_target_t, 1 + num);
+                               table = DMNEW(branch_target_t, 1 + num);
                                iptr->dst.table = table;
                                (table++)->insindex = deftarget;
 
@@ -1030,12 +1114,12 @@ jsr_tail:
 #if defined(ENABLE_VERIFIER)
                                if (!JITDATA_HAS_FLAG_VERIFY(jd)) {
 #endif
-                                       result = resolve_field_lazy(jd, iptr, m);
+                                       result = resolve_field_lazy(m, fr);
                                        if (result == resolveFailed)
                                                return false;
 
                                        if (result != resolveSucceeded) {
-                                               uf = create_unresolved_field(m->class, m, iptr);
+                                               uf = resolve_create_unresolved_field(m->class, m, iptr);
 
                                                if (uf == NULL)
                                                        return false;
@@ -1043,7 +1127,7 @@ jsr_tail:
                                                /* store the unresolved_field pointer */
 
                                                iptr->sx.s23.s3.uf = uf;
-                                               iptr->flags.bits = INS_FLAG_UNRESOLVED;
+                                               iptr->flags.bits |= INS_FLAG_UNRESOLVED;
                                        }
 #if defined(ENABLE_VERIFIER)
                                }
@@ -1103,12 +1187,28 @@ invoke_method:
 #if defined(ENABLE_VERIFIER)
                        if (!JITDATA_HAS_FLAG_VERIFY(jd)) {
 #endif
-                               result = resolve_method_lazy(jd, iptr, m);
+                               result = resolve_method_lazy(m, mr, 
+                                               (opcode == JAVA_INVOKESPECIAL));
                                if (result == resolveFailed)
                                        return false;
 
-                               if (result != resolveSucceeded) {
-                                       um = create_unresolved_method(m->class, m, iptr);
+                               if (result == resolveSucceeded) {
+                                       methodinfo *mi = iptr->sx.s23.s3.fmiref->p.method;
+
+                                       /* if this call is monomorphic, turn it into an INVOKESPECIAL */
+
+                                       assert(IS_FMIREF_RESOLVED(iptr->sx.s23.s3.fmiref));
+
+                                       if ((iptr->opc == ICMD_INVOKEVIRTUAL)
+                                               && (mi->flags & (ACC_FINAL | ACC_PRIVATE)))
+                                       {
+                                               iptr->opc = ICMD_INVOKESPECIAL;
+                                       }
+                               }
+                               else {
+                                       um = resolve_create_unresolved_method(m->class, m, mr,
+                                                       (opcode == JAVA_INVOKESTATIC),
+                                                       (opcode == JAVA_INVOKESPECIAL));
 
                                        if (!um)
                                                return false;
@@ -1116,7 +1216,7 @@ invoke_method:
                                        /* store the unresolved_method pointer */
 
                                        iptr->sx.s23.s3.um = um;
-                                       iptr->flags.bits = INS_FLAG_UNRESOLVED;
+                                       iptr->flags.bits |= INS_FLAG_UNRESOLVED;
                                }
 #if defined(ENABLE_VERIFIER)
                        }
@@ -1153,12 +1253,12 @@ invoke_method:
 
                        if (cr->name->text[0] == '[') {
                                /* array type cast-check */
-                               flags = INS_FLAG_ARRAY;
+                               flags = INS_FLAG_CHECK | INS_FLAG_ARRAY;
                                jd->isleafmethod = false;
                        }
                        else {
                                /* object type cast-check */
-                               flags = 0;
+                               flags = INS_FLAG_CHECK;
                        }
                        OP_S3_CLASSINFO_OR_CLASSREF(opcode, c, cr, flags);
                        break;
@@ -1197,7 +1297,8 @@ invoke_method:
                        else
 #endif
                        {
-                               OP(ICMD_CHECKNULL_POP);
+                               OP_CHECK_EXCEPTION(ICMD_CHECKNULL);
+                               OP(ICMD_POP);
                        }
                        break;
 
@@ -1210,7 +1311,8 @@ invoke_method:
                        else
 #endif
                        {
-                               OP(ICMD_CHECKNULL_POP);
+                               OP_CHECK_EXCEPTION(ICMD_CHECKNULL);
+                               OP(ICMD_POP);
                        }
                        break;
 
@@ -1221,7 +1323,11 @@ invoke_method:
                        bte = builtintable_get_internal(BUILTIN_idiv);
                        OP_BUILTIN_ARITHMETIC(opcode, bte);
 #else
+# if SUPPORT_HARDWARE_DIVIDE_BY_ZERO
                        OP(opcode);
+# else
+                       OP_CHECK_EXCEPTION(opcode);
+# endif
 #endif
                        break;
 
@@ -1230,7 +1336,11 @@ invoke_method:
                        bte = builtintable_get_internal(BUILTIN_irem);
                        OP_BUILTIN_ARITHMETIC(opcode, bte);
 #else
+# if SUPPORT_HARDWARE_DIVIDE_BY_ZERO
                        OP(opcode);
+# else
+                       OP_CHECK_EXCEPTION(opcode);
+# endif
 #endif
                        break;
 
@@ -1239,7 +1349,11 @@ invoke_method:
                        bte = builtintable_get_internal(BUILTIN_ldiv);
                        OP_BUILTIN_ARITHMETIC(opcode, bte);
 #else
+# if SUPPORT_HARDWARE_DIVIDE_BY_ZERO
                        OP(opcode);
+# else
+                       OP_CHECK_EXCEPTION(opcode);
+# endif
 #endif
                        break;
 
@@ -1248,7 +1362,11 @@ invoke_method:
                        bte = builtintable_get_internal(BUILTIN_lrem);
                        OP_BUILTIN_ARITHMETIC(opcode, bte);
 #else
+# if SUPPORT_HARDWARE_DIVIDE_BY_ZERO
                        OP(opcode);
+# else
+                       OP_CHECK_EXCEPTION(opcode);
+# endif
 #endif
                        break;
 
@@ -1447,6 +1565,8 @@ invoke_method:
 
        if (!jd->basicblockindex[0] || (jd->basicblockindex[0] > 1))
                b_count++;
+       else
+               jd->branchtoentry = true;
 
        /* copy local to method variables */
 
@@ -1468,7 +1588,6 @@ invoke_method:
        MZERO(bptr, basicblock, b_count + 1);
 
        b_count = 0;
-       jd->c_block_nr = 0;
 
        /* additional block if target 0 is not first intermediate instruction */
 
@@ -1478,8 +1597,8 @@ invoke_method:
                bptr->iinstr = jd->instructions;
                /* bptr->icount is set when the next block is allocated */
 
+               bptr->nr = b_count++;
                bptr++;
-               b_count++;
                bptr[-1].next = bptr;
        }
 
@@ -1510,8 +1629,8 @@ invoke_method:
 
                        jd->basicblockindex[p] = b_count;
 
+                       bptr->nr = b_count++;
                        bptr++;
-                       b_count++;
                        bptr[-1].next = bptr;
                }
        }
@@ -1525,37 +1644,15 @@ invoke_method:
        /* allocate additional block at end */
 
        BASICBLOCK_INIT(bptr,m);
+       bptr->nr = b_count;
+       jd->basicblockindex[m->jcodelength] = b_count;
 
        /* set basicblock pointers in exception table */
 
-       if (cd->exceptiontablelength > 0) {
-               cd->exceptiontable[cd->exceptiontablelength - 1].down = NULL;
-       }
-
-       for (i = 0; i < cd->exceptiontablelength; ++i) {
-               p = cd->exceptiontable[i].startpc;
-               cd->exceptiontable[i].start = jd->basicblocks + jd->basicblockindex[p];
-
-               p = cd->exceptiontable[i].endpc;
-               cd->exceptiontable[i].end = (p == m->jcodelength) ? (jd->basicblocks + jd->basicblockcount /*+ 1*/) : (jd->basicblocks + jd->basicblockindex[p]);
-
-               p = cd->exceptiontable[i].handlerpc;
-               cd->exceptiontable[i].handler = jd->basicblocks + jd->basicblockindex[p];
-       }
-
-       /* XXX activate this if you want to try inlining */
-#if 0
-       for (i = 0; i < m->exceptiontablelength; ++i) {
-               p = m->exceptiontable[i].startpc;
-               m->exceptiontable[i].start = jd->basicblocks + jd->basicblockindex[p];
+       if (!parse_resolve_exception_table(jd))
+               return false;
 
-               p = m->exceptiontable[i].endpc;
-               m->exceptiontable[i].end = (p == m->jcodelength) ? (jd->basicblocks + jd->basicblockcount /*+ 1*/) : (jd->basicblocks + jd->basicblockindex[p]);
-
-               p = m->exceptiontable[i].handlerpc;
-               m->exceptiontable[i].handler = jd->basicblocks + jd->basicblockindex[p];
-       }
-#endif
+       /* store the local map */
 
        jd->local_map = local_map;
 
@@ -1572,7 +1669,7 @@ invoke_method:
                /* iterate over local_map[0..m->maxlocals*5] and set all existing  */
                /* index,type pairs (local_map[index*5+type]==1) to an unique value */
                /* -> == new local var index */
-               for(i = 0; i < (cd->maxlocals * 5); i++, mapptr++) {
+               for(i = 0; i < (m->maxlocals * 5); i++, mapptr++) {
                        if (*mapptr)
                                *mapptr = nlocals++;
                        else
@@ -1601,10 +1698,8 @@ invoke_method:
                /* extra variables.                                             */
 
 #if defined(ENABLE_VERIFIER)
-               if (JITDATA_HAS_FLAG_VERIFY(jd)) {
-                       jd->varcount += VERIFIER_EXTRA_LOCALS + VERIFIER_EXTRA_VARS + m->maxstack;
-                       jd->vartop   += VERIFIER_EXTRA_LOCALS + VERIFIER_EXTRA_VARS + m->maxstack;
-               }
+               jd->varcount += VERIFIER_EXTRA_LOCALS + VERIFIER_EXTRA_VARS + m->maxstack;
+               jd->vartop   += VERIFIER_EXTRA_LOCALS + VERIFIER_EXTRA_VARS + m->maxstack;
 #endif
                /* allocate and initialize the variable array */
 
@@ -1613,7 +1708,7 @@ invoke_method:
 
                /* set types of all locals in jd->var */
 
-               for(mapptr = local_map, i = 0; i < (cd->maxlocals * 5); i++, mapptr++)
+               for(mapptr = local_map, i = 0; i < (m->maxlocals * 5); i++, mapptr++)
                        if (*mapptr != UNUSED)
                                VAR(*mapptr)->type = i%5;
        }