X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=src%2Fvm%2Fjit%2Fparse.c;h=9a8e4e4cb99e0ae78203f079c29ec375a326fb9e;hb=d24a28c1e12a8f8ef7d2c660c5ba5d1d278c4ef8;hp=4040988f6787d72a91011f26b544accc3ada7e0d;hpb=e5bff596161b810886a0c4569b36934a265f941b;p=cacao.git diff --git a/src/vm/jit/parse.c b/src/vm/jit/parse.c index 4040988f6..9a8e4e4cb 100644 --- a/src/vm/jit/parse.c +++ b/src/vm/jit/parse.c @@ -24,14 +24,13 @@ Contact: cacao@cacaojvm.org - Author: Andreas Krall - - Changes: Carolyn Oates + Authors: Andreas Krall + Carolyn Oates Edwin Steiner Joseph Wenninger Christian Thalinger - $Id: parse.c 4988 2006-05-29 21:48:50Z edwin $ + $Id: parse.c 6173 2006-12-11 19:55:31Z twisti $ */ @@ -45,6 +44,11 @@ #include "mm/memory.h" #include "native/native.h" + +#if defined(ENABLE_THREADS) +# include "threads/native/lock.h" +#endif + #include "toolbox/logging.h" #include "vm/builtin.h" #include "vm/exceptions.h" @@ -55,1428 +59,368 @@ #include "vm/options.h" #include "vm/statistics.h" #include "vm/stringlocal.h" +#include "vm/suck.h" #include "vm/jit/asmpart.h" #include "vm/jit/jit.h" #include "vm/jit/parse.h" #include "vm/jit/patcher.h" #include "vm/jit/loop/loop.h" -/******************************************************************************* - - 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. - -*******************************************************************************/ - -static exceptiontable * fillextable(methodinfo *m, - exceptiontable *extable, - exceptiontable *raw_extable, - int exceptiontablelength, - int *block_count) -{ - int b_count, p, src; - - if (exceptiontablelength == 0) - return extable; +#define INSTRUCTIONS_INCREMENT 5 /* number of additional instructions to */ + /* allocate if space runs out */ - b_count = *block_count; - 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; - block_insert(p); - - p = raw_extable[src].endpc; /* see JVM Spec 4.7.3 */ - CHECK_BYTECODE_INDEX_EXCLUSIVE(p); +/* parserdata_t ***************************************************************/ -#if defined(ENABLE_VERIFIER) - if (p <= raw_extable[src].startpc) { - *exceptionptr = new_verifyerror(m, - "Invalid exception handler range"); - return NULL; - } -#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) - block_insert(p); +typedef struct parsedata_t parsedata_t; - /* the start of the handler becomes a basic block start */ - p = raw_extable[src].handlerpc; - CHECK_BYTECODE_INDEX(p); - extable->handlerpc = p; - block_insert(p); - - extable->catchtype = raw_extable[src].catchtype; - extable->next = NULL; - extable->down = &extable[1]; - extable--; - } +struct parsedata_t { + instruction *instructions; /* instruction array */ + s4 instructionslength; /* length of the instruction array */ + u1 *instructionstart; +}; - *block_count = b_count; - - /* everything ok */ - return extable; -#if defined(ENABLE_VERIFIER) -throw_invalid_bytecode_index: - *exceptionptr = - new_verifyerror(m, "Illegal bytecode index in exception table"); - return NULL; -#endif -} +/* parse_setup ***************************************************************** -/*** macro for checking the length of the bytecode ***/ + Fills the passed parsedata_t structure. -#if defined(ENABLE_VERIFIER) -#define CHECK_END_OF_BYTECODE(neededlength) \ - do { \ - if ((neededlength) > m->jcodelength) \ - goto throw_unexpected_end_of_bytecode; \ - } while (0) -#else /* !ENABLE_VERIFIER */ -#define CHECK_END_OF_BYTECODE(neededlength) -#endif /* ENABLE_VERIFIER */ +*******************************************************************************/ -bool new_parse(jitdata *jd) +static void parse_setup(jitdata *jd, parsedata_t *pd) { - methodinfo *m; /* method being parsed */ - codegendata *cd; - int p; /* java instruction counter */ - int nextp; /* start of next java instruction */ - int opcode; /* java opcode */ - int i; /* temporary for different uses (ctrs) */ - int ipc = 0; /* intermediate instruction counter */ - int b_count = 0; /* 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 */ - instruction *iptr; /* current ptr into instruction array */ - u1 *instructionstart; /* 1 for pcs which are valid instr. starts */ + methodinfo *m; - constant_classref *cr; - constant_classref *compr; - classinfo *c; - builtintable_entry *bte; + /* get required compiler data */ - constant_FMIref *mr; - methoddesc *md; - unresolved_method *um; - resolve_result_t result; + m = jd->m; - u2 lineindex = 0; - u2 currentline = 0; - u2 linepcchange = 0; + /* Allocate instruction array and block index table (1 additional + for end ipc). */ - /* get required compiler data */ + jd->basicblockindex = DMNEW(s4, m->jcodelength + 1); + pd->instructionstart = DMNEW(u1, m->jcodelength + 1); - m = jd->m; - cd = jd->cd; + MZERO(jd->basicblockindex, s4, m->jcodelength + 1); + MZERO(pd->instructionstart, u1, m->jcodelength + 1); - /* allocate instruction array and block index table */ - - /* 1 additional for end ipc */ - m->basicblockindex = DMNEW(s4, m->jcodelength + 1); - memset(m->basicblockindex, 0, sizeof(s4) * (m->jcodelength + 1)); + /* Set the length of the instruction array. We simply add 5 more + instruction, as this seems to be a reasonable value. */ - instructionstart = DMNEW(u1, m->jcodelength + 1); - memset(instructionstart, 0, sizeof(u1) * (m->jcodelength + 1)); + pd->instructionslength = m->jcodelength + 1; - /* 1 additional for TRACEBUILTIN and 4 for MONITORENTER/EXIT */ - /* additional MONITOREXITS are reached by branches which are 3 bytes */ - - iptr = m->instructions = DMNEW(instruction, m->jcodelength + 5); + /* allocate the instruction array */ - /* Zero the intermediate instructions array so we don't have any - * invalid pointers in it if we cannot finish analyse_stack(). */ + pd->instructions = DMNEW(instruction, pd->instructionslength); - memset(iptr, 0, sizeof(instruction) * (m->jcodelength + 5)); - - /* compute branch targets of exception table */ + /* Zero the intermediate instructions array so we don't have any + invalid pointers in it if we cannot finish stack_analyse(). */ - if (!fillextable(m, - &(cd->exceptiontable[cd->exceptiontablelength-1]), - m->exceptiontable, - m->exceptiontablelength, - &b_count)) - { - return false; - } + MZERO(pd->instructions, instruction, pd->instructionslength); +} - s_count = 1 + m->exceptiontablelength; /* initialize stack element counter */ -#if defined(ENABLE_THREADS) - if (checksync && (m->flags & ACC_SYNCHRONIZED)) { - m->isleafmethod = false; - } -#endif +/* parse_realloc_instructions ************************************************** - /* scan all java instructions */ - currentline = 0; - linepcchange = 0; + Reallocate the instructions array so there is room for at least N + additional instructions. - if (m->linenumbercount == 0) { - lineindex = 0; - } - else { - linepcchange = m->linenumbers[0].start_pc; - } + RETURN VALUE: + the new value for iptr - for (p = 0; p < m->jcodelength; p = nextp) { - - /* mark this position as a valid instruction start */ - instructionstart[p] = 1; - if (linepcchange == p) { - if (m->linenumbercount > lineindex) { -next_linenumber: - currentline = m->linenumbers[lineindex].line_number; - lineindex++; - if (lineindex < m->linenumbercount) { - linepcchange = m->linenumbers[lineindex].start_pc; - if (linepcchange == p) - goto next_linenumber; - } - } - } +*******************************************************************************/ - /* fetch next opcode */ -fetch_opcode: - opcode = code_get_u1(p, m); +static instruction *parse_realloc_instructions(parsedata_t *pd, s4 ipc, s4 n) +{ + /* increase the size of the instruction array */ - m->basicblockindex[p] |= (ipc << 1); /*store intermed cnt*/ + pd->instructionslength += (n + INSTRUCTIONS_INCREMENT); - /* some compilers put a JAVA_NOP after a blockend instruction */ + /* reallocate the array */ - if (blockend && (opcode != JAVA_NOP)) { - /* start new block */ + pd->instructions = DMREALLOC(pd->instructions, instruction, ipc, + pd->instructionslength); + MZERO(pd->instructions + ipc, instruction, (pd->instructionslength - ipc)); - block_insert(p); - blockend = false; - } + /* return the iptr */ - nextp = p + jcommandsize[opcode]; /* compute next instruction start */ + return pd->instructions + ipc; +} - CHECK_END_OF_BYTECODE(nextp); - s_count += stackreq[opcode]; /* compute stack element count */ - switch (opcode) { - case JAVA_NOP: - break; +/* parse_mark_exception_boundaries ********************************************* - /* pushing constants onto the stack p */ + Mark exception handlers and the boundaries of the handled regions as + basic block boundaries. - case JAVA_BIPUSH: - LOADCONST_I(code_get_s1(p+1,m)); - break; + IN: + jd...............current jitdata - case JAVA_SIPUSH: - LOADCONST_I(code_get_s2(p+1,m)); - break; + RETURN VALUE: + >= 0.............the number of new basic blocks marked + -1...............an exception has been thrown - case JAVA_LDC1: - i = code_get_u1(p + 1, m); - goto pushconstantitem; +*******************************************************************************/ - case JAVA_LDC2: - case JAVA_LDC2W: - i = code_get_u2(p + 1, m); +static int parse_mark_exception_boundaries(jitdata *jd) +{ + s4 b_count; + s4 pc; + s4 i; + s4 len; + raw_exception_entry *rex; + methodinfo *m; + + m = jd->m; + + len = m->rawexceptiontablelength; - pushconstantitem: + if (len == 0) + return 0; -#if defined(ENABLE_VERIFIER) - if (i >= m->class->cpcount) { - *exceptionptr = new_verifyerror(m, - "Attempt to access constant outside range"); - return false; - } -#endif + b_count = 0; + rex = m->rawexceptiontable; - switch (m->class->cptags[i]) { - case CONSTANT_Integer: - LOADCONST_I(((constant_integer *) (m->class->cpinfos[i]))->value); - break; - case CONSTANT_Long: - LOADCONST_L(((constant_long *) (m->class->cpinfos[i]))->value); - break; - case CONSTANT_Float: - LOADCONST_F(((constant_float *) (m->class->cpinfos[i]))->value); - break; - case CONSTANT_Double: - LOADCONST_D(((constant_double *) (m->class->cpinfos[i]))->value); - break; - case CONSTANT_String: - LOADCONST_A(literalstring_new((utf *) (m->class->cpinfos[i]))); - break; - case CONSTANT_Class: - cr = (constant_classref *) (m->class->cpinfos[i]); + for (i = 0; i < len; ++i, ++rex) { - if (!resolve_classref(m, cr, resolveLazy, true, - true, &c)) - return false; + /* the start of the handled region becomes a basic block start */ - /* if not resolved, c == NULL */ + pc = rex->startpc; + CHECK_BYTECODE_INDEX(pc); + MARK_BASICBLOCK(pc); + + pc = rex->endpc; /* see JVM Spec 4.7.3 */ + CHECK_BYTECODE_INDEX_EXCLUSIVE(pc); - if (c) { - iptr->target = (void*) 0x02; /* XXX target used temporarily as flag */ - LOADCONST_A(c); - } - else { - iptr->target = (void*) 0x03; /* XXX target used temporarily as flag */ - LOADCONST_A(cr); - } - break; + /* check that the range is valid */ #if defined(ENABLE_VERIFIER) - default: - *exceptionptr = new_verifyerror(m, - "Invalid constant type to push"); - return false; + if (pc <= rex->startpc) { + exceptions_throw_verifyerror(m, + "Invalid exception handler range"); + return -1; + } #endif - } - break; - - case JAVA_ACONST_NULL: - LOADCONST_A(NULL); - break; - - case JAVA_ICONST_M1: - case JAVA_ICONST_0: - case JAVA_ICONST_1: - case JAVA_ICONST_2: - case JAVA_ICONST_3: - case JAVA_ICONST_4: - case JAVA_ICONST_5: - LOADCONST_I(opcode - JAVA_ICONST_0); - break; - - case JAVA_LCONST_0: - case JAVA_LCONST_1: - LOADCONST_L(opcode - JAVA_LCONST_0); - break; - - case JAVA_FCONST_0: - case JAVA_FCONST_1: - case JAVA_FCONST_2: - LOADCONST_F(opcode - JAVA_FCONST_0); - break; - - case JAVA_DCONST_0: - case JAVA_DCONST_1: - LOADCONST_D(opcode - JAVA_DCONST_0); - break; + + /* 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.) */ - /* loading variables onto the stack */ + if (pc < m->jcodelength) + MARK_BASICBLOCK(pc); + else + jd->branchtoend = true; - case JAVA_ILOAD: - case JAVA_FLOAD: - case JAVA_ALOAD: - if (!iswide) { - i = code_get_u1(p + 1,m); - } - else { - i = code_get_u2(p + 1,m); - nextp = p + 3; - iswide = false; - } - OP1LOAD_ONEWORD(opcode, i); - break; + /* the start of the handler becomes a basic block start */ - case JAVA_LLOAD: - case JAVA_DLOAD: - if (!iswide) { - i = code_get_u1(p + 1,m); - } - else { - i = code_get_u2(p + 1,m); - nextp = p + 3; - iswide = false; - } - OP1LOAD_TWOWORD(opcode, i); - break; + pc = rex->handlerpc; + CHECK_BYTECODE_INDEX(pc); + MARK_BASICBLOCK(pc); + } - case JAVA_ILOAD_0: - case JAVA_ILOAD_1: - case JAVA_ILOAD_2: - case JAVA_ILOAD_3: - OP1LOAD_ONEWORD(ICMD_ILOAD, opcode - JAVA_ILOAD_0); - break; + /* everything ok */ - case JAVA_LLOAD_0: - case JAVA_LLOAD_1: - case JAVA_LLOAD_2: - case JAVA_LLOAD_3: - OP1LOAD_TWOWORD(ICMD_LLOAD, opcode - JAVA_LLOAD_0); - break; + return b_count; - case JAVA_FLOAD_0: - case JAVA_FLOAD_1: - case JAVA_FLOAD_2: - case JAVA_FLOAD_3: - OP1LOAD_ONEWORD(ICMD_FLOAD, opcode - JAVA_FLOAD_0); - break; +#if defined(ENABLE_VERIFIER) +throw_invalid_bytecode_index: + exceptions_throw_verifyerror(m, + "Illegal bytecode index in exception table"); + return -1; +#endif +} - case JAVA_DLOAD_0: - case JAVA_DLOAD_1: - case JAVA_DLOAD_2: - case JAVA_DLOAD_3: - OP1LOAD_TWOWORD(ICMD_DLOAD, opcode - JAVA_DLOAD_0); - break; - case JAVA_ALOAD_0: - case JAVA_ALOAD_1: - case JAVA_ALOAD_2: - case JAVA_ALOAD_3: - OP1LOAD_ONEWORD(ICMD_ALOAD, opcode - JAVA_ALOAD_0); - break; +/* parse_resolve_exception_table *********************************************** - /* storing stack values into local variables */ + Enter the exception handlers and their ranges, resolved to basicblock *s, + in the jitdata. - case JAVA_ISTORE: - case JAVA_FSTORE: - case JAVA_ASTORE: - if (!iswide) { - i = code_get_u1(p + 1,m); - } - else { - i = code_get_u2(p + 1,m); - iswide = false; - nextp = p + 3; - } - OP1STORE_ONEWORD(opcode, i); - break; + IN: + jd...............current jitdata - case JAVA_LSTORE: - case JAVA_DSTORE: - if (!iswide) { - i = code_get_u1(p + 1,m); - } - else { - i = code_get_u2(p + 1,m); - iswide = false; - nextp = p + 3; - } - OP1STORE_TWOWORD(opcode, i); - break; + RETURN VALUE: + true.............everything ok + false............an exception has been thrown - case JAVA_ISTORE_0: - case JAVA_ISTORE_1: - case JAVA_ISTORE_2: - case JAVA_ISTORE_3: - OP1STORE_ONEWORD(ICMD_ISTORE, opcode - JAVA_ISTORE_0); - break; +*******************************************************************************/ - case JAVA_LSTORE_0: - case JAVA_LSTORE_1: - case JAVA_LSTORE_2: - case JAVA_LSTORE_3: - OP1STORE_TWOWORD(ICMD_LSTORE, opcode - JAVA_LSTORE_0); - break; +static bool parse_resolve_exception_table(jitdata *jd) +{ + methodinfo *m; + raw_exception_entry *rex; + exception_entry *ex; + s4 i; + s4 len; + classinfo *exclass; - case JAVA_FSTORE_0: - case JAVA_FSTORE_1: - case JAVA_FSTORE_2: - case JAVA_FSTORE_3: - OP1STORE_ONEWORD(ICMD_FSTORE, opcode - JAVA_FSTORE_0); - break; + m = jd->m; - case JAVA_DSTORE_0: - case JAVA_DSTORE_1: - case JAVA_DSTORE_2: - case JAVA_DSTORE_3: - OP1STORE_TWOWORD(ICMD_DSTORE, opcode - JAVA_DSTORE_0); - break; - - case JAVA_ASTORE_0: - case JAVA_ASTORE_1: - case JAVA_ASTORE_2: - case JAVA_ASTORE_3: - OP1STORE_ONEWORD(ICMD_ASTORE, opcode - JAVA_ASTORE_0); - break; - - case JAVA_IINC: - { - int v; - - if (!iswide) { - i = code_get_u1(p + 1,m); - v = code_get_s1(p + 2,m); - - } - else { - i = code_get_u2(p + 1,m); - v = code_get_s2(p + 3,m); - iswide = false; - nextp = p + 5; - } - INDEX_ONEWORD(i); - OP2I(opcode, i, v); - } - break; - - /* wider index for loading, storing and incrementing */ - - case JAVA_WIDE: - iswide = true; - p++; - goto fetch_opcode; - - /* managing arrays ****************************************************/ - - case JAVA_NEWARRAY: - switch (code_get_s1(p + 1, m)) { - case 4: - bte = builtintable_get_internal(BUILTIN_newarray_boolean); - break; - case 5: - bte = builtintable_get_internal(BUILTIN_newarray_char); - break; - case 6: - bte = builtintable_get_internal(BUILTIN_newarray_float); - break; - case 7: - bte = builtintable_get_internal(BUILTIN_newarray_double); - break; - case 8: - bte = builtintable_get_internal(BUILTIN_newarray_byte); - break; - case 9: - bte = builtintable_get_internal(BUILTIN_newarray_short); - break; - case 10: - bte = builtintable_get_internal(BUILTIN_newarray_int); - break; - case 11: - bte = builtintable_get_internal(BUILTIN_newarray_long); - break; -#if defined(ENABLE_VERIFIER) - default: - *exceptionptr = new_verifyerror(m, - "Invalid array-type to create"); - return false; -#endif - } - BUILTIN(bte, true, NULL, currentline); - break; - - case JAVA_ANEWARRAY: - i = code_get_u2(p + 1, m); - compr = (constant_classref *) class_getconstant(m->class, i, CONSTANT_Class); - if (!compr) - return false; - - if (!(cr = class_get_classref_multiarray_of(1, compr))) - return false; - - if (!resolve_classref(m, cr, resolveLazy, true, true, &c)) - return false; - - LOADCONST_A_BUILTIN(c, cr); - bte = builtintable_get_internal(BUILTIN_newarray); - BUILTIN(bte, true, NULL, currentline); - s_count++; - break; - - case JAVA_MULTIANEWARRAY: - m->isleafmethod = false; - i = code_get_u2(p + 1, m); - { - s4 v = code_get_u1(p + 3, m); - - cr = (constant_classref *) class_getconstant(m->class, i, CONSTANT_Class); - if (!cr) - return false; - - if (!resolve_classref(m, cr, resolveLazy, true, true, &c)) - return false; - - /* if unresolved, c == NULL */ - OP2AT(opcode, v, c, cr, currentline); - } - break; - - case JAVA_IFEQ: - case JAVA_IFLT: - case JAVA_IFLE: - case JAVA_IFNE: - case JAVA_IFGT: - case JAVA_IFGE: - case JAVA_IFNULL: - case JAVA_IFNONNULL: - case JAVA_IF_ICMPEQ: - case JAVA_IF_ICMPNE: - case JAVA_IF_ICMPLT: - case JAVA_IF_ICMPGT: - case JAVA_IF_ICMPLE: - case JAVA_IF_ICMPGE: - case JAVA_IF_ACMPEQ: - case JAVA_IF_ACMPNE: - case JAVA_GOTO: - case JAVA_JSR: - i = p + code_get_s2(p + 1,m); - CHECK_BYTECODE_INDEX(i); - block_insert(i); - blockend = true; - OP1(opcode, i); - break; - - case JAVA_GOTO_W: - case JAVA_JSR_W: - i = p + code_get_s4(p + 1,m); - CHECK_BYTECODE_INDEX(i); - block_insert(i); - blockend = true; - OP1(opcode, i); - break; - - case JAVA_RET: - if (!iswide) { - i = code_get_u1(p + 1,m); - } - else { - i = code_get_u2(p + 1,m); - nextp = p + 3; - iswide = false; - } - blockend = true; - - OP1LOAD_ONEWORD(opcode, i); - break; - - case JAVA_IRETURN: - case JAVA_LRETURN: - case JAVA_FRETURN: - case JAVA_DRETURN: - case JAVA_ARETURN: - case JAVA_RETURN: - blockend = true; - /* zero val.a so no patcher is inserted */ - /* the type checker may set this later */ - iptr->val.a = NULL; - OP(opcode); - break; - - case JAVA_ATHROW: - blockend = true; - /* zero val.a so no patcher is inserted */ - /* the type checker may set this later */ - iptr->val.a = NULL; - OP(opcode); - break; - - - /* table jumps ********************************************************/ - - case JAVA_LOOKUPSWITCH: - { - s4 num, j; - s4 *tablep; -#if defined(ENABLE_VERIFIER) - s4 prevvalue = 0; -#endif - - blockend = true; - nextp = ALIGN((p + 1), 4); - - CHECK_END_OF_BYTECODE(nextp + 8); - - tablep = (s4 *) (m->jcode + nextp); - - OP2A(opcode, 0, tablep, currentline); - - /* default target */ - - j = p + code_get_s4(nextp, m); - *tablep = j; /* restore for little endian */ - tablep++; - nextp += 4; - CHECK_BYTECODE_INDEX(j); - block_insert(j); - - /* number of pairs */ - - num = code_get_u4(nextp, m); - *tablep = num; - tablep++; - nextp += 4; - - CHECK_END_OF_BYTECODE(nextp + 8 * num); - - for (i = 0; i < num; i++) { - /* value */ - - j = code_get_s4(nextp, m); - *tablep = j; /* restore for little endian */ - tablep++; - nextp += 4; - -#if defined(ENABLE_VERIFIER) - /* check if the lookup table is sorted correctly */ - - if (i && (j <= prevvalue)) { - *exceptionptr = new_verifyerror(m, "Unsorted lookup switch"); - return false; - } - prevvalue = j; -#endif - - /* target */ - - j = p + code_get_s4(nextp,m); - *tablep = j; /* restore for little endian */ - tablep++; - nextp += 4; - CHECK_BYTECODE_INDEX(j); - block_insert(j); - } - - break; - } - - - case JAVA_TABLESWITCH: - { - s4 num, j; - s4 *tablep; - - blockend = true; - nextp = ALIGN((p + 1), 4); - - CHECK_END_OF_BYTECODE(nextp + 12); - - tablep = (s4 *) (m->jcode + nextp); - - OP2A(opcode, 0, tablep, currentline); - - /* default target */ - - j = p + code_get_s4(nextp, m); - *tablep = j; /* restore for little endian */ - tablep++; - nextp += 4; - CHECK_BYTECODE_INDEX(j); - block_insert(j); - - /* lower bound */ - - j = code_get_s4(nextp, m); - *tablep = j; /* restore for little endian */ - tablep++; - nextp += 4; - - /* upper bound */ - - num = code_get_s4(nextp, m); - *tablep = num; /* restore for little endian */ - tablep++; - nextp += 4; - - num -= j; /* difference of upper - lower */ - -#if defined(ENABLE_VERIFIER) - if (num < 0) { - *exceptionptr = new_verifyerror(m, - "invalid TABLESWITCH: upper bound < lower bound"); - return false; - } -#endif - - CHECK_END_OF_BYTECODE(nextp + 4 * (num + 1)); - - for (i = 0; i <= num; i++) { - j = p + code_get_s4(nextp,m); - *tablep = j; /* restore for little endian */ - tablep++; - nextp += 4; - CHECK_BYTECODE_INDEX(j); - block_insert(j); - } - - break; - } - - - /* load and store of object fields ************************************/ - - case JAVA_AASTORE: - OP(opcode); - m->isleafmethod = false; - break; - - case JAVA_GETSTATIC: - case JAVA_PUTSTATIC: - case JAVA_GETFIELD: - case JAVA_PUTFIELD: - { - constant_FMIref *fr; - unresolved_field *uf; - - i = code_get_u2(p + 1, m); - fr = class_getconstant(m->class, i, - CONSTANT_Fieldref); - if (!fr) - return false; - - OP2A_NOINC(opcode, fr->parseddesc.fd->type, fr, currentline); - - /* only with -noverify, otherwise the typechecker does this */ - -#if defined(ENABLE_VERIFIER) - if (!opt_verify) { -#endif - result = resolve_field_lazy(iptr,NULL,m); - if (result == resolveFailed) - return false; - - if (result != resolveSucceeded) { - uf = create_unresolved_field(m->class, - m, iptr); - - if (!uf) - return false; - - /* store the unresolved_field pointer */ - - /* XXX this will be changed */ - iptr->val.a = uf; - iptr->target = (void*) 0x01; /* XXX target temporarily used as flag */ - } - else { - iptr->target = NULL; - } -#if defined(ENABLE_VERIFIER) - } - else { - iptr->target = NULL; - } -#endif - PINC; - } - break; - - - /* method invocation **************************************************/ - - case JAVA_INVOKESTATIC: - i = code_get_u2(p + 1, m); - mr = class_getconstant(m->class, i, - CONSTANT_Methodref); - if (!mr) - return false; - - md = mr->parseddesc.md; - - if (!md->params) - if (!descriptor_params_from_paramtypes(md, ACC_STATIC)) - return false; - - goto invoke_method; - - case JAVA_INVOKEINTERFACE: - i = code_get_u2(p + 1, m); - - mr = class_getconstant(m->class, i, - CONSTANT_InterfaceMethodref); - - goto invoke_nonstatic_method; - - case JAVA_INVOKESPECIAL: - case JAVA_INVOKEVIRTUAL: - i = code_get_u2(p + 1, m); - mr = class_getconstant(m->class, i, - CONSTANT_Methodref); - -invoke_nonstatic_method: - if (!mr) - return false; - - md = mr->parseddesc.md; - - if (!md->params) - if (!descriptor_params_from_paramtypes(md, 0)) - return false; - -invoke_method: - m->isleafmethod = false; - - OP2A_NOINC(opcode, 0, mr, currentline); - - /* only with -noverify, otherwise the typechecker does this */ - -#if defined(ENABLE_VERIFIER) - if (!opt_verify) { -#endif - result = resolve_method_lazy(iptr,NULL,m); - if (result == resolveFailed) - return false; - - if (result != resolveSucceeded) { - um = create_unresolved_method(m->class, - m, iptr); - - if (!um) - return false; - - /* store the unresolved_method pointer */ - - /* XXX this will be changed */ - iptr->val.a = um; - iptr->target = (void*) 0x01; /* XXX target temporarily used as flag */ - } - else { - /* the method could be resolved */ - iptr->target = NULL; - } -#if defined(ENABLE_VERIFIER) - } - else { - iptr->target = NULL; - } -#endif - PINC; - break; - - /* miscellaneous object operations ************************************/ - - case JAVA_NEW: - i = code_get_u2(p + 1, m); - cr = (constant_classref *) class_getconstant(m->class, i, CONSTANT_Class); - if (!cr) - return false; - - if (!resolve_classref(m, cr, resolveLazy, true, true, - &c)) - return false; - - LOADCONST_A_BUILTIN(c, cr); - bte = builtintable_get_internal(BUILTIN_new); - BUILTIN(bte, true, NULL, currentline); - s_count++; - break; - - case JAVA_CHECKCAST: - i = code_get_u2(p + 1, m); - cr = (constant_classref *) class_getconstant(m->class, i, CONSTANT_Class); - if (!cr) - return false; - - if (!resolve_classref(m, cr, resolveLazy, true, - true, &c)) - return false; - - if (cr->name->text[0] == '[') { - /* array type cast-check */ - OP2AT(opcode, 0, c, cr, currentline); - m->isleafmethod = false; - - } - else { - /* object type cast-check */ - OP2AT(opcode, 1, c, cr, currentline); - } - break; - - case JAVA_INSTANCEOF: - i = code_get_u2(p + 1,m); - cr = (constant_classref *) class_getconstant(m->class, i, CONSTANT_Class); - if (!cr) - return false; - - if (!resolve_classref(m, cr, resolveLazy, true, true, &c)) - return false; - - if (cr->name->text[0] == '[') { - /* array type cast-check */ - LOADCONST_A_BUILTIN(c, cr); - bte = builtintable_get_internal(BUILTIN_arrayinstanceof); - BUILTIN(bte, false, NULL, currentline); - s_count++; - - } - else { - /* object type cast-check */ - OP2AT(opcode, 1, c, cr, currentline); - } - break; - - case JAVA_MONITORENTER: -#if defined(ENABLE_THREADS) - if (checksync) { - OP(ICMD_CHECKNULL); - bte = builtintable_get_internal(BUILTIN_monitorenter); - BUILTIN(bte, false, NULL, currentline); - } - else -#endif - { - OP(ICMD_CHECKNULL); - OP(ICMD_POP); - } - break; - - case JAVA_MONITOREXIT: -#if defined(ENABLE_THREADS) - if (checksync) { - bte = builtintable_get_internal(BUILTIN_monitorexit); - BUILTIN(bte, false, NULL, currentline); - } - else -#endif - { - OP(ICMD_POP); - } - break; - - /* any other basic operation ******************************************/ - - case JAVA_IDIV: -#if !SUPPORT_DIVISION - bte = builtintable_get_internal(BUILTIN_idiv); - OP2A(opcode, bte->md->paramcount, bte, currentline); - m->isleafmethod = false; -#else - OP(opcode); -#endif - break; - - case JAVA_IREM: -#if !SUPPORT_DIVISION - bte = builtintable_get_internal(BUILTIN_irem); - OP2A(opcode, bte->md->paramcount, bte, currentline); - m->isleafmethod = false; -#else - OP(opcode); -#endif - break; - - case JAVA_LDIV: -#if !(SUPPORT_DIVISION && SUPPORT_LONG && SUPPORT_LONG_DIV) - bte = builtintable_get_internal(BUILTIN_ldiv); - OP2A(opcode, bte->md->paramcount, bte, currentline); - m->isleafmethod = false; -#else - OP(opcode); -#endif - break; - - case JAVA_LREM: -#if !(SUPPORT_DIVISION && SUPPORT_LONG && SUPPORT_LONG_DIV) - bte = builtintable_get_internal(BUILTIN_lrem); - OP2A(opcode, bte->md->paramcount, bte, currentline); - m->isleafmethod = false; -#else - OP(opcode); -#endif - break; - - case JAVA_FREM: -#if defined(__I386__) - OP(opcode); -#else - bte = builtintable_get_internal(BUILTIN_frem); - BUILTIN(bte, false, NULL, currentline); -#endif - break; - - case JAVA_DREM: -#if defined(__I386__) - OP(opcode); -#else - bte = builtintable_get_internal(BUILTIN_drem); - BUILTIN(bte, false, NULL, currentline); -#endif - break; - - case JAVA_F2I: -#if defined(__ALPHA__) - if (!opt_noieee) { - bte = builtintable_get_internal(BUILTIN_f2i); - BUILTIN(bte, false, NULL, currentline); - } - else -#endif - { - OP(opcode); - } - break; - - case JAVA_F2L: -#if defined(__ALPHA__) - if (!opt_noieee) { - bte = builtintable_get_internal(BUILTIN_f2l); - BUILTIN(bte, false, NULL, currentline); - } - else -#endif - { - OP(opcode); - } - break; - - case JAVA_D2I: -#if defined(__ALPHA__) - if (!opt_noieee) { - bte = builtintable_get_internal(BUILTIN_d2i); - BUILTIN(bte, false, NULL, currentline); - } - else -#endif - { - OP(opcode); - } - break; - - case JAVA_D2L: -#if defined(__ALPHA__) - if (!opt_noieee) { - bte = builtintable_get_internal(BUILTIN_d2l); - BUILTIN(bte, false, NULL, currentline); - } - else -#endif - { - OP(opcode); - } - break; - - /* check for invalid opcodes if the verifier is enabled */ -#if defined(ENABLE_VERIFIER) - case JAVA_BREAKPOINT: - *exceptionptr = - new_verifyerror(m, "Quick instructions shouldn't appear yet."); - return false; - - case 186: /* unused opcode */ - case 203: - case 204: - case 205: - case 206: - case 207: - case 208: - case 209: - case 210: - case 211: - case 212: - case 213: - case 214: - case 215: - case 216: - case 217: - case 218: - case 219: - case 220: - case 221: - case 222: - case 223: - case 224: - case 225: - case 226: - case 227: - case 228: - case 229: - case 230: - case 231: - case 232: - case 233: - case 234: - case 235: - case 236: - case 237: - case 238: - case 239: - case 240: - case 241: - case 242: - case 243: - case 244: - case 245: - case 246: - case 247: - case 248: - case 249: - case 250: - case 251: - case 252: - case 253: - case 254: - case 255: - *exceptionptr = - new_verifyerror(m,"Illegal opcode %d at instr %d\n", - opcode, ipc); - return false; - break; -#endif /* defined(ENABLE_VERIFIER) */ - - default: - /* straight-forward translation to ICMD */ - OP(opcode); - break; - - } /* end switch */ - -#if defined(ENABLE_VERIFIER) - /* If WIDE was used correctly, iswide should have been reset by now. */ - if (iswide) { - *exceptionptr = new_verifyerror(m, - "Illegal instruction: WIDE before incompatible opcode"); - return false; - } -#endif /* defined(ENABLE_VERIFIER) */ - - } /* end for */ - -#if defined(ENABLE_VERIFIER) - if (p != m->jcodelength) { - *exceptionptr = new_verifyerror(m, - "Command-sequence crosses code-boundary"); - return false; - } - - if (!blockend) { - *exceptionptr = new_verifyerror(m, "Falling off the end of the code"); - return false; - } -#endif /* defined(ENABLE_VERIFIER) */ - - /* adjust block count if target 0 is not first intermediate instruction */ - - if (!m->basicblockindex[0] || (m->basicblockindex[0] > 1)) - b_count++; - - /* copy local to method variables */ - - m->instructioncount = ipc; - m->basicblockcount = b_count; - m->stackcount = s_count + m->basicblockcount * m->maxstack; - - /* allocate stack table */ - - m->stack = DMNEW(stackelement, m->stackcount); - - { - basicblock *bptr; - - bptr = m->basicblocks = DMNEW(basicblock, b_count + 1); /* one more for end ipc */ - - b_count = 0; - m->c_debug_nr = 0; - - /* additional block if target 0 is not first intermediate instruction */ - - if (!m->basicblockindex[0] || (m->basicblockindex[0] > 1)) { - BASICBLOCK_INIT(bptr,m); - - bptr->iinstr = m->instructions; - /* bptr->icount is set when the next block is allocated */ - - bptr++; - b_count++; - bptr[-1].next = bptr; - } - - /* allocate blocks */ - - for (p = 0; p < m->jcodelength; p++) { - if (m->basicblockindex[p] & 1) { - /* Check if this block starts at the beginning of an */ - /* instruction. */ -#if defined(ENABLE_VERIFIER) - if (!instructionstart[p]) { - *exceptionptr = new_verifyerror(m, - "Branch into middle of instruction"); - return false; - } -#endif - - /* allocate the block */ - - BASICBLOCK_INIT(bptr,m); - - bptr->iinstr = m->instructions + (m->basicblockindex[p] >> 1); - if (b_count) { - bptr[-1].icount = bptr->iinstr - bptr[-1].iinstr; - } - /* bptr->icount is set when the next block is allocated */ - - m->basicblockindex[p] = b_count; - - bptr++; - b_count++; - bptr[-1].next = bptr; - } - } + len = m->rawexceptiontablelength; - /* set instruction count of last real block */ + /* common case: no handler entries */ - if (b_count) { - bptr[-1].icount = (m->instructions + m->instructioncount) - bptr[-1].iinstr; - } + if (len == 0) + return true; - /* allocate additional block at end */ + /* allocate the exception table */ - BASICBLOCK_INIT(bptr,m); - - bptr->instack = bptr->outstack = NULL; - bptr->indepth = bptr->outdepth = 0; - bptr->iinstr = NULL; - bptr->icount = 0; - bptr->next = NULL; + jd->exceptiontablelength = len; + jd->exceptiontable = DMNEW(exception_entry, len + 1); /* XXX why +1? */ - /* set basicblock pointers in exception table */ + /* copy and resolve the entries */ - 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 = m->basicblocks + m->basicblockindex[p]; + ex = jd->exceptiontable; + rex = m->rawexceptiontable; - p = cd->exceptiontable[i].endpc; - cd->exceptiontable[i].end = (p == m->jcodelength) ? (m->basicblocks + m->basicblockcount /*+ 1*/) : (m->basicblocks + m->basicblockindex[p]); + for (i = 0; i < len; ++i, ++rex, ++ex) { + /* resolve instruction indices to basic blocks */ - p = cd->exceptiontable[i].handlerpc; - cd->exceptiontable[i].handler = m->basicblocks + m->basicblockindex[p]; - } + ex->start = BLOCK_OF(rex->startpc); + ex->end = BLOCK_OF(rex->endpc); + ex->handler = BLOCK_OF(rex->handlerpc); - /* 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 = m->basicblocks + m->basicblockindex[p]; + /* lazily resolve the catchtype */ - p = m->exceptiontable[i].endpc; - m->exceptiontable[i].end = (p == m->jcodelength) ? (m->basicblocks + m->basicblockcount /*+ 1*/) : (m->basicblocks + m->basicblockindex[p]); + if (rex->catchtype.any != NULL) { + if (!resolve_classref_or_classinfo(m, + rex->catchtype, + resolveLazy, true, false, + &exclass)) + return false; - p = m->exceptiontable[i].handlerpc; - m->exceptiontable[i].handler = m->basicblocks + m->basicblockindex[p]; - } -#endif + /* 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 */ } - /* everything's ok */ + /* terminate the ->down linked list */ + + assert(ex != jd->exceptiontable); + ex[-1].down = NULL; return true; +} -#if defined(ENABLE_VERIFIER) -throw_unexpected_end_of_bytecode: - *exceptionptr = new_verifyerror(m, "Unexpected end of bytecode"); - return false; +/******************************************************************************* -throw_invalid_bytecode_index: - *exceptionptr = - new_verifyerror(m, "Illegal target of branch instruction"); - return false; + function 'parse' scans the JavaVM code and generates intermediate code -throw_illegal_local_variable_number: - *exceptionptr = - new_verifyerror(m, "Illegal local variable number"); - return false; - -#endif /* ENABLE_VERIFIER */ -} + 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) +#define CHECK_END_OF_BYTECODE(neededlength) \ + do { \ + if ((neededlength) > m->jcodelength) \ + goto throw_unexpected_end_of_bytecode; \ + } while (0) +#else /* !ENABLE_VERIFIER */ +#define CHECK_END_OF_BYTECODE(neededlength) +#endif /* ENABLE_VERIFIER */ bool parse(jitdata *jd) { - methodinfo *m; - codegendata *cd; - int p; /* java instruction counter */ - int nextp; /* start of next java instruction */ - int opcode; /* java opcode */ - int i; /* temporary for different uses (ctrs)*/ - int ipc = 0; /* intermediate instruction counter */ - int b_count = 0; /* 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*/ - instruction *iptr; /* current ptr into instruction array */ - - u1 *instructionstart; /* 1 for pcs which are valid instr. starts */ - + methodinfo *m; /* method being parsed */ + parsedata_t pd; + instruction *iptr; /* current ptr into instruction array */ + s4 ipc; /* intermediate instruction counter */ + s4 p; /* java instruction counter */ + s4 nextp; /* start of next java instruction */ + s4 opcode; /* java opcode */ + s4 i; + s4 j; + 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 */ constant_classref *cr; constant_classref *compr; classinfo *c; builtintable_entry *bte; - - constant_FMIref *mr; - methoddesc *md; - unresolved_method *um; - resolve_result_t result; - - u2 lineindex = 0; - u2 currentline = 0; - u2 linepcchange = 0; - + constant_FMIref *mr; + methoddesc *md; + unresolved_method *um; + resolve_result_t result; + u2 lineindex = 0; + u2 currentline = 0; + u2 linepcchange = 0; + u4 flags; + basicblock *bptr; + + int *local_map; /* local pointer to renaming structore */ + /* is assigned to rd->local_map at the end */ /* get required compiler data */ - m = jd->m; - cd = jd->cd; + m = jd->m; - /* allocate instruction array and block index table */ - - /* 1 additional for end ipc */ - m->basicblockindex = DMNEW(s4, m->jcodelength + 1); - memset(m->basicblockindex, 0, sizeof(s4) * (m->jcodelength + 1)); - - instructionstart = DMNEW(u1, m->jcodelength + 1); - memset(instructionstart, 0, sizeof(u1) * (m->jcodelength + 1)); - - /* 1 additional for TRACEBUILTIN and 4 for MONITORENTER/EXIT */ - /* additional MONITOREXITS are reached by branches which are 3 bytes */ - - iptr = m->instructions = DMNEW(instruction, m->jcodelength + 5); - - /* Zero the intermediate instructions array so we don't have any - * invalid pointers in it if we cannot finish analyse_stack(). */ - - memset(iptr, 0, sizeof(instruction) * (m->jcodelength + 5)); - - /* compute branch targets of exception table */ + /* allocate buffers for local variable renaming */ + 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; + local_map[i * 5 + 3] = 0; + local_map[i * 5 + 4] = 0; + } - if (!fillextable(m, - &(cd->exceptiontable[cd->exceptiontablelength-1]), - m->exceptiontable, - m->exceptiontablelength, - &b_count)) - { + /* initialize the parse data structures */ + + parse_setup(jd, &pd); + + /* initialize local variables */ + + iptr = pd.instructions; + ipc = 0; + + /* mark basic block boundaries for exception table */ + + 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)) { - m->isleafmethod = false; - } -#endif + s_count = 1 + m->rawexceptiontablelength; + + /* setup line number info */ - /* scan all java instructions */ currentline = 0; linepcchange = 0; if (m->linenumbercount == 0) { lineindex = 0; - } + } else { linepcchange = m->linenumbers[0].start_pc; } + /*** LOOP OVER ALL BYTECODE INSTRUCTIONS **********************************/ + for (p = 0; p < m->jcodelength; p = nextp) { - + /* mark this position as a valid instruction start */ - instructionstart[p] = 1; + + pd.instructionstart[p] = 1; + + /* change the current line number, if necessary */ + + /* XXX rewrite this using pointer arithmetic */ + if (linepcchange == p) { if (m->linenumbercount > lineindex) { next_linenumber: @@ -1490,53 +434,79 @@ next_linenumber: } } - /* fetch next opcode */ fetch_opcode: - opcode = code_get_u1(p, m); + /* fetch next opcode */ - m->basicblockindex[p] |= (ipc << 1); /*store intermed cnt*/ + opcode = SUCK_BE_U1(m->jcode + p); /* some compilers put a JAVA_NOP after a blockend instruction */ if (blockend && (opcode != JAVA_NOP)) { /* start new block */ - block_insert(p); + MARK_BASICBLOCK(p); blockend = false; } - nextp = p + jcommandsize[opcode]; /* compute next instruction start */ + /* We need a NOP as last instruction in each basic block + for basic block reordering (may be replaced with a GOTO + later). */ + + if (jd->basicblockindex[p] & 1) { + INSTRUCTIONS_CHECK(1); + OP(ICMD_NOP); + } + + /* store intermediate instruction count (bit 0 mark block starts) */ + + jd->basicblockindex[p] |= (ipc << 1); + + /* compute next instruction start */ + + nextp = p + jcommandsize[opcode]; CHECK_END_OF_BYTECODE(nextp); - s_count += stackreq[opcode]; /* compute stack element count */ + /* add stack elements produced by this instruction */ + + s_count += stackreq[opcode]; + + /* We check here for the space of 1 instruction in the + instruction array. If an opcode is converted to more than + 1 instruction, this is checked in the corresponding + case. */ + + INSTRUCTIONS_CHECK(1); + + /* translate this bytecode instruction */ switch (opcode) { + case JAVA_NOP: break; - /* pushing constants onto the stack p */ + /* pushing constants onto the stack ***********************************/ case JAVA_BIPUSH: - LOADCONST_I(code_get_s1(p+1,m)); + OP_LOADCONST_I(SUCK_BE_S1(m->jcode + p + 1)); break; case JAVA_SIPUSH: - LOADCONST_I(code_get_s2(p+1,m)); + OP_LOADCONST_I(SUCK_BE_S2(m->jcode + p + 1)); break; case JAVA_LDC1: - i = code_get_u1(p + 1, m); + i = SUCK_BE_U1(m->jcode + p + 1); goto pushconstantitem; case JAVA_LDC2: case JAVA_LDC2W: - i = code_get_u2(p + 1, m); + i = SUCK_BE_U2(m->jcode + p + 1); pushconstantitem: #if defined(ENABLE_VERIFIER) if (i >= m->class->cpcount) { - *exceptionptr = new_verifyerror(m, + exceptions_throw_verifyerror(m, "Attempt to access constant outside range"); return false; } @@ -1544,42 +514,35 @@ fetch_opcode: switch (m->class->cptags[i]) { case CONSTANT_Integer: - LOADCONST_I(((constant_integer *) (m->class->cpinfos[i]))->value); + OP_LOADCONST_I(((constant_integer *) (m->class->cpinfos[i]))->value); break; case CONSTANT_Long: - LOADCONST_L(((constant_long *) (m->class->cpinfos[i]))->value); + OP_LOADCONST_L(((constant_long *) (m->class->cpinfos[i]))->value); break; case CONSTANT_Float: - LOADCONST_F(((constant_float *) (m->class->cpinfos[i]))->value); + OP_LOADCONST_F(((constant_float *) (m->class->cpinfos[i]))->value); break; case CONSTANT_Double: - LOADCONST_D(((constant_double *) (m->class->cpinfos[i]))->value); + OP_LOADCONST_D(((constant_double *) (m->class->cpinfos[i]))->value); break; case CONSTANT_String: - LOADCONST_A(literalstring_new((utf *) (m->class->cpinfos[i]))); + OP_LOADCONST_STRING(literalstring_new((utf *) (m->class->cpinfos[i]))); break; case CONSTANT_Class: cr = (constant_classref *) (m->class->cpinfos[i]); - if (!resolve_classref(m, cr, resolveLazy, true, - true, &c)) + if (!resolve_classref(m, cr, resolveLazy, true, true, &c)) return false; /* if not resolved, c == NULL */ - if (c) { - iptr->target = (void*) 0x02; /* XXX target used temporarily as flag */ - LOADCONST_A(c); - } - else { - iptr->target = (void*) 0x03; /* XXX target used temporarily as flag */ - LOADCONST_A(cr); - } + OP_LOADCONST_CLASSINFO_OR_CLASSREF_CHECK(c, cr); + break; #if defined(ENABLE_VERIFIER) default: - *exceptionptr = new_verifyerror(m, + exceptions_throw_verifyerror(m, "Invalid constant type to push"); return false; #endif @@ -1587,7 +550,7 @@ fetch_opcode: break; case JAVA_ACONST_NULL: - LOADCONST_A(NULL); + OP_LOADCONST_NULL(); break; case JAVA_ICONST_M1: @@ -1597,174 +560,233 @@ fetch_opcode: case JAVA_ICONST_3: case JAVA_ICONST_4: case JAVA_ICONST_5: - LOADCONST_I(opcode - JAVA_ICONST_0); + OP_LOADCONST_I(opcode - JAVA_ICONST_0); break; case JAVA_LCONST_0: case JAVA_LCONST_1: - LOADCONST_L(opcode - JAVA_LCONST_0); + OP_LOADCONST_L(opcode - JAVA_LCONST_0); break; case JAVA_FCONST_0: case JAVA_FCONST_1: case JAVA_FCONST_2: - LOADCONST_F(opcode - JAVA_FCONST_0); + OP_LOADCONST_F(opcode - JAVA_FCONST_0); break; case JAVA_DCONST_0: case JAVA_DCONST_1: - LOADCONST_D(opcode - JAVA_DCONST_0); + OP_LOADCONST_D(opcode - JAVA_DCONST_0); + break; + + /* stack operations ***************************************************/ + + /* We need space for additional ICMDs so we can translate these */ + /* instructions to sequences of ICMD_COPY and ICMD_MOVE instructions. */ + + case JAVA_DUP_X1: + INSTRUCTIONS_CHECK(4); + OP(opcode); + OP(ICMD_NOP); + OP(ICMD_NOP); + OP(ICMD_NOP); + break; + + case JAVA_DUP_X2: + INSTRUCTIONS_CHECK(6); + OP(opcode); + OP(ICMD_NOP); + OP(ICMD_NOP); + OP(ICMD_NOP); + OP(ICMD_NOP); + OP(ICMD_NOP); + break; + + case JAVA_DUP2: + INSTRUCTIONS_CHECK(2); + OP(opcode); + OP(ICMD_NOP); break; - /* loading variables onto the stack */ + case JAVA_DUP2_X1: + INSTRUCTIONS_CHECK(7); + OP(opcode); + OP(ICMD_NOP); + OP(ICMD_NOP); + OP(ICMD_NOP); + OP(ICMD_NOP); + OP(ICMD_NOP); + OP(ICMD_NOP); + break; + + case JAVA_DUP2_X2: + INSTRUCTIONS_CHECK(9); + OP(opcode); + OP(ICMD_NOP); + OP(ICMD_NOP); + OP(ICMD_NOP); + OP(ICMD_NOP); + OP(ICMD_NOP); + OP(ICMD_NOP); + OP(ICMD_NOP); + OP(ICMD_NOP); + break; + + case JAVA_SWAP: + INSTRUCTIONS_CHECK(3); + OP(opcode); + OP(ICMD_NOP); + OP(ICMD_NOP); + break; + + /* local variable access instructions *********************************/ case JAVA_ILOAD: case JAVA_FLOAD: case JAVA_ALOAD: - if (!iswide) { - i = code_get_u1(p + 1,m); - } + if (iswide == false) { + i = SUCK_BE_U1(m->jcode + p + 1); + } else { - i = code_get_u2(p + 1,m); + i = SUCK_BE_U2(m->jcode + p + 1); nextp = p + 3; iswide = false; } - OP1LOAD_ONEWORD(opcode, i); + OP_LOAD_ONEWORD(opcode, i, opcode - JAVA_ILOAD); break; case JAVA_LLOAD: case JAVA_DLOAD: - if (!iswide) { - i = code_get_u1(p + 1,m); - } + if (iswide == false) { + i = SUCK_BE_U1(m->jcode + p + 1); + } else { - i = code_get_u2(p + 1,m); + i = SUCK_BE_U2(m->jcode + p + 1); nextp = p + 3; iswide = false; } - OP1LOAD_TWOWORD(opcode, i); + OP_LOAD_TWOWORD(opcode, i, opcode - JAVA_ILOAD); break; case JAVA_ILOAD_0: case JAVA_ILOAD_1: case JAVA_ILOAD_2: case JAVA_ILOAD_3: - OP1LOAD_ONEWORD(ICMD_ILOAD, opcode - JAVA_ILOAD_0); + OP_LOAD_ONEWORD(ICMD_ILOAD, opcode - JAVA_ILOAD_0, TYPE_INT); break; case JAVA_LLOAD_0: case JAVA_LLOAD_1: case JAVA_LLOAD_2: case JAVA_LLOAD_3: - OP1LOAD_TWOWORD(ICMD_LLOAD, opcode - JAVA_LLOAD_0); + OP_LOAD_TWOWORD(ICMD_LLOAD, opcode - JAVA_LLOAD_0, TYPE_LNG); break; case JAVA_FLOAD_0: case JAVA_FLOAD_1: case JAVA_FLOAD_2: case JAVA_FLOAD_3: - OP1LOAD_ONEWORD(ICMD_FLOAD, opcode - JAVA_FLOAD_0); + OP_LOAD_ONEWORD(ICMD_FLOAD, opcode - JAVA_FLOAD_0, TYPE_FLT); break; case JAVA_DLOAD_0: case JAVA_DLOAD_1: case JAVA_DLOAD_2: case JAVA_DLOAD_3: - OP1LOAD_TWOWORD(ICMD_DLOAD, opcode - JAVA_DLOAD_0); + OP_LOAD_TWOWORD(ICMD_DLOAD, opcode - JAVA_DLOAD_0, TYPE_DBL); break; case JAVA_ALOAD_0: case JAVA_ALOAD_1: case JAVA_ALOAD_2: case JAVA_ALOAD_3: - OP1LOAD_ONEWORD(ICMD_ALOAD, opcode - JAVA_ALOAD_0); + OP_LOAD_ONEWORD(ICMD_ALOAD, opcode - JAVA_ALOAD_0, TYPE_ADR); break; - /* storing stack values into local variables */ - case JAVA_ISTORE: case JAVA_FSTORE: case JAVA_ASTORE: - if (!iswide) { - i = code_get_u1(p + 1,m); - } + if (iswide == false) { + i = SUCK_BE_U1(m->jcode + p + 1); + } else { - i = code_get_u2(p + 1,m); + i = SUCK_BE_U2(m->jcode + p + 1); iswide = false; nextp = p + 3; } - OP1STORE_ONEWORD(opcode, i); + OP_STORE_ONEWORD(opcode, i, opcode - JAVA_ISTORE); break; case JAVA_LSTORE: case JAVA_DSTORE: - if (!iswide) { - i = code_get_u1(p + 1,m); - } + if (iswide == false) { + i = SUCK_BE_U1(m->jcode + p + 1); + } else { - i = code_get_u2(p + 1,m); + i = SUCK_BE_U2(m->jcode + p + 1); iswide = false; nextp = p + 3; } - OP1STORE_TWOWORD(opcode, i); + OP_STORE_TWOWORD(opcode, i, opcode - JAVA_ISTORE); break; case JAVA_ISTORE_0: case JAVA_ISTORE_1: case JAVA_ISTORE_2: case JAVA_ISTORE_3: - OP1STORE_ONEWORD(ICMD_ISTORE, opcode - JAVA_ISTORE_0); + OP_STORE_ONEWORD(ICMD_ISTORE, opcode - JAVA_ISTORE_0, TYPE_INT); break; case JAVA_LSTORE_0: case JAVA_LSTORE_1: case JAVA_LSTORE_2: case JAVA_LSTORE_3: - OP1STORE_TWOWORD(ICMD_LSTORE, opcode - JAVA_LSTORE_0); + OP_STORE_TWOWORD(ICMD_LSTORE, opcode - JAVA_LSTORE_0, TYPE_LNG); break; case JAVA_FSTORE_0: case JAVA_FSTORE_1: case JAVA_FSTORE_2: case JAVA_FSTORE_3: - OP1STORE_ONEWORD(ICMD_FSTORE, opcode - JAVA_FSTORE_0); + OP_STORE_ONEWORD(ICMD_FSTORE, opcode - JAVA_FSTORE_0, TYPE_FLT); break; case JAVA_DSTORE_0: case JAVA_DSTORE_1: case JAVA_DSTORE_2: case JAVA_DSTORE_3: - OP1STORE_TWOWORD(ICMD_DSTORE, opcode - JAVA_DSTORE_0); + OP_STORE_TWOWORD(ICMD_DSTORE, opcode - JAVA_DSTORE_0, TYPE_DBL); break; case JAVA_ASTORE_0: case JAVA_ASTORE_1: case JAVA_ASTORE_2: case JAVA_ASTORE_3: - OP1STORE_ONEWORD(ICMD_ASTORE, opcode - JAVA_ASTORE_0); + OP_STORE_ONEWORD(ICMD_ASTORE, opcode - JAVA_ASTORE_0, TYPE_ADR); break; case JAVA_IINC: { int v; - - if (!iswide) { - i = code_get_u1(p + 1,m); - v = code_get_s1(p + 2,m); - } + if (iswide == false) { + i = SUCK_BE_U1(m->jcode + p + 1); + v = SUCK_BE_S1(m->jcode + p + 2); + + } else { - i = code_get_u2(p + 1,m); - v = code_get_s2(p + 3,m); + i = SUCK_BE_U2(m->jcode + p + 1); + v = SUCK_BE_S2(m->jcode + p + 3); iswide = false; nextp = p + 5; } INDEX_ONEWORD(i); - OP2I(opcode, i, v); + LOCALTYPE_USED(i, TYPE_INT); + OP_LOCALINDEX_I(opcode, i, v); } break; - /* wider index for loading, storing and incrementing */ + /* wider index for loading, storing and incrementing ******************/ case JAVA_WIDE: iswide = true; @@ -1774,7 +796,7 @@ fetch_opcode: /* managing arrays ****************************************************/ case JAVA_NEWARRAY: - switch (code_get_s1(p + 1, m)) { + switch (SUCK_BE_S1(m->jcode + p + 1)) { case 4: bte = builtintable_get_internal(BUILTIN_newarray_boolean); break; @@ -1801,16 +823,15 @@ fetch_opcode: break; #if defined(ENABLE_VERIFIER) default: - *exceptionptr = new_verifyerror(m, - "Invalid array-type to create"); + exceptions_throw_verifyerror(m, "Invalid array-type to create"); return false; #endif } - BUILTIN(bte, true, NULL, currentline); + OP_BUILTIN_CHECK_EXCEPTION(bte); break; case JAVA_ANEWARRAY: - i = code_get_u2(p + 1, m); + i = SUCK_BE_U2(m->jcode + p + 1); compr = (constant_classref *) class_getconstant(m->class, i, CONSTANT_Class); if (!compr) return false; @@ -1821,29 +842,32 @@ fetch_opcode: if (!resolve_classref(m, cr, resolveLazy, true, true, &c)) return false; - LOADCONST_A_BUILTIN(c, cr); + INSTRUCTIONS_CHECK(2); + OP_LOADCONST_CLASSINFO_OR_CLASSREF_NOCHECK(c, cr); bte = builtintable_get_internal(BUILTIN_newarray); - BUILTIN(bte, true, NULL, currentline); + OP_BUILTIN_CHECK_EXCEPTION(bte); s_count++; break; case JAVA_MULTIANEWARRAY: - m->isleafmethod = false; - i = code_get_u2(p + 1, m); - { - s4 v = code_get_u1(p + 3, m); - - cr = (constant_classref *) class_getconstant(m->class, i, CONSTANT_Class); - if (!cr) - return false; - - if (!resolve_classref(m, cr, resolveLazy, true, true, &c)) - return false; - - /* if unresolved, c == NULL */ - OP2AT(opcode, v, c, cr, currentline); - } - break; + jd->isleafmethod = false; + i = SUCK_BE_U2(m->jcode + p + 1); + j = SUCK_BE_U1(m->jcode + p + 3); + + cr = (constant_classref *) class_getconstant(m->class, i, CONSTANT_Class); + if (cr == NULL) + return false; + + if (!resolve_classref(m, cr, resolveLazy, true, true, &c)) + return false; + + /* if unresolved, c == NULL */ + + iptr->s1.argcount = j; + OP_S3_CLASSINFO_OR_CLASSREF(opcode, c, cr, 0 /* flags */); + break; + + /* control flow instructions ******************************************/ case JAVA_IFEQ: case JAVA_IFLT: @@ -1862,35 +886,48 @@ fetch_opcode: case JAVA_IF_ACMPEQ: case JAVA_IF_ACMPNE: case JAVA_GOTO: - case JAVA_JSR: - i = p + code_get_s2(p + 1,m); + i = p + SUCK_BE_S2(m->jcode + p + 1); CHECK_BYTECODE_INDEX(i); - block_insert(i); + MARK_BASICBLOCK(i); blockend = true; - OP1(opcode, i); + OP_INSINDEX(opcode, i); break; case JAVA_GOTO_W: - case JAVA_JSR_W: - i = p + code_get_s4(p + 1,m); + i = p + SUCK_BE_S4(m->jcode + p + 1); + CHECK_BYTECODE_INDEX(i); + MARK_BASICBLOCK(i); + blockend = true; + OP_INSINDEX(opcode, i); + break; + + case JAVA_JSR: + i = p + SUCK_BE_S2(m->jcode + p + 1); +jsr_tail: CHECK_BYTECODE_INDEX(i); - block_insert(i); + MARK_BASICBLOCK(i); blockend = true; - OP1(opcode, i); + OP_PREPARE_ZEROFLAGS(JAVA_JSR); + iptr->sx.s23.s3.jsrtarget.insindex = i; + PINC; break; + case JAVA_JSR_W: + i = p + SUCK_BE_S4(m->jcode + p + 1); + goto jsr_tail; + case JAVA_RET: - if (!iswide) { - i = code_get_u1(p + 1,m); - } + if (iswide == false) { + i = SUCK_BE_U1(m->jcode + p + 1); + } else { - i = code_get_u2(p + 1,m); + i = SUCK_BE_U2(m->jcode + p + 1); nextp = p + 3; iswide = false; } blockend = true; - - OP1LOAD_ONEWORD(opcode, i); + + OP_LOAD_ONEWORD(opcode, i, TYPE_ADR); break; case JAVA_IRETURN: @@ -1900,86 +937,84 @@ fetch_opcode: case JAVA_ARETURN: case JAVA_RETURN: blockend = true; - /* zero val.a so no patcher is inserted */ - /* the type checker may set this later */ - iptr->val.a = NULL; + /* XXX ARETURN will need a flag in the typechecker */ OP(opcode); break; case JAVA_ATHROW: blockend = true; - /* zero val.a so no patcher is inserted */ - /* the type checker may set this later */ - iptr->val.a = NULL; + /* XXX ATHROW will need a flag in the typechecker */ OP(opcode); break; - + /* table jumps ********************************************************/ case JAVA_LOOKUPSWITCH: { s4 num, j; - s4 *tablep; + lookup_target_t *lookup; #if defined(ENABLE_VERIFIER) s4 prevvalue = 0; #endif - blockend = true; - nextp = ALIGN((p + 1), 4); + nextp = MEMORY_ALIGN((p + 1), 4); CHECK_END_OF_BYTECODE(nextp + 8); - tablep = (s4 *) (m->jcode + nextp); - - OP2A(opcode, 0, tablep, currentline); + OP_PREPARE_ZEROFLAGS(opcode); /* default target */ - j = p + code_get_s4(nextp, m); - *tablep = j; /* restore for little endian */ - tablep++; + j = p + SUCK_BE_S4(m->jcode + nextp); + iptr->sx.s23.s3.lookupdefault.insindex = j; nextp += 4; CHECK_BYTECODE_INDEX(j); - block_insert(j); + MARK_BASICBLOCK(j); /* number of pairs */ - num = code_get_u4(nextp, m); - *tablep = num; - tablep++; + num = SUCK_BE_U4(m->jcode + nextp); + iptr->sx.s23.s2.lookupcount = num; nextp += 4; + /* allocate the intermediate code table */ + + lookup = DMNEW(lookup_target_t, num); + iptr->dst.lookup = lookup; + + /* iterate over the lookup table */ + CHECK_END_OF_BYTECODE(nextp + 8 * num); for (i = 0; i < num; i++) { /* value */ - j = code_get_s4(nextp, m); - *tablep = j; /* restore for little endian */ - tablep++; + j = SUCK_BE_S4(m->jcode + nextp); + lookup->value = j; + nextp += 4; #if defined(ENABLE_VERIFIER) /* check if the lookup table is sorted correctly */ - + if (i && (j <= prevvalue)) { - *exceptionptr = new_verifyerror(m, "Unsorted lookup switch"); + exceptions_throw_verifyerror(m, "Unsorted lookup switch"); return false; } prevvalue = j; #endif - /* target */ - j = p + code_get_s4(nextp,m); - *tablep = j; /* restore for little endian */ - tablep++; + j = p + SUCK_BE_S4(m->jcode + nextp); + lookup->target.insindex = j; + lookup++; nextp += 4; CHECK_BYTECODE_INDEX(j); - block_insert(j); + MARK_BASICBLOCK(j); } + PINC; break; } @@ -1987,61 +1022,66 @@ fetch_opcode: case JAVA_TABLESWITCH: { s4 num, j; - s4 *tablep; + s4 deftarget; + branch_target_t *table; blockend = true; - nextp = ALIGN((p + 1), 4); + nextp = MEMORY_ALIGN((p + 1), 4); CHECK_END_OF_BYTECODE(nextp + 12); - tablep = (s4 *) (m->jcode + nextp); - - OP2A(opcode, 0, tablep, currentline); + OP_PREPARE_ZEROFLAGS(opcode); /* default target */ - j = p + code_get_s4(nextp, m); - *tablep = j; /* restore for little endian */ - tablep++; + deftarget = p + SUCK_BE_S4(m->jcode + nextp); nextp += 4; - CHECK_BYTECODE_INDEX(j); - block_insert(j); + CHECK_BYTECODE_INDEX(deftarget); + MARK_BASICBLOCK(deftarget); /* lower bound */ - j = code_get_s4(nextp, m); - *tablep = j; /* restore for little endian */ - tablep++; + j = SUCK_BE_S4(m->jcode + nextp); + iptr->sx.s23.s2.tablelow = j; nextp += 4; /* upper bound */ - num = code_get_s4(nextp, m); - *tablep = num; /* restore for little endian */ - tablep++; + num = SUCK_BE_S4(m->jcode + nextp); + iptr->sx.s23.s3.tablehigh = num; nextp += 4; - num -= j; /* difference of upper - lower */ + /* calculate the number of table entries */ + + num = num - j + 1; #if defined(ENABLE_VERIFIER) - if (num < 0) { - *exceptionptr = new_verifyerror(m, + if (num < 1) { + exceptions_throw_verifyerror(m, "invalid TABLESWITCH: upper bound < lower bound"); return false; } #endif + /* create the intermediate code table */ + /* the first entry is the default target */ - CHECK_END_OF_BYTECODE(nextp + 4 * (num + 1)); + table = DMNEW(branch_target_t, 1 + num); + iptr->dst.table = table; + (table++)->insindex = deftarget; - for (i = 0; i <= num; i++) { - j = p + code_get_s4(nextp,m); - *tablep = j; /* restore for little endian */ - tablep++; + /* iterate over the target table */ + + CHECK_END_OF_BYTECODE(nextp + 4 * num); + + for (i = 0; i < num; i++) { + j = p + SUCK_BE_S4(m->jcode + nextp); + (table++)->insindex = j; nextp += 4; CHECK_BYTECODE_INDEX(j); - block_insert(j); + MARK_BASICBLOCK(j); } + PINC; break; } @@ -2050,7 +1090,7 @@ fetch_opcode: case JAVA_AASTORE: OP(opcode); - m->isleafmethod = false; + jd->isleafmethod = false; break; case JAVA_GETSTATIC: @@ -2061,175 +1101,172 @@ fetch_opcode: constant_FMIref *fr; unresolved_field *uf; - i = code_get_u2(p + 1, m); - fr = class_getconstant(m->class, i, - CONSTANT_Fieldref); + i = SUCK_BE_U2(m->jcode + p + 1); + fr = class_getconstant(m->class, i, CONSTANT_Fieldref); if (!fr) return false; - OP2A_NOINC(opcode, fr->parseddesc.fd->type, fr, currentline); + OP_PREPARE_ZEROFLAGS(opcode); + iptr->sx.s23.s3.fmiref = fr; /* only with -noverify, otherwise the typechecker does this */ #if defined(ENABLE_VERIFIER) - if (!opt_verify) { + if (!JITDATA_HAS_FLAG_VERIFY(jd)) { #endif - result = resolve_field_lazy(iptr,NULL,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) + if (uf == NULL) return false; /* store the unresolved_field pointer */ - /* XXX this will be changed */ - iptr->val.a = uf; - iptr->target = (void*) 0x01; /* XXX target temporarily used as flag */ - } - else { - iptr->target = NULL; + iptr->sx.s23.s3.uf = uf; + iptr->flags.bits |= INS_FLAG_UNRESOLVED; } #if defined(ENABLE_VERIFIER) } - else { - iptr->target = NULL; - } #endif PINC; } break; - + /* method invocation **************************************************/ case JAVA_INVOKESTATIC: - i = code_get_u2(p + 1, m); - mr = class_getconstant(m->class, i, - CONSTANT_Methodref); - if (!mr) + i = SUCK_BE_U2(m->jcode + p + 1); + mr = class_getconstant(m->class, i, CONSTANT_Methodref); + + if (mr == NULL) return false; md = mr->parseddesc.md; - if (!md->params) + if (md->params == NULL) if (!descriptor_params_from_paramtypes(md, ACC_STATIC)) return false; goto invoke_method; case JAVA_INVOKEINTERFACE: - i = code_get_u2(p + 1, m); - - mr = class_getconstant(m->class, i, - CONSTANT_InterfaceMethodref); + i = SUCK_BE_U2(m->jcode + p + 1); + + mr = class_getconstant(m->class, i, CONSTANT_InterfaceMethodref); goto invoke_nonstatic_method; case JAVA_INVOKESPECIAL: case JAVA_INVOKEVIRTUAL: - i = code_get_u2(p + 1, m); - mr = class_getconstant(m->class, i, - CONSTANT_Methodref); + i = SUCK_BE_U2(m->jcode + p + 1); + mr = class_getconstant(m->class, i, CONSTANT_Methodref); invoke_nonstatic_method: - if (!mr) + if (mr == NULL) return false; md = mr->parseddesc.md; - if (!md->params) + if (md->params == NULL) if (!descriptor_params_from_paramtypes(md, 0)) return false; invoke_method: - m->isleafmethod = false; + jd->isleafmethod = false; - OP2A_NOINC(opcode, 0, mr, currentline); + OP_PREPARE_ZEROFLAGS(opcode); + iptr->sx.s23.s3.fmiref = mr; /* only with -noverify, otherwise the typechecker does this */ #if defined(ENABLE_VERIFIER) - if (!opt_verify) { + if (!JITDATA_HAS_FLAG_VERIFY(jd)) { #endif - result = resolve_method_lazy(iptr,NULL,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 */ - /* XXX this will be changed */ - iptr->val.a = um; - iptr->target = (void*) 0x01; /* XXX target temporarily used as flag */ - } - else { - /* the method could be resolved */ - iptr->target = NULL; + iptr->sx.s23.s3.um = um; + iptr->flags.bits |= INS_FLAG_UNRESOLVED; } #if defined(ENABLE_VERIFIER) } - else { - iptr->target = NULL; - } #endif PINC; break; - /* miscellaneous object operations ************************************/ + /* instructions taking class arguments ********************************/ case JAVA_NEW: - i = code_get_u2(p + 1, m); + i = SUCK_BE_U2(m->jcode + p + 1); cr = (constant_classref *) class_getconstant(m->class, i, CONSTANT_Class); if (!cr) return false; - if (!resolve_classref(m, cr, resolveLazy, true, true, - &c)) + if (!resolve_classref(m, cr, resolveLazy, true, true, &c)) return false; - LOADCONST_A_BUILTIN(c, cr); + INSTRUCTIONS_CHECK(2); + OP_LOADCONST_CLASSINFO_OR_CLASSREF_NOCHECK(c, cr); bte = builtintable_get_internal(BUILTIN_new); - BUILTIN(bte, true, NULL, currentline); + OP_BUILTIN_CHECK_EXCEPTION(bte); s_count++; break; case JAVA_CHECKCAST: - i = code_get_u2(p + 1, m); + i = SUCK_BE_U2(m->jcode + p + 1); cr = (constant_classref *) class_getconstant(m->class, i, CONSTANT_Class); - if (!cr) + if (cr == NULL) return false; - if (!resolve_classref(m, cr, resolveLazy, true, - true, &c)) + if (!resolve_classref(m, cr, resolveLazy, true, true, &c)) return false; if (cr->name->text[0] == '[') { /* array type cast-check */ - OP2AT(opcode, 0, c, cr, currentline); - m->isleafmethod = false; - - } + flags = INS_FLAG_CHECK | INS_FLAG_ARRAY; + jd->isleafmethod = false; + } else { /* object type cast-check */ - OP2AT(opcode, 1, c, cr, currentline); + flags = INS_FLAG_CHECK; } + OP_S3_CLASSINFO_OR_CLASSREF(opcode, c, cr, flags); break; case JAVA_INSTANCEOF: - i = code_get_u2(p + 1,m); + i = SUCK_BE_U2(m->jcode + p + 1); cr = (constant_classref *) class_getconstant(m->class, i, CONSTANT_Class); - if (!cr) + if (cr == NULL) return false; if (!resolve_classref(m, cr, resolveLazy, true, true, &c)) @@ -2237,85 +1274,99 @@ invoke_method: if (cr->name->text[0] == '[') { /* array type cast-check */ - LOADCONST_A_BUILTIN(c, cr); + INSTRUCTIONS_CHECK(2); + OP_LOADCONST_CLASSINFO_OR_CLASSREF_NOCHECK(c, cr); bte = builtintable_get_internal(BUILTIN_arrayinstanceof); - BUILTIN(bte, false, NULL, currentline); + OP_BUILTIN_NO_EXCEPTION(bte); s_count++; - - } + } else { /* object type cast-check */ - OP2AT(opcode, 1, c, cr, currentline); + OP_S3_CLASSINFO_OR_CLASSREF(opcode, c, cr, 0 /* flags*/); } break; + /* synchronization instructions ***************************************/ + case JAVA_MONITORENTER: #if defined(ENABLE_THREADS) if (checksync) { - OP(ICMD_CHECKNULL); - bte = builtintable_get_internal(BUILTIN_monitorenter); - BUILTIN(bte, false, NULL, currentline); - } + bte = builtintable_get_internal(LOCK_monitor_enter); + OP_BUILTIN_CHECK_EXCEPTION(bte); + } else #endif - { - OP(ICMD_CHECKNULL); - OP(ICMD_POP); - } + { + OP_CHECK_EXCEPTION(ICMD_CHECKNULL); + OP(ICMD_POP); + } break; case JAVA_MONITOREXIT: #if defined(ENABLE_THREADS) if (checksync) { - bte = builtintable_get_internal(BUILTIN_monitorexit); - BUILTIN(bte, false, NULL, currentline); - } + bte = builtintable_get_internal(LOCK_monitor_exit); + OP_BUILTIN_CHECK_EXCEPTION(bte); + } else #endif - { - OP(ICMD_POP); - } + { + OP_CHECK_EXCEPTION(ICMD_CHECKNULL); + OP(ICMD_POP); + } break; - /* any other basic operation ******************************************/ + /* arithmetic instructions that may become builtin functions **********/ case JAVA_IDIV: #if !SUPPORT_DIVISION bte = builtintable_get_internal(BUILTIN_idiv); - OP2A(opcode, bte->md->paramcount, bte, currentline); - m->isleafmethod = false; + OP_BUILTIN_ARITHMETIC(opcode, bte); #else +# if SUPPORT_HARDWARE_DIVIDE_BY_ZERO OP(opcode); +# else + OP_CHECK_EXCEPTION(opcode); +# endif #endif break; case JAVA_IREM: #if !SUPPORT_DIVISION bte = builtintable_get_internal(BUILTIN_irem); - OP2A(opcode, bte->md->paramcount, bte, currentline); - m->isleafmethod = false; + OP_BUILTIN_ARITHMETIC(opcode, bte); #else +# if SUPPORT_HARDWARE_DIVIDE_BY_ZERO OP(opcode); +# else + OP_CHECK_EXCEPTION(opcode); +# endif #endif break; case JAVA_LDIV: #if !(SUPPORT_DIVISION && SUPPORT_LONG && SUPPORT_LONG_DIV) bte = builtintable_get_internal(BUILTIN_ldiv); - OP2A(opcode, bte->md->paramcount, bte, currentline); - m->isleafmethod = false; + OP_BUILTIN_ARITHMETIC(opcode, bte); #else +# if SUPPORT_HARDWARE_DIVIDE_BY_ZERO OP(opcode); +# else + OP_CHECK_EXCEPTION(opcode); +# endif #endif break; case JAVA_LREM: #if !(SUPPORT_DIVISION && SUPPORT_LONG && SUPPORT_LONG_DIV) bte = builtintable_get_internal(BUILTIN_lrem); - OP2A(opcode, bte->md->paramcount, bte, currentline); - m->isleafmethod = false; + OP_BUILTIN_ARITHMETIC(opcode, bte); #else +# if SUPPORT_HARDWARE_DIVIDE_BY_ZERO OP(opcode); +# else + OP_CHECK_EXCEPTION(opcode); +# endif #endif break; @@ -2324,7 +1375,7 @@ invoke_method: OP(opcode); #else bte = builtintable_get_internal(BUILTIN_frem); - BUILTIN(bte, false, NULL, currentline); + OP_BUILTIN_NO_EXCEPTION(bte); #endif break; @@ -2333,7 +1384,7 @@ invoke_method: OP(opcode); #else bte = builtintable_get_internal(BUILTIN_drem); - BUILTIN(bte, false, NULL, currentline); + OP_BUILTIN_NO_EXCEPTION(bte); #endif break; @@ -2341,59 +1392,60 @@ invoke_method: #if defined(__ALPHA__) if (!opt_noieee) { bte = builtintable_get_internal(BUILTIN_f2i); - BUILTIN(bte, false, NULL, currentline); - } + OP_BUILTIN_NO_EXCEPTION(bte); + } else #endif - { - OP(opcode); - } + { + OP(opcode); + } break; case JAVA_F2L: #if defined(__ALPHA__) if (!opt_noieee) { bte = builtintable_get_internal(BUILTIN_f2l); - BUILTIN(bte, false, NULL, currentline); - } - else + OP_BUILTIN_NO_EXCEPTION(bte); + } + else #endif - { - OP(opcode); - } + { + OP(opcode); + } break; case JAVA_D2I: #if defined(__ALPHA__) if (!opt_noieee) { bte = builtintable_get_internal(BUILTIN_d2i); - BUILTIN(bte, false, NULL, currentline); - } + OP_BUILTIN_NO_EXCEPTION(bte); + } else #endif - { - OP(opcode); - } + { + OP(opcode); + } break; case JAVA_D2L: #if defined(__ALPHA__) if (!opt_noieee) { bte = builtintable_get_internal(BUILTIN_d2l); - BUILTIN(bte, false, NULL, currentline); - } + OP_BUILTIN_NO_EXCEPTION(bte); + } else #endif - { - OP(opcode); - } + { + OP(opcode); + } break; + /* invalid opcodes ****************************************************/ + /* check for invalid opcodes if the verifier is enabled */ #if defined(ENABLE_VERIFIER) case JAVA_BREAKPOINT: - *exceptionptr = - new_verifyerror(m, "Quick instructions shouldn't appear yet."); + exceptions_throw_verifyerror(m, "Quick instructions shouldn't appear, yet."); return false; case 186: /* unused opcode */ @@ -2450,24 +1502,27 @@ invoke_method: case 253: case 254: case 255: - *exceptionptr = - new_verifyerror(m,"Illegal opcode %d at instr %d\n", - opcode, ipc); + exceptions_throw_verifyerror(m, "Illegal opcode %d at instr %d\n", + opcode, ipc); return false; break; #endif /* defined(ENABLE_VERIFIER) */ + /* opcodes that don't require translation *****************************/ + default: /* straight-forward translation to ICMD */ OP(opcode); break; - + } /* end switch */ + /* verifier checks ****************************************************/ + #if defined(ENABLE_VERIFIER) /* If WIDE was used correctly, iswide should have been reset by now. */ if (iswide) { - *exceptionptr = new_verifyerror(m, + exceptions_throw_verifyerror(m, "Illegal instruction: WIDE before incompatible opcode"); return false; } @@ -2475,156 +1530,209 @@ invoke_method: } /* end for */ + if (JITDATA_HAS_FLAG_REORDER(jd)) { + /* add a NOP to the last basic block */ + + INSTRUCTIONS_CHECK(1); + OP(ICMD_NOP); + } + + /*** END OF LOOP **********************************************************/ + + /* assert that we did not write more ICMDs than allocated */ + + assert(ipc <= pd.instructionslength); + assert(ipc == (iptr - pd.instructions)); + + /*** verifier checks ******************************************************/ + #if defined(ENABLE_VERIFIER) if (p != m->jcodelength) { - *exceptionptr = new_verifyerror(m, + exceptions_throw_verifyerror(m, "Command-sequence crosses code-boundary"); return false; } if (!blockend) { - *exceptionptr = new_verifyerror(m, "Falling off the end of the code"); + exceptions_throw_verifyerror(m, "Falling off the end of the code"); return false; } #endif /* defined(ENABLE_VERIFIER) */ + /*** setup the methodinfo, allocate stack and basic blocks ****************/ + /* adjust block count if target 0 is not first intermediate instruction */ - if (!m->basicblockindex[0] || (m->basicblockindex[0] > 1)) + if (!jd->basicblockindex[0] || (jd->basicblockindex[0] > 1)) b_count++; + else + jd->branchtoentry = true; /* copy local to method variables */ - m->instructioncount = ipc; - m->basicblockcount = b_count; - m->stackcount = s_count + m->basicblockcount * m->maxstack; + jd->instructions = pd.instructions; + jd->instructioncount = ipc; + jd->basicblockcount = b_count; + jd->stackcount = s_count + jd->basicblockcount * m->maxstack; /* in-stacks */ /* allocate stack table */ - m->stack = DMNEW(stackelement, m->stackcount); + jd->stack = DMNEW(stackelement, jd->stackcount); - { - basicblock *bptr; + /* build basic block list */ - bptr = m->basicblocks = DMNEW(basicblock, b_count + 1); /* one more for end ipc */ + bptr = jd->basicblocks = DMNEW(basicblock, b_count + 1); /* one more for end ipc */ - b_count = 0; - m->c_debug_nr = 0; - - /* additional block if target 0 is not first intermediate instruction */ + /* zero out all basic block structures */ - if (!m->basicblockindex[0] || (m->basicblockindex[0] > 1)) { - BASICBLOCK_INIT(bptr,m); + MZERO(bptr, basicblock, b_count + 1); - bptr->iinstr = m->instructions; - /* bptr->icount is set when the next block is allocated */ + b_count = 0; - bptr++; - b_count++; - bptr[-1].next = bptr; - } + /* additional block if target 0 is not first intermediate instruction */ - /* allocate blocks */ + if (!jd->basicblockindex[0] || (jd->basicblockindex[0] > 1)) { + BASICBLOCK_INIT(bptr, m); - for (p = 0; p < m->jcodelength; p++) { - if (m->basicblockindex[p] & 1) { - /* Check if this block starts at the beginning of an */ - /* instruction. */ + bptr->iinstr = jd->instructions; + /* bptr->icount is set when the next block is allocated */ + + bptr->nr = b_count++; + bptr++; + bptr[-1].next = bptr; + } + + /* allocate blocks */ + + for (p = 0; p < m->jcodelength; p++) { + if (jd->basicblockindex[p] & 1) { #if defined(ENABLE_VERIFIER) - if (!instructionstart[p]) { - *exceptionptr = new_verifyerror(m, + /* Check if this block starts at the beginning of an + instruction. */ + + if (!pd.instructionstart[p]) { + exceptions_throw_verifyerror(m, "Branch into middle of instruction"); - return false; - } + return false; + } #endif - /* allocate the block */ + /* allocate the block */ - BASICBLOCK_INIT(bptr,m); + BASICBLOCK_INIT(bptr, m); - bptr->iinstr = m->instructions + (m->basicblockindex[p] >> 1); - if (b_count) { - bptr[-1].icount = bptr->iinstr - bptr[-1].iinstr; - } - /* bptr->icount is set when the next block is allocated */ + bptr->iinstr = jd->instructions + (jd->basicblockindex[p] >> 1); + if (b_count) { + bptr[-1].icount = bptr->iinstr - bptr[-1].iinstr; + } + /* bptr->icount is set when the next block is allocated */ - m->basicblockindex[p] = b_count; + jd->basicblockindex[p] = b_count; - bptr++; - b_count++; - bptr[-1].next = bptr; - } + bptr->nr = b_count++; + bptr++; + bptr[-1].next = bptr; } + } - /* set instruction count of last real block */ + /* set instruction count of last real block */ - if (b_count) { - bptr[-1].icount = (m->instructions + m->instructioncount) - bptr[-1].iinstr; - } + if (b_count) { + bptr[-1].icount = (jd->instructions + jd->instructioncount) - bptr[-1].iinstr; + } - /* allocate additional block at end */ + /* allocate additional block at end */ - BASICBLOCK_INIT(bptr,m); - - bptr->instack = bptr->outstack = NULL; - bptr->indepth = bptr->outdepth = 0; - bptr->iinstr = NULL; - bptr->icount = 0; - bptr->next = NULL; + BASICBLOCK_INIT(bptr,m); + bptr->nr = b_count; + jd->basicblockindex[m->jcodelength] = b_count; + + /* set basicblock pointers in exception table */ + + if (!parse_resolve_exception_table(jd)) + return false; + + /* store the local map */ + + jd->local_map = local_map; - /* set basicblock pointers in exception table */ + /* calculate local variable renaming */ - if (cd->exceptiontablelength > 0) { - cd->exceptiontable[cd->exceptiontablelength - 1].down = NULL; + { + s4 nlocals = 0; + s4 i; + + s4 *mapptr; + + mapptr = 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 < (m->maxlocals * 5); i++, mapptr++) { + if (*mapptr) + *mapptr = nlocals++; + else + *mapptr = UNUSED; } - - for (i = 0; i < cd->exceptiontablelength; ++i) { - p = cd->exceptiontable[i].startpc; - cd->exceptiontable[i].start = m->basicblocks + m->basicblockindex[p]; - p = cd->exceptiontable[i].endpc; - cd->exceptiontable[i].end = (p == m->jcodelength) ? (m->basicblocks + m->basicblockcount /*+ 1*/) : (m->basicblocks + m->basicblockindex[p]); + jd->localcount = nlocals; + + /* calculate the (maximum) number of variables needed */ + + jd->varcount = + nlocals /* local variables */ + + jd->basicblockcount * m->maxstack /* invars */ + + s_count; /* variables created within blocks (non-invar) */ - p = cd->exceptiontable[i].handlerpc; - cd->exceptiontable[i].handler = m->basicblocks + m->basicblockindex[p]; - } + /* reserve the first indices for local variables */ - /* 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 = m->basicblocks + m->basicblockindex[p]; + jd->vartop = nlocals; - p = m->exceptiontable[i].endpc; - m->exceptiontable[i].end = (p == m->jcodelength) ? (m->basicblocks + m->basicblockcount /*+ 1*/) : (m->basicblocks + m->basicblockindex[p]); + /* reserve extra variables needed by stack analyse */ - p = m->exceptiontable[i].handlerpc; - m->exceptiontable[i].handler = m->basicblocks + m->basicblockindex[p]; - } + jd->varcount += STACK_EXTRA_VARS; + jd->vartop += STACK_EXTRA_VARS; + + /* The verifier needs space for saving invars in some cases and */ + /* extra variables. */ + +#if defined(ENABLE_VERIFIER) + 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 */ + + jd->var = DMNEW(varinfo, jd->varcount); + MZERO(jd->var, varinfo, jd->varcount); + /* set types of all locals in jd->var */ + + for(mapptr = local_map, i = 0; i < (m->maxlocals * 5); i++, mapptr++) + if (*mapptr != UNUSED) + VAR(*mapptr)->type = i%5; } /* everything's ok */ return true; + /*** goto labels for throwing verifier exceptions *************************/ + #if defined(ENABLE_VERIFIER) throw_unexpected_end_of_bytecode: - *exceptionptr = new_verifyerror(m, "Unexpected end of bytecode"); + exceptions_throw_verifyerror(m, "Unexpected end of bytecode"); return false; throw_invalid_bytecode_index: - *exceptionptr = - new_verifyerror(m, "Illegal target of branch instruction"); + exceptions_throw_verifyerror(m, "Illegal target of branch instruction"); return false; throw_illegal_local_variable_number: - *exceptionptr = - new_verifyerror(m, "Illegal local variable number"); + exceptions_throw_verifyerror(m, "Illegal local variable number"); return false; - + #endif /* ENABLE_VERIFIER */ }