(SBRSTART): New macro.
(COPY_VAL_AND_TYPE_VAR): New macro, propagate SBRSTART.
(COPY_VAL_AND_TYPE): Use COPY_VAL_AND_TYPE_VAR.
(stack_create_invars): Cleaned up, use COPY_VAL_AND_TYPE_VAR.
(stack_create_invars_from_outvars): Use COPY_VAL_AND_TYPE_VAR.
(stack_check_invars): Check against merging of subroutines. Wrapped
verifier checks in #if defined(ENABLE_VERIFIER).
(stack_check_invars_from_outvars): Likewise.
(stack_reanalyse_block): Wrapped verifier checks in
#if defined(ENABLE_VERIFIER).
(stack_analyse): Prepare a real variable for the handler stack.
Implemented re-analysing of blocks. Set SBRSTART for JSR.
* src/vm/jit/parse.c (parse): Reserve extra variables needed by
stack_analyse.
* src/vm/global.h (STACK_EXTRA_VARS): New macro.
Joseph Wenninger
Christian Thalinger
Joseph Wenninger
Christian Thalinger
- $Id: global.h 5658 2006-10-04 10:10:01Z twisti $
+ $Id: global.h 5721 2006-10-08 11:39:41Z edwin $
/* The verifier needs additional variables in the variable array. Since these */
/* must be reserved and set by parse.c and stack.c, we define these numbers */
/* here to avoid mysterious hard-coded constants. */
/* The verifier needs additional variables in the variable array. Since these */
/* must be reserved and set by parse.c and stack.c, we define these numbers */
/* here to avoid mysterious hard-coded constants. */
+/* stack.c needs an extra variable if the verifier is disabled. */
#if defined(ENABLE_VERIFIER)
# define VERIFIER_EXTRA_LOCALS 1
# define VERIFIER_EXTRA_VARS 1
#if defined(ENABLE_VERIFIER)
# define VERIFIER_EXTRA_LOCALS 1
# define VERIFIER_EXTRA_VARS 1
+# define STACK_EXTRA_VARS 0
#else
# define VERIFIER_EXTRA_LOCALS 0
# define VERIFIER_EXTRA_VARS 0
#else
# define VERIFIER_EXTRA_LOCALS 0
# define VERIFIER_EXTRA_VARS 0
+# define STACK_EXTRA_VARS 1
#endif
#endif /* _GLOBAL_H */
#endif
#endif /* _GLOBAL_H */
Joseph Wenninger
Christian Thalinger
Joseph Wenninger
Christian Thalinger
- $Id: parse.c 5718 2006-10-07 23:56:43Z edwin $
+ $Id: parse.c 5721 2006-10-08 11:39:41Z edwin $
+ /* 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. */
/* The verifier needs space for saving invars in some cases and */
/* extra variables. */
Christian Thalinger
Christian Ullrich
Christian Thalinger
Christian Ullrich
- $Id: stack.c 5717 2006-10-07 23:02:53Z edwin $
+ $Id: stack.c 5721 2006-10-08 11:39:41Z edwin $
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
+/* For returnAddresses we use a field of the typeinfo to store from which */
+/* subroutine the returnAddress will return, if used. */
+/* XXX It would be nicer to use typeinfo.typeclass, but the verifier seems */
+/* to need it initialised to NULL. This should be investigated. */
+
+#if defined(ENABLE_VERIFIER)
+#define SBRSTART typeinfo.elementclass.any
+#endif
+
+
/* stackdata_t *****************************************************************
This struct holds internal data during stack analysis.
/* stackdata_t *****************************************************************
This struct holds internal data during stack analysis.
/* macro for propagating constant values ****************************/
/* macro for propagating constant values ****************************/
-#define COPY_VAL_AND_TYPE(sd, sindex, dindex) \
+#if defined(ENABLE_VERIFIER)
+#define COPY_VAL_AND_TYPE_VAR(sv, dv) \
+ do { \
+ (dv)->type = (sv)->type; \
+ (dv)->vv = (sv)->vv; \
+ (dv)->SBRSTART = (sv)->SBRSTART; \
+ } while (0)
+#else
+#define COPY_VAL_AND_TYPE_VAR(sv, dv) \
- (sd).var[(dindex)].type = (sd).var[(sindex)].type; \
- (sd).var[(dindex)].vv = (sd).var[(sindex)].vv; \
- } while (0) \
+ (dv)->type = (sv)->type; \
+ (dv)->vv = (sv)->vv; \
+ } while (0)
+#endif
+
+#define COPY_VAL_AND_TYPE(sd, sindex, dindex) \
+ COPY_VAL_AND_TYPE_VAR((sd).var + (sindex), (sd).var + (dindex))
/* stack modelling macros *******************************************/
/* stack modelling macros *******************************************/
stackptr sp;
int i;
int index;
stackptr sp;
int i;
int index;
+ varinfo *dv;
+ varinfo *sv;
assert(sd->vartop + stackdepth <= sd->varcount);
assert(sd->vartop + stackdepth <= sd->varcount);
i = stackdepth;
for (sp = curstack; i--; sp = sp->prev) {
b->invars[i] = --index;
i = stackdepth;
for (sp = curstack; i--; sp = sp->prev) {
b->invars[i] = --index;
- v = sd->var + index;
- v->type = sp->type;
- v->flags = INOUT;
- v->vv = sd->var[sp->varnum].vv;
-#if defined(STACK_VERBOSE) && 0
- printf("\tinvar[%d]: %d\n", i, sd->var[b->invars[i]]);
-#endif
+ dv = sd->var + index;
+ sv = sd->var + sp->varnum;
+ dv->flags = INOUT;
+ COPY_VAL_AND_TYPE_VAR(sv, dv);
}
/* copy the current state of the local variables */
/* (one extra local is needed by the verifier) */
}
/* copy the current state of the local variables */
/* (one extra local is needed by the verifier) */
- v = DMNEW(varinfo, sd->localcount + VERIFIER_EXTRA_LOCALS);
- b->inlocals = v;
+ dv = DMNEW(varinfo, sd->localcount + VERIFIER_EXTRA_LOCALS);
+ b->inlocals = dv;
for (i=0; i<sd->localcount; ++i)
for (i=0; i<sd->localcount; ++i)
for (i=0; i<n; ++i, ++dv) {
sv = sd->var + sd->bptr->outvars[i];
b->invars[i] = sd->vartop++;
for (i=0; i<n; ++i, ++dv) {
sv = sd->var + sd->bptr->outvars[i];
b->invars[i] = sd->vartop++;
+ COPY_VAL_AND_TYPE_VAR(sv, dv);
stackptr sp;
basicblock *orig;
bool separable;
stackptr sp;
basicblock *orig;
bool separable;
+ varinfo *sv;
+ varinfo *dv;
#if defined(STACK_VERBOSE)
printf("stack_check_invars(L%03d)\n", b->nr);
#if defined(STACK_VERBOSE)
printf("stack_check_invars(L%03d)\n", b->nr);
+#if defined(ENABLE_VERIFIER)
if (i != stackdepth) {
exceptions_throw_verifyerror(sd->m, "Stack depth mismatch");
return NULL;
}
if (i != stackdepth) {
exceptions_throw_verifyerror(sd->m, "Stack depth mismatch");
return NULL;
}
sp = curstack;
for (i = orig->indepth; i--; sp = sp->prev) {
sp = curstack;
for (i = orig->indepth; i--; sp = sp->prev) {
- if (sd->var[b->invars[i]].type != sp->type) {
- exceptions_throw_verifyerror_for_stack(sd->m,
- sd->var[b->invars[i]].type);
+ dv = sd->var + b->invars[i];
+ sv = sd->var + sp->varnum;
+
+#if defined(ENABLE_VERIFIER)
+ if (dv->type != sp->type) {
+ exceptions_throw_verifyerror_for_stack(sd->m, dv->type);
if (sp->type == TYPE_RET) {
if (sp->type == TYPE_RET) {
- if (sd->var[b->invars[i]].vv.retaddr != sd->var[sp->varnum].vv.retaddr) {
+#if defined(ENABLE_VERIFIER)
+ if (dv->SBRSTART != sv->SBRSTART) {
+ exceptions_throw_verifyerror(sd->m, "Mismatched stack types");
+ return NULL;
+ }
+#endif
+ if (dv->vv.retaddr != sv->vv.retaddr) {
separable = true;
/* don't break! have to check the remaining stackslots */
}
separable = true;
/* don't break! have to check the remaining stackslots */
}
if (b->inlocals) {
for (i=0; i<sd->localcount; ++i) {
if (b->inlocals) {
for (i=0; i<sd->localcount; ++i) {
- if (sd->var[i].type == TYPE_RET && b->inlocals[i].type == TYPE_RET) {
- if (sd->var[i].vv.retaddr != b->inlocals[i].vv.retaddr) {
+ dv = b->inlocals + i;
+ sv = sd->var + i;
+ if (sv->type == TYPE_RET && dv->type == TYPE_RET) {
+ if (
+#if defined(ENABLE_VERIFIER)
+ (sv->SBRSTART == dv->SBRSTART) &&
+#endif
+ (sv->vv.retaddr != dv->vv.retaddr))
+ {
separable = true;
break;
}
separable = true;
break;
}
if (!separable) {
/* XXX mark mixed type variables void */
/* XXX cascading collapse? */
if (!separable) {
/* XXX mark mixed type variables void */
/* XXX cascading collapse? */
+#if defined(ENABLE_VERIFIER)
+ if (b->inlocals) {
+ for (i=0; i<sd->localcount; ++i) {
+ dv = b->inlocals + i;
+ sv = sd->var + i;
+ if ((sv->type == TYPE_RET && dv->type == TYPE_RET)
+ && (sv->SBRSTART != dv->SBRSTART))
+ {
+ dv->type = TYPE_VOID;
+ b->flags = BBTYPECHECK_REACHED;
+ sd->repeat = true; /* This is very rare, so just repeat */
+ }
+ }
+ }
+#endif
+
#if defined(STACK_VERBOSE)
printf("------> using L%03d\n", b->nr);
#endif
#if defined(STACK_VERBOSE)
printf("------> using L%03d\n", b->nr);
#endif
i = orig->indepth;
n = sd->bptr->outdepth;
i = orig->indepth;
n = sd->bptr->outdepth;
+#if defined(ENABLE_VERIFIER)
if (i != n) {
exceptions_throw_verifyerror(sd->m, "Stack depth mismatch");
return NULL;
}
if (i != n) {
exceptions_throw_verifyerror(sd->m, "Stack depth mismatch");
return NULL;
}
for (i=0; i<n; ++i, ++dv) {
sv = sd->var + sd->bptr->outvars[i];
for (i=0; i<n; ++i, ++dv) {
sv = sd->var + sd->bptr->outvars[i];
+
+#if defined(ENABLE_VERIFIER)
if (sv->type != dv->type) {
exceptions_throw_verifyerror_for_stack(sd->m, dv->type);
return NULL;
}
if (sv->type != dv->type) {
exceptions_throw_verifyerror_for_stack(sd->m, dv->type);
return NULL;
}
if (dv->type == TYPE_RET) {
if (dv->type == TYPE_RET) {
+#if defined(ENABLE_VERIFIER)
+ if (sv->SBRSTART != dv->SBRSTART) {
+ exceptions_throw_verifyerror(sd->m, "Mismatched stack types");
+ return NULL;
+ }
+#endif
if (sv->vv.retaddr != dv->vv.retaddr) {
separable = true;
/* don't break! have to check the remaining stackslots */
if (sv->vv.retaddr != dv->vv.retaddr) {
separable = true;
/* don't break! have to check the remaining stackslots */
if (b->inlocals) {
for (i=0; i<sd->localcount; ++i) {
if (b->inlocals) {
for (i=0; i<sd->localcount; ++i) {
- if (sd->var[i].type == TYPE_RET && b->inlocals[i].type == TYPE_RET) {
- if (sd->var[i].vv.retaddr != b->inlocals[i].vv.retaddr) {
+ dv = b->inlocals + i;
+ sv = sd->var + i;
+ if (
+#if defined(ENABLE_VERIFIER)
+ (sv->SBRSTART == dv->SBRSTART) &&
+#endif
+ (sv->type == TYPE_RET && dv->type == TYPE_RET))
+ {
+ if (sv->vv.retaddr != dv->vv.retaddr) {
separable = true;
break;
}
separable = true;
break;
}
if (!separable) {
/* XXX mark mixed type variables void */
/* XXX cascading collapse? */
if (!separable) {
/* XXX mark mixed type variables void */
/* XXX cascading collapse? */
+#if defined(ENABLE_VERIFIER)
+ if (b->inlocals) {
+ for (i=0; i<sd->localcount; ++i) {
+ dv = b->inlocals + i;
+ sv = sd->var + i;
+ if ((sv->type == TYPE_RET && dv->type == TYPE_RET)
+ && (sv->SBRSTART != dv->SBRSTART))
+ {
+ dv->type = TYPE_VOID;
+ b->flags = BBTYPECHECK_REACHED;
+ sd->repeat = true; /* This is very rare, so just repeat */
+ }
+ }
+ }
+#endif
+
#if defined(STACK_VERBOSE)
printf("------> using L%03d\n", b->nr);
#endif
#if defined(STACK_VERBOSE)
printf("------> using L%03d\n", b->nr);
#endif
case ICMD_RET:
j = iptr->s1.varindex;
case ICMD_RET:
j = iptr->s1.varindex;
+#if defined(ENABLE_VERIFIER)
if (sd->var[j].type != TYPE_RET) {
exceptions_throw_verifyerror(sd->m, "RET with non-returnAddress value");
return false;
}
if (sd->var[j].type != TYPE_RET) {
exceptions_throw_verifyerror(sd->m, "RET with non-returnAddress value");
return false;
}
iptr->dst.block = stack_mark_reached_from_outvars(sd, sd->var[j].vv.retaddr);
superblockend = true;
iptr->dst.block = stack_mark_reached_from_outvars(sd, sd->var[j].vv.retaddr);
superblockend = true;
sd.localcount = jd->localcount;
sd.var = jd->var;
sd.handlers = DMNEW(exceptiontable *, cd->exceptiontablelength + 1);
sd.localcount = jd->localcount;
sd.var = jd->var;
sd.handlers = DMNEW(exceptiontable *, cd->exceptiontablelength + 1);
+
+ /* prepare the variable for exception handler stacks */
+ /* (has been reserved by STACK_EXTRA_VARS, or VERIFIER_EXTRA_VARS) */
+
sd.exstack.type = TYPE_ADR;
sd.exstack.prev = NULL;
sd.exstack.type = TYPE_ADR;
sd.exstack.prev = NULL;
- sd.exstack.varnum = 0; /* XXX do we need a real variable index here? */
+ sd.exstack.varnum = sd.localcount;
+ sd.var[sd.exstack.varnum].type = TYPE_ADR;
#if defined(ENABLE_LSRA)
m->maxlifetimes = 0;
#if defined(ENABLE_LSRA)
m->maxlifetimes = 0;
+ if (sd.bptr->flags == BBTYPECHECK_REACHED) {
+ /* re-analyse a block because its input changed */
+ if (!stack_reanalyse_block(&sd))
+ return false;
+ superblockend = true; /* XXX */
+ continue;
+ }
+
if (superblockend && (sd.bptr->flags < BBREACHED)) {
/* This block has not been reached so far, and we */
/* don't fall into it, so we'll have to iterate again. */
if (superblockend && (sd.bptr->flags < BBREACHED)) {
/* This block has not been reached so far, and we */
/* don't fall into it, so we'll have to iterate again. */
/* analysed, yet. Analyse it on the next iteration. */
sd.repeat = true;
/* analysed, yet. Analyse it on the next iteration. */
sd.repeat = true;
+ /* XXX superblockend? */
j = iptr->s1.varindex =
jd->local_map[iptr->s1.varindex * 5 + TYPE_ADR];
j = iptr->s1.varindex =
jd->local_map[iptr->s1.varindex * 5 + TYPE_ADR];
+#if defined(ENABLE_VERIFIER)
if (sd.var[j].type != TYPE_RET) {
exceptions_throw_verifyerror(m, "RET with non-returnAddress value");
return false;
}
if (sd.var[j].type != TYPE_RET) {
exceptions_throw_verifyerror(m, "RET with non-returnAddress value");
return false;
}
j = iptr->s1.varindex =
jd->local_map[iptr->s1.varindex * 5 + i];
j = iptr->s1.varindex =
jd->local_map[iptr->s1.varindex * 5 + i];
+#if defined(ENABLE_VERIFIER)
if (sd.var[j].type == TYPE_RET) {
exceptions_throw_verifyerror(m, "forbidden load of returnAddress");
return false;
}
if (sd.var[j].type == TYPE_RET) {
exceptions_throw_verifyerror(m, "forbidden load of returnAddress");
return false;
}
#if defined(ENABLE_SSA)
if (ls != NULL) {
#if defined(ENABLE_SSA)
if (ls != NULL) {
case ICMD_JSR:
OP0_1(TYPE_RET);
case ICMD_JSR:
OP0_1(TYPE_RET);
- assert(sd.bptr->next); /* XXX exception */
- sd.var[curstack->varnum].vv.retaddr = sd.bptr->next;
-
tbptr = BLOCK_OF(iptr->sx.s23.s3.jsrtarget.insindex);
tbptr->type = BBTYPE_SBR;
tbptr = BLOCK_OF(iptr->sx.s23.s3.jsrtarget.insindex);
tbptr->type = BBTYPE_SBR;
+ assert(sd.bptr->next); /* XXX exception */
+ sd.var[curstack->varnum].vv.retaddr = sd.bptr->next;
+#if defined(ENABLE_VERIFIER)
+ sd.var[curstack->varnum].SBRSTART = (void*) tbptr;
+#endif
+
tbptr = stack_mark_reached(&sd, tbptr, curstack, stackdepth);
if (!tbptr)
return false;
tbptr = stack_mark_reached(&sd, tbptr, curstack, stackdepth);
if (!tbptr)
return false;