X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=src%2Fvm%2Fjit%2Fparse.c;h=9a8e4e4cb99e0ae78203f079c29ec375a326fb9e;hb=d24a28c1e12a8f8ef7d2c660c5ba5d1d278c4ef8;hp=461c5e7381c3407f23e9a7e5c2c995416e718ae4;hpb=147723b8c69c648e6a83ce1fb394becccf1fc28c;p=cacao.git diff --git a/src/vm/jit/parse.c b/src/vm/jit/parse.c index 461c5e738..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 5497 2006-09-14 18:55:03Z edwin $ + $Id: parse.c 6173 2006-12-11 19:55:31Z twisti $ */ @@ -99,10 +98,10 @@ static void parse_setup(jitdata *jd, parsedata_t *pd) /* Allocate instruction array and block index table (1 additional for end ipc). */ - jd->new_basicblockindex = DMNEW(s4, m->jcodelength + 1); + jd->basicblockindex = DMNEW(s4, m->jcodelength + 1); pd->instructionstart = DMNEW(u1, m->jcodelength + 1); - MZERO(jd->new_basicblockindex, s4, m->jcodelength + 1); + MZERO(jd->basicblockindex, s4, m->jcodelength + 1); MZERO(pd->instructionstart, u1, m->jcodelength + 1); /* Set the length of the instruction array. We simply add 5 more @@ -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 * new_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; + + if (len == 0) + return 0; + + b_count = 0; + rex = m->rawexceptiontable; - b_count = *block_count; + 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) @@ -237,11 +333,9 @@ throw_invalid_bytecode_index: #define CHECK_END_OF_BYTECODE(neededlength) #endif /* ENABLE_VERIFIER */ -bool new_parse(jitdata *jd) +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 new_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 new_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 new_parse(jitdata *jd) iptr = pd.instructions; ipc = 0; - /* compute branch targets of exception table */ + /* mark basic block boundaries for exception table */ - if (!new_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 */ @@ -364,9 +448,18 @@ fetch_opcode: blockend = false; } + /* 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->new_basicblockindex[p] |= (ipc << 1); + jd->basicblockindex[p] |= (ipc << 1); /* compute next instruction start */ @@ -492,18 +585,21 @@ fetch_opcode: /* instructions to sequences of ICMD_COPY and ICMD_MOVE instructions. */ case JAVA_DUP_X1: - INSTRUCTIONS_CHECK(3); + INSTRUCTIONS_CHECK(4); OP(opcode); OP(ICMD_NOP); OP(ICMD_NOP); + OP(ICMD_NOP); break; case JAVA_DUP_X2: - INSTRUCTIONS_CHECK(4); + INSTRUCTIONS_CHECK(6); OP(opcode); OP(ICMD_NOP); OP(ICMD_NOP); OP(ICMD_NOP); + OP(ICMD_NOP); + OP(ICMD_NOP); break; case JAVA_DUP2: @@ -513,28 +609,34 @@ fetch_opcode: break; case JAVA_DUP2_X1: - INSTRUCTIONS_CHECK(5); + 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(6); + 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(2); + INSTRUCTIONS_CHECK(3); OP(opcode); OP(ICMD_NOP); + OP(ICMD_NOP); break; /* local variable access instructions *********************************/ @@ -856,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); @@ -924,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); @@ -963,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; @@ -1012,12 +1114,12 @@ jsr_tail: #if defined(ENABLE_VERIFIER) if (!JITDATA_HAS_FLAG_VERIFY(jd)) { #endif - result = new_resolve_field_lazy(jd, iptr, m); + result = resolve_field_lazy(m, fr); if (result == resolveFailed) return false; if (result != resolveSucceeded) { - uf = new_create_unresolved_field(m->class, m, iptr); + uf = resolve_create_unresolved_field(m->class, m, iptr); if (uf == NULL) return false; @@ -1025,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) } @@ -1085,12 +1187,28 @@ invoke_method: #if defined(ENABLE_VERIFIER) if (!JITDATA_HAS_FLAG_VERIFY(jd)) { #endif - result = new_resolve_method_lazy(jd, iptr, m); + result = resolve_method_lazy(m, mr, + (opcode == JAVA_INVOKESPECIAL)); if (result == resolveFailed) return false; - if (result != resolveSucceeded) { - um = new_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; @@ -1098,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) } @@ -1135,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; @@ -1179,7 +1297,8 @@ invoke_method: else #endif { - OP(ICMD_CHECKNULL_POP); + OP_CHECK_EXCEPTION(ICMD_CHECKNULL); + OP(ICMD_POP); } break; @@ -1192,7 +1311,8 @@ invoke_method: else #endif { - OP(ICMD_CHECKNULL_POP); + OP_CHECK_EXCEPTION(ICMD_CHECKNULL); + OP(ICMD_POP); } break; @@ -1203,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; @@ -1212,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; @@ -1221,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; @@ -1230,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; @@ -1394,10 +1530,12 @@ invoke_method: } /* end for */ - /* add a NOP to the last basic block */ + if (JITDATA_HAS_FLAG_REORDER(jd)) { + /* add a NOP to the last basic block */ - INSTRUCTIONS_CHECK(1); - OP(ICMD_NOP); + INSTRUCTIONS_CHECK(1); + OP(ICMD_NOP); + } /*** END OF LOOP **********************************************************/ @@ -1425,48 +1563,49 @@ invoke_method: /* adjust block count if target 0 is not first intermediate instruction */ - if (!jd->new_basicblockindex[0] || (jd->new_basicblockindex[0] > 1)) + if (!jd->basicblockindex[0] || (jd->basicblockindex[0] > 1)) b_count++; + else + jd->branchtoentry = true; /* copy local to method variables */ - jd->new_instructions = pd.instructions; - jd->new_instructioncount = ipc; - jd->new_basicblockcount = b_count; - jd->new_stackcount = s_count + jd->new_basicblockcount * m->maxstack; /* in-stacks */ + jd->instructions = pd.instructions; + jd->instructioncount = ipc; + jd->basicblockcount = b_count; + jd->stackcount = s_count + jd->basicblockcount * m->maxstack; /* in-stacks */ /* allocate stack table */ - jd->new_stack = DMNEW(stackelement, jd->new_stackcount); + jd->stack = DMNEW(stackelement, jd->stackcount); /* build basic block list */ - bptr = jd->new_basicblocks = DMNEW(basicblock, b_count + 1); /* one more for end ipc */ + bptr = jd->basicblocks = DMNEW(basicblock, b_count + 1); /* one more for end ipc */ /* zero out all basic block structures */ MZERO(bptr, basicblock, b_count + 1); b_count = 0; - jd->new_c_debug_nr = 0; /* additional block if target 0 is not first intermediate instruction */ - if (!jd->new_basicblockindex[0] || (jd->new_basicblockindex[0] > 1)) { + if (!jd->basicblockindex[0] || (jd->basicblockindex[0] > 1)) { BASICBLOCK_INIT(bptr, m); - bptr->iinstr = jd->new_instructions; + 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; } /* allocate blocks */ for (p = 0; p < m->jcodelength; p++) { - if (jd->new_basicblockindex[p] & 1) { + if (jd->basicblockindex[p] & 1) { #if defined(ENABLE_VERIFIER) /* Check if this block starts at the beginning of an instruction. */ @@ -1482,16 +1621,16 @@ invoke_method: BASICBLOCK_INIT(bptr, m); - bptr->iinstr = jd->new_instructions + (jd->new_basicblockindex[p] >> 1); + 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 */ - jd->new_basicblockindex[p] = b_count; + jd->basicblockindex[p] = b_count; + bptr->nr = b_count++; bptr++; - b_count++; bptr[-1].next = bptr; } } @@ -1499,43 +1638,21 @@ invoke_method: /* set instruction count of last real block */ if (b_count) { - bptr[-1].icount = (jd->new_instructions + jd->new_instructioncount) - bptr[-1].iinstr; + bptr[-1].icount = (jd->instructions + jd->instructioncount) - bptr[-1].iinstr; } /* 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->new_basicblocks + jd->new_basicblockindex[p]; - - p = cd->exceptiontable[i].endpc; - cd->exceptiontable[i].end = (p == m->jcodelength) ? (jd->new_basicblocks + jd->new_basicblockcount /*+ 1*/) : (jd->new_basicblocks + jd->new_basicblockindex[p]); - - p = cd->exceptiontable[i].handlerpc; - cd->exceptiontable[i].handler = jd->new_basicblocks + jd->new_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->new_basicblocks + jd->new_basicblockindex[p]; - - p = m->exceptiontable[i].endpc; - m->exceptiontable[i].end = (p == m->jcodelength) ? (jd->new_basicblocks + jd->new_basicblockcount /*+ 1*/) : (jd->new_basicblocks + jd->new_basicblockindex[p]); + if (!parse_resolve_exception_table(jd)) + return false; - p = m->exceptiontable[i].handlerpc; - m->exceptiontable[i].handler = jd->new_basicblocks + jd->new_basicblockindex[p]; - } -#endif + /* store the local map */ jd->local_map = local_map; @@ -1552,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 @@ -1565,21 +1682,24 @@ invoke_method: jd->varcount = nlocals /* local variables */ - + jd->new_basicblockcount * m->maxstack /* invars */ + + jd->basicblockcount * m->maxstack /* invars */ + s_count; /* variables created within blocks (non-invar) */ /* reserve the first indices for local variables */ jd->vartop = nlocals; + /* reserve extra variables needed by stack analyse */ + + 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) - 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 */ @@ -1588,9 +1708,9 @@ 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) - jd->var[*mapptr].type = i%5; + VAR(*mapptr)->type = i%5; } /* everything's ok */