Contact: cacao@cacaojvm.org
- Author: Andreas Krall
-
- Changes: Carolyn Oates
+ Authors: Andreas Krall
+ Carolyn Oates
Edwin Steiner
Joseph Wenninger
Christian Thalinger
- $Id: parse.c 5435 2006-09-08 18:14:50Z edwin $
+ $Id: parse.c 6173 2006-12-11 19:55:31Z twisti $
*/
/* 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
}
-/* parse_check_instructions ****************************************************
+/* parse_realloc_instructions **************************************************
+
+ Reallocate the instructions array so there is room for at least N
+ additional instructions.
- Checks if there's enough room in the instructions array for the
- required instructions. If not, reallocate the data structures.
+ RETURN VALUE:
+ the new value for iptr
*******************************************************************************/
-static instruction *parse_check_instructions(parsedata_t *pd, s4 ipc)
+static instruction *parse_realloc_instructions(parsedata_t *pd, s4 ipc, s4 n)
{
/* increase the size of the instruction array */
- pd->instructionslength += INSTRUCTIONS_INCREMENT;
+ pd->instructionslength += (n + INSTRUCTIONS_INCREMENT);
/* reallocate the array */
pd->instructions = DMREALLOC(pd->instructions, instruction, ipc,
pd->instructionslength);
+ MZERO(pd->instructions + ipc, instruction, (pd->instructionslength - ipc));
/* return the iptr */
}
-/*******************************************************************************
+/* parse_mark_exception_boundaries *********************************************
- function 'parse' scans the JavaVM code and generates intermediate code
+ Mark exception handlers and the boundaries of the handled regions as
+ basic block boundaries.
- During parsing the block index table is used to store at bit pos 0
- a flag which marks basic block starts and at position 1 to 31 the
- intermediate instruction index. After parsing the block index table
- is scanned, for marked positions a block is generated and the block
- number is stored in the block index table.
+ IN:
+ jd...............current jitdata
+
+ RETURN VALUE:
+ >= 0.............the number of new basic blocks marked
+ -1...............an exception has been thrown
*******************************************************************************/
-static exceptiontable * 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;
- b_count = *block_count;
+ if (len == 0)
+ return 0;
+
+ b_count = 0;
+ rex = m->rawexceptiontable;
+
+ for (i = 0; i < len; ++i, ++rex) {
- for (src = exceptiontablelength-1; src >=0; src--) {
/* the start of the handled region becomes a basic block start */
- p = raw_extable[src].startpc;
- CHECK_BYTECODE_INDEX(p);
- extable->startpc = p;
- MARK_BASICBLOCK(p);
+
+ pc = rex->startpc;
+ CHECK_BYTECODE_INDEX(pc);
+ MARK_BASICBLOCK(pc);
- p = raw_extable[src].endpc; /* see JVM Spec 4.7.3 */
- CHECK_BYTECODE_INDEX_EXCLUSIVE(p);
+ pc = rex->endpc; /* see JVM Spec 4.7.3 */
+ CHECK_BYTECODE_INDEX_EXCLUSIVE(pc);
+
+ /* check that the range is valid */
#if defined(ENABLE_VERIFIER)
- if (p <= raw_extable[src].startpc) {
+ if (pc <= rex->startpc) {
exceptions_throw_verifyerror(m,
"Invalid exception handler range");
- return NULL;
+ return -1;
}
#endif
- extable->endpc = p;
/* end of handled region becomes a basic block boundary */
/* (If it is the bytecode end, we'll use the special */
/* end block that is created anyway.) */
- if (p < m->jcodelength)
- MARK_BASICBLOCK(p);
+
+ if (pc < m->jcodelength)
+ MARK_BASICBLOCK(pc);
+ else
+ jd->branchtoend = true;
/* the start of the handler becomes a basic block start */
- p = raw_extable[src].handlerpc;
- CHECK_BYTECODE_INDEX(p);
- extable->handlerpc = p;
- MARK_BASICBLOCK(p);
-
- extable->catchtype = raw_extable[src].catchtype;
- extable->next = NULL;
- extable->down = &extable[1];
- extable--;
+
+ pc = rex->handlerpc;
+ CHECK_BYTECODE_INDEX(pc);
+ MARK_BASICBLOCK(pc);
}
- *block_count = b_count;
-
/* everything ok */
- return extable;
+
+ return b_count;
#if defined(ENABLE_VERIFIER)
throw_invalid_bytecode_index:
exceptions_throw_verifyerror(m,
"Illegal bytecode index in exception table");
- return NULL;
+ return -1;
#endif
}
+
+/* parse_resolve_exception_table ***********************************************
+
+ Enter the exception handlers and their ranges, resolved to basicblock *s,
+ in the jitdata.
+
+ IN:
+ jd...............current jitdata
+
+ RETURN VALUE:
+ true.............everything ok
+ false............an exception has been thrown
+
+*******************************************************************************/
+
+static bool parse_resolve_exception_table(jitdata *jd)
+{
+ methodinfo *m;
+ raw_exception_entry *rex;
+ exception_entry *ex;
+ s4 i;
+ s4 len;
+ classinfo *exclass;
+
+ m = jd->m;
+
+ len = m->rawexceptiontablelength;
+
+ /* common case: no handler entries */
+
+ if (len == 0)
+ return true;
+
+ /* allocate the exception table */
+
+ jd->exceptiontablelength = len;
+ jd->exceptiontable = DMNEW(exception_entry, len + 1); /* XXX why +1? */
+
+ /* copy and resolve the entries */
+
+ ex = jd->exceptiontable;
+ rex = m->rawexceptiontable;
+
+ for (i = 0; i < len; ++i, ++rex, ++ex) {
+ /* resolve instruction indices to basic blocks */
+
+ ex->start = BLOCK_OF(rex->startpc);
+ ex->end = BLOCK_OF(rex->endpc);
+ ex->handler = BLOCK_OF(rex->handlerpc);
+
+ /* lazily resolve the catchtype */
+
+ if (rex->catchtype.any != NULL) {
+ if (!resolve_classref_or_classinfo(m,
+ rex->catchtype,
+ resolveLazy, true, false,
+ &exclass))
+ return false;
+
+ /* if resolved, enter the result of resolution in the table */
+
+ if (exclass != NULL)
+ rex->catchtype.cls = exclass;
+ }
+
+ ex->catchtype = rex->catchtype;
+ ex->next = NULL; /* set by loop analysis */
+ ex->down = ex + 1; /* link to next exception entry */
+ }
+
+ /* terminate the ->down linked list */
+
+ assert(ex != jd->exceptiontable);
+ ex[-1].down = NULL;
+
+ return true;
+}
+
+
+/*******************************************************************************
+
+ function 'parse' scans the JavaVM code and generates intermediate code
+
+ During parsing the block index table is used to store at bit pos 0
+ a flag which marks basic block starts and at position 1 to 31 the
+ intermediate instruction index. After parsing the block index table
+ is scanned, for marked positions a block is generated and the block
+ number is stored in the block index table.
+
+*******************************************************************************/
+
/*** macro for checking the length of the bytecode ***/
#if defined(ENABLE_VERIFIER)
#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 */
s4 opcode; /* java opcode */
s4 i;
s4 j;
- int b_count = 0; /* basic block counter */
+ int b_count; /* basic block counter */
int s_count = 0; /* stack element counter */
bool blockend = false; /* true if basic block end has been reached */
bool iswide = false; /* true if last instruction was a wide */
/* get required compiler data */
m = jd->m;
- code = jd->code;
- cd = jd->cd;
/* allocate buffers for local variable renaming */
- local_map = DMNEW(int, cd->maxlocals * 5);
- for (i = 0; i < cd->maxlocals; i++) {
+ local_map = DMNEW(int, m->maxlocals * 5);
+ for (i = 0; i < m->maxlocals; i++) {
local_map[i * 5 + 0] = 0;
local_map[i * 5 + 1] = 0;
local_map[i * 5 + 2] = 0;
iptr = pd.instructions;
ipc = 0;
- /* compute branch targets of exception table */
+ /* mark basic block boundaries for exception table */
- if (!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 */
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 */
/* 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:
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 *********************************/
s4 prevvalue = 0;
#endif
blockend = true;
- nextp = ALIGN((p + 1), 4);
+ nextp = MEMORY_ALIGN((p + 1), 4);
CHECK_END_OF_BYTECODE(nextp + 8);
branch_target_t *table;
blockend = true;
- nextp = ALIGN((p + 1), 4);
+ nextp = MEMORY_ALIGN((p + 1), 4);
CHECK_END_OF_BYTECODE(nextp + 12);
/* create the intermediate code table */
/* the first entry is the default target */
- table = MNEW(branch_target_t, 1 + num);
+ table = DMNEW(branch_target_t, 1 + num);
iptr->dst.table = table;
(table++)->insindex = deftarget;
#if defined(ENABLE_VERIFIER)
if (!JITDATA_HAS_FLAG_VERIFY(jd)) {
#endif
- result = new_resolve_field_lazy(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;
/* store the unresolved_field pointer */
iptr->sx.s23.s3.uf = uf;
- iptr->flags.bits = INS_FLAG_UNRESOLVED;
+ iptr->flags.bits |= INS_FLAG_UNRESOLVED;
}
#if defined(ENABLE_VERIFIER)
}
#if defined(ENABLE_VERIFIER)
if (!JITDATA_HAS_FLAG_VERIFY(jd)) {
#endif
- result = new_resolve_method_lazy(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;
/* store the unresolved_method pointer */
iptr->sx.s23.s3.um = um;
- iptr->flags.bits = INS_FLAG_UNRESOLVED;
+ iptr->flags.bits |= INS_FLAG_UNRESOLVED;
}
#if defined(ENABLE_VERIFIER)
}
if (cr->name->text[0] == '[') {
/* array type cast-check */
- flags = INS_FLAG_ARRAY;
+ flags = INS_FLAG_CHECK | INS_FLAG_ARRAY;
jd->isleafmethod = false;
}
else {
/* object type cast-check */
- flags = 0;
+ flags = INS_FLAG_CHECK;
}
OP_S3_CLASSINFO_OR_CLASSREF(opcode, c, cr, flags);
break;
else
#endif
{
- OP(ICMD_CHECKNULL_POP);
+ OP_CHECK_EXCEPTION(ICMD_CHECKNULL);
+ OP(ICMD_POP);
}
break;
else
#endif
{
- OP(ICMD_CHECKNULL_POP);
+ OP_CHECK_EXCEPTION(ICMD_CHECKNULL);
+ OP(ICMD_POP);
}
break;
bte = builtintable_get_internal(BUILTIN_idiv);
OP_BUILTIN_ARITHMETIC(opcode, bte);
#else
+# if SUPPORT_HARDWARE_DIVIDE_BY_ZERO
OP(opcode);
+# else
+ OP_CHECK_EXCEPTION(opcode);
+# endif
#endif
break;
bte = builtintable_get_internal(BUILTIN_irem);
OP_BUILTIN_ARITHMETIC(opcode, bte);
#else
+# if SUPPORT_HARDWARE_DIVIDE_BY_ZERO
OP(opcode);
+# else
+ OP_CHECK_EXCEPTION(opcode);
+# endif
#endif
break;
bte = builtintable_get_internal(BUILTIN_ldiv);
OP_BUILTIN_ARITHMETIC(opcode, bte);
#else
+# if SUPPORT_HARDWARE_DIVIDE_BY_ZERO
OP(opcode);
+# else
+ OP_CHECK_EXCEPTION(opcode);
+# endif
#endif
break;
bte = builtintable_get_internal(BUILTIN_lrem);
OP_BUILTIN_ARITHMETIC(opcode, bte);
#else
+# if SUPPORT_HARDWARE_DIVIDE_BY_ZERO
OP(opcode);
+# else
+ OP_CHECK_EXCEPTION(opcode);
+# endif
#endif
break;
} /* 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 **********************************************************/
/* 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. */
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;
}
}
/* 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];
+ if (!parse_resolve_exception_table(jd))
+ return false;
- 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]);
-
- 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;
mapptr = local_map;
/* iterate over local_map[0..m->maxlocals*5] and set all existing */
- /* index,type pairs (localmap[index*5+type]==1) to an unique value */
+ /* 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
}
jd->localcount = nlocals;
- /* if dropped varindices for temp stackslots get reused(?max 2* */
- /* m->maxstack elements for stack), nlocals + s_count would be */
- /* sufficient */
- jd->varcount = nlocals + s_count +
- jd->new_basicblockcount * m->maxstack; /* out-stacks */
-
+
+ /* 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) */
+
+ /* 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)
+ 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 < (cd->maxlocals * 5); i++, mapptr++)
+ /* set types of all locals in jd->var */
+
+ 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 */