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 $
*/
pd->instructions = DMREALLOC(pd->instructions, instruction, ipc,
pd->instructionslength);
+ MZERO(pd->instructions + ipc, instruction, (pd->instructionslength - ipc));
/* return the iptr */
}
-/*******************************************************************************
+/* 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)
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 */
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 */
/* 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;
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 */
s4 prevvalue = 0;
#endif
blockend = true;
- nextp = ALIGN((p + 1), 4);
+ nextp = MEMORY_ALIGN((p + 1), 4);
CHECK_END_OF_BYTECODE(nextp + 8);
branch_target_t *table;
blockend = true;
- nextp = ALIGN((p + 1), 4);
+ nextp = MEMORY_ALIGN((p + 1), 4);
CHECK_END_OF_BYTECODE(nextp + 12);
/* 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;
#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;
/* 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)
}
#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;
/* 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)
}
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;
else
#endif
{
- OP(ICMD_CHECKNULL_POP);
+ OP_CHECK_EXCEPTION(ICMD_CHECKNULL);
+ OP(ICMD_POP);
}
break;
else
#endif
{
- OP(ICMD_CHECKNULL_POP);
+ OP_CHECK_EXCEPTION(ICMD_CHECKNULL);
+ OP(ICMD_POP);
}
break;
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;
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;
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;
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;
if (!jd->basicblockindex[0] || (jd->basicblockindex[0] > 1))
b_count++;
+ else
+ jd->branchtoentry = true;
/* copy local to method variables */
MZERO(bptr, basicblock, b_count + 1);
b_count = 0;
- jd->c_block_nr = 0;
/* additional block if target 0 is not first intermediate instruction */
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;
}
jd->basicblockindex[p] = b_count;
+ bptr->nr = b_count++;
bptr++;
- b_count++;
bptr[-1].next = bptr;
}
}
/* 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;
/* 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
/* 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 */
/* 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;
}