calls instead of machine instructions, using the C calling
convention.
- $Id: builtin.c 862 2004-01-06 23:42:01Z stefan $
+ $Id: builtin.c 868 2004-01-10 20:12:10Z edwin $
*/
return (java_arrayheader *) Java_java_lang_VMObject_clone(0, 0, (java_lang_Cloneable *) o);
}
+s4 builtin_dummy()
+{
+ panic("Internal error: builtin_dummy called (native function is missing)");
+ return 0; /* for the compiler */
+}
+
/*
* These are local overrides for various environment variables in Emacs.
Changes: Edwin Steiner
- $Id: builtin.h 862 2004-01-06 23:42:01Z stefan $
+ $Id: builtin.h 868 2004-01-10 20:12:10Z edwin $
*/
java_arrayheader *builtin_clone_array(void *env, java_arrayheader *o);
/* NOT AN OP */
+/* builtin_dummy just panics if it is executed. */
+s4 builtin_dummy();
+/* NOT AN OP */
+
/* conversion helper functions */
inline float intBitsToFloat(s4 i);
Changes: Christian Thalinger
- $Id: jit.h 845 2004-01-05 10:38:06Z twisti $
+ $Id: jit.h 868 2004-01-10 20:12:10Z edwin $
*/
};
+/********** op1 values for ACONST instructions ********************************/
+
+#define ACONST_LOAD 0 /* ACONST_NULL or LDC instruction */
+#define ACONST_BUILTIN 1 /* constant argument for a builtin function call */
+
/********** JavaVM operation codes (sorted) and instruction lengths ***********/
extern char *icmd_names[256];
Changes: Carolyn Oates
Edwin Steiner
- $Id: parse.c 863 2004-01-07 18:50:41Z edwin $
+ $Id: parse.c 868 2004-01-10 20:12:10Z edwin $
*/
#define LOADCONST_F(v) iptr->opc=ICMD_FCONST;iptr->op1=0;iptr->val.f=(v);PINC
#define LOADCONST_D(v) iptr->opc=ICMD_DCONST;iptr->op1=0;iptr->val.d=(v);PINC
#define LOADCONST_A(v) iptr->opc=ICMD_ACONST;iptr->op1=0;iptr->val.a=(v);PINC
+
+/* ACONST instructions generated as arguments for builtin functions
+ * have op1 set to non-zero. This is used for stack overflow checking
+ * in stack.c. */
+#define LOADCONST_A_BUILTIN(v) \
+ iptr->opc=ICMD_ACONST;iptr->op1=1;iptr->val.a=(v);PINC
+
#define OP(o) iptr->opc=(o);iptr->op1=0;iptr->val.l=0;PINC
#define OP1(o,o1) iptr->opc=(o);iptr->op1=(o1);iptr->val.l=(0);PINC
#define OP2I(o,o1,v) iptr->opc=(o);iptr->op1=(o1);iptr->val.i=(v);PINC
i = code_get_u2(p + 1);
{
classinfo *component = (classinfo*)class_getconstant(class, i, CONSTANT_Class);
- LOADCONST_A(class_array_of(component)->vftbl);
+ LOADCONST_A_BUILTIN(class_array_of(component)->vftbl);
s_count++;
case JAVA_NEW:
i = code_get_u2 (p+1);
- LOADCONST_A(class_getconstant(class, i, CONSTANT_Class));
+ LOADCONST_A_BUILTIN(class_getconstant(class, i, CONSTANT_Class));
s_count++;
BUILTIN1(BUILTIN_new, TYPE_ADR);
break;
classinfo *cls = (classinfo*)class_getconstant(class, i, CONSTANT_Class);
if (cls->vftbl->arraydesc) {
/* array type cast-check */
- LOADCONST_A(cls->vftbl);
+ LOADCONST_A_BUILTIN(cls->vftbl);
s_count++;
BUILTIN2(BUILTIN_checkarraycast, TYPE_ADR);
}
else { /* object type cast-check */
/*
-+ LOADCONST_A(class_getconstant(class, i, CONSTANT_Class));
++ LOADCONST_A_BUILTIN(class_getconstant(class, i, CONSTANT_Class));
+ s_count++;
+ BUILTIN2(BUILTIN_checkcast, TYPE_ADR);
+ */
classinfo *cls = (classinfo*)class_getconstant(class, i, CONSTANT_Class);
if (cls->vftbl->arraydesc) {
/* array type cast-check */
- LOADCONST_A(cls->vftbl);
+ LOADCONST_A_BUILTIN(cls->vftbl);
s_count++;
BUILTIN2(BUILTIN_arrayinstanceof, TYPE_INT);
}
else { /* object type cast-check */
/*
- LOADCONST_A(class_getconstant(class, i, CONSTANT_Class));
+ LOADCONST_A_BUILTIN(class_getconstant(class, i, CONSTANT_Class));
s_count++;
BUILTIN2(BUILTIN_instanceof, TYPE_INT);
+ */
Changes: Edwin Steiner
- $Id: stack.c 846 2004-01-05 10:40:42Z twisti $
+ $Id: stack.c 868 2004-01-10 20:12:10Z edwin $
*/
#define REQUIRE_4 REQUIRE(4)
/* overflow check */
-/* XXX we allow ACONST to exceed the maximum stack depth because it is
- * generated for builtin calls. Maybe we should check against maximum
- * stack depth only at block boundaries?
+/* XXX we allow ACONST instructions inserted as arguments to builtin
+ * functions to exceed the maximum stack depth. Maybe we should check
+ * against maximum stack depth only at block boundaries?
*/
#define CHECKOVERFLOW \
do { \
if (stackdepth > maxstack) { \
- if (iptr[0].opc != ICMD_ACONST) \
+ if (iptr[0].opc != ICMD_ACONST \
+ || iptr[0].op1 == 0) \
{OVERFLOW;} \
} \
} while(0)
* - check for matching stack depth at merging points
* - check for matching basic types[2] at merging points
* - check basic types for instruction input (except for BUILTIN*
- * opcodes and MULTIANEWARRAY)
+ * opcodes, INVOKE* opcodes and MULTIANEWARRAY)
*
* [1]) XXX Checking this after the instruction should be ok. parse.c
* counts the number of required stack slots in such a way that it is
iptr->val.a = (void *) iptr->dst;
tbptr->type = BBTYPE_SBR;
+
+ /* We need to check for overflow right here because
+ * the pushed value is poped after MARKREACHED. */
CHECKOVERFLOW;
MARKREACHED(tbptr, copy);
OP1_0ANY;
Authors: Edwin Steiner
- $Id: typecheck.c 822 2003-12-31 16:00:58Z edwin $
+ $Id: typecheck.c 868 2004-01-10 20:12:10Z edwin $
*/
typeinfo_print_locals(file,vtype,vinfo,touched,vnum);
}
+static
+void
+typestack_print(FILE *file,stackptr stack)
+{
+ while (stack) {
+ typeinfo_print_stacktype(file,stack->type,&stack->typeinfo);
+ stack = stack->prev;
+ if (stack) fprintf(file," ");
+ }
+}
+
+static
+void
+typestate_print(FILE *file,stackptr instack,typevector *localset,int size)
+{
+ fprintf(file,"Stack: ");
+ typestack_print(file,instack);
+ fprintf(file," Locals:");
+ typevectorset_print(file,localset,size);
+}
+
#if 0
static
#endif
+/****************************************************************************/
+/* TYPESTACK FUNCTIONS */
+/****************************************************************************/
+
+#define TYPESTACK_IS_RETURNADDRESS(sptr) \
+ TYPE_IS_RETURNADDRESS((sptr)->type,(sptr)->typeinfo)
+
+#define TYPESTACK_IS_REFERENCE(sptr) \
+ TYPE_IS_REFERENCE((sptr)->type,(sptr)->typeinfo)
+
+#define TYPESTACK_RETURNADDRESSSET(sptr) \
+ ((typeinfo_retaddr_set*)TYPEINFO_RETURNADDRESS((sptr)->typeinfo))
+
+#define RETURNADDRESSSET_SEEK(set,pos) \
+ do {int i; for (i=pos;i--;) set=set->alt;} while(0)
+
+static void
+typestack_copy(stackptr dst,stackptr y,typevector *selected)
+{
+ typevector *sel;
+ typeinfo_retaddr_set *sety;
+ typeinfo_retaddr_set *new;
+ typeinfo_retaddr_set **next;
+ int k;
+
+ for (;dst; dst=dst->prev, y=y->prev) {
+ if (!y) panic("Stack depth mismatch");
+ if (dst->type != y->type)
+ panic("Stack type mismatch");
+ LOG3("copy %p -> %p (type %d)",y,dst,dst->type);
+ if (dst->type == TYPE_ADDRESS) {
+ if (TYPEINFO_IS_PRIMITIVE(y->typeinfo)) {
+ /* We copy the returnAddresses from the selected
+ * states only. */
+
+ LOG("copying returnAddress");
+ sety = TYPESTACK_RETURNADDRESSSET(y);
+ next = &new;
+ for (k=0,sel=selected; sel; sel=sel->alt) {
+ LOG1("selected k=%d",sel->k);
+ while (k<sel->k) {
+ sety = sety->alt;
+ k++;
+ }
+ *next = DNEW(typeinfo_retaddr_set);
+ (*next)->addr = sety->addr;
+ next = &((*next)->alt);
+ }
+ *next = NULL;
+ TYPEINFO_INIT_RETURNADDRESS(dst->typeinfo,new);
+ }
+ else {
+ TYPEINFO_CLONE(y->typeinfo,dst->typeinfo);
+ }
+ }
+ }
+ if (y) panic("Stack depth mismatch");
+}
+
+static void
+typestack_put_retaddr(stackptr dst,void *retaddr,typevector *loc)
+{
+#ifdef TYPECHECK_DEBUG
+ if (dst->type != TYPE_ADDRESS)
+ panic("Internal error: Storing returnAddress in non-address slot");
+#endif
+
+
+ TYPEINFO_INIT_RETURNADDRESS(dst->typeinfo,NULL);
+ for (;loc; loc=loc->alt) {
+ typeinfo_retaddr_set *set = DNEW(typeinfo_retaddr_set);
+ set->addr = retaddr;
+ set->alt = TYPESTACK_RETURNADDRESSSET(dst);
+ TYPEINFO_INIT_RETURNADDRESS(dst->typeinfo,set);
+ }
+}
+
+static bool
+typestack_canmerge(stackptr a,stackptr b)
+{
+ for (; a; a = a->prev, b = b->prev) {
+ if (!b) return false;
+ if (a->type != b->type) return false;
+ if (a->type == TYPE_ADDRESS) {
+ if (((TYPEINFO_IS_PRIMITIVE(a->typeinfo)) ? 1 : 0)
+ ^
+ ((TYPEINFO_IS_PRIMITIVE(b->typeinfo)) ? 1 : 0))
+ return false;
+ }
+ }
+ if (b) return false;
+ return true;
+}
+
+static void
+typestack_collapse(stackptr dst)
+{
+ for (; dst; dst = dst->prev) {
+ if (TYPESTACK_IS_RETURNADDRESS(dst))
+ TYPESTACK_RETURNADDRESSSET(dst)->alt = NULL;
+ }
+}
+
+/* 'dst' and 'y' are assumed to have passed typestack_canmerge! */
+static bool
+typestack_merge(stackptr dst,stackptr y)
+{
+ bool changed = false;
+ for (; dst; dst = dst->prev, y=y->prev) {
+ if (TYPESTACK_IS_REFERENCE(dst))
+ changed |= typeinfo_merge(&(dst->typeinfo),&(y->typeinfo));
+ }
+ return changed;
+}
+
+static void
+typestack_add(stackptr dst,stackptr y,int ky)
+{
+ typeinfo_retaddr_set *setd;
+ typeinfo_retaddr_set *sety;
+
+ for (; dst; dst = dst->prev, y=y->prev) {
+ if (TYPESTACK_IS_RETURNADDRESS(dst)) {
+ setd = TYPESTACK_RETURNADDRESSSET(dst);
+ sety = TYPESTACK_RETURNADDRESSSET(y);
+ RETURNADDRESSSET_SEEK(sety,ky);
+ while (setd->alt)
+ setd=setd->alt;
+ setd->alt = DNEW(typeinfo_retaddr_set);
+ setd->alt->addr = sety->addr;
+ setd->alt->alt = NULL;
+ }
+ }
+}
+
+/* 'a' and 'b' are assumed to have passed typestack_canmerge! */
+static bool
+typestack_separable_with(stackptr a,stackptr b,int kb)
+{
+ typeinfo_retaddr_set *seta;
+ typeinfo_retaddr_set *setb;
+
+ for (; a; a = a->prev, b = b->prev) {
+#ifdef TYPECHECK_DEBUG
+ if (!b) panic("Internal error: typestack_separable_from: different depth");
+#endif
+ if (TYPESTACK_IS_RETURNADDRESS(a)) {
+#ifdef TYPECHECK_DEBUG
+ if (!TYPESTACK_IS_RETURNADDRESS(b))
+ panic("Internal error: typestack_separable_from: unmergable stacks");
+#endif
+ seta = TYPESTACK_RETURNADDRESSSET(a);
+ setb = TYPESTACK_RETURNADDRESSSET(b);
+ RETURNADDRESSSET_SEEK(setb,kb);
+
+ for (;seta;seta=seta->alt)
+ if (seta->addr != setb->addr) return true;
+ }
+ }
+#ifdef TYPECHECK_DEBUG
+ if (b) panic("Internal error: typestack_separable_from: different depth");
+#endif
+ return false;
+}
+
+/* 'a' and 'b' are assumed to have passed typestack_canmerge! */
+static bool
+typestack_separable_from(stackptr a,int ka,stackptr b,int kb)
+{
+ typeinfo_retaddr_set *seta;
+ typeinfo_retaddr_set *setb;
+ int i;
+
+ for (; a; a = a->prev, b = b->prev) {
+#ifdef TYPECHECK_DEBUG
+ if (!b) panic("Internal error: typestack_separable_from: different depth");
+#endif
+ if (TYPESTACK_IS_RETURNADDRESS(a)) {
+#ifdef TYPECHECK_DEBUG
+ if (!TYPESTACK_IS_RETURNADDRESS(b))
+ panic("Internal error: typestack_separable_from: unmergable stacks");
+#endif
+ seta = TYPESTACK_RETURNADDRESSSET(a);
+ setb = TYPESTACK_RETURNADDRESSSET(b);
+ RETURNADDRESSSET_SEEK(seta,ka);
+ RETURNADDRESSSET_SEEK(setb,kb);
+
+ if (seta->addr != setb->addr) return true;
+ }
+ }
+#ifdef TYPECHECK_DEBUG
+ if (b) panic("Internal error: typestack_separable_from: different depth");
+#endif
+ return false;
+}
+
+/****************************************************************************/
+/* TYPESTATE FUNCTIONS */
+/****************************************************************************/
+
+static bool
+typestate_merge(stackptr deststack,typevector *destloc,
+ stackptr ystack,typevector *yloc,
+ /* int retindex,void *retaddr, */
+ int locsize)
+{
+ typevector *dvec,*yvec;
+ int kd,ky;
+ bool changed = false;
+
+#ifdef TYPECHECK_DEBUG
+ /* Do some sanity checks */
+ /*
+ if (retindex < -1 || retindex >= locsize || (retindex >= 0 && !retaddr))
+ panic("Internal error: typestate_merge: invalid arguments");
+ */
+#endif
+
+ LOG("merge:");
+ LOGSTR("dstack: "); DOLOG(typestack_print(get_logfile(),deststack)); LOGNL;
+ LOGSTR("ystack: "); DOLOG(typestack_print(get_logfile(),ystack)); LOGNL;
+ LOGSTR("dloc : "); DOLOG(typevectorset_print(get_logfile(),destloc,locsize)); LOGNL;
+ LOGSTR("yloc : "); DOLOG(typevectorset_print(get_logfile(),yloc,locsize)); LOGNL;
+
+ /* Check if the stack types of deststack and ystack match */
+
+ /* XXX move this check into typestack_merge? */
+ if (!typestack_canmerge(deststack,ystack))
+ panic("Stack depth or stack type mismatch");
+
+ /* The stack is always merged. If there are returnAddresses on
+ * the stack they are ignored in this step. */
+
+ changed |= typestack_merge(deststack,ystack);
+
+ for (yvec=yloc; yvec; yvec=yvec->alt) {
+ ky = yvec->k;
+
+ /* If retindex >= 0 we select only those states (ystack,yvec)
+ * with returnAddress retaddr in variable no. retindex. */
+
+ /*
+ if (retindex >= 0) {
+ if (!TYPEDESC_IS_RETURNADDRESS(yvec->td[retindex]))
+ panic("Illegal instruction: RET on non-returnAddress");
+ if (TYPEINFO_RETURNADDRESS(yvec->td[retindex].info)
+ != retaddr)
+ continue;
+ }
+ */
+
+ /* Check if the typestates (deststack,destloc) will be
+ * separable when (ystack,yvec) is added. */
+
+ if (!typestack_separable_with(deststack,ystack,ky)
+ && !typevectorset_separable_with(destloc,yvec,locsize))
+ {
+ /* No, the resulting set won't be separable, thus we
+ * may merge all states in (deststack,destloc) and
+ * (ystack,yvec). */
+
+ typestack_collapse(deststack);
+ typevectorset_collapse(destloc,locsize);
+ typevector_merge(destloc,yvec,locsize);
+ }
+ else {
+ /* Yes, the resulting set will be separable. Thus we check
+ * if we may merge (ystack,yvec) with a single state in
+ * (deststack,destloc). */
+
+ for (dvec=destloc,kd=0; dvec; dvec=dvec->alt, kd++) {
+ if (!typestack_separable_from(ystack,ky,deststack,kd)
+ && !typevector_separable_from(yvec,dvec,locsize))
+ {
+ /* The typestate (ystack,yvec) is not separable from
+ * (deststack,dvec) by any returnAddress. Thus we may
+ * merge the states. */
+
+ changed |= typevector_merge(dvec,yvec,locsize);
+
+ goto merged;
+ }
+ }
+
+ /* The typestate (ystack,yvec) is separable from all typestates
+ * (deststack,destloc). Thus we must add this state to the
+ * result set. */
+
+ typestack_add(deststack,ystack,ky);
+ typevectorset_add(destloc,yvec,locsize);
+ changed = true;
+ }
+
+ merged:
+
+ }
+
+ LOG("result:");
+ LOGSTR("dstack: "); DOLOG(typestack_print(get_logfile(),deststack)); LOGNL;
+ LOGSTR("dloc : "); DOLOG(typevectorset_print(get_logfile(),destloc,locsize)); LOGNL;
+
+ return changed;
+}
+
+/* Globals used:
+ * block
+ */
+static bool
+typestate_reach(void *localbuf,
+ basicblock *current,
+ basicblock *destblock,
+ stackptr ystack,typevector *yloc,
+ int locsize)
+{
+ typevector *yvec;
+ typevector *destloc;
+ int destidx;
+ bool repeat = false;
+ bool changed = false;
+
+ destidx = destblock - block;
+ destloc = MGET_TYPEVECTOR(localbuf,destidx,locsize);
+
+ if (destblock->flags == BBTYPECHECK_UNDEF) {
+ /* The destblock has never been reached before */
+
+ LOG1("block (index %04d) reached first time",destidx);
+
+ typestack_copy(destblock->instack,ystack,yloc);
+ COPY_TYPEVECTORSET(yloc,destloc,locsize);
+ changed = true;
+ }
+ else {
+ /* The destblock has already been reached before */
+
+ LOG1("block (index %04d) reached before",destidx);
+
+ changed = typestate_merge(destblock->instack,destloc,
+ ystack,yloc,locsize);
+ }
+
+ if (changed) {
+ LOG("changed!");
+ destblock->flags = BBTYPECHECK_REACHED;
+ if (destblock <= current) {repeat = true; LOG("REPEAT!");}
+ }
+ return repeat;
+}
+
+/* Globals used:
+ * see typestate_reach
+ */
+static bool
+typestate_ret(void *localbuf,
+ basicblock *current,
+ stackptr ystack,typevector *yloc,
+ int retindex,int locsize)
+{
+ typevector *yvec;
+ typevector *selected;
+ basicblock *destblock;
+ bool repeat = false;
+
+ for (yvec=yloc; yvec; ) {
+ if (!TYPEDESC_IS_RETURNADDRESS(yvec->td[retindex]))
+ panic("Illegal instruction: RET on non-returnAddress");
+
+ destblock = (basicblock*) TYPEINFO_RETURNADDRESS(yvec->td[retindex].info);
+
+ selected = typevectorset_select(&yvec,retindex,destblock);
+
+ repeat |= typestate_reach(localbuf,current,destblock,
+ ystack,selected,locsize);
+ }
+ return repeat;
+}
+
+static bool
+typestate_jsr(void *localbuf,
+ basicblock *current,basicblock *destblock,
+ stackptr ystack,typevector *yloc,
+ int locsize)
+{
+ typestack_put_retaddr(ystack,current+1,yloc);
+ return typestate_reach(localbuf,current,destblock,ystack,yloc,locsize);
+}
+
/****************************************************************************/
/* HELPER FUNCTIONS */
/****************************************************************************/
* jsr_record of the first block of the subroutine.
*/
struct jsr_record {
- basicblock *target; /* target of the JSR instruction (first block of subroutine) */
- jsr_record *next; /* for chaining in nested try ... finally */ /* XXX make it sbr_next? */
- u1 *sbr_touched; /* specifies which variables the subroutine touches */
- u1 *sbr_vtype; /* Types of local variables after RET */
- typeinfo *sbr_vinfo; /* Types of local variables after RET */
- u1 touched[1]; /* touched flags for local variables */
+ basicblock *target; /* target of the JSR instruction (first block of subroutine) */
+ jsr_record *next; /* for chaining in nested try ... finally */ /* XXX make it sbr_next? */
+ u1 *sbr_touched; /* specifies which variables the subroutine touches */
+ u1 *sbr_vtype; /* Types of local variables after RET */
+ typeinfo *sbr_vinfo; /* Types of local variables after RET */
+ instruction *sbr_ret; /* RET instruction of the subroutine */
+ u1 touched[1]; /* touched flags for local variables */
};
/****************************************************************************/
#define STORE_ONEWORD(num,type) \
do {INDEX_ONEWORD(num); \
- SET_VARIABLE(num,type);} while(0)
+ typevectorset_store(localset,num,type,NULL);} while(0)
#define STORE_TWOWORD(num,type) \
do {INDEX_TWOWORD(num); \
- SET_VARIABLE(num,type); \
- vtype[(num)+1] = TYPE_VOID; \
- TOUCH_VARIABLE((num)+1);} while(0)
+ typevectorset_store_twoword(localset,num,type);} while(0)
#define CHECK_ONEWORD(num,type) \
do {INDEX_ONEWORD(num); \
- if (vtype[(num)] != (type)) panic("Variable type mismatch"); \
- TOUCH_VARIABLE(num);} while(0)
+ if (!typevectorset_checktype(localset,num,type)) \
+ panic("Variable type mismatch"); \
+ } while(0)
#define CHECK_TWOWORD(num,type) \
do {INDEX_TWOWORD(num); \
- if (vtype[(num)] != (type)) panic("Variable type mismatch"); \
- TOUCH_VARIABLE(num); \
- TOUCH_VARIABLE((num)+1);} while(0)
+ if (!typevectorset_checktype(localset,num,type)) \
+ panic("Variable type mismatch"); \
+ } while(0)
/* XXX maybe it's faster to copy always */
#define COPYTYPE(source,dest) \
srcstack = srcstack->prev; \
} \
for (macro_i=0; macro_i<numlocals; ++macro_i) \
- if (vtype[macro_i] == TYPE_ADR && \
- TYPEINFO_IS_NEWOBJECT(vinfo[macro_i])) \
+ if (localset->td[macro_i].type == TYPE_ADR && \
+ TYPEINFO_IS_NEWOBJECT(localset->td[macro_i].info)) \
panic("Branching backwards with uninitialized object in local variable"); \
} while(0)
#define TYPECHECK_REACH(way) \
do { \
LOG2("reaching block %04d (%d)",tbptr-block,way); \
- if (tbptr <= bptr && way != REACH_THROW) \
+ if (tbptr <= bptr) \
TYPECHECK_BRANCH_BACKWARDS; \
- srcstack = dst; \
- dststack = tbptr->instack; \
- ttype = vartype + numlocals*(tbptr-block); \
- tinfo = vartypeinfo + numlocals*(tbptr-block); \
- if (tbptr->flags == BBTYPECHECK_UNDEF) { \
- /* This block is reached for the first time */ \
- if (way == REACH_JSR) { \
- TYPECHECK_ADD_JSR; \
- TYPECHECK_COPYVARS; \
- } \
- else { \
- if (way != REACH_THROW) TYPECHECK_COPYJSR(jsrchain); \
- TYPECHECK_COPYVARS; \
- } \
- if (way != REACH_THROW) TYPECHECK_COPYSTACK; \
- changed = true; \
- } else { \
- /* This block has been reached before */ \
- changed = false; \
- if (way == REACH_JSR) \
- TYPECHECK_CHECK_JSR_CHAIN; \
- else if (way != REACH_THROW) \
- TYPECHECK_MERGEJSR; \
- TYPECHECK_MERGEVARS; \
- if (way != REACH_THROW) TYPECHECK_MERGESTACK; \
- } \
- if (changed) { \
- LOG("REACHED!"); \
- tbptr->flags = BBTYPECHECK_REACHED; \
- if (tbptr <= bptr) {repeat = true; LOG("REPEAT!");} \
- } \
+ repeat |= typestate_reach(localbuf,bptr,tbptr,dst, \
+ localset,numlocals); \
LOG("done."); \
} while (0)
if (initmethod && class != class_java_lang_Object) { \
/* check the marker variable */ \
LOG("Checking <init> marker"); \
- if (vtype[numlocals-1] == TYPE_VOID) \
+ if (!typevectorset_checktype(localset,numlocals-1,TYPE_INT))\
panic("<init> method does not initialize 'this'"); \
} \
} while (0)
basicblock *tbptr; /* temporary for target block */
int numlocals; /* number of local variables */
int validlocals; /* number of valid local variable indices */
- u1 *vartype; /* type of each local for each basic block */
- typeinfo *vartypeinfo; /* type of each local for each basic block */
- u1 *vtype; /* type of each local for current instruction */
- typeinfo *vinfo; /* type of each local for current instruction */
- u1 *ttype; /* temporary pointer */
- typeinfo *tinfo; /* temporary pointer */
+
+ void *localbuf; /* local variable types for each block start */
+ typevector *localset; /* typevector set for local variables */
+ typevector *lset; /* temporary pointer */
+ typedescriptor *td; /* temporary pointer */
+
typeinfo tempinfo; /* temporary */
- int returntype; /* return type of current method */
- typeinfo returntypeinfo; /* typeinfo for return type */
+
+ typedescriptor returntype; /* return type of current method */
+
u1 *ptype; /* parameter types of called method */
typeinfo *pinfo; /* parameter typeinfos of called method */
int rtype; /* return type of called method */
typeinfo rinfo; /* typeinfo for return type of called method */
stackptr dst; /* output stack of current instruction */
- basicblock **tptr; /* pointer into target list of switch instructions */
+ basicblock **tptr; /* pointer into target list of switch instr. */
jsr_record **jsrbuffer; /* JSR target chain for each basic block */
jsr_record *jsrchain; /* JSR chain for current block */
jsr_record *jsrtemp,*jsrtemp2; /* temporary variables */
if (initmethod) numlocals++;
/* allocate the buffers for local variables */
- vartype = DMNEW(u1,numlocals * (block_count+1));
- vartypeinfo = DMNEW(typeinfo,numlocals * (block_count+1));
- touched = DMNEW(u1,numlocals);
- vtype = vartype + numlocals * block_count;
- vinfo = vartypeinfo + numlocals * block_count;
- memset(vartype,TYPE_VOID,numlocals * (block_count+1) * sizeof(u1));
- memset(vartypeinfo,0,numlocals * (block_count+1) * sizeof(typeinfo));
+ localbuf = DMNEW_TYPEVECTOR(block_count+1, numlocals);
+ localset = MGET_TYPEVECTOR(localbuf,block_count,numlocals);
+ memset(localbuf,0,(block_count+1) * TYPEVECTOR_SIZE(numlocals));
- LOG("Variable buffer initialized.\n");
+ LOG("Variable buffer allocated.\n");
/* allocate the buffer for storing JSR target chains */
jsrbuffer = DMNEW(jsr_record*,block_count);
/* initialize the variable types of the first block */
/* to the types of the arguments */
- ttype = vartype;
- tinfo = vartypeinfo;
+ lset = MGET_TYPEVECTOR(localbuf,0,numlocals);
+ td = lset->td;
+ i = numlocals;
/* if this is an instance method initialize the "this" ref type */
if (!(method->flags & ACC_STATIC)) {
- *ttype++ = TYPE_ADDRESS;
+ td->type = TYPE_ADDRESS;
if (initmethod)
- TYPEINFO_INIT_NEWOBJECT(*tinfo,NULL);
+ TYPEINFO_INIT_NEWOBJECT(td->info,NULL);
else
- TYPEINFO_INIT_CLASSINFO(*tinfo,class);
- tinfo++;
+ TYPEINFO_INIT_CLASSINFO(td->info,class);
+ td++;
+ i--;
}
LOG("'this' argument set.\n");
/* the rest of the arguments and the return type */
- typeinfo_init_from_method_args(method->descriptor,ttype,tinfo,
- numlocals - (tinfo-vartypeinfo),
- true, /* two word types use two slots */
- &returntype,&returntypeinfo);
+ i = typedescriptors_init_from_method_args(td,method->descriptor,
+ i,
+ true, /* two word types use two slots */
+ &returntype);
+ td += i;
+ i = numlocals - (td - lset->td);
+ while (i--) {
+ td->type = TYPE_VOID;
+ td++;
+ }
LOG("Arguments set.\n");
handlers[len] = NULL;
/* init variable types at the start of this block */
- for (i=0; i<numlocals; ++i) {
- vtype[i] = vartype[numlocals*b_index + i];
- TYPEINFO_COPY(vartypeinfo[numlocals*b_index + i],vinfo[i]);
-
- if (handlers[0] &&
- vtype[i] == TYPE_ADR && TYPEINFO_IS_NEWOBJECT(vinfo[i]))
- panic("Uninitialized object in local variable inside try block");
- }
+ COPY_TYPEVECTORSET(MGET_TYPEVECTOR(localbuf,b_index,numlocals),
+ localset,numlocals);
+ if (handlers[0])
+ for (i=0; i<numlocals; ++i)
+ if (localset->td[i].type == TYPE_ADR
+ && TYPEINFO_IS_NEWOBJECT(localset->td[i].info))
+ panic("Uninitialized object in local variable inside try block");
/* init JSR target chain */
if ((jsrchain = jsrbuffer[b_index]) != NULL) {
#ifdef TYPECHECK_VERBOSE
if (typecheckverbose) {
if (subroutine) {LOGSTR1("subroutine L%03d\n",subroutine->target->debug_nr);LOGFLUSH;}
- typeinfo_print_block(get_logfile(),curstack,numlocals,vtype,vinfo,(jsrchain) ? touched : NULL);
+ typestate_print(get_logfile(),curstack,localset,numlocals);
LOGNL; LOGFLUSH;
}
#endif
COPYTYPE(curstack->prev,dst);
break;
+ /****************************************/
+ /* PRIMITIVE VARIABLE ACCESS */
+
+ case ICMD_ILOAD: CHECK_ONEWORD(iptr->op1,TYPE_INT); break;
+ case ICMD_FLOAD: CHECK_ONEWORD(iptr->op1,TYPE_FLOAT); break;
+ case ICMD_IINC: CHECK_ONEWORD(iptr->op1,TYPE_INT); break;
+ case ICMD_LLOAD: CHECK_TWOWORD(iptr->op1,TYPE_LONG); break;
+ case ICMD_DLOAD: CHECK_TWOWORD(iptr->op1,TYPE_DOUBLE); break;
+
+ case ICMD_FSTORE: STORE_ONEWORD(iptr->op1,TYPE_FLOAT); break;
+ case ICMD_ISTORE: STORE_ONEWORD(iptr->op1,TYPE_INT); break;
+ case ICMD_LSTORE: STORE_TWOWORD(iptr->op1,TYPE_LONG); break;
+ case ICMD_DSTORE: STORE_TWOWORD(iptr->op1,TYPE_DOUBLE); break;
+
/****************************************/
/* LOADING ADDRESS FROM VARIABLE */
case ICMD_ALOAD:
- CHECK_ONEWORD(iptr->op1,TYPE_ADR);
+ INDEX_ONEWORD(iptr->op1);
/* loading a returnAddress is not allowed */
- if (TYPEINFO_IS_PRIMITIVE(vinfo[iptr->op1]))
- panic("illegal instruction: ALOAD loading returnAddress");
+ if (!typevectorset_checkreference(localset,iptr->op1))
+ panic("illegal instruction: ALOAD loading non-reference");
- TYPEINFO_COPY(vinfo[iptr->op1],dst->typeinfo);
+ typevectorset_copymergedtype(localset,iptr->op1,&(dst->typeinfo));
break;
/****************************************/
if (handlers[0] &&
TYPEINFO_IS_NEWOBJECT(curstack->typeinfo))
panic("Storing uninitialized object in local variable inside try block");
-
- STORE_ONEWORD(iptr->op1,TYPE_ADDRESS);
- TYPEINFO_COPY(curstack->typeinfo,vinfo[iptr->op1]);
+
+ INDEX_ONEWORD(iptr->op1);
+ if (TYPESTACK_IS_RETURNADDRESS(curstack))
+ typevectorset_store_retaddr(localset,iptr->op1,&(curstack->typeinfo));
+ else
+ typevectorset_store(localset,iptr->op1,TYPE_ADDRESS,
+ &(curstack->typeinfo));
break;
/****************************************/
panic("illegal instruction: ARRAYLENGTH on non-array");
maythrow = true;
break;
-
+
+ /* XXX unify cases? */
case ICMD_BALOAD:
if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(curstack->prev->typeinfo,ARRAYTYPE_BOOLEAN)
&& !TYPEINFO_MAYBE_PRIMITIVE_ARRAY(curstack->prev->typeinfo,ARRAYTYPE_BYTE))
break;
/****************************************/
- /* OPERATIONS WITH UNCHECKED INPUT */
+ /* ADDRESS CONSTANTS */
+
+ case ICMD_ACONST:
+ if (iptr->val.a == NULL)
+ TYPEINFO_INIT_NULLTYPE(dst->typeinfo);
+ else
+ /* XXX constants for builtin functions */
+ /* string constants */
+ TYPEINFO_INIT_CLASSINFO(dst->typeinfo,class_java_lang_String);
+ break;
+
+ /****************************************/
+ /* CHECKCAST AND INSTANCEOF */
case ICMD_CHECKCAST:
TYPECHECK_ADR(curstack);
/* XXX optimize statically? */
break;
- case ICMD_ACONST:
- if (iptr->val.a == NULL)
- TYPEINFO_INIT_NULLTYPE(dst->typeinfo);
- else
- /* XXX constants for builtin functions */
- /* string constants */
- TYPEINFO_INIT_CLASSINFO(dst->typeinfo,class_java_lang_String);
- break;
-
/****************************************/
/* BRANCH INSTRUCTIONS */
case ICMD_TABLESWITCH:
{
s4 *s4ptr = iptr->val.a;
- s4ptr++; /* skip default */
- i = *s4ptr++; /* low */
+ s4ptr++; /* skip default */
+ i = *s4ptr++; /* low */
i = *s4ptr++ - i + 2; /* +1 for default target */
}
goto switch_instruction_tail;
case ICMD_LOOKUPSWITCH:
{
s4 *s4ptr = iptr->val.a;
- s4ptr++; /* skip default */
- i = *s4ptr++ + 1; /* count +1 for default target */
+ s4ptr++; /* skip default */
+ i = *s4ptr++ + 1; /* count +1 for default */
}
switch_instruction_tail:
tptr = (basicblock **)iptr->target;
if (!TYPEINFO_IS_REFERENCE(curstack->typeinfo))
panic("illegal instruction: ARETURN on non-reference");
- if (returntype != TYPE_ADDRESS
- || !typeinfo_is_assignable(&curstack->typeinfo,&returntypeinfo))
+ if (returntype.type != TYPE_ADDRESS
+ || !typeinfo_is_assignable(&curstack->typeinfo,&(returntype.info)))
panic("Return type mismatch");
goto return_tail;
case ICMD_IRETURN:
- if (returntype != TYPE_INT) panic("Return type mismatch");
+ if (returntype.type != TYPE_INT) panic("Return type mismatch");
goto return_tail;
case ICMD_LRETURN:
- if (returntype != TYPE_LONG) panic("Return type mismatch");
+ if (returntype.type != TYPE_LONG) panic("Return type mismatch");
goto return_tail;
case ICMD_FRETURN:
- if (returntype != TYPE_FLOAT) panic("Return type mismatch");
+ if (returntype.type != TYPE_FLOAT) panic("Return type mismatch");
goto return_tail;
case ICMD_DRETURN:
- if (returntype != TYPE_DOUBLE) panic("Return type mismatch");
+ if (returntype.type != TYPE_DOUBLE) panic("Return type mismatch");
goto return_tail;
case ICMD_RETURN:
- if (returntype != TYPE_VOID) panic("Return type mismatch");
+ if (returntype.type != TYPE_VOID) panic("Return type mismatch");
return_tail:
TYPECHECK_LEAVE;
superblockend = true;
*/
dst = (stackptr) iptr->val.a;
- /* push return address */
- TYPEINFO_INIT_PRIMITIVE(dst->typeinfo);
+ tbptr = (basicblock *) iptr->target;
+ repeat |= typestate_jsr(localbuf,bptr,tbptr,dst,localset,numlocals);
+#if 0
+ TYPEINFO_INIT_RETURNADDRESS(dst->typeinfo,tbptr);
LOG("reaching block...");
/* add the target to the JSR target chain and */
/* propagate stack and variables to the target block */
- tbptr = (basicblock *) iptr->target;
TYPECHECK_REACH(REACH_JSR);
/* set dst to the stack after the subroutine execution */
repeat = true;
superblockend = true;
}
- /* XXX may throw? I don't think. */
+#endif
+ /* XXX may throw? I don't think so. */
+ superblockend = true;
break;
case ICMD_RET:
/* check returnAddress variable */
- CHECK_ONEWORD(iptr->op1,TYPE_ADR);
-
- if (!TYPEINFO_IS_PRIMITIVE(vinfo[iptr->op1]))
+ INDEX_ONEWORD(iptr->op1);
+ if (!typevectorset_checkretaddr(localset,iptr->op1))
panic("illegal instruction: RET using non-returnAddress variable");
+ repeat |= typestate_ret(localbuf,bptr,curstack,
+ localset,iptr->op1,numlocals);
+
+#if 0
/* check if we are inside a subroutine */
if (!subroutine)
panic("RET outside of subroutine");
+ /* check if the right returnAddress is used (XXX is this too strict?) */
+ if ((basicblock*)TYPEINFO_RETURNADDRESS(vinfo[iptr->op1])
+ != subroutine->target)
+ panic("RET uses returnAddress of another subroutine");
+
/* determine which variables are touched by this subroutine */
/* and their types */
if (subroutine->sbr_touched) {
+ /* We have reached a RET in this subroutine before. */
+
+ /* Check if there is more than one RET instruction
+ * returning from this subroutine. */
+ if (subroutine->sbr_ret != iptr)
+ panic("JSR subroutine has more than one RET instruction");
+
+ /* Merge the array of touched locals and their types */
for (i=0; i<numlocals; ++i)
subroutine->sbr_touched[i] |= touched[i];
ttype = subroutine->sbr_vtype;
tinfo = subroutine->sbr_vinfo;
TYPECHECK_MERGEVARS;
+ /* XXX check if subroutine changed types? */
}
else {
+ /* This is the first time we reach a RET in this subroutine */
+ subroutine->sbr_ret = iptr;
subroutine->sbr_touched = DMNEW(u1,numlocals);
memcpy(subroutine->sbr_touched,touched,sizeof(u1)*numlocals);
subroutine->sbr_vtype = DMNEW(u1,numlocals);
if (vtype[i] == TYPE_ADR)
TYPEINFO_CLONE(vinfo[i],subroutine->sbr_vinfo[i]);
}
- /* XXX check if subroutine changed types? */
LOGSTR("subroutine touches:");
DOLOG(typeinfo_print_locals(get_logfile(),subroutine->sbr_vtype,subroutine->sbr_vinfo,
subroutine->sbr_touched,numlocals));
LOGNL; LOGFLUSH;
- /* reach blocks after JSR statements */
+ /* XXX reach blocks after JSR statements */
for (i=0; i<block_count; ++i) {
tbptr = block + i;
LOG1("block L%03d",tbptr->debug_nr);
continue;
tbptr++;
- LOG1("RET reaches block %04d",tbptr-block);
+ LOG1("RET reaches block L%03d",tbptr->debug_nr);
/*TYPECHECK_REACH(REACH_RET);*/
}
+#endif
superblockend = true;
break;
srcstack = srcstack->prev;
}
/* replace uninitialized object type in locals */
- for (i=0; i<numlocals; ++i) {
- if (vtype[i] == TYPE_ADR
- && TYPEINFO_IS_NEWOBJECT(vinfo[i])
- && TYPEINFO_NEWOBJECT_INSTRUCTION(vinfo[i]) == ins)
- {
- LOG1("replacing uninitialized type in local %d",i);
- TYPEINFO_INIT_CLASSINFO(vinfo[i],initclass);
- }
- }
+ typevectorset_init_object(localset,ins,initclass,numlocals);
/* initializing the 'this' reference? */
if (!ins) {
/* set our marker variable to type int */
LOG("setting <init> marker");
- vtype[numlocals-1] = TYPE_INT;
+ typevectorset_store(localset,numlocals-1,TYPE_INT,NULL);
}
else {
/* initializing an instance created with NEW */
panic("Invalid instruction: NEW creating instance of abstract class");
TYPEINFO_INIT_NEWOBJECT(dst->typeinfo,iptr);
}
- /* XXX unify the following cases */
+ /* XXX unify the following cases? */
else if (ISBUILTIN(BUILTIN_newarray_boolean)) {
TYPECHECK_INT(curstack);
TYPEINFO_INIT_PRIMITIVE_ARRAY(dst->typeinfo,ARRAYTYPE_BOOLEAN);
break;
/****************************************/
- /* PRIMITIVE VARIABLE ACCESS */
+ /* UNCHECKED OPERATIONS */
+
+ /* These ops have no input or output to be checked */
+ /* (apart from the checks done in analyse_stack). */
+ /* XXX only add cases for them in debug mode? */
+
+ case ICMD_NOP:
+ case ICMD_POP:
+ case ICMD_POP2:
+ break;
+
+ /****************************************/
+ /* SIMPLE EXCEPTION THROWING TESTS */
+
+ case ICMD_CHECKASIZE:
+ /* The argument to CHECKASIZE is typechecked by
+ * typechecking the array creation instructions. */
+
+ /* FALLTHROUGH! */
+ case ICMD_NULLCHECKPOP:
+ /* NULLCHECKPOP just requires that the stack top
+ * is an address. This is checked in stack.c */
+
+ maythrow = true;
+ break;
- case ICMD_ILOAD: CHECK_ONEWORD(iptr->op1,TYPE_INT); break;
- case ICMD_FLOAD: CHECK_ONEWORD(iptr->op1,TYPE_FLOAT); break;
- case ICMD_IINC: CHECK_ONEWORD(iptr->op1,TYPE_INT); break;
- case ICMD_LLOAD: CHECK_TWOWORD(iptr->op1,TYPE_LONG); break;
- case ICMD_DLOAD: CHECK_TWOWORD(iptr->op1,TYPE_DOUBLE); break;
-
- case ICMD_FSTORE: STORE_ONEWORD(iptr->op1,TYPE_FLOAT); break;
- case ICMD_ISTORE: STORE_ONEWORD(iptr->op1,TYPE_INT); break;
- case ICMD_LSTORE: STORE_TWOWORD(iptr->op1,TYPE_LONG); break;
- case ICMD_DSTORE: STORE_TWOWORD(iptr->op1,TYPE_DOUBLE); break;
-
/****************************************/
/* INSTRUCTIONS WHICH SHOULD HAVE BEEN */
- /* REPLACED BY BUILTIN CALLS */
+ /* REPLACED BY OTHER OPCODES */
case ICMD_NEW:
case ICMD_NEWARRAY:
panic("Internal error: unexpected instruction encountered");
break;
- /****************************************/
- /* UNCHECKED OPERATIONS */
-
- /* These ops have no input or output to be checked */
- /* (apart from the checks done in analyse_stack). */
- /* XXX only add cases for them in debug mode? */
-
- case ICMD_NOP:
- case ICMD_POP:
- case ICMD_POP2:
- case ICMD_READONLY_ARG: /* XXX ? */
- case ICMD_CLEAR_ARGREN: /* XXX ? */
- break;
-
- case ICMD_CHECKASIZE:
- case ICMD_NULLCHECKPOP:
- maythrow = true;
+ case ICMD_READONLY_ARG:
+ case ICMD_CLEAR_ARGREN:
+ /* XXX only check this in debug mode? */
+ LOG2("ICMD %d at %d\n", iptr->opc, (int)(iptr-instr));
+ LOG("Should have been replaced in stack.c.");
+ panic("Internal error: unexpected pseudo instruction encountered");
break;
-
+
/****************************************/
/* ARITHMETIC AND CONVERSION */
- /* (These instructions are typechecked in analyse_stack.) */
- /* The following instructions may throw a runtime exception: */
+ /*********************************************
+ * Instructions below...
+ * *) don't operate on local variables,
+ * *) don't operate on references,
+ * *) don't operate on returnAddresses.
+ *
+ * (These instructions are typechecked in
+ * analyse_stack.)
+ ********************************************/
+
+ /* Instructions which may throw a runtime exception: */
case ICMD_IDIV:
case ICMD_IREM:
maythrow = true;
break;
- /* The following instructions never throw a runtime exception: */
+ /* Instructions which never throw a runtime exception: */
/* XXX only add cases for them in debug mode? */
case ICMD_ICONST:
i = 0;
while (handlers[i]) {
tbptr = handlers[i]->handler;
- TYPECHECK_REACH(REACH_THROW); /* XXX jsr chain? */
+ repeat |= typestate_reach(localbuf,bptr,tbptr,
+ tbptr->instack,localset,numlocals);
i++;
}
}
LOG("instructions done");
LOGSTR("RESULT=> ");
- DOLOG(typeinfo_print_block(get_logfile(),curstack,numlocals,vtype,vinfo,(jsrchain) ? touched : NULL));
+ DOLOG(typestate_print(get_logfile(),curstack,localset,numlocals));
LOGNL; LOGFLUSH;
/* propagate stack and variables to the following block */
Mark Probst
Edwin Steiner
- $Id: loader.c 867 2004-01-07 22:05:04Z edwin $
+ $Id: loader.c 868 2004-01-10 20:12:10Z edwin $
*/
checks whether a method-descriptor is valid and aborts otherwise.
All referenced classes are inserted into the list of unloaded classes.
+
+ The number of arguments is returned. A long or double argument is counted
+ as two arguments.
*******************************************************************************/
-static void checkmethoddescriptor (utf *d)
+static int checkmethoddescriptor (utf *d)
{
char *utf_ptr = d->text; /* current position in utf text */
char *end_pos = utf_end(d); /* points behind utf string */
/* XXX we cannot count the this argument here because
* we don't know if the method is static. */
if (*utf_ptr == 'J' || *utf_ptr == 'D')
+ argcount+=2;
+ else
argcount++;
- if (++argcount > 255)
- panic("Invalid method descriptor: too many arguments");
class_from_descriptor(utf_ptr,end_pos,&utf_ptr,
CLASSLOAD_NEW
| CLASSLOAD_NULLPRIMITIVE
| CLASSLOAD_NULLPRIMITIVE
| CLASSLOAD_CHECKEND);
+ if (argcount > 255)
+ panic("Invalid method descriptor: too many arguments");
+
+ return argcount;
+
/* XXX use the following if -noverify */
#if 0
/* XXX check length */
if ((f->flags & (ACC_STATIC | ACC_PUBLIC | ACC_FINAL))
!= (ACC_STATIC | ACC_PUBLIC | ACC_FINAL))
panic("Interface field is not declared static final public");
+ if ((f->flags & ACC_TRANSIENT) != 0)
+ panic("Interface field declared transient");
}
}
static void method_load(methodinfo *m, classinfo *c)
{
u4 attrnum, i, e;
+ int argcount;
#ifdef STATISTICS
count_all_methods++;
m->flags = suck_u2();
m->name = class_getconstant(c, suck_u2(), CONSTANT_Utf8);
m->descriptor = class_getconstant(c, suck_u2(), CONSTANT_Utf8);
- checkmethoddescriptor(m->descriptor);
+ argcount = checkmethoddescriptor(m->descriptor);
+ if ((m->flags & ACC_STATIC) == 0)
+ argcount++; /* count the 'this' argument */
- /* check flag consistency */
if (opt_verify) {
+ if (argcount > 255)
+ panic("Method has more than 255 arguments");
+
+ /* check flag consistency */
/* XXX could check if <clinit> is STATIC */
if (m->name != utf_clinit) {
i = (m->flags & (ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED));
suck_u4();
m->maxstack = suck_u2();
m->maxlocals = suck_u2();
+ if (m->maxlocals < argcount)
+ panic("max_locals is smaller than the number of arguments");
+
codelen = suck_u4();
if (codelen == 0)
panic("bytecode has zero length");
ASSERT_LEFT(length);
if (opt_verify &&
!is_valid_utf(classbuf_pos+1, classbuf_pos+1+length))
- panic("Invalid UTF-8 string");
+ {
+ dolog("Invalid UTF-8 string (constant pool index %d)",idx);
+ panic("Invalid UTF-8 string");
+ }
/* insert utf-string into the utf-symboltable */
cpinfos [idx] = utf_new(classbuf_pos+1, length);
/* skip bytes of the string */
/* check ACC flags consistency */
if ((c->flags & ACC_INTERFACE) != 0) {
- if ((c->flags & ACC_ABSTRACT) == 0)
- panic("Interface class not declared abstract");
+ if ((c->flags & ACC_ABSTRACT) == 0) {
+ /* XXX We work around this because interfaces in JDK 1.1 are
+ * not declared abstract. */
+
+ c->flags |= ACC_ABSTRACT;
+ /* panic("Interface class not declared abstract"); */
+ }
if ((c->flags & (ACC_FINAL | ACC_SUPER)) != 0)
panic("Interface class has invalid flags");
}
+ if ((c->flags & (ACC_ABSTRACT | ACC_FINAL)) == (ACC_ABSTRACT | ACC_FINAL))
+ panic("Class is declared both abstract and final");
/* this class */
i = suck_u2();
list_addlast(&unlinkedclasses, c);
return;
}
- if ((ic->flags & ACC_INTERFACE) == 0)
+ if ((ic->flags & ACC_INTERFACE) == 0) {
+ dolog("Specified interface is not declared as interface:");
+ log_utf(ic->name);
+ dolog("in");
+ log_utf(c->name);
panic("Specified interface is not declared as interface");
+ }
}
/* check super class */
calls instead of machine instructions, using the C calling
convention.
- $Id: builtin.c 862 2004-01-06 23:42:01Z stefan $
+ $Id: builtin.c 868 2004-01-10 20:12:10Z edwin $
*/
return (java_arrayheader *) Java_java_lang_VMObject_clone(0, 0, (java_lang_Cloneable *) o);
}
+s4 builtin_dummy()
+{
+ panic("Internal error: builtin_dummy called (native function is missing)");
+ return 0; /* for the compiler */
+}
+
/*
* These are local overrides for various environment variables in Emacs.
Changes: Edwin Steiner
- $Id: builtin.h 862 2004-01-06 23:42:01Z stefan $
+ $Id: builtin.h 868 2004-01-10 20:12:10Z edwin $
*/
java_arrayheader *builtin_clone_array(void *env, java_arrayheader *o);
/* NOT AN OP */
+/* builtin_dummy just panics if it is executed. */
+s4 builtin_dummy();
+/* NOT AN OP */
+
/* conversion helper functions */
inline float intBitsToFloat(s4 i);
Changes: Christian Thalinger
- $Id: jit.h 845 2004-01-05 10:38:06Z twisti $
+ $Id: jit.h 868 2004-01-10 20:12:10Z edwin $
*/
};
+/********** op1 values for ACONST instructions ********************************/
+
+#define ACONST_LOAD 0 /* ACONST_NULL or LDC instruction */
+#define ACONST_BUILTIN 1 /* constant argument for a builtin function call */
+
/********** JavaVM operation codes (sorted) and instruction lengths ***********/
extern char *icmd_names[256];
Changes: Carolyn Oates
Edwin Steiner
- $Id: parse.c 863 2004-01-07 18:50:41Z edwin $
+ $Id: parse.c 868 2004-01-10 20:12:10Z edwin $
*/
#define LOADCONST_F(v) iptr->opc=ICMD_FCONST;iptr->op1=0;iptr->val.f=(v);PINC
#define LOADCONST_D(v) iptr->opc=ICMD_DCONST;iptr->op1=0;iptr->val.d=(v);PINC
#define LOADCONST_A(v) iptr->opc=ICMD_ACONST;iptr->op1=0;iptr->val.a=(v);PINC
+
+/* ACONST instructions generated as arguments for builtin functions
+ * have op1 set to non-zero. This is used for stack overflow checking
+ * in stack.c. */
+#define LOADCONST_A_BUILTIN(v) \
+ iptr->opc=ICMD_ACONST;iptr->op1=1;iptr->val.a=(v);PINC
+
#define OP(o) iptr->opc=(o);iptr->op1=0;iptr->val.l=0;PINC
#define OP1(o,o1) iptr->opc=(o);iptr->op1=(o1);iptr->val.l=(0);PINC
#define OP2I(o,o1,v) iptr->opc=(o);iptr->op1=(o1);iptr->val.i=(v);PINC
i = code_get_u2(p + 1);
{
classinfo *component = (classinfo*)class_getconstant(class, i, CONSTANT_Class);
- LOADCONST_A(class_array_of(component)->vftbl);
+ LOADCONST_A_BUILTIN(class_array_of(component)->vftbl);
s_count++;
case JAVA_NEW:
i = code_get_u2 (p+1);
- LOADCONST_A(class_getconstant(class, i, CONSTANT_Class));
+ LOADCONST_A_BUILTIN(class_getconstant(class, i, CONSTANT_Class));
s_count++;
BUILTIN1(BUILTIN_new, TYPE_ADR);
break;
classinfo *cls = (classinfo*)class_getconstant(class, i, CONSTANT_Class);
if (cls->vftbl->arraydesc) {
/* array type cast-check */
- LOADCONST_A(cls->vftbl);
+ LOADCONST_A_BUILTIN(cls->vftbl);
s_count++;
BUILTIN2(BUILTIN_checkarraycast, TYPE_ADR);
}
else { /* object type cast-check */
/*
-+ LOADCONST_A(class_getconstant(class, i, CONSTANT_Class));
++ LOADCONST_A_BUILTIN(class_getconstant(class, i, CONSTANT_Class));
+ s_count++;
+ BUILTIN2(BUILTIN_checkcast, TYPE_ADR);
+ */
classinfo *cls = (classinfo*)class_getconstant(class, i, CONSTANT_Class);
if (cls->vftbl->arraydesc) {
/* array type cast-check */
- LOADCONST_A(cls->vftbl);
+ LOADCONST_A_BUILTIN(cls->vftbl);
s_count++;
BUILTIN2(BUILTIN_arrayinstanceof, TYPE_INT);
}
else { /* object type cast-check */
/*
- LOADCONST_A(class_getconstant(class, i, CONSTANT_Class));
+ LOADCONST_A_BUILTIN(class_getconstant(class, i, CONSTANT_Class));
s_count++;
BUILTIN2(BUILTIN_instanceof, TYPE_INT);
+ */
Changes: Edwin Steiner
- $Id: stack.c 846 2004-01-05 10:40:42Z twisti $
+ $Id: stack.c 868 2004-01-10 20:12:10Z edwin $
*/
#define REQUIRE_4 REQUIRE(4)
/* overflow check */
-/* XXX we allow ACONST to exceed the maximum stack depth because it is
- * generated for builtin calls. Maybe we should check against maximum
- * stack depth only at block boundaries?
+/* XXX we allow ACONST instructions inserted as arguments to builtin
+ * functions to exceed the maximum stack depth. Maybe we should check
+ * against maximum stack depth only at block boundaries?
*/
#define CHECKOVERFLOW \
do { \
if (stackdepth > maxstack) { \
- if (iptr[0].opc != ICMD_ACONST) \
+ if (iptr[0].opc != ICMD_ACONST \
+ || iptr[0].op1 == 0) \
{OVERFLOW;} \
} \
} while(0)
* - check for matching stack depth at merging points
* - check for matching basic types[2] at merging points
* - check basic types for instruction input (except for BUILTIN*
- * opcodes and MULTIANEWARRAY)
+ * opcodes, INVOKE* opcodes and MULTIANEWARRAY)
*
* [1]) XXX Checking this after the instruction should be ok. parse.c
* counts the number of required stack slots in such a way that it is
iptr->val.a = (void *) iptr->dst;
tbptr->type = BBTYPE_SBR;
+
+ /* We need to check for overflow right here because
+ * the pushed value is poped after MARKREACHED. */
CHECKOVERFLOW;
MARKREACHED(tbptr, copy);
OP1_0ANY;
Authors: Edwin Steiner
- $Id: typecheck.c 822 2003-12-31 16:00:58Z edwin $
+ $Id: typecheck.c 868 2004-01-10 20:12:10Z edwin $
*/
typeinfo_print_locals(file,vtype,vinfo,touched,vnum);
}
+static
+void
+typestack_print(FILE *file,stackptr stack)
+{
+ while (stack) {
+ typeinfo_print_stacktype(file,stack->type,&stack->typeinfo);
+ stack = stack->prev;
+ if (stack) fprintf(file," ");
+ }
+}
+
+static
+void
+typestate_print(FILE *file,stackptr instack,typevector *localset,int size)
+{
+ fprintf(file,"Stack: ");
+ typestack_print(file,instack);
+ fprintf(file," Locals:");
+ typevectorset_print(file,localset,size);
+}
+
#if 0
static
#endif
+/****************************************************************************/
+/* TYPESTACK FUNCTIONS */
+/****************************************************************************/
+
+#define TYPESTACK_IS_RETURNADDRESS(sptr) \
+ TYPE_IS_RETURNADDRESS((sptr)->type,(sptr)->typeinfo)
+
+#define TYPESTACK_IS_REFERENCE(sptr) \
+ TYPE_IS_REFERENCE((sptr)->type,(sptr)->typeinfo)
+
+#define TYPESTACK_RETURNADDRESSSET(sptr) \
+ ((typeinfo_retaddr_set*)TYPEINFO_RETURNADDRESS((sptr)->typeinfo))
+
+#define RETURNADDRESSSET_SEEK(set,pos) \
+ do {int i; for (i=pos;i--;) set=set->alt;} while(0)
+
+static void
+typestack_copy(stackptr dst,stackptr y,typevector *selected)
+{
+ typevector *sel;
+ typeinfo_retaddr_set *sety;
+ typeinfo_retaddr_set *new;
+ typeinfo_retaddr_set **next;
+ int k;
+
+ for (;dst; dst=dst->prev, y=y->prev) {
+ if (!y) panic("Stack depth mismatch");
+ if (dst->type != y->type)
+ panic("Stack type mismatch");
+ LOG3("copy %p -> %p (type %d)",y,dst,dst->type);
+ if (dst->type == TYPE_ADDRESS) {
+ if (TYPEINFO_IS_PRIMITIVE(y->typeinfo)) {
+ /* We copy the returnAddresses from the selected
+ * states only. */
+
+ LOG("copying returnAddress");
+ sety = TYPESTACK_RETURNADDRESSSET(y);
+ next = &new;
+ for (k=0,sel=selected; sel; sel=sel->alt) {
+ LOG1("selected k=%d",sel->k);
+ while (k<sel->k) {
+ sety = sety->alt;
+ k++;
+ }
+ *next = DNEW(typeinfo_retaddr_set);
+ (*next)->addr = sety->addr;
+ next = &((*next)->alt);
+ }
+ *next = NULL;
+ TYPEINFO_INIT_RETURNADDRESS(dst->typeinfo,new);
+ }
+ else {
+ TYPEINFO_CLONE(y->typeinfo,dst->typeinfo);
+ }
+ }
+ }
+ if (y) panic("Stack depth mismatch");
+}
+
+static void
+typestack_put_retaddr(stackptr dst,void *retaddr,typevector *loc)
+{
+#ifdef TYPECHECK_DEBUG
+ if (dst->type != TYPE_ADDRESS)
+ panic("Internal error: Storing returnAddress in non-address slot");
+#endif
+
+
+ TYPEINFO_INIT_RETURNADDRESS(dst->typeinfo,NULL);
+ for (;loc; loc=loc->alt) {
+ typeinfo_retaddr_set *set = DNEW(typeinfo_retaddr_set);
+ set->addr = retaddr;
+ set->alt = TYPESTACK_RETURNADDRESSSET(dst);
+ TYPEINFO_INIT_RETURNADDRESS(dst->typeinfo,set);
+ }
+}
+
+static bool
+typestack_canmerge(stackptr a,stackptr b)
+{
+ for (; a; a = a->prev, b = b->prev) {
+ if (!b) return false;
+ if (a->type != b->type) return false;
+ if (a->type == TYPE_ADDRESS) {
+ if (((TYPEINFO_IS_PRIMITIVE(a->typeinfo)) ? 1 : 0)
+ ^
+ ((TYPEINFO_IS_PRIMITIVE(b->typeinfo)) ? 1 : 0))
+ return false;
+ }
+ }
+ if (b) return false;
+ return true;
+}
+
+static void
+typestack_collapse(stackptr dst)
+{
+ for (; dst; dst = dst->prev) {
+ if (TYPESTACK_IS_RETURNADDRESS(dst))
+ TYPESTACK_RETURNADDRESSSET(dst)->alt = NULL;
+ }
+}
+
+/* 'dst' and 'y' are assumed to have passed typestack_canmerge! */
+static bool
+typestack_merge(stackptr dst,stackptr y)
+{
+ bool changed = false;
+ for (; dst; dst = dst->prev, y=y->prev) {
+ if (TYPESTACK_IS_REFERENCE(dst))
+ changed |= typeinfo_merge(&(dst->typeinfo),&(y->typeinfo));
+ }
+ return changed;
+}
+
+static void
+typestack_add(stackptr dst,stackptr y,int ky)
+{
+ typeinfo_retaddr_set *setd;
+ typeinfo_retaddr_set *sety;
+
+ for (; dst; dst = dst->prev, y=y->prev) {
+ if (TYPESTACK_IS_RETURNADDRESS(dst)) {
+ setd = TYPESTACK_RETURNADDRESSSET(dst);
+ sety = TYPESTACK_RETURNADDRESSSET(y);
+ RETURNADDRESSSET_SEEK(sety,ky);
+ while (setd->alt)
+ setd=setd->alt;
+ setd->alt = DNEW(typeinfo_retaddr_set);
+ setd->alt->addr = sety->addr;
+ setd->alt->alt = NULL;
+ }
+ }
+}
+
+/* 'a' and 'b' are assumed to have passed typestack_canmerge! */
+static bool
+typestack_separable_with(stackptr a,stackptr b,int kb)
+{
+ typeinfo_retaddr_set *seta;
+ typeinfo_retaddr_set *setb;
+
+ for (; a; a = a->prev, b = b->prev) {
+#ifdef TYPECHECK_DEBUG
+ if (!b) panic("Internal error: typestack_separable_from: different depth");
+#endif
+ if (TYPESTACK_IS_RETURNADDRESS(a)) {
+#ifdef TYPECHECK_DEBUG
+ if (!TYPESTACK_IS_RETURNADDRESS(b))
+ panic("Internal error: typestack_separable_from: unmergable stacks");
+#endif
+ seta = TYPESTACK_RETURNADDRESSSET(a);
+ setb = TYPESTACK_RETURNADDRESSSET(b);
+ RETURNADDRESSSET_SEEK(setb,kb);
+
+ for (;seta;seta=seta->alt)
+ if (seta->addr != setb->addr) return true;
+ }
+ }
+#ifdef TYPECHECK_DEBUG
+ if (b) panic("Internal error: typestack_separable_from: different depth");
+#endif
+ return false;
+}
+
+/* 'a' and 'b' are assumed to have passed typestack_canmerge! */
+static bool
+typestack_separable_from(stackptr a,int ka,stackptr b,int kb)
+{
+ typeinfo_retaddr_set *seta;
+ typeinfo_retaddr_set *setb;
+ int i;
+
+ for (; a; a = a->prev, b = b->prev) {
+#ifdef TYPECHECK_DEBUG
+ if (!b) panic("Internal error: typestack_separable_from: different depth");
+#endif
+ if (TYPESTACK_IS_RETURNADDRESS(a)) {
+#ifdef TYPECHECK_DEBUG
+ if (!TYPESTACK_IS_RETURNADDRESS(b))
+ panic("Internal error: typestack_separable_from: unmergable stacks");
+#endif
+ seta = TYPESTACK_RETURNADDRESSSET(a);
+ setb = TYPESTACK_RETURNADDRESSSET(b);
+ RETURNADDRESSSET_SEEK(seta,ka);
+ RETURNADDRESSSET_SEEK(setb,kb);
+
+ if (seta->addr != setb->addr) return true;
+ }
+ }
+#ifdef TYPECHECK_DEBUG
+ if (b) panic("Internal error: typestack_separable_from: different depth");
+#endif
+ return false;
+}
+
+/****************************************************************************/
+/* TYPESTATE FUNCTIONS */
+/****************************************************************************/
+
+static bool
+typestate_merge(stackptr deststack,typevector *destloc,
+ stackptr ystack,typevector *yloc,
+ /* int retindex,void *retaddr, */
+ int locsize)
+{
+ typevector *dvec,*yvec;
+ int kd,ky;
+ bool changed = false;
+
+#ifdef TYPECHECK_DEBUG
+ /* Do some sanity checks */
+ /*
+ if (retindex < -1 || retindex >= locsize || (retindex >= 0 && !retaddr))
+ panic("Internal error: typestate_merge: invalid arguments");
+ */
+#endif
+
+ LOG("merge:");
+ LOGSTR("dstack: "); DOLOG(typestack_print(get_logfile(),deststack)); LOGNL;
+ LOGSTR("ystack: "); DOLOG(typestack_print(get_logfile(),ystack)); LOGNL;
+ LOGSTR("dloc : "); DOLOG(typevectorset_print(get_logfile(),destloc,locsize)); LOGNL;
+ LOGSTR("yloc : "); DOLOG(typevectorset_print(get_logfile(),yloc,locsize)); LOGNL;
+
+ /* Check if the stack types of deststack and ystack match */
+
+ /* XXX move this check into typestack_merge? */
+ if (!typestack_canmerge(deststack,ystack))
+ panic("Stack depth or stack type mismatch");
+
+ /* The stack is always merged. If there are returnAddresses on
+ * the stack they are ignored in this step. */
+
+ changed |= typestack_merge(deststack,ystack);
+
+ for (yvec=yloc; yvec; yvec=yvec->alt) {
+ ky = yvec->k;
+
+ /* If retindex >= 0 we select only those states (ystack,yvec)
+ * with returnAddress retaddr in variable no. retindex. */
+
+ /*
+ if (retindex >= 0) {
+ if (!TYPEDESC_IS_RETURNADDRESS(yvec->td[retindex]))
+ panic("Illegal instruction: RET on non-returnAddress");
+ if (TYPEINFO_RETURNADDRESS(yvec->td[retindex].info)
+ != retaddr)
+ continue;
+ }
+ */
+
+ /* Check if the typestates (deststack,destloc) will be
+ * separable when (ystack,yvec) is added. */
+
+ if (!typestack_separable_with(deststack,ystack,ky)
+ && !typevectorset_separable_with(destloc,yvec,locsize))
+ {
+ /* No, the resulting set won't be separable, thus we
+ * may merge all states in (deststack,destloc) and
+ * (ystack,yvec). */
+
+ typestack_collapse(deststack);
+ typevectorset_collapse(destloc,locsize);
+ typevector_merge(destloc,yvec,locsize);
+ }
+ else {
+ /* Yes, the resulting set will be separable. Thus we check
+ * if we may merge (ystack,yvec) with a single state in
+ * (deststack,destloc). */
+
+ for (dvec=destloc,kd=0; dvec; dvec=dvec->alt, kd++) {
+ if (!typestack_separable_from(ystack,ky,deststack,kd)
+ && !typevector_separable_from(yvec,dvec,locsize))
+ {
+ /* The typestate (ystack,yvec) is not separable from
+ * (deststack,dvec) by any returnAddress. Thus we may
+ * merge the states. */
+
+ changed |= typevector_merge(dvec,yvec,locsize);
+
+ goto merged;
+ }
+ }
+
+ /* The typestate (ystack,yvec) is separable from all typestates
+ * (deststack,destloc). Thus we must add this state to the
+ * result set. */
+
+ typestack_add(deststack,ystack,ky);
+ typevectorset_add(destloc,yvec,locsize);
+ changed = true;
+ }
+
+ merged:
+
+ }
+
+ LOG("result:");
+ LOGSTR("dstack: "); DOLOG(typestack_print(get_logfile(),deststack)); LOGNL;
+ LOGSTR("dloc : "); DOLOG(typevectorset_print(get_logfile(),destloc,locsize)); LOGNL;
+
+ return changed;
+}
+
+/* Globals used:
+ * block
+ */
+static bool
+typestate_reach(void *localbuf,
+ basicblock *current,
+ basicblock *destblock,
+ stackptr ystack,typevector *yloc,
+ int locsize)
+{
+ typevector *yvec;
+ typevector *destloc;
+ int destidx;
+ bool repeat = false;
+ bool changed = false;
+
+ destidx = destblock - block;
+ destloc = MGET_TYPEVECTOR(localbuf,destidx,locsize);
+
+ if (destblock->flags == BBTYPECHECK_UNDEF) {
+ /* The destblock has never been reached before */
+
+ LOG1("block (index %04d) reached first time",destidx);
+
+ typestack_copy(destblock->instack,ystack,yloc);
+ COPY_TYPEVECTORSET(yloc,destloc,locsize);
+ changed = true;
+ }
+ else {
+ /* The destblock has already been reached before */
+
+ LOG1("block (index %04d) reached before",destidx);
+
+ changed = typestate_merge(destblock->instack,destloc,
+ ystack,yloc,locsize);
+ }
+
+ if (changed) {
+ LOG("changed!");
+ destblock->flags = BBTYPECHECK_REACHED;
+ if (destblock <= current) {repeat = true; LOG("REPEAT!");}
+ }
+ return repeat;
+}
+
+/* Globals used:
+ * see typestate_reach
+ */
+static bool
+typestate_ret(void *localbuf,
+ basicblock *current,
+ stackptr ystack,typevector *yloc,
+ int retindex,int locsize)
+{
+ typevector *yvec;
+ typevector *selected;
+ basicblock *destblock;
+ bool repeat = false;
+
+ for (yvec=yloc; yvec; ) {
+ if (!TYPEDESC_IS_RETURNADDRESS(yvec->td[retindex]))
+ panic("Illegal instruction: RET on non-returnAddress");
+
+ destblock = (basicblock*) TYPEINFO_RETURNADDRESS(yvec->td[retindex].info);
+
+ selected = typevectorset_select(&yvec,retindex,destblock);
+
+ repeat |= typestate_reach(localbuf,current,destblock,
+ ystack,selected,locsize);
+ }
+ return repeat;
+}
+
+static bool
+typestate_jsr(void *localbuf,
+ basicblock *current,basicblock *destblock,
+ stackptr ystack,typevector *yloc,
+ int locsize)
+{
+ typestack_put_retaddr(ystack,current+1,yloc);
+ return typestate_reach(localbuf,current,destblock,ystack,yloc,locsize);
+}
+
/****************************************************************************/
/* HELPER FUNCTIONS */
/****************************************************************************/
* jsr_record of the first block of the subroutine.
*/
struct jsr_record {
- basicblock *target; /* target of the JSR instruction (first block of subroutine) */
- jsr_record *next; /* for chaining in nested try ... finally */ /* XXX make it sbr_next? */
- u1 *sbr_touched; /* specifies which variables the subroutine touches */
- u1 *sbr_vtype; /* Types of local variables after RET */
- typeinfo *sbr_vinfo; /* Types of local variables after RET */
- u1 touched[1]; /* touched flags for local variables */
+ basicblock *target; /* target of the JSR instruction (first block of subroutine) */
+ jsr_record *next; /* for chaining in nested try ... finally */ /* XXX make it sbr_next? */
+ u1 *sbr_touched; /* specifies which variables the subroutine touches */
+ u1 *sbr_vtype; /* Types of local variables after RET */
+ typeinfo *sbr_vinfo; /* Types of local variables after RET */
+ instruction *sbr_ret; /* RET instruction of the subroutine */
+ u1 touched[1]; /* touched flags for local variables */
};
/****************************************************************************/
#define STORE_ONEWORD(num,type) \
do {INDEX_ONEWORD(num); \
- SET_VARIABLE(num,type);} while(0)
+ typevectorset_store(localset,num,type,NULL);} while(0)
#define STORE_TWOWORD(num,type) \
do {INDEX_TWOWORD(num); \
- SET_VARIABLE(num,type); \
- vtype[(num)+1] = TYPE_VOID; \
- TOUCH_VARIABLE((num)+1);} while(0)
+ typevectorset_store_twoword(localset,num,type);} while(0)
#define CHECK_ONEWORD(num,type) \
do {INDEX_ONEWORD(num); \
- if (vtype[(num)] != (type)) panic("Variable type mismatch"); \
- TOUCH_VARIABLE(num);} while(0)
+ if (!typevectorset_checktype(localset,num,type)) \
+ panic("Variable type mismatch"); \
+ } while(0)
#define CHECK_TWOWORD(num,type) \
do {INDEX_TWOWORD(num); \
- if (vtype[(num)] != (type)) panic("Variable type mismatch"); \
- TOUCH_VARIABLE(num); \
- TOUCH_VARIABLE((num)+1);} while(0)
+ if (!typevectorset_checktype(localset,num,type)) \
+ panic("Variable type mismatch"); \
+ } while(0)
/* XXX maybe it's faster to copy always */
#define COPYTYPE(source,dest) \
srcstack = srcstack->prev; \
} \
for (macro_i=0; macro_i<numlocals; ++macro_i) \
- if (vtype[macro_i] == TYPE_ADR && \
- TYPEINFO_IS_NEWOBJECT(vinfo[macro_i])) \
+ if (localset->td[macro_i].type == TYPE_ADR && \
+ TYPEINFO_IS_NEWOBJECT(localset->td[macro_i].info)) \
panic("Branching backwards with uninitialized object in local variable"); \
} while(0)
#define TYPECHECK_REACH(way) \
do { \
LOG2("reaching block %04d (%d)",tbptr-block,way); \
- if (tbptr <= bptr && way != REACH_THROW) \
+ if (tbptr <= bptr) \
TYPECHECK_BRANCH_BACKWARDS; \
- srcstack = dst; \
- dststack = tbptr->instack; \
- ttype = vartype + numlocals*(tbptr-block); \
- tinfo = vartypeinfo + numlocals*(tbptr-block); \
- if (tbptr->flags == BBTYPECHECK_UNDEF) { \
- /* This block is reached for the first time */ \
- if (way == REACH_JSR) { \
- TYPECHECK_ADD_JSR; \
- TYPECHECK_COPYVARS; \
- } \
- else { \
- if (way != REACH_THROW) TYPECHECK_COPYJSR(jsrchain); \
- TYPECHECK_COPYVARS; \
- } \
- if (way != REACH_THROW) TYPECHECK_COPYSTACK; \
- changed = true; \
- } else { \
- /* This block has been reached before */ \
- changed = false; \
- if (way == REACH_JSR) \
- TYPECHECK_CHECK_JSR_CHAIN; \
- else if (way != REACH_THROW) \
- TYPECHECK_MERGEJSR; \
- TYPECHECK_MERGEVARS; \
- if (way != REACH_THROW) TYPECHECK_MERGESTACK; \
- } \
- if (changed) { \
- LOG("REACHED!"); \
- tbptr->flags = BBTYPECHECK_REACHED; \
- if (tbptr <= bptr) {repeat = true; LOG("REPEAT!");} \
- } \
+ repeat |= typestate_reach(localbuf,bptr,tbptr,dst, \
+ localset,numlocals); \
LOG("done."); \
} while (0)
if (initmethod && class != class_java_lang_Object) { \
/* check the marker variable */ \
LOG("Checking <init> marker"); \
- if (vtype[numlocals-1] == TYPE_VOID) \
+ if (!typevectorset_checktype(localset,numlocals-1,TYPE_INT))\
panic("<init> method does not initialize 'this'"); \
} \
} while (0)
basicblock *tbptr; /* temporary for target block */
int numlocals; /* number of local variables */
int validlocals; /* number of valid local variable indices */
- u1 *vartype; /* type of each local for each basic block */
- typeinfo *vartypeinfo; /* type of each local for each basic block */
- u1 *vtype; /* type of each local for current instruction */
- typeinfo *vinfo; /* type of each local for current instruction */
- u1 *ttype; /* temporary pointer */
- typeinfo *tinfo; /* temporary pointer */
+
+ void *localbuf; /* local variable types for each block start */
+ typevector *localset; /* typevector set for local variables */
+ typevector *lset; /* temporary pointer */
+ typedescriptor *td; /* temporary pointer */
+
typeinfo tempinfo; /* temporary */
- int returntype; /* return type of current method */
- typeinfo returntypeinfo; /* typeinfo for return type */
+
+ typedescriptor returntype; /* return type of current method */
+
u1 *ptype; /* parameter types of called method */
typeinfo *pinfo; /* parameter typeinfos of called method */
int rtype; /* return type of called method */
typeinfo rinfo; /* typeinfo for return type of called method */
stackptr dst; /* output stack of current instruction */
- basicblock **tptr; /* pointer into target list of switch instructions */
+ basicblock **tptr; /* pointer into target list of switch instr. */
jsr_record **jsrbuffer; /* JSR target chain for each basic block */
jsr_record *jsrchain; /* JSR chain for current block */
jsr_record *jsrtemp,*jsrtemp2; /* temporary variables */
if (initmethod) numlocals++;
/* allocate the buffers for local variables */
- vartype = DMNEW(u1,numlocals * (block_count+1));
- vartypeinfo = DMNEW(typeinfo,numlocals * (block_count+1));
- touched = DMNEW(u1,numlocals);
- vtype = vartype + numlocals * block_count;
- vinfo = vartypeinfo + numlocals * block_count;
- memset(vartype,TYPE_VOID,numlocals * (block_count+1) * sizeof(u1));
- memset(vartypeinfo,0,numlocals * (block_count+1) * sizeof(typeinfo));
+ localbuf = DMNEW_TYPEVECTOR(block_count+1, numlocals);
+ localset = MGET_TYPEVECTOR(localbuf,block_count,numlocals);
+ memset(localbuf,0,(block_count+1) * TYPEVECTOR_SIZE(numlocals));
- LOG("Variable buffer initialized.\n");
+ LOG("Variable buffer allocated.\n");
/* allocate the buffer for storing JSR target chains */
jsrbuffer = DMNEW(jsr_record*,block_count);
/* initialize the variable types of the first block */
/* to the types of the arguments */
- ttype = vartype;
- tinfo = vartypeinfo;
+ lset = MGET_TYPEVECTOR(localbuf,0,numlocals);
+ td = lset->td;
+ i = numlocals;
/* if this is an instance method initialize the "this" ref type */
if (!(method->flags & ACC_STATIC)) {
- *ttype++ = TYPE_ADDRESS;
+ td->type = TYPE_ADDRESS;
if (initmethod)
- TYPEINFO_INIT_NEWOBJECT(*tinfo,NULL);
+ TYPEINFO_INIT_NEWOBJECT(td->info,NULL);
else
- TYPEINFO_INIT_CLASSINFO(*tinfo,class);
- tinfo++;
+ TYPEINFO_INIT_CLASSINFO(td->info,class);
+ td++;
+ i--;
}
LOG("'this' argument set.\n");
/* the rest of the arguments and the return type */
- typeinfo_init_from_method_args(method->descriptor,ttype,tinfo,
- numlocals - (tinfo-vartypeinfo),
- true, /* two word types use two slots */
- &returntype,&returntypeinfo);
+ i = typedescriptors_init_from_method_args(td,method->descriptor,
+ i,
+ true, /* two word types use two slots */
+ &returntype);
+ td += i;
+ i = numlocals - (td - lset->td);
+ while (i--) {
+ td->type = TYPE_VOID;
+ td++;
+ }
LOG("Arguments set.\n");
handlers[len] = NULL;
/* init variable types at the start of this block */
- for (i=0; i<numlocals; ++i) {
- vtype[i] = vartype[numlocals*b_index + i];
- TYPEINFO_COPY(vartypeinfo[numlocals*b_index + i],vinfo[i]);
-
- if (handlers[0] &&
- vtype[i] == TYPE_ADR && TYPEINFO_IS_NEWOBJECT(vinfo[i]))
- panic("Uninitialized object in local variable inside try block");
- }
+ COPY_TYPEVECTORSET(MGET_TYPEVECTOR(localbuf,b_index,numlocals),
+ localset,numlocals);
+ if (handlers[0])
+ for (i=0; i<numlocals; ++i)
+ if (localset->td[i].type == TYPE_ADR
+ && TYPEINFO_IS_NEWOBJECT(localset->td[i].info))
+ panic("Uninitialized object in local variable inside try block");
/* init JSR target chain */
if ((jsrchain = jsrbuffer[b_index]) != NULL) {
#ifdef TYPECHECK_VERBOSE
if (typecheckverbose) {
if (subroutine) {LOGSTR1("subroutine L%03d\n",subroutine->target->debug_nr);LOGFLUSH;}
- typeinfo_print_block(get_logfile(),curstack,numlocals,vtype,vinfo,(jsrchain) ? touched : NULL);
+ typestate_print(get_logfile(),curstack,localset,numlocals);
LOGNL; LOGFLUSH;
}
#endif
COPYTYPE(curstack->prev,dst);
break;
+ /****************************************/
+ /* PRIMITIVE VARIABLE ACCESS */
+
+ case ICMD_ILOAD: CHECK_ONEWORD(iptr->op1,TYPE_INT); break;
+ case ICMD_FLOAD: CHECK_ONEWORD(iptr->op1,TYPE_FLOAT); break;
+ case ICMD_IINC: CHECK_ONEWORD(iptr->op1,TYPE_INT); break;
+ case ICMD_LLOAD: CHECK_TWOWORD(iptr->op1,TYPE_LONG); break;
+ case ICMD_DLOAD: CHECK_TWOWORD(iptr->op1,TYPE_DOUBLE); break;
+
+ case ICMD_FSTORE: STORE_ONEWORD(iptr->op1,TYPE_FLOAT); break;
+ case ICMD_ISTORE: STORE_ONEWORD(iptr->op1,TYPE_INT); break;
+ case ICMD_LSTORE: STORE_TWOWORD(iptr->op1,TYPE_LONG); break;
+ case ICMD_DSTORE: STORE_TWOWORD(iptr->op1,TYPE_DOUBLE); break;
+
/****************************************/
/* LOADING ADDRESS FROM VARIABLE */
case ICMD_ALOAD:
- CHECK_ONEWORD(iptr->op1,TYPE_ADR);
+ INDEX_ONEWORD(iptr->op1);
/* loading a returnAddress is not allowed */
- if (TYPEINFO_IS_PRIMITIVE(vinfo[iptr->op1]))
- panic("illegal instruction: ALOAD loading returnAddress");
+ if (!typevectorset_checkreference(localset,iptr->op1))
+ panic("illegal instruction: ALOAD loading non-reference");
- TYPEINFO_COPY(vinfo[iptr->op1],dst->typeinfo);
+ typevectorset_copymergedtype(localset,iptr->op1,&(dst->typeinfo));
break;
/****************************************/
if (handlers[0] &&
TYPEINFO_IS_NEWOBJECT(curstack->typeinfo))
panic("Storing uninitialized object in local variable inside try block");
-
- STORE_ONEWORD(iptr->op1,TYPE_ADDRESS);
- TYPEINFO_COPY(curstack->typeinfo,vinfo[iptr->op1]);
+
+ INDEX_ONEWORD(iptr->op1);
+ if (TYPESTACK_IS_RETURNADDRESS(curstack))
+ typevectorset_store_retaddr(localset,iptr->op1,&(curstack->typeinfo));
+ else
+ typevectorset_store(localset,iptr->op1,TYPE_ADDRESS,
+ &(curstack->typeinfo));
break;
/****************************************/
panic("illegal instruction: ARRAYLENGTH on non-array");
maythrow = true;
break;
-
+
+ /* XXX unify cases? */
case ICMD_BALOAD:
if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(curstack->prev->typeinfo,ARRAYTYPE_BOOLEAN)
&& !TYPEINFO_MAYBE_PRIMITIVE_ARRAY(curstack->prev->typeinfo,ARRAYTYPE_BYTE))
break;
/****************************************/
- /* OPERATIONS WITH UNCHECKED INPUT */
+ /* ADDRESS CONSTANTS */
+
+ case ICMD_ACONST:
+ if (iptr->val.a == NULL)
+ TYPEINFO_INIT_NULLTYPE(dst->typeinfo);
+ else
+ /* XXX constants for builtin functions */
+ /* string constants */
+ TYPEINFO_INIT_CLASSINFO(dst->typeinfo,class_java_lang_String);
+ break;
+
+ /****************************************/
+ /* CHECKCAST AND INSTANCEOF */
case ICMD_CHECKCAST:
TYPECHECK_ADR(curstack);
/* XXX optimize statically? */
break;
- case ICMD_ACONST:
- if (iptr->val.a == NULL)
- TYPEINFO_INIT_NULLTYPE(dst->typeinfo);
- else
- /* XXX constants for builtin functions */
- /* string constants */
- TYPEINFO_INIT_CLASSINFO(dst->typeinfo,class_java_lang_String);
- break;
-
/****************************************/
/* BRANCH INSTRUCTIONS */
case ICMD_TABLESWITCH:
{
s4 *s4ptr = iptr->val.a;
- s4ptr++; /* skip default */
- i = *s4ptr++; /* low */
+ s4ptr++; /* skip default */
+ i = *s4ptr++; /* low */
i = *s4ptr++ - i + 2; /* +1 for default target */
}
goto switch_instruction_tail;
case ICMD_LOOKUPSWITCH:
{
s4 *s4ptr = iptr->val.a;
- s4ptr++; /* skip default */
- i = *s4ptr++ + 1; /* count +1 for default target */
+ s4ptr++; /* skip default */
+ i = *s4ptr++ + 1; /* count +1 for default */
}
switch_instruction_tail:
tptr = (basicblock **)iptr->target;
if (!TYPEINFO_IS_REFERENCE(curstack->typeinfo))
panic("illegal instruction: ARETURN on non-reference");
- if (returntype != TYPE_ADDRESS
- || !typeinfo_is_assignable(&curstack->typeinfo,&returntypeinfo))
+ if (returntype.type != TYPE_ADDRESS
+ || !typeinfo_is_assignable(&curstack->typeinfo,&(returntype.info)))
panic("Return type mismatch");
goto return_tail;
case ICMD_IRETURN:
- if (returntype != TYPE_INT) panic("Return type mismatch");
+ if (returntype.type != TYPE_INT) panic("Return type mismatch");
goto return_tail;
case ICMD_LRETURN:
- if (returntype != TYPE_LONG) panic("Return type mismatch");
+ if (returntype.type != TYPE_LONG) panic("Return type mismatch");
goto return_tail;
case ICMD_FRETURN:
- if (returntype != TYPE_FLOAT) panic("Return type mismatch");
+ if (returntype.type != TYPE_FLOAT) panic("Return type mismatch");
goto return_tail;
case ICMD_DRETURN:
- if (returntype != TYPE_DOUBLE) panic("Return type mismatch");
+ if (returntype.type != TYPE_DOUBLE) panic("Return type mismatch");
goto return_tail;
case ICMD_RETURN:
- if (returntype != TYPE_VOID) panic("Return type mismatch");
+ if (returntype.type != TYPE_VOID) panic("Return type mismatch");
return_tail:
TYPECHECK_LEAVE;
superblockend = true;
*/
dst = (stackptr) iptr->val.a;
- /* push return address */
- TYPEINFO_INIT_PRIMITIVE(dst->typeinfo);
+ tbptr = (basicblock *) iptr->target;
+ repeat |= typestate_jsr(localbuf,bptr,tbptr,dst,localset,numlocals);
+#if 0
+ TYPEINFO_INIT_RETURNADDRESS(dst->typeinfo,tbptr);
LOG("reaching block...");
/* add the target to the JSR target chain and */
/* propagate stack and variables to the target block */
- tbptr = (basicblock *) iptr->target;
TYPECHECK_REACH(REACH_JSR);
/* set dst to the stack after the subroutine execution */
repeat = true;
superblockend = true;
}
- /* XXX may throw? I don't think. */
+#endif
+ /* XXX may throw? I don't think so. */
+ superblockend = true;
break;
case ICMD_RET:
/* check returnAddress variable */
- CHECK_ONEWORD(iptr->op1,TYPE_ADR);
-
- if (!TYPEINFO_IS_PRIMITIVE(vinfo[iptr->op1]))
+ INDEX_ONEWORD(iptr->op1);
+ if (!typevectorset_checkretaddr(localset,iptr->op1))
panic("illegal instruction: RET using non-returnAddress variable");
+ repeat |= typestate_ret(localbuf,bptr,curstack,
+ localset,iptr->op1,numlocals);
+
+#if 0
/* check if we are inside a subroutine */
if (!subroutine)
panic("RET outside of subroutine");
+ /* check if the right returnAddress is used (XXX is this too strict?) */
+ if ((basicblock*)TYPEINFO_RETURNADDRESS(vinfo[iptr->op1])
+ != subroutine->target)
+ panic("RET uses returnAddress of another subroutine");
+
/* determine which variables are touched by this subroutine */
/* and their types */
if (subroutine->sbr_touched) {
+ /* We have reached a RET in this subroutine before. */
+
+ /* Check if there is more than one RET instruction
+ * returning from this subroutine. */
+ if (subroutine->sbr_ret != iptr)
+ panic("JSR subroutine has more than one RET instruction");
+
+ /* Merge the array of touched locals and their types */
for (i=0; i<numlocals; ++i)
subroutine->sbr_touched[i] |= touched[i];
ttype = subroutine->sbr_vtype;
tinfo = subroutine->sbr_vinfo;
TYPECHECK_MERGEVARS;
+ /* XXX check if subroutine changed types? */
}
else {
+ /* This is the first time we reach a RET in this subroutine */
+ subroutine->sbr_ret = iptr;
subroutine->sbr_touched = DMNEW(u1,numlocals);
memcpy(subroutine->sbr_touched,touched,sizeof(u1)*numlocals);
subroutine->sbr_vtype = DMNEW(u1,numlocals);
if (vtype[i] == TYPE_ADR)
TYPEINFO_CLONE(vinfo[i],subroutine->sbr_vinfo[i]);
}
- /* XXX check if subroutine changed types? */
LOGSTR("subroutine touches:");
DOLOG(typeinfo_print_locals(get_logfile(),subroutine->sbr_vtype,subroutine->sbr_vinfo,
subroutine->sbr_touched,numlocals));
LOGNL; LOGFLUSH;
- /* reach blocks after JSR statements */
+ /* XXX reach blocks after JSR statements */
for (i=0; i<block_count; ++i) {
tbptr = block + i;
LOG1("block L%03d",tbptr->debug_nr);
continue;
tbptr++;
- LOG1("RET reaches block %04d",tbptr-block);
+ LOG1("RET reaches block L%03d",tbptr->debug_nr);
/*TYPECHECK_REACH(REACH_RET);*/
}
+#endif
superblockend = true;
break;
srcstack = srcstack->prev;
}
/* replace uninitialized object type in locals */
- for (i=0; i<numlocals; ++i) {
- if (vtype[i] == TYPE_ADR
- && TYPEINFO_IS_NEWOBJECT(vinfo[i])
- && TYPEINFO_NEWOBJECT_INSTRUCTION(vinfo[i]) == ins)
- {
- LOG1("replacing uninitialized type in local %d",i);
- TYPEINFO_INIT_CLASSINFO(vinfo[i],initclass);
- }
- }
+ typevectorset_init_object(localset,ins,initclass,numlocals);
/* initializing the 'this' reference? */
if (!ins) {
/* set our marker variable to type int */
LOG("setting <init> marker");
- vtype[numlocals-1] = TYPE_INT;
+ typevectorset_store(localset,numlocals-1,TYPE_INT,NULL);
}
else {
/* initializing an instance created with NEW */
panic("Invalid instruction: NEW creating instance of abstract class");
TYPEINFO_INIT_NEWOBJECT(dst->typeinfo,iptr);
}
- /* XXX unify the following cases */
+ /* XXX unify the following cases? */
else if (ISBUILTIN(BUILTIN_newarray_boolean)) {
TYPECHECK_INT(curstack);
TYPEINFO_INIT_PRIMITIVE_ARRAY(dst->typeinfo,ARRAYTYPE_BOOLEAN);
break;
/****************************************/
- /* PRIMITIVE VARIABLE ACCESS */
+ /* UNCHECKED OPERATIONS */
+
+ /* These ops have no input or output to be checked */
+ /* (apart from the checks done in analyse_stack). */
+ /* XXX only add cases for them in debug mode? */
+
+ case ICMD_NOP:
+ case ICMD_POP:
+ case ICMD_POP2:
+ break;
+
+ /****************************************/
+ /* SIMPLE EXCEPTION THROWING TESTS */
+
+ case ICMD_CHECKASIZE:
+ /* The argument to CHECKASIZE is typechecked by
+ * typechecking the array creation instructions. */
+
+ /* FALLTHROUGH! */
+ case ICMD_NULLCHECKPOP:
+ /* NULLCHECKPOP just requires that the stack top
+ * is an address. This is checked in stack.c */
+
+ maythrow = true;
+ break;
- case ICMD_ILOAD: CHECK_ONEWORD(iptr->op1,TYPE_INT); break;
- case ICMD_FLOAD: CHECK_ONEWORD(iptr->op1,TYPE_FLOAT); break;
- case ICMD_IINC: CHECK_ONEWORD(iptr->op1,TYPE_INT); break;
- case ICMD_LLOAD: CHECK_TWOWORD(iptr->op1,TYPE_LONG); break;
- case ICMD_DLOAD: CHECK_TWOWORD(iptr->op1,TYPE_DOUBLE); break;
-
- case ICMD_FSTORE: STORE_ONEWORD(iptr->op1,TYPE_FLOAT); break;
- case ICMD_ISTORE: STORE_ONEWORD(iptr->op1,TYPE_INT); break;
- case ICMD_LSTORE: STORE_TWOWORD(iptr->op1,TYPE_LONG); break;
- case ICMD_DSTORE: STORE_TWOWORD(iptr->op1,TYPE_DOUBLE); break;
-
/****************************************/
/* INSTRUCTIONS WHICH SHOULD HAVE BEEN */
- /* REPLACED BY BUILTIN CALLS */
+ /* REPLACED BY OTHER OPCODES */
case ICMD_NEW:
case ICMD_NEWARRAY:
panic("Internal error: unexpected instruction encountered");
break;
- /****************************************/
- /* UNCHECKED OPERATIONS */
-
- /* These ops have no input or output to be checked */
- /* (apart from the checks done in analyse_stack). */
- /* XXX only add cases for them in debug mode? */
-
- case ICMD_NOP:
- case ICMD_POP:
- case ICMD_POP2:
- case ICMD_READONLY_ARG: /* XXX ? */
- case ICMD_CLEAR_ARGREN: /* XXX ? */
- break;
-
- case ICMD_CHECKASIZE:
- case ICMD_NULLCHECKPOP:
- maythrow = true;
+ case ICMD_READONLY_ARG:
+ case ICMD_CLEAR_ARGREN:
+ /* XXX only check this in debug mode? */
+ LOG2("ICMD %d at %d\n", iptr->opc, (int)(iptr-instr));
+ LOG("Should have been replaced in stack.c.");
+ panic("Internal error: unexpected pseudo instruction encountered");
break;
-
+
/****************************************/
/* ARITHMETIC AND CONVERSION */
- /* (These instructions are typechecked in analyse_stack.) */
- /* The following instructions may throw a runtime exception: */
+ /*********************************************
+ * Instructions below...
+ * *) don't operate on local variables,
+ * *) don't operate on references,
+ * *) don't operate on returnAddresses.
+ *
+ * (These instructions are typechecked in
+ * analyse_stack.)
+ ********************************************/
+
+ /* Instructions which may throw a runtime exception: */
case ICMD_IDIV:
case ICMD_IREM:
maythrow = true;
break;
- /* The following instructions never throw a runtime exception: */
+ /* Instructions which never throw a runtime exception: */
/* XXX only add cases for them in debug mode? */
case ICMD_ICONST:
i = 0;
while (handlers[i]) {
tbptr = handlers[i]->handler;
- TYPECHECK_REACH(REACH_THROW); /* XXX jsr chain? */
+ repeat |= typestate_reach(localbuf,bptr,tbptr,
+ tbptr->instack,localset,numlocals);
i++;
}
}
LOG("instructions done");
LOGSTR("RESULT=> ");
- DOLOG(typeinfo_print_block(get_logfile(),curstack,numlocals,vtype,vinfo,(jsrchain) ? touched : NULL));
+ DOLOG(typestate_print(get_logfile(),curstack,localset,numlocals));
LOGNL; LOGFLUSH;
/* propagate stack and variables to the following block */
Authors: Edwin Steiner
- $Id: typeinfo.c 733 2003-12-12 17:29:40Z stefan $
+ $Id: typeinfo.c 868 2004-01-10 20:12:10Z edwin $
*/
#include "loader.h"
#include "toolbox/loging.h"
#include "toolbox/memory.h"
+#include "jit/jit.h" /* XXX move typeinfo.* into jit/ */
#define CLASS_IMPLEMENTS_INTERFACE(cls,index) \
( ((index) < (cls)->vftbl->interfacetablelength) \
&& (VFTBLINTERFACETABLE((cls)->vftbl,(index)) != NULL) )
+/**********************************************************************/
+/* TYPEVECTOR FUNCTIONS */
+/**********************************************************************/
+
+typevector *
+typevectorset_copy(typevector *src,int k,int size)
+{
+ typevector *dst = DNEW_TYPEVECTOR(size);
+
+ memcpy(dst,src,TYPEVECTOR_SIZE(size));
+ dst->k = k;
+ if (src->alt)
+ dst->alt = typevectorset_copy(src->alt,k+1,size);
+ return dst;
+}
+
+#if 0
+typevector *
+typevectorset_copy_select(typevector *src,
+ int retindex,void *retaddr,int size)
+{
+ typevector *dst;
+
+ for (;src; src=src->alt) {
+ if (TYPEINFO_RETURNADDRESS(src->td[retindex].info) != retaddr)
+ continue;
+
+ dst = DNEW_TYPEVECTOR(size);
+ memcpy(dst,src,TYPEVECTOR_SIZE(size));
+ if (src->alt)
+ dst->alt = typevectorset_copy_select(src->alt,retindex,retaddr,size);
+ return dst;
+ }
+
+ return NULL;
+}
+
+void
+typevectorset_copy_select_to(typevector *src,typevector *dst,
+ int retindex,void *retaddr,int size)
+{
+ for (;src; src=src->alt) {
+ if (TYPEINFO_RETURNADDRESS(src->td[retindex].info) != retaddr)
+ continue;
+
+ memcpy(dst,src,TYPEVECTOR_SIZE(size));
+ if (src->alt)
+ dst->alt = typevectorset_copy_select(src->alt,retindex,retaddr,size);
+ return dst;
+ }
+
+ return NULL;
+}
+#endif
+
+bool
+typevectorset_checktype(typevector *vec,int index,int type)
+{
+ do {
+ if (vec->td[index].type != type)
+ return false;
+ } while ((vec = vec->alt) != NULL);
+ return true;
+}
+
+bool
+typevectorset_checkreference(typevector *vec,int index)
+{
+ do {
+ if (!TYPEDESC_IS_REFERENCE(vec->td[index]))
+ return false;
+ } while ((vec = vec->alt) != NULL);
+ return true;
+}
+
+bool
+typevectorset_checkretaddr(typevector *vec,int index)
+{
+ do {
+ if (!TYPEDESC_IS_RETURNADDRESS(vec->td[index]))
+ return false;
+ } while ((vec = vec->alt) != NULL);
+ return true;
+}
+
+int
+typevectorset_copymergedtype(typevector *vec,int index,typeinfo *dst)
+{
+ int type;
+ typedescriptor *td;
+
+ td = vec->td + index;
+ type = td->type;
+ TYPEINFO_COPY(td->info,*dst);
+
+ if (vec->alt) {
+ int primitive;
+
+ primitive = TYPEINFO_IS_PRIMITIVE(*dst) ? 1 : 0;
+
+ while ((vec = vec->alt) != NULL) {
+ td = vec->td + index;
+ if (type != td->type)
+ return TYPE_VOID;
+
+ if (type == TYPE_ADDRESS) {
+ if ((TYPEINFO_IS_PRIMITIVE(td->info) ? 1 : 0) != primitive)
+ return TYPE_VOID;
+ typeinfo_merge(dst,&(td->info));
+ }
+ }
+ }
+ return type;
+}
+
+int
+typevectorset_mergedtype(typevector *vec,int index,typeinfo *temp,typeinfo **result)
+{
+ if (vec->alt) {
+ *result = temp;
+ return typevectorset_copymergedtype(vec,index,temp);
+ }
+
+ *result = &(vec->td[index].info);
+ return vec->td[index].type;
+}
+
+typeinfo *
+typevectorset_mergedtypeinfo(typevector *vec,int index,typeinfo *temp)
+{
+ typeinfo *result;
+ int type = typevectorset_mergedtype(vec,index,temp,&result);
+ return (type == TYPE_ADDRESS) ? result : NULL;
+}
+
+void
+typevectorset_store(typevector *vec,int index,int type,typeinfo *info)
+{
+ /* XXX check if a separator was overwritten */
+ do {
+ vec->td[index].type = type;
+ if (info)
+ TYPEINFO_COPY(*info,vec->td[index].info);
+ if (index > 0 && IS_2_WORD_TYPE(vec->td[index-1].type))
+ vec->td[index-1].type = TYPE_VOID;
+ } while ((vec = vec->alt) != NULL);
+}
+
+void
+typevectorset_store_retaddr(typevector *vec,int index,typeinfo *info)
+{
+ typeinfo_retaddr_set *adr;
+
+ /* XXX check if a separator was overwritten */
+ adr = (typeinfo_retaddr_set*) TYPEINFO_RETURNADDRESS(*info);
+ do {
+ vec->td[index].type = TYPE_ADDRESS;
+ TYPEINFO_INIT_RETURNADDRESS(vec->td[index].info,adr->addr);
+ if (index > 0 && IS_2_WORD_TYPE(vec->td[index-1].type))
+ vec->td[index-1].type = TYPE_VOID;
+ adr = adr->alt;
+ } while ((vec = vec->alt) != NULL);
+}
+
+void
+typevectorset_store_twoword(typevector *vec,int index,int type)
+{
+ /* XXX check if a separator was overwritten */
+ do {
+ vec->td[index].type = type;
+ vec->td[index+1].type = TYPE_VOID;
+ if (index > 0 && IS_2_WORD_TYPE(vec->td[index-1].type))
+ vec->td[index-1].type = TYPE_VOID;
+ } while ((vec = vec->alt) != NULL);
+}
+
+void
+typevectorset_init_object(typevector *set,void *ins,classinfo *initclass,
+ int size)
+{
+ int i;
+
+ for (;set; set=set->alt) {
+ for (i=0; i<size; ++i) {
+ if (set->td[i].type == TYPE_ADR
+ && TYPEINFO_IS_NEWOBJECT(set->td[i].info)
+ && TYPEINFO_NEWOBJECT_INSTRUCTION(set->td[i].info) == ins)
+ {
+ TYPEINFO_INIT_CLASSINFO(set->td[i].info,initclass);
+ }
+ }
+ }
+}
+
+bool
+typevector_merge(typevector *dst,typevector *y,int size)
+{
+ bool changed = false;
+
+ typedescriptor *a = dst->td;
+ typedescriptor *b = y->td;
+ while (size--) {
+ if (a->type != TYPE_VOID && a->type != b->type) {
+ a->type = TYPE_VOID;
+ changed = true;
+ }
+ else if (a->type == TYPE_ADDRESS) {
+ if (TYPEINFO_IS_PRIMITIVE(a->info)) {
+ /* 'a' is a returnAddress */
+ if (!TYPEINFO_IS_PRIMITIVE(b->info)
+ || (TYPEINFO_RETURNADDRESS(a->info)
+ != TYPEINFO_RETURNADDRESS(b->info)))
+ {
+ a->type = TYPE_VOID;
+ changed = true;
+ }
+ }
+ else {
+ /* 'a' is a reference */
+ if (TYPEINFO_IS_PRIMITIVE(b->info)) {
+ a->type = TYPE_VOID;
+ changed = true;
+ }
+ else {
+ changed |= typeinfo_merge(&(a->info),&(b->info));
+ }
+ }
+ }
+ a++;
+ b++;
+ }
+ return changed;
+}
+
+bool typevector_separable_from(typevector *a,typevector *b,int size)
+{
+ typedescriptor *tda = a->td;
+ typedescriptor *tdb = b->td;
+ for (;size--; tda++,tdb++) {
+ if (TYPEDESC_IS_RETURNADDRESS(*tda)
+ && TYPEDESC_IS_RETURNADDRESS(*tdb)
+ && TYPEINFO_RETURNADDRESS(tda->info)
+ != TYPEINFO_RETURNADDRESS(tdb->info))
+ return true;
+ }
+ return false;
+}
+
+void
+typevectorset_add(typevector *dst,typevector *v,int size)
+{
+ while (dst->alt)
+ dst = dst->alt;
+ dst->alt = DNEW_TYPEVECTOR(size);
+ memcpy(dst->alt,v,TYPEVECTOR_SIZE(size));
+ dst->alt->alt = NULL;
+ dst->alt->k = dst->k + 1;
+}
+
+#if 0
+void
+typevectorset_union(typevector *dst,typevector *v,int size)
+{
+ while (dst->alt)
+ dst = dst->alt;
+ dst->alt = typevectorset_copy(v,size);
+}
+#endif
+
+typevector *
+typevectorset_select(typevector **set,int retindex,void *retaddr)
+{
+ typevector *selected;
+
+ if (!*set) return NULL;
+
+ if (TYPEINFO_RETURNADDRESS((*set)->td[retindex].info) == retaddr) {
+ selected = *set;
+ *set = selected->alt;
+ selected->alt = typevectorset_select(set,retindex,retaddr);
+ }
+ else {
+ selected = typevectorset_select(&((*set)->alt),retindex,retaddr);
+ }
+ return selected;
+}
+
+/* XXX delete */
+#if 0
+bool
+typevectorset_separable(typevector *vec,int size)
+{
+ int i;
+ typevector *v;
+
+ for (i=0; i<size; ++i) {
+ v = vec;
+ do {
+ if (!TYPEDESC_IS_RETURNADDRESS(v->td[i]))
+ goto next_index;
+
+ v = v->alt;
+ if (!v) return true;
+ } while (v);
+ next_index:
+ }
+ return false;
+}
+#endif
+
+bool
+typevectorset_separable_with(typevector *set,typevector *add,int size)
+{
+ int i;
+ typevector *v;
+ void *addr;
+ bool separable;
+
+ for (i=0; i<size; ++i) {
+ if (!TYPEDESC_IS_RETURNADDRESS(add->td[i]))
+ continue;
+ addr = TYPEINFO_RETURNADDRESS(add->td[i].info);
+
+ v = set;
+ separable = false;
+ do {
+ if (!TYPEDESC_IS_RETURNADDRESS(v->td[i]))
+ goto next_index;
+ if (TYPEINFO_RETURNADDRESS(v->td[i].info) != addr)
+ separable = true;
+ v = v->alt;
+ if (!v && separable) return true;
+ } while (v);
+ next_index:
+ }
+ return false;
+}
+
+bool
+typevectorset_collapse(typevector *dst,int size)
+{
+ bool changed = false;
+
+ while (dst->alt) {
+ typevector_merge(dst,dst->alt,size);
+ dst->alt = dst->alt->alt;
+ changed = true;
+ }
+ return changed;
+}
+
/**********************************************************************/
/* READ-ONLY FUNCTIONS */
/* The following functions don't change typeinfo data. */
}
}
+int
+typedescriptors_init_from_method_args(typedescriptor *td,
+ utf *desc,
+ int buflen,bool twoword,
+ typedescriptor *returntype)
+{
+ char *utf_ptr = desc->text; /* current position in utf text */
+ char *end_pos = utf_end(desc); /* points behind utf string */
+ int args = 0;
+ classinfo *cls;
+
+ /* method descriptor must start with parenthesis */
+ if (utf_ptr == end_pos || *utf_ptr++ != '(') panic ("Missing '(' in method descriptor");
+
+ /* check arguments */
+ while (utf_ptr != end_pos && *utf_ptr != ')') {
+ if (++args > buflen)
+ panic("Buffer too small for method arguments.");
+
+ td->type = type_from_descriptor(&cls,utf_ptr,end_pos,&utf_ptr,
+ CLASSLOAD_NEW
+ | CLASSLOAD_NULLPRIMITIVE
+ | CLASSLOAD_NOVOID);
+
+ if (cls)
+ TYPEINFO_INIT_CLASSINFO(td->info,cls);
+ else {
+ TYPEINFO_INIT_PRIMITIVE(td->info);
+ }
+ td++;
+
+ if (twoword && (td[-1].type == TYPE_LONG || td[-1].type == TYPE_DOUBLE)) {
+ if (++args > buflen)
+ panic("Buffer too small for method arguments.");
+ td->type = TYPE_VOID;
+ TYPEINFO_INIT_PRIMITIVE(td->info);
+ td++;
+ }
+ }
+ utf_ptr++; /* skip ')' */
+
+ /* check returntype */
+ if (returntype) {
+ returntype->type = type_from_descriptor(&cls,utf_ptr,end_pos,&utf_ptr,
+ CLASSLOAD_NULLPRIMITIVE
+ | CLASSLOAD_NEW
+ | CLASSLOAD_CHECKEND);
+ if (cls)
+ TYPEINFO_INIT_CLASSINFO(returntype->info,cls);
+ else
+ TYPEINFO_INIT_PRIMITIVE(returntype->info);
+ }
+ return args;
+}
+
void
typeinfo_init_component(typeinfo *srcarray,typeinfo *dst)
{
return false;
/* Merging two returnAddress types is ok. */
- if (!dest->typeclass && !y->typeclass)
+ if (!dest->typeclass && !y->typeclass) {
+#ifdef TYPEINFO_DEBUG
+ if (TYPEINFO_RETURNADDRESS(*dest) != TYPEINFO_RETURNADDRESS(*y))
+ panic("Internal error: typeinfo_merge merges different returnAddresses");
+#endif
return false;
+ }
/* Primitive types cannot be merged with reference types */
+ /* XXX only check this in debug mode? */
if (!dest->typeclass || !y->typeclass)
typeinfo_merge_error("Trying to merge primitive types.",dest,y);
int i;
char ind[TYPEINFO_MAXINDENT + 1];
instruction *ins;
+ basicblock *bptr;
if (indent > TYPEINFO_MAXINDENT) indent = TYPEINFO_MAXINDENT;
ind[i] = (char) 0;
if (TYPEINFO_IS_PRIMITIVE(*info)) {
- fprintf(file,"%sprimitive\n",ind);
+ bptr = (basicblock*) TYPEINFO_RETURNADDRESS(*info);
+ if (bptr)
+ fprintf(file,"%sreturnAddress (L%03d)\n",ind,bptr->debug_nr);
+ else
+ fprintf(file,"%sprimitive\n",ind);
return;
}
{
int i;
instruction *ins;
+ basicblock *bptr;
if (TYPEINFO_IS_PRIMITIVE(*info)) {
- fprintf(file,"primitive");
+ bptr = (basicblock*) TYPEINFO_RETURNADDRESS(*info);
+ if (bptr)
+ fprintf(file,"ret(L%03d)",bptr->debug_nr);
+ else
+ fprintf(file,"primitive");
return;
}
case TYPE_DOUBLE: fprintf(file,"D"); break;
case TYPE_LONG: fprintf(file,"J"); break;
case TYPE_ADDRESS:
- if (TYPEINFO_IS_PRIMITIVE(*info))
- fprintf(file,"R"); /* returnAddress */
- else {
- typeinfo_print_short(file,info);
- }
+ typeinfo_print_short(file,info);
break;
default:
}
}
+void
+typeinfo_print_stacktype(FILE *file,int type,typeinfo *info)
+{
+ if (type == TYPE_ADDRESS && TYPEINFO_IS_PRIMITIVE(*info)) {
+ typeinfo_retaddr_set *set = (typeinfo_retaddr_set*)
+ TYPEINFO_RETURNADDRESS(*info);
+ fprintf(file,"ret(L%03d",((basicblock*)(set->addr))->debug_nr);
+ set = set->alt;
+ while (set) {
+ fprintf(file,"|L%03d",((basicblock*)(set->addr))->debug_nr);
+ set = set->alt;
+ }
+ fprintf(file,")");
+ }
+ else
+ typeinfo_print_type(file,type,info);
+}
+
+void
+typedescriptor_print(FILE *file,typedescriptor *td)
+{
+ typeinfo_print_type(file,td->type,&(td->info));
+}
+
+void
+typevector_print(FILE *file,typevector *vec,int size)
+{
+ int i;
+
+ fprintf(file,"[%d]",vec->k);
+ for (i=0; i<size; ++i) {
+ fprintf(file," %d=",i);
+ typedescriptor_print(file,vec->td + i);
+ }
+}
+
+void
+typevectorset_print(FILE *file,typevector *set,int size)
+{
+ int i;
+ typevector *vec;
+
+ fprintf(file,"[%d",set->k);
+ vec = set->alt;
+ while (vec) {
+ fprintf(file,"|%d",vec->k);
+ vec = vec->alt;
+ }
+ fprintf(file,"]");
+
+ for (i=0; i<size; ++i) {
+ fprintf(file," %d=",i);
+ typedescriptor_print(file,set->td + i);
+ vec = set->alt;
+ while (vec) {
+ fprintf(file,"|");
+ typedescriptor_print(file,vec->td + i);
+ vec = vec->alt;
+ }
+ }
+}
+
#endif /* TYPEINFO_DEBUG */
Authors: Edwin Steiner
- $Id: typeinfo.h 795 2003-12-16 22:27:52Z edwin $
+ $Id: typeinfo.h 868 2004-01-10 20:12:10Z edwin $
*/
typedef struct typeinfo typeinfo;
typedef struct typeinfo_mergedlist typeinfo_mergedlist;
+typedef struct typedescriptor typedescriptor;
+typedef struct typevector typevector;
+typedef struct typeinfo_retaddr_set typeinfo_retaddr_set;
/* global variables ***********************************************************/
* access typeinfo structures!
*/
struct typeinfo {
- classinfo *typeclass;
- classinfo *elementclass; /* valid if dimension>0 */
- typeinfo_mergedlist *merged;
- u1 dimension;
- u1 elementtype; /* valid if dimension>0 */
+ classinfo *typeclass;
+ classinfo *elementclass; /* valid if dimension>0 */ /* XXX various uses */
+ typeinfo_mergedlist *merged;
+ u1 dimension;
+ u1 elementtype; /* valid if dimension>0 */
};
struct typeinfo_mergedlist {
- s4 count;
- classinfo *list[1]; /* variable length! */
+ s4 count;
+ classinfo *list[1]; /* variable length! */
+};
+
+struct typeinfo_retaddr_set {
+ typeinfo_retaddr_set *alt; /* next alternative in set */
+ void *addr; /* return address */
+};
+
+struct typedescriptor {
+ typeinfo info; /* valid if type == TYPE_ADR */
+ u1 type; /* basic type (TYPE_INT, ...) */
+};
+
+/* typevectors are used to store the types of local variables */
+
+struct typevector {
+ typevector *alt; /* next alternative in typevector set */
+ int k; /* for lining up with the stack set */
+ typedescriptor td[1]; /* variable length! */
};
/****************************************************************************/
/* MACROS */
/****************************************************************************/
-/* NOTE: These macros take typeinfo *structs* not pointers as arguments.
- * You have to dereference any pointers.
+/* NOTE: The TYPEINFO macros take typeinfo *structs*, not pointers as
+ * arguments. You have to dereference any pointers.
*/
+/* typevectors **************************************************************/
+
+#define TYPEVECTOR_SIZE(size) \
+ ((sizeof(typevector) - sizeof(typedescriptor)) \
+ + (size)*sizeof(typedescriptor))
+
+#define DNEW_TYPEVECTOR(size) \
+ ((typevector*)dump_alloc(TYPEVECTOR_SIZE(size)))
+
+#define DMNEW_TYPEVECTOR(num,size) \
+ ((void*)dump_alloc((num) * TYPEVECTOR_SIZE(size)))
+
+#define MGET_TYPEVECTOR(array,index,size) \
+ ((typevector*) (((u1*)(array)) + TYPEVECTOR_SIZE(size) * (index)))
+
+#define COPY_TYPEVECTORSET(src,dst,size) \
+ do {memcpy(dst,src,TYPEVECTOR_SIZE(size)); \
+ dst->k = 0; \
+ if ((src)->alt) { \
+ (dst)->alt = typevectorset_copy((src)->alt,1,size); \
+ }} while(0)
+
/* internally used macros ***************************************************/
/* internal, don't use this explicitly! */
#define TYPEINFO_IS_NEWOBJECT(info) \
((info).typeclass == pseudo_class_New)
+/* only use this if TYPEINFO_IS_PRIMITIVE returned true! */
+#define TYPEINFO_RETURNADDRESS(info) \
+ ((void *)(info).elementclass)
+
/* only use this if TYPEINFO_IS_NEWOBJECT returned true! */
#define TYPEINFO_NEWOBJECT_INSTRUCTION(info) \
((void *)(info).elementclass)
( TYPEINFO_IS_ARRAY(info) \
&& TYPEINFO_IS_ARRAY_OF_REFS_NOCHECK(info) )
+#define TYPE_IS_RETURNADDRESS(type,info) \
+ ( ((type)==TYPE_ADDRESS) \
+ && TYPEINFO_IS_PRIMITIVE(info) )
+
+#define TYPE_IS_REFERENCE(type,info) \
+ ( ((type)==TYPE_ADDRESS) \
+ && !TYPEINFO_IS_PRIMITIVE(info) )
+
+#define TYPEDESC_IS_RETURNADDRESS(td) \
+ TYPE_IS_RETURNADDRESS((td).type,(td).info)
+
+#define TYPEDESC_IS_REFERENCE(td) \
+ TYPE_IS_REFERENCE((td).type,(td).info)
+
/* queries allowing the null type ********************************************/
#define TYPEINFO_MAYBE_ARRAY(info) \
(info).dimension = 0; \
(info).elementtype = 0;} while(0)
+#define TYPEINFO_INIT_RETURNADDRESS(info,adr) \
+ do {(info).typeclass = NULL; \
+ (info).elementclass = (classinfo*) (adr); \
+ (info).merged = NULL; \
+ (info).dimension = 0; \
+ (info).elementtype = 0;} while(0)
+
#define TYPEINFO_INIT_NON_ARRAY_CLASSINFO(info,cinfo) \
do {(info).typeclass = (cinfo); \
(info).elementclass = NULL; \
/* FUNCTIONS */
/****************************************************************************/
+/* typevector functions *****************************************************/
+
+/* element read-only access */
+bool typevectorset_checktype(typevector *set,int index,int type);
+bool typevectorset_checkreference(typevector *set,int index);
+bool typevectorset_checkretaddr(typevector *set,int index);
+int typevectorset_copymergedtype(typevector *set,int index,typeinfo *dst);
+typeinfo *typevectorset_mergedtypeinfo(typevector *set,int index,typeinfo *temp);
+int typevectorset_mergedtype(typevector *set,int index,typeinfo *temp,typeinfo **result);
+
+/* element write access */
+void typevectorset_store(typevector *set,int index,int type,typeinfo *info);
+void typevectorset_store_retaddr(typevector *set,int index,typeinfo *info);
+void typevectorset_store_twoword(typevector *set,int index,int type);
+void typevectorset_init_object(typevector *set,void *ins,classinfo *initclass,int size);
+
+/* vector functions */
+bool typevector_separable_from(typevector *a,typevector *b,int size);
+bool typevector_merge(typevector *dst,typevector *y,int size);
+
+/* vector set functions */
+typevector *typevectorset_copy(typevector *src,int k,int size);
+/* typevector *typevectorset_copy_select(typevector *src,
+ int retindex,void *retaddr,int size);
+ void typevectorset_copy_select_to(typevector *src,typevector *dst,
+ int retindex,void *retaddr,int size); */
+/* bool typevectorset_separable(typevector *set,int size); */
+bool typevectorset_separable_with(typevector *set,typevector *add,int size);
+bool typevectorset_collapse(typevector *dst,int size);
+void typevectorset_add(typevector *dst,typevector *v,int size);
+/* void typevectorset_union(typevector *dst,typevector *v,int size); */
+typevector *typevectorset_select(typevector **set,int retindex,void *retaddr);
+
/* inquiry functions (read-only) ********************************************/
bool typeinfo_is_array(typeinfo *info);
typeinfo *infobuf,
int buflen,bool twoword,
int *returntype,typeinfo *returntypeinfo);
+int typedescriptors_init_from_method_args(typedescriptor *td,
+ utf *desc,
+ int buflen,bool twoword,
+ typedescriptor *returntype);
void typeinfo_clone(typeinfo *src,typeinfo *dest);
void typeinfo_print(FILE *file,typeinfo *info,int indent);
void typeinfo_print_short(FILE *file,typeinfo *info);
void typeinfo_print_type(FILE *file,int type,typeinfo *info);
+void typeinfo_print_stacktype(FILE *file,int type,typeinfo *info);
+void typedescriptor_print(FILE *file,typedescriptor *td);
+void typevector_print(FILE *file,typevector *vec,int size);
+void typevectorset_print(FILE *file,typevector *set,int size);
#endif /* TYPEINFO_DEBUG */
Mark Probst
Edwin Steiner
- $Id: loader.c 867 2004-01-07 22:05:04Z edwin $
+ $Id: loader.c 868 2004-01-10 20:12:10Z edwin $
*/
checks whether a method-descriptor is valid and aborts otherwise.
All referenced classes are inserted into the list of unloaded classes.
+
+ The number of arguments is returned. A long or double argument is counted
+ as two arguments.
*******************************************************************************/
-static void checkmethoddescriptor (utf *d)
+static int checkmethoddescriptor (utf *d)
{
char *utf_ptr = d->text; /* current position in utf text */
char *end_pos = utf_end(d); /* points behind utf string */
/* XXX we cannot count the this argument here because
* we don't know if the method is static. */
if (*utf_ptr == 'J' || *utf_ptr == 'D')
+ argcount+=2;
+ else
argcount++;
- if (++argcount > 255)
- panic("Invalid method descriptor: too many arguments");
class_from_descriptor(utf_ptr,end_pos,&utf_ptr,
CLASSLOAD_NEW
| CLASSLOAD_NULLPRIMITIVE
| CLASSLOAD_NULLPRIMITIVE
| CLASSLOAD_CHECKEND);
+ if (argcount > 255)
+ panic("Invalid method descriptor: too many arguments");
+
+ return argcount;
+
/* XXX use the following if -noverify */
#if 0
/* XXX check length */
if ((f->flags & (ACC_STATIC | ACC_PUBLIC | ACC_FINAL))
!= (ACC_STATIC | ACC_PUBLIC | ACC_FINAL))
panic("Interface field is not declared static final public");
+ if ((f->flags & ACC_TRANSIENT) != 0)
+ panic("Interface field declared transient");
}
}
static void method_load(methodinfo *m, classinfo *c)
{
u4 attrnum, i, e;
+ int argcount;
#ifdef STATISTICS
count_all_methods++;
m->flags = suck_u2();
m->name = class_getconstant(c, suck_u2(), CONSTANT_Utf8);
m->descriptor = class_getconstant(c, suck_u2(), CONSTANT_Utf8);
- checkmethoddescriptor(m->descriptor);
+ argcount = checkmethoddescriptor(m->descriptor);
+ if ((m->flags & ACC_STATIC) == 0)
+ argcount++; /* count the 'this' argument */
- /* check flag consistency */
if (opt_verify) {
+ if (argcount > 255)
+ panic("Method has more than 255 arguments");
+
+ /* check flag consistency */
/* XXX could check if <clinit> is STATIC */
if (m->name != utf_clinit) {
i = (m->flags & (ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED));
suck_u4();
m->maxstack = suck_u2();
m->maxlocals = suck_u2();
+ if (m->maxlocals < argcount)
+ panic("max_locals is smaller than the number of arguments");
+
codelen = suck_u4();
if (codelen == 0)
panic("bytecode has zero length");
ASSERT_LEFT(length);
if (opt_verify &&
!is_valid_utf(classbuf_pos+1, classbuf_pos+1+length))
- panic("Invalid UTF-8 string");
+ {
+ dolog("Invalid UTF-8 string (constant pool index %d)",idx);
+ panic("Invalid UTF-8 string");
+ }
/* insert utf-string into the utf-symboltable */
cpinfos [idx] = utf_new(classbuf_pos+1, length);
/* skip bytes of the string */
/* check ACC flags consistency */
if ((c->flags & ACC_INTERFACE) != 0) {
- if ((c->flags & ACC_ABSTRACT) == 0)
- panic("Interface class not declared abstract");
+ if ((c->flags & ACC_ABSTRACT) == 0) {
+ /* XXX We work around this because interfaces in JDK 1.1 are
+ * not declared abstract. */
+
+ c->flags |= ACC_ABSTRACT;
+ /* panic("Interface class not declared abstract"); */
+ }
if ((c->flags & (ACC_FINAL | ACC_SUPER)) != 0)
panic("Interface class has invalid flags");
}
+ if ((c->flags & (ACC_ABSTRACT | ACC_FINAL)) == (ACC_ABSTRACT | ACC_FINAL))
+ panic("Class is declared both abstract and final");
/* this class */
i = suck_u2();
list_addlast(&unlinkedclasses, c);
return;
}
- if ((ic->flags & ACC_INTERFACE) == 0)
+ if ((ic->flags & ACC_INTERFACE) == 0) {
+ dolog("Specified interface is not declared as interface:");
+ log_utf(ic->name);
+ dolog("in");
+ log_utf(c->name);
panic("Specified interface is not declared as interface");
+ }
}
/* check super class */
- the heap
- additional support functions
- $Id: tables.c 775 2003-12-14 12:57:05Z edwin $
+ $Id: tables.c 868 2004-01-10 20:12:10Z edwin $
*/
if (len != 1) return false; /* Java special */
}
else {
- if (v < min_codepoint[len]) return false; /* overlong UTF-8 */
+ /* XXX Sun Java seems to allow overlong UTF-8 encodings */
+ /* if (v < min_codepoint[len]) return false; */ /* overlong UTF-8 */
}
/* surrogates in UTF-8 seem to be allowed in Java classfiles */
- the heap
- additional support functions
- $Id: tables.c 775 2003-12-14 12:57:05Z edwin $
+ $Id: tables.c 868 2004-01-10 20:12:10Z edwin $
*/
if (len != 1) return false; /* Java special */
}
else {
- if (v < min_codepoint[len]) return false; /* overlong UTF-8 */
+ /* XXX Sun Java seems to allow overlong UTF-8 encodings */
+ /* if (v < min_codepoint[len]) return false; */ /* overlong UTF-8 */
}
/* surrogates in UTF-8 seem to be allowed in Java classfiles */
Authors: Edwin Steiner
- $Id: typeinfo.c 733 2003-12-12 17:29:40Z stefan $
+ $Id: typeinfo.c 868 2004-01-10 20:12:10Z edwin $
*/
#include "loader.h"
#include "toolbox/loging.h"
#include "toolbox/memory.h"
+#include "jit/jit.h" /* XXX move typeinfo.* into jit/ */
#define CLASS_IMPLEMENTS_INTERFACE(cls,index) \
( ((index) < (cls)->vftbl->interfacetablelength) \
&& (VFTBLINTERFACETABLE((cls)->vftbl,(index)) != NULL) )
+/**********************************************************************/
+/* TYPEVECTOR FUNCTIONS */
+/**********************************************************************/
+
+typevector *
+typevectorset_copy(typevector *src,int k,int size)
+{
+ typevector *dst = DNEW_TYPEVECTOR(size);
+
+ memcpy(dst,src,TYPEVECTOR_SIZE(size));
+ dst->k = k;
+ if (src->alt)
+ dst->alt = typevectorset_copy(src->alt,k+1,size);
+ return dst;
+}
+
+#if 0
+typevector *
+typevectorset_copy_select(typevector *src,
+ int retindex,void *retaddr,int size)
+{
+ typevector *dst;
+
+ for (;src; src=src->alt) {
+ if (TYPEINFO_RETURNADDRESS(src->td[retindex].info) != retaddr)
+ continue;
+
+ dst = DNEW_TYPEVECTOR(size);
+ memcpy(dst,src,TYPEVECTOR_SIZE(size));
+ if (src->alt)
+ dst->alt = typevectorset_copy_select(src->alt,retindex,retaddr,size);
+ return dst;
+ }
+
+ return NULL;
+}
+
+void
+typevectorset_copy_select_to(typevector *src,typevector *dst,
+ int retindex,void *retaddr,int size)
+{
+ for (;src; src=src->alt) {
+ if (TYPEINFO_RETURNADDRESS(src->td[retindex].info) != retaddr)
+ continue;
+
+ memcpy(dst,src,TYPEVECTOR_SIZE(size));
+ if (src->alt)
+ dst->alt = typevectorset_copy_select(src->alt,retindex,retaddr,size);
+ return dst;
+ }
+
+ return NULL;
+}
+#endif
+
+bool
+typevectorset_checktype(typevector *vec,int index,int type)
+{
+ do {
+ if (vec->td[index].type != type)
+ return false;
+ } while ((vec = vec->alt) != NULL);
+ return true;
+}
+
+bool
+typevectorset_checkreference(typevector *vec,int index)
+{
+ do {
+ if (!TYPEDESC_IS_REFERENCE(vec->td[index]))
+ return false;
+ } while ((vec = vec->alt) != NULL);
+ return true;
+}
+
+bool
+typevectorset_checkretaddr(typevector *vec,int index)
+{
+ do {
+ if (!TYPEDESC_IS_RETURNADDRESS(vec->td[index]))
+ return false;
+ } while ((vec = vec->alt) != NULL);
+ return true;
+}
+
+int
+typevectorset_copymergedtype(typevector *vec,int index,typeinfo *dst)
+{
+ int type;
+ typedescriptor *td;
+
+ td = vec->td + index;
+ type = td->type;
+ TYPEINFO_COPY(td->info,*dst);
+
+ if (vec->alt) {
+ int primitive;
+
+ primitive = TYPEINFO_IS_PRIMITIVE(*dst) ? 1 : 0;
+
+ while ((vec = vec->alt) != NULL) {
+ td = vec->td + index;
+ if (type != td->type)
+ return TYPE_VOID;
+
+ if (type == TYPE_ADDRESS) {
+ if ((TYPEINFO_IS_PRIMITIVE(td->info) ? 1 : 0) != primitive)
+ return TYPE_VOID;
+ typeinfo_merge(dst,&(td->info));
+ }
+ }
+ }
+ return type;
+}
+
+int
+typevectorset_mergedtype(typevector *vec,int index,typeinfo *temp,typeinfo **result)
+{
+ if (vec->alt) {
+ *result = temp;
+ return typevectorset_copymergedtype(vec,index,temp);
+ }
+
+ *result = &(vec->td[index].info);
+ return vec->td[index].type;
+}
+
+typeinfo *
+typevectorset_mergedtypeinfo(typevector *vec,int index,typeinfo *temp)
+{
+ typeinfo *result;
+ int type = typevectorset_mergedtype(vec,index,temp,&result);
+ return (type == TYPE_ADDRESS) ? result : NULL;
+}
+
+void
+typevectorset_store(typevector *vec,int index,int type,typeinfo *info)
+{
+ /* XXX check if a separator was overwritten */
+ do {
+ vec->td[index].type = type;
+ if (info)
+ TYPEINFO_COPY(*info,vec->td[index].info);
+ if (index > 0 && IS_2_WORD_TYPE(vec->td[index-1].type))
+ vec->td[index-1].type = TYPE_VOID;
+ } while ((vec = vec->alt) != NULL);
+}
+
+void
+typevectorset_store_retaddr(typevector *vec,int index,typeinfo *info)
+{
+ typeinfo_retaddr_set *adr;
+
+ /* XXX check if a separator was overwritten */
+ adr = (typeinfo_retaddr_set*) TYPEINFO_RETURNADDRESS(*info);
+ do {
+ vec->td[index].type = TYPE_ADDRESS;
+ TYPEINFO_INIT_RETURNADDRESS(vec->td[index].info,adr->addr);
+ if (index > 0 && IS_2_WORD_TYPE(vec->td[index-1].type))
+ vec->td[index-1].type = TYPE_VOID;
+ adr = adr->alt;
+ } while ((vec = vec->alt) != NULL);
+}
+
+void
+typevectorset_store_twoword(typevector *vec,int index,int type)
+{
+ /* XXX check if a separator was overwritten */
+ do {
+ vec->td[index].type = type;
+ vec->td[index+1].type = TYPE_VOID;
+ if (index > 0 && IS_2_WORD_TYPE(vec->td[index-1].type))
+ vec->td[index-1].type = TYPE_VOID;
+ } while ((vec = vec->alt) != NULL);
+}
+
+void
+typevectorset_init_object(typevector *set,void *ins,classinfo *initclass,
+ int size)
+{
+ int i;
+
+ for (;set; set=set->alt) {
+ for (i=0; i<size; ++i) {
+ if (set->td[i].type == TYPE_ADR
+ && TYPEINFO_IS_NEWOBJECT(set->td[i].info)
+ && TYPEINFO_NEWOBJECT_INSTRUCTION(set->td[i].info) == ins)
+ {
+ TYPEINFO_INIT_CLASSINFO(set->td[i].info,initclass);
+ }
+ }
+ }
+}
+
+bool
+typevector_merge(typevector *dst,typevector *y,int size)
+{
+ bool changed = false;
+
+ typedescriptor *a = dst->td;
+ typedescriptor *b = y->td;
+ while (size--) {
+ if (a->type != TYPE_VOID && a->type != b->type) {
+ a->type = TYPE_VOID;
+ changed = true;
+ }
+ else if (a->type == TYPE_ADDRESS) {
+ if (TYPEINFO_IS_PRIMITIVE(a->info)) {
+ /* 'a' is a returnAddress */
+ if (!TYPEINFO_IS_PRIMITIVE(b->info)
+ || (TYPEINFO_RETURNADDRESS(a->info)
+ != TYPEINFO_RETURNADDRESS(b->info)))
+ {
+ a->type = TYPE_VOID;
+ changed = true;
+ }
+ }
+ else {
+ /* 'a' is a reference */
+ if (TYPEINFO_IS_PRIMITIVE(b->info)) {
+ a->type = TYPE_VOID;
+ changed = true;
+ }
+ else {
+ changed |= typeinfo_merge(&(a->info),&(b->info));
+ }
+ }
+ }
+ a++;
+ b++;
+ }
+ return changed;
+}
+
+bool typevector_separable_from(typevector *a,typevector *b,int size)
+{
+ typedescriptor *tda = a->td;
+ typedescriptor *tdb = b->td;
+ for (;size--; tda++,tdb++) {
+ if (TYPEDESC_IS_RETURNADDRESS(*tda)
+ && TYPEDESC_IS_RETURNADDRESS(*tdb)
+ && TYPEINFO_RETURNADDRESS(tda->info)
+ != TYPEINFO_RETURNADDRESS(tdb->info))
+ return true;
+ }
+ return false;
+}
+
+void
+typevectorset_add(typevector *dst,typevector *v,int size)
+{
+ while (dst->alt)
+ dst = dst->alt;
+ dst->alt = DNEW_TYPEVECTOR(size);
+ memcpy(dst->alt,v,TYPEVECTOR_SIZE(size));
+ dst->alt->alt = NULL;
+ dst->alt->k = dst->k + 1;
+}
+
+#if 0
+void
+typevectorset_union(typevector *dst,typevector *v,int size)
+{
+ while (dst->alt)
+ dst = dst->alt;
+ dst->alt = typevectorset_copy(v,size);
+}
+#endif
+
+typevector *
+typevectorset_select(typevector **set,int retindex,void *retaddr)
+{
+ typevector *selected;
+
+ if (!*set) return NULL;
+
+ if (TYPEINFO_RETURNADDRESS((*set)->td[retindex].info) == retaddr) {
+ selected = *set;
+ *set = selected->alt;
+ selected->alt = typevectorset_select(set,retindex,retaddr);
+ }
+ else {
+ selected = typevectorset_select(&((*set)->alt),retindex,retaddr);
+ }
+ return selected;
+}
+
+/* XXX delete */
+#if 0
+bool
+typevectorset_separable(typevector *vec,int size)
+{
+ int i;
+ typevector *v;
+
+ for (i=0; i<size; ++i) {
+ v = vec;
+ do {
+ if (!TYPEDESC_IS_RETURNADDRESS(v->td[i]))
+ goto next_index;
+
+ v = v->alt;
+ if (!v) return true;
+ } while (v);
+ next_index:
+ }
+ return false;
+}
+#endif
+
+bool
+typevectorset_separable_with(typevector *set,typevector *add,int size)
+{
+ int i;
+ typevector *v;
+ void *addr;
+ bool separable;
+
+ for (i=0; i<size; ++i) {
+ if (!TYPEDESC_IS_RETURNADDRESS(add->td[i]))
+ continue;
+ addr = TYPEINFO_RETURNADDRESS(add->td[i].info);
+
+ v = set;
+ separable = false;
+ do {
+ if (!TYPEDESC_IS_RETURNADDRESS(v->td[i]))
+ goto next_index;
+ if (TYPEINFO_RETURNADDRESS(v->td[i].info) != addr)
+ separable = true;
+ v = v->alt;
+ if (!v && separable) return true;
+ } while (v);
+ next_index:
+ }
+ return false;
+}
+
+bool
+typevectorset_collapse(typevector *dst,int size)
+{
+ bool changed = false;
+
+ while (dst->alt) {
+ typevector_merge(dst,dst->alt,size);
+ dst->alt = dst->alt->alt;
+ changed = true;
+ }
+ return changed;
+}
+
/**********************************************************************/
/* READ-ONLY FUNCTIONS */
/* The following functions don't change typeinfo data. */
}
}
+int
+typedescriptors_init_from_method_args(typedescriptor *td,
+ utf *desc,
+ int buflen,bool twoword,
+ typedescriptor *returntype)
+{
+ char *utf_ptr = desc->text; /* current position in utf text */
+ char *end_pos = utf_end(desc); /* points behind utf string */
+ int args = 0;
+ classinfo *cls;
+
+ /* method descriptor must start with parenthesis */
+ if (utf_ptr == end_pos || *utf_ptr++ != '(') panic ("Missing '(' in method descriptor");
+
+ /* check arguments */
+ while (utf_ptr != end_pos && *utf_ptr != ')') {
+ if (++args > buflen)
+ panic("Buffer too small for method arguments.");
+
+ td->type = type_from_descriptor(&cls,utf_ptr,end_pos,&utf_ptr,
+ CLASSLOAD_NEW
+ | CLASSLOAD_NULLPRIMITIVE
+ | CLASSLOAD_NOVOID);
+
+ if (cls)
+ TYPEINFO_INIT_CLASSINFO(td->info,cls);
+ else {
+ TYPEINFO_INIT_PRIMITIVE(td->info);
+ }
+ td++;
+
+ if (twoword && (td[-1].type == TYPE_LONG || td[-1].type == TYPE_DOUBLE)) {
+ if (++args > buflen)
+ panic("Buffer too small for method arguments.");
+ td->type = TYPE_VOID;
+ TYPEINFO_INIT_PRIMITIVE(td->info);
+ td++;
+ }
+ }
+ utf_ptr++; /* skip ')' */
+
+ /* check returntype */
+ if (returntype) {
+ returntype->type = type_from_descriptor(&cls,utf_ptr,end_pos,&utf_ptr,
+ CLASSLOAD_NULLPRIMITIVE
+ | CLASSLOAD_NEW
+ | CLASSLOAD_CHECKEND);
+ if (cls)
+ TYPEINFO_INIT_CLASSINFO(returntype->info,cls);
+ else
+ TYPEINFO_INIT_PRIMITIVE(returntype->info);
+ }
+ return args;
+}
+
void
typeinfo_init_component(typeinfo *srcarray,typeinfo *dst)
{
return false;
/* Merging two returnAddress types is ok. */
- if (!dest->typeclass && !y->typeclass)
+ if (!dest->typeclass && !y->typeclass) {
+#ifdef TYPEINFO_DEBUG
+ if (TYPEINFO_RETURNADDRESS(*dest) != TYPEINFO_RETURNADDRESS(*y))
+ panic("Internal error: typeinfo_merge merges different returnAddresses");
+#endif
return false;
+ }
/* Primitive types cannot be merged with reference types */
+ /* XXX only check this in debug mode? */
if (!dest->typeclass || !y->typeclass)
typeinfo_merge_error("Trying to merge primitive types.",dest,y);
int i;
char ind[TYPEINFO_MAXINDENT + 1];
instruction *ins;
+ basicblock *bptr;
if (indent > TYPEINFO_MAXINDENT) indent = TYPEINFO_MAXINDENT;
ind[i] = (char) 0;
if (TYPEINFO_IS_PRIMITIVE(*info)) {
- fprintf(file,"%sprimitive\n",ind);
+ bptr = (basicblock*) TYPEINFO_RETURNADDRESS(*info);
+ if (bptr)
+ fprintf(file,"%sreturnAddress (L%03d)\n",ind,bptr->debug_nr);
+ else
+ fprintf(file,"%sprimitive\n",ind);
return;
}
{
int i;
instruction *ins;
+ basicblock *bptr;
if (TYPEINFO_IS_PRIMITIVE(*info)) {
- fprintf(file,"primitive");
+ bptr = (basicblock*) TYPEINFO_RETURNADDRESS(*info);
+ if (bptr)
+ fprintf(file,"ret(L%03d)",bptr->debug_nr);
+ else
+ fprintf(file,"primitive");
return;
}
case TYPE_DOUBLE: fprintf(file,"D"); break;
case TYPE_LONG: fprintf(file,"J"); break;
case TYPE_ADDRESS:
- if (TYPEINFO_IS_PRIMITIVE(*info))
- fprintf(file,"R"); /* returnAddress */
- else {
- typeinfo_print_short(file,info);
- }
+ typeinfo_print_short(file,info);
break;
default:
}
}
+void
+typeinfo_print_stacktype(FILE *file,int type,typeinfo *info)
+{
+ if (type == TYPE_ADDRESS && TYPEINFO_IS_PRIMITIVE(*info)) {
+ typeinfo_retaddr_set *set = (typeinfo_retaddr_set*)
+ TYPEINFO_RETURNADDRESS(*info);
+ fprintf(file,"ret(L%03d",((basicblock*)(set->addr))->debug_nr);
+ set = set->alt;
+ while (set) {
+ fprintf(file,"|L%03d",((basicblock*)(set->addr))->debug_nr);
+ set = set->alt;
+ }
+ fprintf(file,")");
+ }
+ else
+ typeinfo_print_type(file,type,info);
+}
+
+void
+typedescriptor_print(FILE *file,typedescriptor *td)
+{
+ typeinfo_print_type(file,td->type,&(td->info));
+}
+
+void
+typevector_print(FILE *file,typevector *vec,int size)
+{
+ int i;
+
+ fprintf(file,"[%d]",vec->k);
+ for (i=0; i<size; ++i) {
+ fprintf(file," %d=",i);
+ typedescriptor_print(file,vec->td + i);
+ }
+}
+
+void
+typevectorset_print(FILE *file,typevector *set,int size)
+{
+ int i;
+ typevector *vec;
+
+ fprintf(file,"[%d",set->k);
+ vec = set->alt;
+ while (vec) {
+ fprintf(file,"|%d",vec->k);
+ vec = vec->alt;
+ }
+ fprintf(file,"]");
+
+ for (i=0; i<size; ++i) {
+ fprintf(file," %d=",i);
+ typedescriptor_print(file,set->td + i);
+ vec = set->alt;
+ while (vec) {
+ fprintf(file,"|");
+ typedescriptor_print(file,vec->td + i);
+ vec = vec->alt;
+ }
+ }
+}
+
#endif /* TYPEINFO_DEBUG */
Authors: Edwin Steiner
- $Id: typeinfo.h 795 2003-12-16 22:27:52Z edwin $
+ $Id: typeinfo.h 868 2004-01-10 20:12:10Z edwin $
*/
typedef struct typeinfo typeinfo;
typedef struct typeinfo_mergedlist typeinfo_mergedlist;
+typedef struct typedescriptor typedescriptor;
+typedef struct typevector typevector;
+typedef struct typeinfo_retaddr_set typeinfo_retaddr_set;
/* global variables ***********************************************************/
* access typeinfo structures!
*/
struct typeinfo {
- classinfo *typeclass;
- classinfo *elementclass; /* valid if dimension>0 */
- typeinfo_mergedlist *merged;
- u1 dimension;
- u1 elementtype; /* valid if dimension>0 */
+ classinfo *typeclass;
+ classinfo *elementclass; /* valid if dimension>0 */ /* XXX various uses */
+ typeinfo_mergedlist *merged;
+ u1 dimension;
+ u1 elementtype; /* valid if dimension>0 */
};
struct typeinfo_mergedlist {
- s4 count;
- classinfo *list[1]; /* variable length! */
+ s4 count;
+ classinfo *list[1]; /* variable length! */
+};
+
+struct typeinfo_retaddr_set {
+ typeinfo_retaddr_set *alt; /* next alternative in set */
+ void *addr; /* return address */
+};
+
+struct typedescriptor {
+ typeinfo info; /* valid if type == TYPE_ADR */
+ u1 type; /* basic type (TYPE_INT, ...) */
+};
+
+/* typevectors are used to store the types of local variables */
+
+struct typevector {
+ typevector *alt; /* next alternative in typevector set */
+ int k; /* for lining up with the stack set */
+ typedescriptor td[1]; /* variable length! */
};
/****************************************************************************/
/* MACROS */
/****************************************************************************/
-/* NOTE: These macros take typeinfo *structs* not pointers as arguments.
- * You have to dereference any pointers.
+/* NOTE: The TYPEINFO macros take typeinfo *structs*, not pointers as
+ * arguments. You have to dereference any pointers.
*/
+/* typevectors **************************************************************/
+
+#define TYPEVECTOR_SIZE(size) \
+ ((sizeof(typevector) - sizeof(typedescriptor)) \
+ + (size)*sizeof(typedescriptor))
+
+#define DNEW_TYPEVECTOR(size) \
+ ((typevector*)dump_alloc(TYPEVECTOR_SIZE(size)))
+
+#define DMNEW_TYPEVECTOR(num,size) \
+ ((void*)dump_alloc((num) * TYPEVECTOR_SIZE(size)))
+
+#define MGET_TYPEVECTOR(array,index,size) \
+ ((typevector*) (((u1*)(array)) + TYPEVECTOR_SIZE(size) * (index)))
+
+#define COPY_TYPEVECTORSET(src,dst,size) \
+ do {memcpy(dst,src,TYPEVECTOR_SIZE(size)); \
+ dst->k = 0; \
+ if ((src)->alt) { \
+ (dst)->alt = typevectorset_copy((src)->alt,1,size); \
+ }} while(0)
+
/* internally used macros ***************************************************/
/* internal, don't use this explicitly! */
#define TYPEINFO_IS_NEWOBJECT(info) \
((info).typeclass == pseudo_class_New)
+/* only use this if TYPEINFO_IS_PRIMITIVE returned true! */
+#define TYPEINFO_RETURNADDRESS(info) \
+ ((void *)(info).elementclass)
+
/* only use this if TYPEINFO_IS_NEWOBJECT returned true! */
#define TYPEINFO_NEWOBJECT_INSTRUCTION(info) \
((void *)(info).elementclass)
( TYPEINFO_IS_ARRAY(info) \
&& TYPEINFO_IS_ARRAY_OF_REFS_NOCHECK(info) )
+#define TYPE_IS_RETURNADDRESS(type,info) \
+ ( ((type)==TYPE_ADDRESS) \
+ && TYPEINFO_IS_PRIMITIVE(info) )
+
+#define TYPE_IS_REFERENCE(type,info) \
+ ( ((type)==TYPE_ADDRESS) \
+ && !TYPEINFO_IS_PRIMITIVE(info) )
+
+#define TYPEDESC_IS_RETURNADDRESS(td) \
+ TYPE_IS_RETURNADDRESS((td).type,(td).info)
+
+#define TYPEDESC_IS_REFERENCE(td) \
+ TYPE_IS_REFERENCE((td).type,(td).info)
+
/* queries allowing the null type ********************************************/
#define TYPEINFO_MAYBE_ARRAY(info) \
(info).dimension = 0; \
(info).elementtype = 0;} while(0)
+#define TYPEINFO_INIT_RETURNADDRESS(info,adr) \
+ do {(info).typeclass = NULL; \
+ (info).elementclass = (classinfo*) (adr); \
+ (info).merged = NULL; \
+ (info).dimension = 0; \
+ (info).elementtype = 0;} while(0)
+
#define TYPEINFO_INIT_NON_ARRAY_CLASSINFO(info,cinfo) \
do {(info).typeclass = (cinfo); \
(info).elementclass = NULL; \
/* FUNCTIONS */
/****************************************************************************/
+/* typevector functions *****************************************************/
+
+/* element read-only access */
+bool typevectorset_checktype(typevector *set,int index,int type);
+bool typevectorset_checkreference(typevector *set,int index);
+bool typevectorset_checkretaddr(typevector *set,int index);
+int typevectorset_copymergedtype(typevector *set,int index,typeinfo *dst);
+typeinfo *typevectorset_mergedtypeinfo(typevector *set,int index,typeinfo *temp);
+int typevectorset_mergedtype(typevector *set,int index,typeinfo *temp,typeinfo **result);
+
+/* element write access */
+void typevectorset_store(typevector *set,int index,int type,typeinfo *info);
+void typevectorset_store_retaddr(typevector *set,int index,typeinfo *info);
+void typevectorset_store_twoword(typevector *set,int index,int type);
+void typevectorset_init_object(typevector *set,void *ins,classinfo *initclass,int size);
+
+/* vector functions */
+bool typevector_separable_from(typevector *a,typevector *b,int size);
+bool typevector_merge(typevector *dst,typevector *y,int size);
+
+/* vector set functions */
+typevector *typevectorset_copy(typevector *src,int k,int size);
+/* typevector *typevectorset_copy_select(typevector *src,
+ int retindex,void *retaddr,int size);
+ void typevectorset_copy_select_to(typevector *src,typevector *dst,
+ int retindex,void *retaddr,int size); */
+/* bool typevectorset_separable(typevector *set,int size); */
+bool typevectorset_separable_with(typevector *set,typevector *add,int size);
+bool typevectorset_collapse(typevector *dst,int size);
+void typevectorset_add(typevector *dst,typevector *v,int size);
+/* void typevectorset_union(typevector *dst,typevector *v,int size); */
+typevector *typevectorset_select(typevector **set,int retindex,void *retaddr);
+
/* inquiry functions (read-only) ********************************************/
bool typeinfo_is_array(typeinfo *info);
typeinfo *infobuf,
int buflen,bool twoword,
int *returntype,typeinfo *returntypeinfo);
+int typedescriptors_init_from_method_args(typedescriptor *td,
+ utf *desc,
+ int buflen,bool twoword,
+ typedescriptor *returntype);
void typeinfo_clone(typeinfo *src,typeinfo *dest);
void typeinfo_print(FILE *file,typeinfo *info,int indent);
void typeinfo_print_short(FILE *file,typeinfo *info);
void typeinfo_print_type(FILE *file,int type,typeinfo *info);
+void typeinfo_print_stacktype(FILE *file,int type,typeinfo *info);
+void typedescriptor_print(FILE *file,typedescriptor *td);
+void typevector_print(FILE *file,typevector *vec,int size);
+void typevectorset_print(FILE *file,typevector *set,int size);
#endif /* TYPEINFO_DEBUG */