## Process this file with automake to produce Makefile.in
-# $Id: Makefile.am 687 2003-12-04 22:29:54Z edwin $
+# $Id: Makefile.am 696 2003-12-06 20:10:05Z edwin $
@SET_MAKE@
tables.c \
tables.h \
unzip.c \
- typeinfo.c
+ typeinfo.c \
+ typeinfo.h
cacao_LDADD = \
jit/libjit.a \
calls instead of machine instructions, using the C calling
convention.
- $Id: builtin.c 689 2003-12-05 18:03:47Z stefan $
+ $Id: builtin.c 696 2003-12-06 20:10:05Z edwin $
*/
*****************************************************************************/
-s4 builtin_checkarraycast(java_objectheader *o,arraydescriptor *target)
+s4 builtin_checkarraycast(java_objectheader *o,vftbl *target)
{
arraydescriptor *desc;
if (!o) return 1;
if ((desc = o->vftbl->arraydesc) == NULL) return 0;
- return builtin_descriptorscompatible(desc,target);
+ return builtin_descriptorscompatible(desc,target->arraydesc);
}
-s4 builtin_arrayinstanceof(java_objectheader *obj,arraydescriptor *desc)
+s4 builtin_arrayinstanceof(java_objectheader *obj,vftbl *target)
{
if (!obj) return 1;
- return builtin_checkarraycast (obj, desc);
+ return builtin_checkarraycast (obj, target);
}
/************************** exception functions *******************************
s4 builtin_checkcast(java_objectheader *obj, classinfo *class);
s4 asm_builtin_checkcast(java_objectheader *obj, classinfo *class);
-s4 builtin_arrayinstanceof(java_objectheader *obj, arraydescriptor *desc);
+s4 builtin_arrayinstanceof(java_objectheader *obj, vftbl *target);
#ifdef __I386__
s4 asm_builtin_arrayinstanceof(java_objectheader *obj, classinfo *class); /* XXX ? */
#endif
-s4 builtin_checkarraycast(java_objectheader *obj, arraydescriptor *desc);
-s4 asm_builtin_checkarraycast(java_objectheader *obj, arraydescriptor *desc);
+s4 builtin_checkarraycast(java_objectheader *obj, vftbl *target);
+s4 asm_builtin_checkarraycast(java_objectheader *obj, vftbl *target);
java_objectheader *builtin_throw_exception (java_objectheader *exception);
java_objectheader *builtin_trace_exception (java_objectheader *exceptionptr,
Philipp Tomsich
Edwin Steiner
- $Id: global.h 687 2003-12-04 22:29:54Z edwin $
+ $Id: global.h 696 2003-12-06 20:10:05Z edwin $
*/
*/
#define SIZE_FROM_CLASSINFO
+/*
+ * CACAO_TYPECHECK activates typechecking (part of bytecode verification)
+ */
+#define CACAO_TYPECHECK
+
+/*
+ * Macros for configuration of the typechecking code
+ *
+ * TYPEINFO_DEBUG activates debug checks and debug helpers in typeinfo.c
+ * TYPECHECK_DEBUG activates debug checks in typecheck.c
+ * TYPEINFO_DEBUG_TEST activates the typeinfo test at startup.
+ * TYPECHECK_VERBOSE_IMPORTANT activates important debug messages
+ * TYPECHECK_VERBOSE activates all debug messages
+ */
+#define TYPEINFO_DEBUG
+#define TYPECHECK_DEBUG
+/*#define TYPEINFO_DEBUG_TEST*/
+#define TYPECHECK_VERBOSE
+/*#define TYPECHECK_VERBOSE_IMPORTANT*/
+#if defined(TYPECHECK_VERBOSE) || defined(TYPECHECK_VERBOSE_IMPORTANT)
+#define TYPECHECK_VERBOSE_OPT
+#endif
+
/* standard includes **********************************************************/
#include <stdio.h>
extern bool opt_rt; /* Rapid Type Analysis for better inlining CO-RT*/
extern bool opt_xta; /* X Type Analysis for better inlining CO-XTA*/
extern bool opt_vta; /* Variable Type Analysis for better inlining CO-VTA*/
+#ifdef TYPECHECK_VERBOSE_OPT
+extern bool typecheckverbose;
+#endif
//extern int pClassHeir;
//extern int pCallgraph;
## Process this file with automake to produce Makefile.in
-# $Id: Makefile.am 662 2003-11-21 18:06:25Z jowenn $
+# $Id: Makefile.am 696 2003-12-06 20:10:05Z edwin $
SUBDIRS = . loop @ARCH_DIR@
sets.h \
parseRT.c \
parseRTprint.h \
- parseRTstats.c
+ parseRTstats.c \
+ typecheck.c
noinst_HEADERS = \
parse.h \
noinst_LIBRARIES = libjit.a
-libjit_a_SOURCES = jit.c parse.c stack.c inline.c sets.c parseRT.c parseRTstats.c
+libjit_a_SOURCES = jit.c parse.c stack.c inline.c sets.c parseRT.c parseRTstats.c typecheck.c
all-local:
$(MAKE) $(AM_MAKEFLAGS) -C .. jit/@ARCH_DIR@/offsets.h
Authors: Andreas Krall
Reinhard Grafl
- $Id: jit.c 689 2003-12-05 18:03:47Z stefan $
+ $Id: jit.c 696 2003-12-06 20:10:05Z edwin $
*/
basicblock *last_block; /* points to the end of the BB list */
+bool regs_ok; /* true if registers have been allocated */
+
/* list of all classes used by the compiled method which have to be */
/* initialised (if not already done) before execution of this method */
chain *uninitializedclasses;
count_methods++;
intsDisable(); /* disable interrupts */
-
+
+ regs_ok = false;
/* mark start of dump memory area */
parse();
analyse_stack();
+#ifdef CACAO_TYPECHECK
+ typecheck();
+#endif
+
if (opt_loops) {
depthFirst();
analyseGraph();
#endif
regalloc();
+ regs_ok = true;
codegen();
/* intermediate and assembly code listings ********************************/
Changes: Christian Thalinger
- $Id: jit.h 665 2003-11-21 18:36:43Z jowenn $
+ $Id: jit.h 696 2003-12-06 20:10:05Z edwin $
*/
#include "toolbox/chain.h"
#include "global.h"
+#include "typeinfo.h"
/**************************** resolve typedef-cycles **************************/
/* slot types */
+/* XXX use TYPE_ADDRESS, ...? */
#define TYPE_INT 0 /* the stack slot types must numbered in the */
#define TYPE_LNG 1 /* same order as the ICMD_Ixxx to ICMD_Axxx */
#define TYPE_FLT 2 /* instructions (LOAD and STORE) */
struct stackelement {
stackptr prev; /* pointer to next element towards bottom */
int type; /* slot type of stack element */
+#ifdef CACAO_TYPECHECK
+ typeinfo typeinfo; /* info on reference types */
+#endif
int flags; /* flags (SAVED, INMEMORY) */
int varkind; /* kind of variable or register */
int varnum; /* number of variable */
#define BBUNDEF -1
#define BBREACHED 0
#define BBFINISHED 1
+#define BBTYPECHECK_UNDEF 2
+#define BBTYPECHECK_REACHED 3
#define BBTYPE_STD 0 /* standard basic block type */
#define BBTYPE_EXH 1 /* exception handler basic block type */
extern basicblock *last_block; /* points to the end of the BB list */
+extern bool regs_ok; /* true if registers have been allocated */
+
+
/* list of all classes used by the compiled method which have to be */
/* initialised (if not already done) before execution of this method */
extern chain *uninitializedclasses;
void removecompilerstub(u1 *stub);
void removenativestub(u1 *stub);
+/* debug helpers (in stack.c) */
+
+void icmd_print_stack(stackptr s);
+void show_icmd_block(basicblock *bptr);
+void show_icmd(instruction *iptr,bool deadcode);
+void show_icmd_method();
+
#endif /* _JIT_H */
Author: Andreas Krall
Changes: Carolyn Oates
+ Edwin Steiner
- $Id: parse.c 689 2003-12-05 18:03:47Z stefan $
+ $Id: parse.c 696 2003-12-06 20:10:05Z edwin $
*/
classinfo *cls = (classinfo*)class_getconstant(class, i, CONSTANT_Class);
if (cls->vftbl->arraydesc) {
/* array type cast-check */
- LOADCONST_A(cls->vftbl->arraydesc);
+ LOADCONST_A(cls->vftbl);
s_count++;
BUILTIN2((functionptr) asm_builtin_checkarraycast, TYPE_ADR);
}
classinfo *cls = (classinfo*)class_getconstant(class, i, CONSTANT_Class);
if (cls->vftbl->arraydesc) {
/* array type cast-check */
- LOADCONST_A(cls->vftbl->arraydesc);
+ LOADCONST_A(cls->vftbl);
s_count++;
#if defined(__I386__)
BUILTIN2((functionptr) asm_builtin_arrayinstanceof, TYPE_INT);
Authors: Andreas Krall
- $Id: stack.c 665 2003-11-21 18:36:43Z jowenn $
+ Changes: Edwin Steiner
+
+ $Id: stack.c 696 2003-12-06 20:10:05Z edwin $
*/
iptr[0].target = (void *) tbptr;
+ /* XXX This is a dirty hack. The typechecker
+ * needs it because the OP1_0ANY below
+ * overwrites iptr->dst.
+ */
+ iptr->val.a = (void*) iptr->dst;
+
tbptr->type=BBTYPE_SBR;
MARKREACHED(tbptr, copy);
OP1_0ANY;
}
-static void print_stack(stackptr s)
+void icmd_print_stack(stackptr s)
{
int i, j;
stackptr t;
printf(" ");
while (s) {
j--;
+ /* XXX remove */ /* printf("(%d)",s->flags); fflush(stdout); */
if (s->flags & SAVEDVAR)
switch (s->varkind) {
case TEMPVAR:
if (s->flags & INMEMORY)
- printf(" M%02d", s->regoff);
+ printf((regs_ok) ? " M%02d" : " M??", s->regoff);
else if ((s->type == TYPE_FLT) || (s->type == TYPE_DBL))
- printf(" F%02d", s->regoff);
- else
- printf(" %3s", regs[s->regoff]);
+ printf((regs_ok) ? " F%02d" : " F??", s->regoff);
+ else {
+ if (regs_ok) printf(" %3s",regs[s->regoff]); else printf(" ???");
+ }
break;
case STACKVAR:
printf(" I%02d", s->varnum);
switch (s->varkind) {
case TEMPVAR:
if (s->flags & INMEMORY)
- printf(" m%02d", s->regoff);
+ printf((regs_ok) ? " m%02d" : " m??", s->regoff);
else if ((s->type == TYPE_FLT) || (s->type == TYPE_DBL))
- printf(" f%02d", s->regoff);
- else
- printf(" %3s", regs[s->regoff]);
+ printf((regs_ok) ? " f%02d" : " f??", s->regoff);
+ else {
+ if (regs_ok) printf(" %3s",regs[s->regoff]); else printf(" ???");
+ }
break;
case STACKVAR:
printf(" i%02d", s->varnum);
#endif
-static char *builtin_name(functionptr bptr)
+char *icmd_builtin_name(functionptr bptr)
{
builtin_descriptor *bdesc = builtin_desc;
while ((bdesc->bptr != NULL) && (bdesc->bptr != bptr))
if (locals[i][j].type >= 0) {
printf(" (%s) ", jit_type[j]);
if (locals[i][j].flags & INMEMORY)
- printf("m%2d", locals[i][j].regoff);
+ printf((regs_ok) ? "m%2d" : "m??", locals[i][j].regoff);
else if ((j == TYPE_FLT) || (j == TYPE_DBL))
- printf("f%02d", locals[i][j].regoff);
- else
- printf("%3s", regs[locals[i][j].regoff]);
+ printf((regs_ok) ? "f%02d" : "f??", locals[i][j].regoff);
+ else {
+ if (regs_ok) printf("%3s",regs[locals[i][j].regoff]); else printf("???");
+ }
}
printf("\n");
}
printf(" (%s) ", jit_type[j]);
if (interfaces[i][j].flags & SAVEDVAR) {
if (interfaces[i][j].flags & INMEMORY)
- printf("M%2d", interfaces[i][j].regoff);
+ printf((regs_ok) ? "M%2d" : "M??", interfaces[i][j].regoff);
else if ((j == TYPE_FLT) || (j == TYPE_DBL))
- printf("F%02d", interfaces[i][j].regoff);
- else
- printf("%3s", regs[interfaces[i][j].regoff]);
+ printf((regs_ok) ? "F%02d" : "F??", interfaces[i][j].regoff);
+ else {
+ if (regs_ok) printf("%3s",regs[interfaces[i][j].regoff]); else printf("???");
+ }
}
else {
if (interfaces[i][j].flags & INMEMORY)
- printf("m%2d", interfaces[i][j].regoff);
+ printf((regs_ok) ? "m%2d" : "m??", interfaces[i][j].regoff);
else if ((j == TYPE_FLT) || (j == TYPE_DBL))
- printf("f%02d", interfaces[i][j].regoff);
- else
- printf("%3s", regs[interfaces[i][j].regoff]);
+ printf((regs_ok) ? "f%02d" : "f??", interfaces[i][j].regoff);
+ else {
+ if (regs_ok) printf("%3s",regs[interfaces[i][j].regoff]); else printf("???");
+ }
}
}
printf("\n");
for (bptr = block; bptr != NULL; bptr = bptr->next) {
+ show_icmd_block(bptr);
+ }
+}
+
+void
+show_icmd_block(basicblock *bptr)
+{
+ int i, j;
+ int deadcode;
+ s4 *s4ptr;
+ instruction *iptr;
+
if (bptr->flags != BBDELETED) {
deadcode = bptr->flags <= BBREACHED;
printf("[");
if (deadcode)
- for (j = maxstack; j > 0; j--)
+ for (j = method->maxstack; j > 0; j--)
printf(" ? ");
else
- print_stack(bptr->instack);
- printf("] L%03d(%d - %d):\n", bptr->debug_nr, bptr->icount, bptr->pre_count);
+ icmd_print_stack(bptr->instack);
+ printf("] L%03d(%d - %d) flags=%d:\n", bptr->debug_nr, bptr->icount, bptr->pre_count,bptr->flags);
iptr = bptr->iinstr;
for (i=0; i < bptr->icount; i++, iptr++) {
printf("[");
if (deadcode) {
- for (j = maxstack; j > 0; j--)
+ for (j = method->maxstack; j > 0; j--)
printf(" ? ");
}
else
- print_stack(iptr->dst);
- printf("] %4d %s", i, icmd_names[iptr->opc]);
- switch ((int) iptr->opc) {
+ icmd_print_stack(iptr->dst);
+ printf("] %4d ", i);
+ /* XXX remove */ /*fflush(stdout);*/
+ show_icmd(iptr,deadcode);
+ printf("\n");
+ }
+
+ if (showdisassemble && (!deadcode)) {
+#if defined(__I386__) || defined(__X86_64__)
+ u1 *u1ptr;
+ int a;
+
+ printf("\n");
+ i = bptr->mpc;
+ u1ptr = method->mcode + dseglen + i;
+
+ if (bptr->next != NULL) {
+ for (; i < bptr->next->mpc; i++, u1ptr++) {
+ a = disassinstr(u1ptr, i);
+ i += a;
+ u1ptr += a;
+ }
+ printf("\n");
+
+ } else {
+ for (; u1ptr < (u1 *) (method->mcode + method->mcodelength); i++, u1ptr++) {
+ a = disassinstr(u1ptr, i);
+ i += a;
+ u1ptr += a;
+ }
+ printf("\n");
+ }
+#else
+ printf("\n");
+ i = bptr->mpc;
+ s4ptr = (s4 *) (method->mcode + dseglen + i);
+
+ if (bptr->next != NULL) {
+ for (; i < bptr->next->mpc; i += 4, s4ptr++) {
+ disassinstr(*s4ptr, i);
+ }
+ printf("\n");
+ }
+ else {
+ for (; s4ptr < (s4 *) (method->mcode + method->mcodelength); i += 4, s4ptr++) {
+ disassinstr(*s4ptr, i);
+ }
+ printf("\n");
+ }
+#endif
+ }
+ }
+}
+
+void
+show_icmd(instruction *iptr,bool deadcode)
+{
+ int j;
+ s4 *s4ptr;
+ void **tptr;
+
+ printf("%s",icmd_names[iptr->opc]);
+ switch ((int) iptr->opc) {
case ICMD_IADDCONST:
case ICMD_ISUBCONST:
case ICMD_IMULCONST:
case ICMD_BUILTIN3:
case ICMD_BUILTIN2:
case ICMD_BUILTIN1:
- printf(" %s", builtin_name((functionptr) iptr->val.a));
+ printf(" %s", icmd_builtin_name((functionptr) iptr->val.a));
break;
case ICMD_INVOKEVIRTUAL:
case ICMD_INVOKESPECIAL:
case ICMD_IFGE:
case ICMD_IFGT:
case ICMD_IFLE:
- printf("(%d) L%03d", iptr->val.i, ((basicblock *) iptr->target)->debug_nr);
+ if (deadcode)
+ printf("(%d) op1=%d", iptr->val.i, iptr->op1);
+ else
+ printf("(%d) L%03d", iptr->val.i, ((basicblock *) iptr->target)->debug_nr);
break;
case ICMD_IF_LEQ:
case ICMD_IF_LNE:
case ICMD_IF_LGE:
case ICMD_IF_LGT:
case ICMD_IF_LLE:
- printf("(%lld) L%03d", iptr->val.l, ((basicblock *) iptr->target)->debug_nr);
+ if (deadcode)
+ printf("(%lld) op1=%d", iptr->val.l, iptr->op1);
+ else
+ printf("(%lld) L%03d", iptr->val.l, ((basicblock *) iptr->target)->debug_nr);
break;
case ICMD_JSR:
case ICMD_GOTO:
case ICMD_IF_LCMPLE:
case ICMD_IF_ACMPEQ:
case ICMD_IF_ACMPNE:
- printf(" L%03d", ((basicblock *) iptr->target)->debug_nr);
+ if (deadcode)
+ printf(" op1=%d", iptr->op1);
+ else
+ printf(" L%03d", ((basicblock *) iptr->target)->debug_nr);
break;
case ICMD_TABLESWITCH:
s4ptr = iptr->val.a;
- tptr = (void **) iptr->target;
-
- printf(" L%03d;", ((basicblock *) *tptr)->debug_nr);
- /* default */
- s4ptr++;
- tptr++;
+ if (deadcode) {
+ printf(" %d;", *s4ptr);
+ }
+ else {
+ tptr = (void **) iptr->target;
+ printf(" L%03d;", ((basicblock *) *tptr)->debug_nr);
+ tptr++;
+ }
+ s4ptr++; /* skip default */
j = *s4ptr++; /* low */
j = *s4ptr++ - j; /* high */
while (j >= 0) {
- printf(" L%03d", ((basicblock *) *tptr)->debug_nr);
- tptr++;
+ if (deadcode)
+ printf(" %d", *s4ptr++);
+ else {
+ printf(" L%03d", ((basicblock *) *tptr)->debug_nr);
+ tptr++;
+ }
j--;
}
break;
case ICMD_LOOKUPSWITCH:
s4ptr = iptr->val.a;
- tptr = (void **) iptr->target;
-
- printf(" L%03d", ((basicblock *) *tptr)->debug_nr);
- s4ptr++; /* default */
- j = *s4ptr; /* count */
- tptr++;
- while (--j >= 0) {
+ if (deadcode) {
+ printf(" %d;", *s4ptr);
+ }
+ else {
+ tptr = (void **) iptr->target;
printf(" L%03d", ((basicblock *) *tptr)->debug_nr);
tptr++;
}
- break;
- }
- printf("\n");
- }
-
- if (showdisassemble && (!deadcode)) {
-#if defined(__I386__) || defined(__X86_64__)
- u1 *u1ptr;
- int a;
-
- printf("\n");
- i = bptr->mpc;
- u1ptr = method->mcode + dseglen + i;
-
- if (bptr->next != NULL) {
- for (; i < bptr->next->mpc; i++, u1ptr++) {
- a = disassinstr(u1ptr, i);
- i += a;
- u1ptr += a;
- }
- printf("\n");
+ s4ptr++; /* default */
+ j = *s4ptr++; /* count */
- } else {
- for (; u1ptr < (u1 *) (method->mcode + method->mcodelength); i++, u1ptr++) {
- a = disassinstr(u1ptr, i);
- i += a;
- u1ptr += a;
+ while (--j >= 0) {
+ if (deadcode) {
+ s4ptr++; /* skip value */
+ printf(" %d",*s4ptr++);
+ }
+ else {
+ printf(" L%03d", ((basicblock *) *tptr)->debug_nr);
+ tptr++;
+ }
}
- printf("\n");
- }
-#else
- printf("\n");
- i = bptr->mpc;
- s4ptr = (s4 *) (method->mcode + dseglen + i);
-
- if (bptr->next != NULL) {
- for (; i < bptr->next->mpc; i += 4, s4ptr++) {
- disassinstr(*s4ptr, i);
- }
- printf("\n");
- }
- else {
- for (; s4ptr < (s4 *) (method->mcode + method->mcodelength); i += 4, s4ptr++) {
- disassinstr(*s4ptr, i);
- }
- printf("\n");
- }
-#endif
- }
- }
+ break;
}
}
-
/*
* These are local overrides for various environment variables in Emacs.
* Please do not remove this and leave it at the end of the file, where
--- /dev/null
+/* jit/typecheck.c - typechecking (part of bytecode verification)
+
+ Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
+ R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser,
+ M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck,
+ P. Tomsich, J. Wenninger
+
+ This file is part of CACAO.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+
+ Contact: cacao@complang.tuwien.ac.at
+
+ Authors: Edwin Steiner
+
+ $Id: typecheck.c 696 2003-12-06 20:10:05Z edwin $
+
+*/
+
+#include "global.h" /* must be here because of CACAO_TYPECHECK */
+
+#ifdef CACAO_TYPECHECK
+
+#include "jit.h"
+#include "builtin.h"
+#include "tables.h"
+#include "loader.h"
+#include "types.h"
+#include "toolbox/loging.h"
+#include "toolbox/memory.h"
+
+#define TOUCHED_YES 0x01
+#define TOUCHED_NO 0x02
+#define TOUCHED_MAYBE (TOUCHED_YES | TOUCHED_NO)
+
+#define REACH_STD 0
+#define REACH_JSR 1
+#define REACH_RET 2
+
+/****************************************************************************/
+/* DEBUG HELPERS */
+/****************************************************************************/
+
+#ifdef TYPECHECK_VERBOSE_OPT
+bool typecheckverbose = false;
+#define DOLOG(action) do { if (typecheckverbose) {action;} } while(0)
+#else
+#define DOLOG(action)
+#endif
+
+#ifdef TYPECHECK_VERBOSE
+#define TYPECHECK_VERBOSE_IMPORTANT
+#define LOG(str) DOLOG(log_text(str))
+#define LOG1(str,a) DOLOG(dolog(str,a))
+#define LOG2(str,a,b) DOLOG(dolog(str,a,b))
+#define LOG3(str,a,b,c) DOLOG(dolog(str,a,b,c))
+#define LOGIF(cond,str) DOLOG(do {if (cond) log_text(str);} while(0))
+#define LOGINFO(info) DOLOG(do {typeinfo_print_short(stdout,info);printf("\n");} while(0))
+#define LOGFLUSH DOLOG(fflush(stdout))
+#define LOGNL DOLOG(printf("\n"))
+#define LOGSTR(str) DOLOG(printf(str))
+#define LOGSTR1(str,a) DOLOG(printf(str,a))
+#define LOGSTR2(str,a,b) DOLOG(printf(str,a,b))
+#define LOGSTR3(str,a,b,c) DOLOG(printf(str,a,b,c))
+#define LOGSTRu(utf) DOLOG(utf_display(utf))
+#else
+#define LOG(str)
+#define LOG1(str,a)
+#define LOG2(str,a,b)
+#define LOG3(str,a,b,c)
+#define LOGIF(cond,str)
+#define LOGINFO(info)
+#define LOGFLUSH
+#define LOGNL
+#define LOGSTR(str)
+#define LOGSTR1(str,a)
+#define LOGSTR2(str,a,b)
+#define LOGSTR3(str,a,b,c)
+#endif
+
+#ifdef TYPECHECK_VERBOSE_IMPORTANT
+#define LOGimp(str) DOLOG(log_text(str))
+#define LOGimpSTR(str) DOLOG(printf(str))
+#define LOGimpSTRu(utf) DOLOG(utf_display(utf))
+#else
+#define LOGimp(str)
+#define LOGimpSTR(str)
+#define LOGimpSTRu(utf)
+#endif
+
+#if defined(TYPECHECK_VERBOSE) || defined(TYPECHECK_VERBOSE_IMPORTANT)
+
+static
+void
+typeinfo_print_locals(FILE *file,u1 *vtype,typeinfo *vinfo,u1 *touched,int num)
+{
+ int i;
+
+ for (i=0; i<num; ++i) {
+ if (touched)
+ fprintf(file," %d%s=",i,
+ (touched[i]==TOUCHED_YES) ? "*"
+ : ((touched[i]==TOUCHED_NO) ? "" : "~"));
+ else
+ fprintf(file," %d=",i);
+ typeinfo_print_type(file,vtype[i],vinfo+i);
+ }
+}
+
+static
+void
+typeinfo_print_stack(FILE *file,stackptr stack)
+{
+ while (stack) {
+ typeinfo_print_type(file,stack->type,&stack->typeinfo);
+ stack = stack->prev;
+ if (stack) fprintf(file," ");
+ }
+}
+
+static
+void
+typeinfo_print_block(FILE *file,stackptr instack,
+ u1 *vtype,typeinfo *vinfo,u1 *touched)
+{
+ fprintf(file,"Stack: ");
+ typeinfo_print_stack(file,instack);
+ fprintf(file," Locals:");
+ typeinfo_print_locals(file,vtype,vinfo,touched,maxlocals);
+}
+
+
+static
+void
+typeinfo_print_blocks(FILE *file,u1 *vtype,typeinfo *vinfo)
+{
+ int bi;
+ /* int j;*/
+
+ for (bi=0; bi<block_count; ++bi) {
+ fprintf(file,"%04d: (%3d) ",bi,block[bi].flags);
+ typeinfo_print_block(file,block[bi].instack,
+ vtype+maxlocals*bi,vinfo+maxlocals*bi,NULL);
+ fprintf(file,"\n");
+
+/* for (j=0; j<block[bi].icount; ++j) { */
+/* fprintf(file,"\t%s\n",icmd_names[block[bi].iinstr[j].opc]); */
+/* } */
+
+ show_icmd_block(block+bi);
+ }
+}
+
+#endif
+
+/****************************************************************************/
+/* INTERNAL DATA STRUCTURES */
+/****************************************************************************/
+
+typedef struct jsr_record jsr_record;
+
+/*
+ * For each basic block we store the chain of JSR instructions which
+ * were used to reach the block (usually zero or one). For more
+ * details on verifying JSR and RET instructions see the Java VM
+ * Specification.
+ *
+ * CAUTION: The fields starting with sbr_ are only valid for the
+ * 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 */
+};
+
+/****************************************************************************/
+/* MACROS USED INTERNALLY IN typecheck() */
+/****************************************************************************/
+
+#define TOUCH_VARIABLE(num) do {if (jsrchain) touched[num] = TOUCHED_YES;} while (0)
+#define TOUCH_TWOWORD(num) do {TOUCH_VARIABLE(num);TOUCH_VARIABLE((num)+1);} while (0)
+
+/* XXX should check num in range? */
+/* XXX invalidate two word variables on store in second half! */
+#define STORE_TYPE(num,type) do {vtype[(num)] = (type); TOUCH_VARIABLE(num);} while(0)
+#define STORE_INVALID(num) STORE_TYPE((num),TYPE_VOID)
+#define STORE_PRIMITIVE(num,type) STORE_TYPE((num),(type))
+#define STORE_TWOWORD(num,type) {STORE_PRIMITIVE((num),(type));STORE_INVALID((num)+1);}
+
+#define CHECKVARTYPE(num,type) \
+ {if (vtype[(num)] != (type)) panic("Variable type mismatch"); TOUCH_VARIABLE(num);}
+
+/* XXX maybe it's faster to copy always */
+#define COPYTYPE(source,dest) \
+ {if ((source)->type == TYPE_ADR) \
+ TYPEINFO_COPY((source)->typeinfo,(dest)->typeinfo);}
+
+#define ISBUILTIN(v) (iptr->val.a == (functionptr)(v))
+
+/* TYPECHECK_COPYVARS: copy the types and typeinfos of the current local
+ * variables to the local variables of the target block.
+ * Input:
+ * vtype......current local variable types
+ * vinfo......current local variable typeinfos
+ * ttype......local variable types of target block
+ * tinfo......local variable typeinfos of target block
+ * maxlocals..number of local variables
+ * Used:
+ * macro_i
+ */
+#define TYPECHECK_COPYVARS \
+ LOG("TYPECHECK_COPYVARS"); \
+ for (macro_i=0; macro_i<maxlocals; ++macro_i) { \
+ if ((ttype[macro_i] = vtype[macro_i]) == TYPE_ADR) \
+ TYPEINFO_CLONE(vinfo[macro_i],tinfo[macro_i]); \
+ }
+
+/* TYPECHECK_MERGEVARS: merge the local variables of the target block
+ * with the current local variables.
+ * Input:
+ * vtype......current local variable types
+ * vinfo......current local variable typeinfos
+ * ttype......local variable types of target block
+ * tinfo......local variable typeinfos of target block
+ * maxlocals..number of local variables
+ * Ouput:
+ * changed....set to true if any typeinfo has changed
+ * Used:
+ * macro_i
+ */
+#define TYPECHECK_MERGEVARS \
+ LOG("TYPECHECK_MERGEVARS"); \
+ for (macro_i=0; macro_i<maxlocals; ++macro_i) { \
+ if ((ttype[macro_i] != TYPE_VOID) && (vtype[macro_i] != ttype[macro_i])) { \
+ LOG3("var %d: type %d + type %d = void",macro_i,ttype[macro_i],vtype[macro_i]); \
+ ttype[macro_i] = TYPE_VOID; \
+ changed = true; \
+ } else if (ttype[macro_i] == TYPE_ADR) { \
+ if ( ((TYPEINFO_IS_PRIMITIVE(tinfo[macro_i])) ? 1 : 0) \
+ ^ \
+ ((TYPEINFO_IS_PRIMITIVE(vinfo[macro_i])) ? 1 : 0)) { \
+ LOG1("var %d: primitive + reference merge",macro_i); \
+ ttype[macro_i] = TYPE_VOID; \
+ changed = true; \
+ } \
+ else { \
+ LOG1("var %d:",macro_i); \
+ LOGINFO(tinfo+macro_i); \
+ LOGINFO(vinfo+macro_i); \
+ changed |= typeinfo_merge(tinfo+macro_i,vinfo+macro_i); \
+ LOGINFO(tinfo+macro_i); \
+ LOGIF(changed,"vars have changed"); \
+ } \
+ }; \
+ }
+
+/* TYPECHECK_MERGEJSR:
+ *
+ * Input:
+ * Ouput:
+ * tbptr......target block
+ * changed....set to true if any typeinfo has changed
+ * maxlocals..number of local variables
+ * touched....current touched flags of local variables
+ * Used:
+ * macro_i, jsrtemp, jsrtemp2
+ */
+#define TYPECHECK_MERGEJSR \
+ do { \
+ LOG("TYPECHECK_MERGEJSR"); \
+ jsrtemp = jsrbuffer[tbptr-block]; \
+ jsrtemp2 = jsrchain; \
+ while (jsrtemp || jsrtemp2) { \
+ if (!jsrtemp || !jsrtemp2) \
+ panic("Merging JSR subroutines of different depth"); \
+ if (jsrtemp->target != jsrtemp2->target) \
+ panic("Merging different JSR subroutines"); \
+ jsrtemp = jsrtemp->next; \
+ jsrtemp2 = jsrtemp2->next; \
+ } \
+ jsrtemp = jsrbuffer[tbptr-block]; \
+ if (jsrtemp) \
+ for (macro_i=0; macro_i<maxlocals; ++macro_i) { \
+ jsrtemp->touched[i] |= touched[i]; \
+ } } while (0)
+
+/* TYPECHECK_COPYSTACK: copy the typeinfos of the current stack to
+ * the input stack of the target block.
+ * Input:
+ * srcstack...current stack
+ * dststack...input stack of target block
+ */
+#define TYPECHECK_COPYSTACK \
+ LOG("TYPECHECK_COPYSTACK"); \
+ while (srcstack) { \
+ LOG1("copy %d",srcstack->type); \
+ if (!dststack) panic("Stack depth mismatch"); \
+ if (srcstack->type != dststack->type) \
+ panic("Type mismatch on stack"); \
+ if (srcstack->type == TYPE_ADR) { \
+ TYPEINFO_CLONE(srcstack->typeinfo,dststack->typeinfo); \
+ } \
+ dststack = dststack->prev; \
+ srcstack = srcstack->prev; \
+ } \
+ if (dststack) panic("Stack depth mismatch");
+
+/* TYPECHECK_MERGESTACK: merge the input stack of the target block
+ * with the current stack.
+ * Input:
+ * srcstack...current stack
+ * dststack...input stack of target block
+ * Ouput:
+ * changed....set to true if any typeinfo has changed
+ */
+#define TYPECHECK_MERGESTACK \
+ LOG("TYPECHECK_MERGESTACK"); \
+ while (srcstack) { \
+ if (!dststack) panic("Stack depth mismatch"); \
+ if (srcstack->type != dststack->type) \
+ panic("Type mismatch on stack"); \
+ if (srcstack->type == TYPE_ADR) { \
+ LOGINFO(&dststack->typeinfo); \
+ LOGINFO(&srcstack->typeinfo); LOGFLUSH; \
+ changed |= typeinfo_merge(&dststack->typeinfo, \
+ &srcstack->typeinfo); \
+ LOGINFO(&dststack->typeinfo); \
+ LOG((changed)?"CHANGED!\n":"not changed.\n"); \
+ } \
+ dststack = dststack->prev; \
+ srcstack = srcstack->prev; \
+ } \
+ if (dststack) panic("Stack depth mismatch");
+
+
+/* TYPECHECK_CHECK_JSR_CHAIN: checks if the target block is reached by
+ * the same JSR targets on all control paths.
+ *
+ * Input:
+ * tbptr......target block
+ * jsrchain...current JSR target chain
+ * jsrbuffer..JSR target chain for each basic block
+ * Output:
+ * panic if the JSR target chains don't match
+ * Used:
+ * jsrtemp, jsrtemp2
+ */
+#define TYPECHECK_CHECK_JSR_CHAIN \
+ do { \
+ jsrtemp = jsrbuffer[tbptr-block]; \
+ if (!jsrtemp) panic("non-subroutine called by JSR"); \
+ if (jsrtemp->target != tbptr) \
+ panic("Merging different JSR subroutines"); \
+ jsrtemp = jsrtemp->next; \
+ jsrtemp2 = jsrchain; \
+ while (jsrtemp || jsrtemp2) { \
+ if (!jsrtemp || !jsrtemp2) \
+ panic("Merging JSR subroutines of different depth"); \
+ if (jsrtemp->target != jsrtemp2->target) \
+ panic("Merging different JSR subroutines"); \
+ jsrtemp = jsrtemp->next; \
+ jsrtemp2 = jsrtemp2->next; \
+ } } while (0)
+
+/* TYPECHECK_ADD_JSR: add a JSR target to the current JSR target chain
+ * and store the resulting chain in the target block.
+ *
+ * Input:
+ * jsrchain...current JSR target chain
+ * tbptr.....the basic block targeted by the JSR
+ * maxlocals..number of local variables
+ * jsrbuffer..JSR target chain for each basic block
+ * Used:
+ * jsrtemp
+ */
+#define TYPECHECK_ADD_JSR \
+ do { \
+ LOG1("adding JSR to block %04d",(tbptr)-block); \
+ jsrtemp = (jsr_record *) dump_alloc(sizeof(jsr_record)+(maxlocals-1)*sizeof(u1)); \
+ jsrtemp->target = (tbptr); \
+ jsrtemp->next = jsrchain; \
+ jsrtemp->sbr_touched = NULL; \
+ memset(&jsrtemp->touched,TOUCHED_NO,sizeof(u1)*maxlocals); \
+ jsrbuffer[tbptr-block] = jsrtemp; \
+ } while (0)
+
+/* TYPECHECK_COPYJSR: copy the current JSR chain to the target block.
+ *
+ * Input:
+ * chain......current JSR target chain
+ * tbptr.....the basic block targeted by the JSR
+ * maxlocals..number of local variables
+ * jsrbuffer..JSR target chain for each basic block
+ * touched....current touched flags of local variables
+ * Used:
+ * jsrtemp
+ */
+#define TYPECHECK_COPYJSR(chain) \
+ do { \
+ LOG("TYPECHECK_COPYJSR"); \
+ if (chain) { \
+ jsrtemp = (jsr_record *) dump_alloc(sizeof(jsr_record)+(maxlocals-1)*sizeof(u1)); \
+ jsrtemp->target = (chain)->target; \
+ jsrtemp->next = (chain)->next; \
+ jsrtemp->sbr_touched = NULL; \
+ memcpy(&jsrtemp->touched,touched,sizeof(u1)*maxlocals); \
+ jsrbuffer[tbptr-block] = jsrtemp; \
+ } \
+ else \
+ jsrbuffer[tbptr-block] = NULL; \
+ } while (0)
+
+/* TYPECHECK_REACH: executed, when the target block (tbptr) can be reached
+ * from the current block (bptr). The types of local variables and
+ * stack slots are propagated to the target block.
+ * Input:
+ * bptr.......current block
+ * tbptr......target block
+ * dst........current output stack pointer
+ * vtype......current local variable types
+ * vinfo......current local variable typeinfos
+ * jsrchain...current JSR target chain
+ * jsrbuffer..JSR target chain for each basic block
+ * way........in which way the block is reached (REACH_ constant)
+ * touched....current touched flags of local variables
+ * Output:
+ * repeat.....changed to true if a block before the current
+ * block has changed
+ * Used:
+ * ttype, tinfo, srcstack, dststack, changed, macro_i
+ */
+#define TYPECHECK_REACH(way) \
+ LOG1("reaching block %04d",tbptr-block); \
+ srcstack = dst; \
+ dststack = tbptr->instack; \
+ ttype = vartype + maxlocals*(tbptr-block); \
+ tinfo = vartypeinfo + maxlocals*(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 { \
+ TYPECHECK_COPYJSR(jsrchain); \
+ TYPECHECK_COPYVARS; \
+ } \
+ TYPECHECK_COPYSTACK; \
+ changed = true; \
+ } else { \
+ /* This block has been reached before */ \
+ changed = false; \
+ if (way == REACH_JSR) \
+ TYPECHECK_CHECK_JSR_CHAIN; \
+ else \
+ TYPECHECK_MERGEJSR; \
+ LOGIF(changed,"changed jsr"); \
+ TYPECHECK_MERGEVARS; \
+ LOGIF(changed,"changed vars"); \
+ TYPECHECK_MERGESTACK; \
+ LOGIF(changed,"changed stack"); \
+ } \
+ if (changed) { \
+ LOG("REACHED!"); \
+ tbptr->flags = BBTYPECHECK_REACHED; \
+ if (tbptr <= bptr) {repeat = true; LOG("MUST REPEAT!");} \
+ } LOG("done.");
+
+/****************************************************************************/
+/* typecheck() */
+/****************************************************************************/
+
+#define MAXPARAMS 255
+
+/* typecheck is called directly after analyse_stack */
+void
+typecheck()
+{
+ int b_count, b_index;
+ stackptr curstack; /* input stack top for current instruction */
+ stackptr srcstack; /* source stack for copying and merging */
+ stackptr dststack; /* target stack for copying and merging */
+ int opcode, macro_i, len, i;
+ bool superblockend; /* true if no fallthrough to next block */
+ bool repeat; /* if true, blocks are iterated over again */
+ bool changed;
+ instruction *iptr = instr; /* pointer to current instruction */
+ basicblock *bptr; /* pointer to current basic block */
+ basicblock *tbptr;
+ 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 */
+ typeinfo tempinfo; /* temporary */
+ int returntype; /* return type of current method */
+ typeinfo returntypeinfo; /* typeinfo for return type */
+ 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 */
+ int changeddepth; /* depth to which the stack has changed */ /* XXX */
+ bool fulltypecheck; /* false == check only changed types */ /* XXX */
+ basicblock **tptr; /* pointer into target list of switch instructions */
+ jsr_record **jsrbuffer; /* JSR target chain for each basic block */
+ jsr_record *jsrchain; /* JSR chain for current block */
+ jsr_record *jsrtemp,*jsrtemp2,*jsrold; /* temporary variables */
+ jsr_record *subroutine; /* jsr_record of the current subroutine */
+ u1 *touched; /* touched flags for local variables */
+
+ LOGSTR("\n==============================================================================\n");
+ DOLOG(show_icmd_method());
+ LOGSTR("\n==============================================================================\n");
+ LOGimpSTR("Entering typecheck: ");
+ LOGimpSTRu(method->name);
+ LOGimpSTR(" ");
+ LOGimpSTRu(method->descriptor);
+ LOGimpSTR(" (class ");
+ LOGimpSTRu(method->class->name);
+ LOGimpSTR(")\n");
+
+ /* XXX allocate buffers for method arguments */
+ ptype = DMNEW(u1,MAXPARAMS);
+ pinfo = DMNEW(typeinfo,MAXPARAMS);
+
+ LOG("Buffer allocated.\n");
+
+ /* reset all BBFINISHED blocks to BBTYPECHECK_UNDEF. */
+ b_count = block_count;
+ bptr = block;
+ while (--b_count >= 0) {
+#ifdef TYPECHECK_DEBUG
+ if (bptr->flags != BBFINISHED && bptr->flags != BBDELETED
+ && bptr->flags != BBUNDEF)
+ {
+ show_icmd_method();
+ LOGSTR1("block flags: %d\n",bptr->flags); LOGFLUSH;
+ panic("Internal error: Unexpected block flags in typecheck()");
+ }
+#endif
+ if (bptr->flags >= BBFINISHED) {
+ bptr->flags = BBTYPECHECK_UNDEF;
+ }
+ bptr++;
+ }
+
+ /* The first block is always reached */
+ if (block_count && block[0].flags == BBTYPECHECK_UNDEF)
+ block[0].flags = BBTYPECHECK_REACHED;
+
+ LOG("Blocks reset.\n");
+
+ /* allocate the buffers for local variables */
+ vartype = DMNEW(u1,maxlocals * (block_count+1));
+ vartypeinfo = DMNEW(typeinfo,maxlocals * (block_count+1));
+ touched = DMNEW(u1,maxlocals);
+ vtype = vartype + maxlocals * block_count;
+ vinfo = vartypeinfo + maxlocals * block_count;
+ memset(vartype,TYPE_VOID,maxlocals * (block_count+1) * sizeof(typeinfo));
+ memset(vartypeinfo,0,maxlocals * (block_count+1) * sizeof(typeinfo));
+
+ LOG("Variable buffer initialized.\n");
+
+ /* allocate the buffer for storing JSR target chains */
+ jsrbuffer = DMNEW(jsr_record*,block_count);
+ memset(jsrbuffer,0,block_count * sizeof(jsr_record*));
+ jsrchain = NULL;
+
+ LOG("jsrbuffer initialized.\n");
+
+ /* initialize the variable types of the first block */
+ /* to the types of the arguments */
+ ttype = vartype;
+ tinfo = vartypeinfo;
+
+ /* if this is an instance method initialize the "this" ref type */
+ if (!(method->flags & ACC_STATIC)) {
+ *ttype++ = TYPE_ADDRESS;
+ TYPEINFO_INIT_CLASSINFO(*tinfo,class);
+ tinfo++;
+ }
+
+ LOG("'this' argument set.\n");
+
+ /* the rest of the arguments and the return type */
+ typeinfo_init_from_method_args(method->descriptor,ttype,tinfo,
+ maxlocals - (tinfo-vartypeinfo),
+ true, /* two word types use two slots */
+ &returntype,&returntypeinfo);
+
+ LOG("Arguments set.\n");
+
+ /* loop while there are still blocks to be checked */
+ fulltypecheck = true; /* XXX */
+ do {
+
+ repeat = false;
+
+ b_count = block_count;
+ bptr = block;
+
+ while (--b_count >= 0) {
+ LOGSTR1("---- BLOCK %04d, ",bptr-block);
+ LOGSTR1("blockflags: %d\n",bptr->flags);
+ LOGFLUSH;
+
+ if (bptr->flags == BBTYPECHECK_REACHED) {
+ LOGSTR1("\n---- BLOCK %04d ------------------------------------------------\n",bptr-block);
+ LOGFLUSH;
+
+ superblockend = false;
+ bptr->flags = BBFINISHED;
+ b_index = bptr - block;
+
+ /* init stack at the start of this block */
+ curstack = bptr->instack;
+
+ /* init variable types at the start of this block */
+ for (i=0; i<maxlocals; ++i) {
+ vtype[i] = vartype[maxlocals*b_index + i];
+ TYPEINFO_COPY(vartypeinfo[maxlocals*b_index + i],vinfo[i]);
+ }
+
+ /* init JSR target chain */
+ if ((jsrchain = jsrbuffer[b_index]) != NULL) {
+#ifdef TYPECHECK_VERBOSE
+ if (typecheckverbose) {
+ LOGSTR("jsr chain:");
+ jsrtemp = jsrchain;
+ while (jsrtemp) {
+ LOGSTR1(" L%03d",jsrtemp->target->debug_nr);
+ jsrtemp = jsrtemp->next;
+ }
+ LOGNL;
+ LOGFLUSH;
+ }
+#endif
+
+ subroutine = jsrbuffer[jsrchain->target - block];
+ memcpy(touched,jsrchain->touched,sizeof(u1)*maxlocals);
+ }
+ else
+ subroutine = NULL;
+#ifdef TYPECHECK_VERBOSE
+ if (typecheckverbose) {
+ if (subroutine) {LOGSTR1("subroutine L%03d\n",subroutine->target->debug_nr);LOGFLUSH;}
+ typeinfo_print_block(stdout,curstack,vtype,vinfo,(jsrchain) ? touched : NULL);
+ LOGNL; LOGFLUSH;
+ }
+#endif
+
+ /* loop over the instructions */
+ len = bptr->icount;
+ iptr = bptr->iinstr;
+ while (--len >= 0) {
+ DOLOG(show_icmd(iptr,false));
+ LOGNL;
+ LOGFLUSH;
+
+ opcode = iptr->opc;
+ dst = iptr->dst;
+
+ switch (opcode) {
+
+ /****************************************/
+ /* STACK MANIPULATIONS */
+
+ /* We just need to copy the typeinfo */
+ /* for slots containing addresses. */
+
+ case ICMD_DUP:
+ COPYTYPE(curstack,dst);
+ break;
+
+ case ICMD_DUP_X1:
+ COPYTYPE(curstack,dst);
+ COPYTYPE(curstack,dst-2);
+ COPYTYPE(curstack->prev,dst-1);
+ break;
+
+ case ICMD_DUP_X2:
+ COPYTYPE(curstack,dst);
+ COPYTYPE(curstack,dst-3);
+ COPYTYPE(curstack->prev,dst-1);
+ COPYTYPE(curstack->prev->prev,dst-2);
+ break;
+
+ case ICMD_DUP2:
+ COPYTYPE(curstack,dst);
+ COPYTYPE(curstack->prev,dst-1);
+ break;
+
+ case ICMD_DUP2_X1:
+ COPYTYPE(curstack,dst);
+ COPYTYPE(curstack->prev,dst-1);
+ COPYTYPE(curstack,dst-3);
+ COPYTYPE(curstack->prev,dst-4);
+ COPYTYPE(curstack->prev->prev,dst-2);
+ break;
+
+ case ICMD_DUP2_X2:
+ COPYTYPE(curstack,dst);
+ COPYTYPE(curstack->prev,dst-1);
+ COPYTYPE(curstack,dst-4);
+ COPYTYPE(curstack->prev,dst-5);
+ COPYTYPE(curstack->prev->prev,dst-2);
+ COPYTYPE(curstack->prev->prev->prev,dst-3);
+ break;
+
+ case ICMD_SWAP:
+ COPYTYPE(curstack,dst-1);
+ COPYTYPE(curstack->prev,dst);
+ break;
+
+ /* XXX only add these cases in debug mode? */
+ case ICMD_POP:
+ break;
+
+ case ICMD_POP2:
+ break;
+
+ /****************************************/
+ /* LOADING ADDRESS FROM VARIABLE */
+
+ case ICMD_ALOAD:
+ CHECKVARTYPE(iptr->op1,TYPE_ADR);
+
+ /* loading a returnAddress is not allowed */
+ if (TYPEINFO_IS_PRIMITIVE(vinfo[iptr->op1]))
+ panic("illegal instruction: ALOAD loading returnAddress");
+
+ TYPEINFO_COPY(vinfo[iptr->op1],dst->typeinfo);
+ break;
+
+ /****************************************/
+ /* STORING ADDRESS TO VARIABLE */
+
+ case ICMD_ASTORE:
+ /* TYPE_ADR has already been checked. */
+ STORE_TYPE(iptr->op1,TYPE_ADDRESS);
+ TYPEINFO_COPY(curstack->typeinfo,vinfo[iptr->op1]);
+ break;
+
+ /****************************************/
+ /* LOADING ADDRESS FROM ARRAY */
+
+ case ICMD_AALOAD:
+ if (!TYPEINFO_MAYBE_ARRAY_OF_REFS(curstack->prev->typeinfo))
+ panic("illegal instruction: AALOAD on non-reference array");
+
+ typeinfo_init_component(&curstack->prev->typeinfo,&dst->typeinfo);
+ break;
+
+ /****************************************/
+ /* STORING ADDRESS TO ARRAY */
+
+ case ICMD_AASTORE:
+ /* XXX also handled by builtin3 */
+ if (!TYPEINFO_MAYBE_ARRAY_OF_REFS(curstack->prev->prev->typeinfo))
+ panic("illegal instruction: AASTORE to non-reference array");
+
+ /* XXX optimize */
+ /*
+ typeinfo_init_component(&curstack->prev->prev->typeinfo,&tempinfo);
+ if (!typeinfo_is_assignable(&curstack->typeinfo,&tempinfo))
+ panic("illegal instruction: AASTORE to incompatible type");
+ */
+ break;
+
+ /****************************************/
+ /* FIELD ACCESS */
+
+ case ICMD_PUTFIELD:
+ if (!TYPEINFO_IS_REFERENCE(curstack->prev->typeinfo))
+ panic("illegal instruction: PUTFIELD on non-reference");
+ if (TYPEINFO_IS_ARRAY(curstack->prev->typeinfo)) /* XXX arraystub */
+ panic("illegal instruction: PUTFIELD on array");
+
+
+ /* XXX */
+ break;
+
+ case ICMD_PUTSTATIC:
+ /* XXX */
+ break;
+
+ case ICMD_GETFIELD:
+ if (!TYPEINFO_IS_REFERENCE(curstack->typeinfo))
+ panic("illegal instruction: GETFIELD on non-reference");
+ if (TYPEINFO_IS_ARRAY(curstack->typeinfo))
+ panic("illegal instruction: GETFIELD on array");
+
+ {
+ fieldinfo *fi = (fieldinfo *)(iptr->val.a);
+ /* XXX check non-static? */
+ if (dst->type == TYPE_ADR) {
+ TYPEINFO_INIT_FROM_FIELDINFO(dst->typeinfo,fi);
+ }
+ else {
+ TYPEINFO_INIT_PRIMITIVE(dst->typeinfo);
+ }
+ }
+ break;
+
+ case ICMD_GETSTATIC:
+ {
+ fieldinfo *fi = (fieldinfo *)(iptr->val.a);
+ /* XXX check static? */
+ if (dst->type == TYPE_ADR) {
+ TYPEINFO_INIT_FROM_FIELDINFO(dst->typeinfo,fi);
+ }
+ else {
+ TYPEINFO_INIT_PRIMITIVE(dst->typeinfo);
+ }
+ }
+ break;
+
+ /****************************************/
+ /* PRIMITIVE ARRAY ACCESS */
+
+ case ICMD_ARRAYLENGTH:
+ /* XXX should this also work on arraystubs? */
+ if (!TYPEINFO_MAYBE_ARRAY(curstack->typeinfo))
+ panic("illegal instruction: ARRAYLENGTH on non-array");
+ break;
+
+ case ICMD_BALOAD:
+ if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(curstack->prev->typeinfo,ARRAYTYPE_BOOLEAN)
+ && !TYPEINFO_MAYBE_PRIMITIVE_ARRAY(curstack->prev->typeinfo,ARRAYTYPE_BYTE))
+ panic("Array type mismatch");
+ break;
+ case ICMD_CALOAD:
+ if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(curstack->prev->typeinfo,ARRAYTYPE_CHAR))
+ panic("Array type mismatch");
+ break;
+ case ICMD_DALOAD:
+ if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(curstack->prev->typeinfo,ARRAYTYPE_DOUBLE))
+ panic("Array type mismatch");
+ break;
+ case ICMD_FALOAD:
+ if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(curstack->prev->typeinfo,ARRAYTYPE_FLOAT))
+ panic("Array type mismatch");
+ break;
+ case ICMD_IALOAD:
+ if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(curstack->prev->typeinfo,ARRAYTYPE_INT))
+ panic("Array type mismatch");
+ break;
+ case ICMD_SALOAD:
+ if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(curstack->prev->typeinfo,ARRAYTYPE_SHORT))
+ panic("Array type mismatch");
+ break;
+ case ICMD_LALOAD:
+ if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(curstack->prev->typeinfo,ARRAYTYPE_LONG))
+ panic("Array type mismatch");
+ break;
+
+ case ICMD_BASTORE:
+ if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(curstack->prev->prev->typeinfo,ARRAYTYPE_BOOLEAN)
+ && !TYPEINFO_MAYBE_PRIMITIVE_ARRAY(curstack->prev->prev->typeinfo,ARRAYTYPE_BYTE))
+ panic("Array type mismatch");
+ break;
+ case ICMD_CASTORE:
+ if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(curstack->prev->prev->typeinfo,ARRAYTYPE_CHAR))
+ panic("Array type mismatch");
+ break;
+ case ICMD_DASTORE:
+ if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(curstack->prev->prev->typeinfo,ARRAYTYPE_DOUBLE))
+ panic("Array type mismatch");
+ break;
+ case ICMD_FASTORE:
+ if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(curstack->prev->prev->typeinfo,ARRAYTYPE_FLOAT))
+ panic("Array type mismatch");
+ break;
+ case ICMD_IASTORE:
+ if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(curstack->prev->prev->typeinfo,ARRAYTYPE_INT))
+ panic("Array type mismatch");
+ break;
+ case ICMD_SASTORE:
+ if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(curstack->prev->prev->typeinfo,ARRAYTYPE_SHORT))
+ panic("Array type mismatch");
+ break;
+ case ICMD_LASTORE:
+ if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(curstack->prev->prev->typeinfo,ARRAYTYPE_LONG))
+ panic("Array type mismatch");
+ break;
+
+ /****************************************/
+ /* OPERATIONS WITH UNCHECKED INPUT */
+
+ case ICMD_CHECKCAST:
+ /* returnAddress is not allowed */
+ if (!TYPEINFO_IS_REFERENCE(curstack->typeinfo))
+ panic("Illegal instruction: INSTANCEOF on non-reference");
+
+ /* XXX check if the cast can be done statically */
+ TYPEINFO_INIT_CLASSINFO(dst->typeinfo,(classinfo *)iptr[0].val.a);
+ /* XXX */
+ break;
+
+ case ICMD_INSTANCEOF:
+ /* returnAddress is not allowed */
+ if (!TYPEINFO_IS_REFERENCE(curstack->typeinfo))
+ panic("Illegal instruction: INSTANCEOF on non-reference");
+
+ /* XXX */
+ 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_GOTO:
+ superblockend = true;
+ /* FALLTHROUGH! */
+ case ICMD_IFNULL:
+ case ICMD_IFNONNULL:
+ case ICMD_IFEQ:
+ case ICMD_IFNE:
+ case ICMD_IFLT:
+ case ICMD_IFGE:
+ case ICMD_IFGT:
+ case ICMD_IFLE:
+ case ICMD_IF_ICMPEQ:
+ case ICMD_IF_ICMPNE:
+ case ICMD_IF_ICMPLT:
+ case ICMD_IF_ICMPGE:
+ case ICMD_IF_ICMPGT:
+ case ICMD_IF_ICMPLE:
+ case ICMD_IF_ACMPEQ:
+ case ICMD_IF_ACMPNE:
+ case ICMD_IF_LEQ:
+ case ICMD_IF_LNE:
+ case ICMD_IF_LLT:
+ case ICMD_IF_LGE:
+ case ICMD_IF_LGT:
+ case ICMD_IF_LLE:
+ case ICMD_IF_LCMPEQ:
+ case ICMD_IF_LCMPNE:
+ case ICMD_IF_LCMPLT:
+ case ICMD_IF_LCMPGE:
+ case ICMD_IF_LCMPGT:
+ case ICMD_IF_LCMPLE:
+ tbptr = (basicblock *) iptr->target;
+
+ /* propagate stack and variables to the target block */
+ TYPECHECK_REACH(REACH_STD);
+ /* XXX */
+ break;
+
+ /****************************************/
+ /* SWITCHES */
+
+ case ICMD_TABLESWITCH:
+ {
+ s4 *s4ptr = iptr->val.a;
+ 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 */
+ }
+ switch_instruction_tail:
+ tptr = (basicblock **)iptr->target;
+
+ while (--i >= 0) {
+ tbptr = *tptr++;
+ LOG2("target %d is block %04d",(tptr-(basicblock **)iptr->target)-1,tbptr-block);
+ TYPECHECK_REACH(REACH_STD);
+ }
+ LOG("switch done");
+ superblockend = true;
+ break;
+
+ /****************************************/
+ /* RETURNS AND THROW */
+
+ case ICMD_ATHROW:
+ TYPEINFO_INIT_CLASSINFO(tempinfo,class_java_lang_Throwable);
+ if (!typeinfo_is_assignable(&curstack->typeinfo,&tempinfo))
+ panic("illegal instruction: ATHROW on non-Throwable");
+ superblockend = true;
+ break;
+
+ case ICMD_ARETURN:
+ if (!TYPEINFO_IS_REFERENCE(curstack->typeinfo))
+ panic("illegal instruction: ARETURN on non-reference");
+
+ if (returntype != TYPE_ADDRESS
+ || !typeinfo_is_assignable(&curstack->typeinfo,&returntypeinfo))
+ panic("Return type mismatch");
+
+ superblockend = true;
+ break;
+
+ case ICMD_IRETURN:
+ if (returntype != TYPE_INT)
+ panic("Return type mismatch");
+ superblockend = true;
+ break;
+ case ICMD_LRETURN:
+ if (returntype != TYPE_LONG)
+ panic("Return type mismatch");
+ superblockend = true;
+ break;
+ case ICMD_FRETURN:
+ if (returntype != TYPE_FLOAT)
+ panic("Return type mismatch");
+ superblockend = true;
+ break;
+ case ICMD_DRETURN:
+ if (returntype != TYPE_DOUBLE)
+ panic("Return type mismatch");
+ superblockend = true;
+ break;
+ case ICMD_RETURN:
+ if (returntype != TYPE_VOID)
+ panic("Return type mismatch");
+ superblockend = true;
+ break;
+
+ /****************************************/
+ /* SUBROUTINE INSTRUCTIONS */
+
+ case ICMD_JSR:
+ LOG("jsr");
+
+ /* XXX This is a dirty hack. It is needed
+ * because of the special handling of ICMD_JSR in stack.c
+ */
+ dst = (stackptr) iptr->val.a;
+
+ /* push return address */
+ TYPEINFO_INIT_PRIMITIVE(dst->typeinfo);
+
+ 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 */
+ /* XXX We assume (as in stack.c) that the
+ * subroutine returns the stack as it was
+ * before the JSR instruction. Is this
+ * correct?
+ */
+ dst = iptr->dst;
+
+ /* Find the jsr_record of the called subroutine */
+ jsrtemp = jsrbuffer[tbptr - block];
+
+ /* Check if we already calculated (at least
+ * for one RET) which variables the
+ * subroutine touches.
+ */
+ if (jsrtemp->sbr_touched) {
+ /* Calculate the local variables after the subroutine call */
+ for (i=0; i<maxlocals; ++i)
+ if (jsrtemp->sbr_touched[i] != TOUCHED_NO) {
+ TOUCH_VARIABLE(i);
+ if ((vtype[i] = jsrtemp->sbr_vtype[i]) == TYPE_ADR)
+ TYPEINFO_CLONE(jsrtemp->sbr_vinfo[i],vinfo[i]);
+ }
+
+ /* continue after the JSR call */
+ superblockend = false;
+ }
+ else {
+ /* We cannot proceed until the subroutine has been typechecked. */
+ /* XXX actually we would not have to check this block again */
+ bptr->flags = BBTYPECHECK_REACHED;
+ repeat = true;
+ superblockend = true;
+ }
+ break;
+
+ case ICMD_RET:
+ /* check returnAddress variable */
+ CHECKVARTYPE(iptr->op1,TYPE_ADR);
+
+ if (!TYPEINFO_IS_PRIMITIVE(vinfo[iptr->op1]))
+ panic("illegal instruction: RET using non-returnAddress variable");
+
+ /* check if we are inside a subroutine */
+ if (!subroutine)
+ panic("RET outside of subroutine");
+
+ /* determine which variables are touched by this subroutine */
+ /* and their types */
+ if (subroutine->sbr_touched) {
+ for (i=0; i<maxlocals; ++i)
+ subroutine->sbr_touched[i] |= touched[i];
+ ttype = subroutine->sbr_vtype;
+ tinfo = subroutine->sbr_vinfo;
+ TYPECHECK_MERGEVARS;
+ }
+ else {
+ subroutine->sbr_touched = DMNEW(u1,maxlocals);
+ memcpy(subroutine->sbr_touched,touched,sizeof(u1)*maxlocals);
+ subroutine->sbr_vtype = DMNEW(u1,maxlocals);
+ memcpy(subroutine->sbr_vtype,vtype,sizeof(u1)*maxlocals);
+ subroutine->sbr_vinfo = DMNEW(typeinfo,maxlocals);
+ for (i=0; i<maxlocals; ++i)
+ if (vtype[i] == TYPE_ADR)
+ TYPEINFO_CLONE(vinfo[i],subroutine->sbr_vinfo[i]);
+ }
+
+ LOGSTR("subroutine touches:");
+ DOLOG(typeinfo_print_locals(stdout,subroutine->sbr_vtype,subroutine->sbr_vinfo,
+ subroutine->sbr_touched,maxlocals));
+ LOGNL; LOGFLUSH;
+
+ /* reach blocks after JSR statements */
+ for (i=0; i<block_count; ++i) {
+ tbptr = block + i;
+ if (tbptr->iinstr[tbptr->icount - 1].opc != ICMD_JSR)
+ continue;
+ if ((basicblock*) tbptr->iinstr[tbptr->icount - 1].target != jsrold->target)
+ continue;
+ tbptr++;
+
+ LOG1("RET reaches block %04d",tbptr-block);
+
+ /*TYPECHECK_REACH(REACH_RET);*/
+ }
+
+ superblockend = true;
+ break;
+
+ /****************************************/
+ /* INVOKATIONS */
+
+ case ICMD_INVOKEVIRTUAL:
+ case ICMD_INVOKESPECIAL:
+ case ICMD_INVOKESTATIC:
+ case ICMD_INVOKEINTERFACE:
+ {
+ /* XXX check access rights */
+
+ methodinfo *mi = (methodinfo*) iptr->val.a;
+ /* XXX might use dst->typeinfo directly if non void */
+ typeinfo_init_from_method_args(mi->descriptor,ptype,pinfo,MAXPARAMS,false,
+ &rtype,&rinfo);
+
+ /* XXX compare rtype and dst->type? */
+ if (rtype != TYPE_VOID) {
+ TYPEINFO_COPY(rinfo,dst->typeinfo);
+ }
+ }
+ break;
+
+ case ICMD_MULTIANEWARRAY:
+ /* check the array lengths on the stack */
+ i = iptr[0].op1;
+ if (i<1) panic("MULTIANEWARRAY with dimensions < 1");
+ srcstack = curstack;
+ while (i--) {
+ if (!srcstack)
+ panic("MULTIANEWARRAY missing array length");
+ if (srcstack->type != TYPE_INT)
+ panic("MULTIANEWARRAY using non-int as array length");
+ srcstack = srcstack->prev;
+ }
+
+ /* set the array type of the result */
+ TYPEINFO_INIT_CLASSINFO(dst->typeinfo,((vftbl *)iptr[0].val.a)->class);
+ break;
+
+ case ICMD_BUILTIN3:
+ if (ISBUILTIN(asm_builtin_aastore)) {
+ /* XXX also handled by ICMD_AASTORE */
+ if (!TYPEINFO_MAYBE_ARRAY_OF_REFS(curstack->prev->prev->typeinfo))
+ panic("illegal instruction: AASTORE to non-reference array");
+
+ /* XXX optimize */
+ /*
+ typeinfo_init_component(&curstack->prev->prev->typeinfo,&tempinfo);
+ if (!typeinfo_is_assignable(&curstack->typeinfo,&tempinfo))
+ panic("illegal instruction: AASTORE to incompatible type");
+ */
+ }
+ /* XXX check for missed builtins in debug mode? */
+ break;
+
+ case ICMD_BUILTIN2:
+ if (
+#if defined(__I386__)
+ ISBUILTIN(asm_builtin_newarray)
+#else
+ ISBUILTIN(builtin_newarray)
+#endif
+ )
+ {
+ if (iptr[-1].opc != ICMD_ACONST)
+ panic("illegal instruction: builtin_newarray without classinfo");
+ TYPEINFO_INIT_CLASSINFO(dst->typeinfo,((vftbl *)iptr[-1].val.a)->class);
+ }
+ else if (ISBUILTIN(asm_builtin_checkarraycast)) {
+ if (iptr[-1].opc != ICMD_ACONST)
+ panic("illegal instruction: asm_builtin_checkarraycast without classinfo");
+ TYPEINFO_INIT_CLASSINFO(dst->typeinfo,((vftbl *)iptr[-1].val.a)->class);
+ }
+ /* XXX check for missed builtins in debug mode? */
+ break;
+
+ case ICMD_BUILTIN1:
+ if (ISBUILTIN(builtin_new)) {
+ if (iptr[-1].opc != ICMD_ACONST)
+ panic("illegal instruction: builtin_new without classinfo");
+ TYPEINFO_INIT_CLASSINFO(dst->typeinfo,(classinfo *)iptr[-1].val.a);
+ }
+ else if (ISBUILTIN(builtin_newarray_boolean)) {
+ TYPEINFO_INIT_PRIMITIVE_ARRAY(dst->typeinfo,ARRAYTYPE_BOOLEAN);
+ }
+ else if (ISBUILTIN(builtin_newarray_char)) {
+ TYPEINFO_INIT_PRIMITIVE_ARRAY(dst->typeinfo,ARRAYTYPE_CHAR);
+ }
+ else if (ISBUILTIN(builtin_newarray_float)) {
+ TYPEINFO_INIT_PRIMITIVE_ARRAY(dst->typeinfo,ARRAYTYPE_FLOAT);
+ }
+ else if (ISBUILTIN(builtin_newarray_double)) {
+ TYPEINFO_INIT_PRIMITIVE_ARRAY(dst->typeinfo,ARRAYTYPE_DOUBLE);
+ }
+ else if (ISBUILTIN(builtin_newarray_byte)) {
+ TYPEINFO_INIT_PRIMITIVE_ARRAY(dst->typeinfo,ARRAYTYPE_BYTE);
+ }
+ else if (ISBUILTIN(builtin_newarray_short)) {
+ TYPEINFO_INIT_PRIMITIVE_ARRAY(dst->typeinfo,ARRAYTYPE_SHORT);
+ }
+ else if (ISBUILTIN(builtin_newarray_int)) {
+ TYPEINFO_INIT_PRIMITIVE_ARRAY(dst->typeinfo,ARRAYTYPE_INT);
+ }
+ else if (ISBUILTIN(builtin_newarray_long)) {
+ TYPEINFO_INIT_PRIMITIVE_ARRAY(dst->typeinfo,ARRAYTYPE_LONG);
+ }
+ /* XXX check for missed builtins in debug mode? */
+ break;
+
+ /****************************************/
+ /* PRIMITIVE VARIABLE ACCESS */
+
+ case ICMD_ILOAD: CHECKVARTYPE(iptr->op1,TYPE_INT); break;
+ case ICMD_LLOAD: CHECKVARTYPE(iptr->op1,TYPE_LONG); break;
+ case ICMD_FLOAD: CHECKVARTYPE(iptr->op1,TYPE_FLOAT); break;
+ case ICMD_DLOAD: CHECKVARTYPE(iptr->op1,TYPE_DOUBLE); break;
+ case ICMD_IINC: CHECKVARTYPE(iptr->op1,TYPE_INT); /*TOUCH_VARIABLE(iptr->op1);*/ break;
+
+ case ICMD_FSTORE: STORE_PRIMITIVE(iptr->op1,TYPE_FLOAT); break;
+ case ICMD_ISTORE: STORE_PRIMITIVE(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 */
+
+ case ICMD_NEW:
+ case ICMD_NEWARRAY:
+ case ICMD_ANEWARRAY:
+ case ICMD_MONITORENTER:
+ case ICMD_MONITOREXIT:
+ /* XXX only check this in debug mode? */
+ LOGSTR2("ICMD %d at %d\n", iptr->opc, (int)(iptr-instr));
+ 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_CHECKASIZE: /* XXX ? */
+ case ICMD_NULLCHECKPOP: /* XXX ? */
+ case ICMD_READONLY_ARG: /* XXX ? */
+ case ICMD_CLEAR_ARGREN: /* XXX ? */
+ break;
+
+ /****************************************/
+ /* ARITHMETIC AND CONVERSION */
+
+ /* These instructions are typechecked in analyse_stack. */
+ /* XXX only add cases for them in debug mode? */
+
+ case ICMD_IADD:
+ case ICMD_ISUB:
+ case ICMD_IMUL:
+ case ICMD_IDIV:
+ case ICMD_IREM:
+ case ICMD_INEG:
+ case ICMD_IAND:
+ case ICMD_IOR:
+ case ICMD_IXOR:
+ case ICMD_ISHL:
+ case ICMD_ISHR:
+ case ICMD_IUSHR:
+ case ICMD_LADD:
+ case ICMD_LSUB:
+ case ICMD_LMUL:
+ case ICMD_LDIV:
+ case ICMD_LREM:
+ case ICMD_LNEG:
+ case ICMD_LAND:
+ case ICMD_LOR:
+ case ICMD_LXOR:
+ case ICMD_LSHL:
+ case ICMD_LSHR:
+ case ICMD_LUSHR:
+ case ICMD_IREM0X10001:
+ case ICMD_LREM0X10001:
+ case ICMD_IDIVPOW2:
+ case ICMD_LDIVPOW2:
+ case ICMD_IADDCONST:
+ case ICMD_ISUBCONST:
+ case ICMD_IMULCONST:
+ case ICMD_IANDCONST:
+ case ICMD_IORCONST:
+ case ICMD_IXORCONST:
+ case ICMD_ISHLCONST:
+ case ICMD_ISHRCONST:
+ case ICMD_IUSHRCONST:
+ case ICMD_IREMPOW2:
+ case ICMD_LADDCONST:
+ case ICMD_LSUBCONST:
+ case ICMD_LMULCONST:
+ case ICMD_LANDCONST:
+ case ICMD_LORCONST:
+ case ICMD_LXORCONST:
+ case ICMD_LSHLCONST:
+ case ICMD_LSHRCONST:
+ case ICMD_LUSHRCONST:
+ case ICMD_LREMPOW2:
+
+ case ICMD_LCMP:
+ case ICMD_LCMPCONST:
+ case ICMD_FCMPL:
+ case ICMD_FCMPG:
+ case ICMD_DCMPL:
+ case ICMD_DCMPG:
+
+ case ICMD_FADD:
+ case ICMD_DADD:
+ case ICMD_FSUB:
+ case ICMD_DSUB:
+ case ICMD_FMUL:
+ case ICMD_DMUL:
+ case ICMD_FDIV:
+ case ICMD_DDIV:
+ case ICMD_FREM:
+ case ICMD_DREM:
+ case ICMD_FNEG:
+ case ICMD_DNEG:
+
+ case ICMD_I2L:
+ case ICMD_I2F:
+ case ICMD_I2D:
+ case ICMD_L2I:
+ case ICMD_L2F:
+ case ICMD_L2D:
+ case ICMD_F2I:
+ case ICMD_F2L:
+ case ICMD_F2D:
+ case ICMD_D2I:
+ case ICMD_D2L:
+ case ICMD_D2F:
+ case ICMD_INT2BYTE:
+ case ICMD_INT2CHAR:
+ case ICMD_INT2SHORT:
+
+ case ICMD_ICONST:
+ case ICMD_LCONST:
+ case ICMD_FCONST:
+ case ICMD_DCONST:
+
+ case ICMD_IFEQ_ICONST:
+ case ICMD_IFNE_ICONST:
+ case ICMD_IFLT_ICONST:
+ case ICMD_IFGE_ICONST:
+ case ICMD_IFGT_ICONST:
+ case ICMD_IFLE_ICONST:
+ case ICMD_ELSE_ICONST:
+
+ break;
+
+ /****************************************/
+
+ default:
+ LOGSTR2("ICMD %d at %d\n", iptr->opc, (int)(iptr-instr));
+ panic("Missing ICMD code during typecheck");
+ }
+
+ /* the output of this instruction becomes the current stack */
+ curstack = dst;
+
+ iptr++;
+ } /* while instructions */
+
+ LOG("instructions done");
+ LOGSTR("RESULT=> ");
+ DOLOG(typeinfo_print_block(stdout,curstack,vtype,vinfo,(jsrchain) ? touched : NULL));
+ LOGNL; LOGFLUSH;
+
+ /* propagate stack and variables to the following block */
+ if (!superblockend) {
+ LOG("reaching following block");
+ tbptr = bptr + 1;
+ while (tbptr->flags == BBDELETED) {
+ tbptr++;
+#ifdef TYPECHECK_DEBUG
+ if ((tbptr-block) >= block_count)
+ panic("Control flow falls off the last block");
+#endif
+ }
+ TYPECHECK_REACH(REACH_STD);
+ }
+
+ } /* if block has to be checked */
+ bptr++;
+ } /* while blocks */
+
+ /* the following iterations only check if any types changed */
+ fulltypecheck = false; /* XXX */
+
+ LOGIF(repeat,"repeat=true");
+ } while (repeat);
+
+ /* XXX reset BB... to BBFINISHED */
+
+ /* XXX free vartype */
+ /* XXX free vartypeinfo */
+ /* XXX free buffers for method arguments. */
+
+ /* XXX add debug check if all non-dead blocks have been checked */
+
+ LOGimp("exiting typecheck");
+}
+
+#undef COPYTYPE
+
+#endif /* CACAO_TYPECHECK */
Changes: Andreas Krall
Roman Obermaiser
Mark Probst
+ Edwin Steiner
- $Id: loader.c 693 2003-12-05 19:00:58Z jowenn $
+ $Id: loader.c 696 2003-12-06 20:10:05Z edwin $
*/
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);
m -> jcode = NULL;
m -> exceptiontable = NULL;
methodinfo *clone;
int namelen;
+ /* XXX remove */ /* dolog("class_new_array: %s",c->name->text); */
+
/* Array classes are not loaded from classfiles. */
list_remove (&unloadedclasses, c);
c->super = class_java_lang_Object;
c->interfacescount = 2;
- c->interfaces = MNEW(classinfo*,2);
+ c->interfaces = MNEW(classinfo*,2); /* XXX use GC? */
c->interfaces[0] = class_java_lang_Cloneable;
c->interfaces[1] = class_java_io_Serializable;
c->methodscount = 1;
- c->methods = MNEW (methodinfo, c->methodscount);
+ c->methods = MNEW (methodinfo, c->methodscount); /* XXX use GC? */
clone = c->methods;
memset(clone,0,sizeof(methodinfo));
char *start = utf_ptr;
bool error = false;
utf *name;
-
+
SKIP_FIELDDESCRIPTOR_SAFE(utf_ptr,end_ptr,error);
if (error) return NULL;
if (next) *next = utf_ptr;
-/* loader.c - class loader header
+/* loader.h - class loader header
Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser,
Authors: Reinhard Grafl
- $Id: loader.h 669 2003-11-23 14:04:20Z edwin $
+ $Id: loader.h 696 2003-12-06 20:10:05Z edwin $
*/
#define CLASSLOAD_SKIP 0
#define CLASSLOAD_NEW 1
#define CLASSLOAD_LOAD 2
+
+#if 0
+#define CLASSLOAD_NEW 0x0000 /* default */
+#define CLASSLOAD_LOAD 0x0001
+#define CLASSLOAD_SKIP 0x0002
+#define CLASSLOAD_PANIC 0x0000 /* default */
+#define CLASSLOAD_NOPANIC 0x0010
+#define CLASSLOAD_PRIMITIVE 0x0000 /* default */
+#define CLASSLOAD_VOID 0x0000 /* default */
+#define CLASSLOAD_NOVOID 0x0020
+#endif
+
classinfo *class_from_descriptor(char *utf_ptr,char *end_ptr,char **next,int mode);
/* (used by class_new, don't use directly) */
- Calling the class loader
- Running the main method
- $Id: main.c 689 2003-12-05 18:03:47Z stefan $
+ $Id: main.c 696 2003-12-06 20:10:05Z edwin $
*/
#define OPT_INLINING 25
#define OPT_RT 26
#define OPT_XTA 27
-#define OPT_VTA 28
+#define OPT_VTA 28
+#define OPT_VERBOSETC 29
struct {char *name; bool arg; int value;} opts[] = {
{"verbose", false, OPT_VERBOSE},
{"verbosegc", false, OPT_VERBOSEGC},
{"verbosecall", false, OPT_VERBOSECALL},
+#ifdef TYPECHECK_VERBOSE
+ {"verbosetc", false, OPT_VERBOSETC},
+#endif
#if defined(__ALPHA__)
{"noieee", false, OPT_NOIEEE},
#endif
printf(" -verbose ............. write more information\n");
printf(" -verbosegc ........... write message for each GC\n");
printf(" -verbosecall ......... write message for each call\n");
+#ifdef TYPECHECK_VERBOSE
+ printf(" -verbosetc ........... write debug messages while typechecking\n");
+#endif
#if defined(__ALPHA__)
printf(" -noieee .............. don't use ieee compliant arithmetic\n");
#endif
case OPT_VERBOSEGC:
collectverbose = true;
break;
+
+#ifdef TYPECHECK_VERBOSE
+ case OPT_VERBOSETC:
+ typecheckverbose = true;
+ break;
+#endif
case OPT_VERBOSECALL:
runverbose = true;
a->data[i - opt_ind] = javastring_new(utf_new_char(argv[i]));
}
-#ifdef DEBUG_TYPES
- typeinfo_test(); /* XXX remove debug */
+#ifdef TYPEINFO_DEBUG_TEST
+ /* test the typeinfo system */
+ typeinfo_test();
#endif
/*class_showmethods(currentThread->group->header.vftbl->class); */
- Calling the class loader
- Running the main method
- $Id: cacao.c 689 2003-12-05 18:03:47Z stefan $
+ $Id: cacao.c 696 2003-12-06 20:10:05Z edwin $
*/
#define OPT_INLINING 25
#define OPT_RT 26
#define OPT_XTA 27
-#define OPT_VTA 28
+#define OPT_VTA 28
+#define OPT_VERBOSETC 29
struct {char *name; bool arg; int value;} opts[] = {
{"verbose", false, OPT_VERBOSE},
{"verbosegc", false, OPT_VERBOSEGC},
{"verbosecall", false, OPT_VERBOSECALL},
+#ifdef TYPECHECK_VERBOSE
+ {"verbosetc", false, OPT_VERBOSETC},
+#endif
#if defined(__ALPHA__)
{"noieee", false, OPT_NOIEEE},
#endif
printf(" -verbose ............. write more information\n");
printf(" -verbosegc ........... write message for each GC\n");
printf(" -verbosecall ......... write message for each call\n");
+#ifdef TYPECHECK_VERBOSE
+ printf(" -verbosetc ........... write debug messages while typechecking\n");
+#endif
#if defined(__ALPHA__)
printf(" -noieee .............. don't use ieee compliant arithmetic\n");
#endif
case OPT_VERBOSEGC:
collectverbose = true;
break;
+
+#ifdef TYPECHECK_VERBOSE
+ case OPT_VERBOSETC:
+ typecheckverbose = true;
+ break;
+#endif
case OPT_VERBOSECALL:
runverbose = true;
a->data[i - opt_ind] = javastring_new(utf_new_char(argv[i]));
}
-#ifdef DEBUG_TYPES
- typeinfo_test(); /* XXX remove debug */
+#ifdef TYPEINFO_DEBUG_TEST
+ /* test the typeinfo system */
+ typeinfo_test();
#endif
/*class_showmethods(currentThread->group->header.vftbl->class); */
calls instead of machine instructions, using the C calling
convention.
- $Id: builtin.c 689 2003-12-05 18:03:47Z stefan $
+ $Id: builtin.c 696 2003-12-06 20:10:05Z edwin $
*/
*****************************************************************************/
-s4 builtin_checkarraycast(java_objectheader *o,arraydescriptor *target)
+s4 builtin_checkarraycast(java_objectheader *o,vftbl *target)
{
arraydescriptor *desc;
if (!o) return 1;
if ((desc = o->vftbl->arraydesc) == NULL) return 0;
- return builtin_descriptorscompatible(desc,target);
+ return builtin_descriptorscompatible(desc,target->arraydesc);
}
-s4 builtin_arrayinstanceof(java_objectheader *obj,arraydescriptor *desc)
+s4 builtin_arrayinstanceof(java_objectheader *obj,vftbl *target)
{
if (!obj) return 1;
- return builtin_checkarraycast (obj, desc);
+ return builtin_checkarraycast (obj, target);
}
/************************** exception functions *******************************
s4 builtin_checkcast(java_objectheader *obj, classinfo *class);
s4 asm_builtin_checkcast(java_objectheader *obj, classinfo *class);
-s4 builtin_arrayinstanceof(java_objectheader *obj, arraydescriptor *desc);
+s4 builtin_arrayinstanceof(java_objectheader *obj, vftbl *target);
#ifdef __I386__
s4 asm_builtin_arrayinstanceof(java_objectheader *obj, classinfo *class); /* XXX ? */
#endif
-s4 builtin_checkarraycast(java_objectheader *obj, arraydescriptor *desc);
-s4 asm_builtin_checkarraycast(java_objectheader *obj, arraydescriptor *desc);
+s4 builtin_checkarraycast(java_objectheader *obj, vftbl *target);
+s4 asm_builtin_checkarraycast(java_objectheader *obj, vftbl *target);
java_objectheader *builtin_throw_exception (java_objectheader *exception);
java_objectheader *builtin_trace_exception (java_objectheader *exceptionptr,
Philipp Tomsich
Edwin Steiner
- $Id: global.h 687 2003-12-04 22:29:54Z edwin $
+ $Id: global.h 696 2003-12-06 20:10:05Z edwin $
*/
*/
#define SIZE_FROM_CLASSINFO
+/*
+ * CACAO_TYPECHECK activates typechecking (part of bytecode verification)
+ */
+#define CACAO_TYPECHECK
+
+/*
+ * Macros for configuration of the typechecking code
+ *
+ * TYPEINFO_DEBUG activates debug checks and debug helpers in typeinfo.c
+ * TYPECHECK_DEBUG activates debug checks in typecheck.c
+ * TYPEINFO_DEBUG_TEST activates the typeinfo test at startup.
+ * TYPECHECK_VERBOSE_IMPORTANT activates important debug messages
+ * TYPECHECK_VERBOSE activates all debug messages
+ */
+#define TYPEINFO_DEBUG
+#define TYPECHECK_DEBUG
+/*#define TYPEINFO_DEBUG_TEST*/
+#define TYPECHECK_VERBOSE
+/*#define TYPECHECK_VERBOSE_IMPORTANT*/
+#if defined(TYPECHECK_VERBOSE) || defined(TYPECHECK_VERBOSE_IMPORTANT)
+#define TYPECHECK_VERBOSE_OPT
+#endif
+
/* standard includes **********************************************************/
#include <stdio.h>
extern bool opt_rt; /* Rapid Type Analysis for better inlining CO-RT*/
extern bool opt_xta; /* X Type Analysis for better inlining CO-XTA*/
extern bool opt_vta; /* Variable Type Analysis for better inlining CO-VTA*/
+#ifdef TYPECHECK_VERBOSE_OPT
+extern bool typecheckverbose;
+#endif
//extern int pClassHeir;
//extern int pCallgraph;
## Process this file with automake to produce Makefile.in
-# $Id: Makefile.am 662 2003-11-21 18:06:25Z jowenn $
+# $Id: Makefile.am 696 2003-12-06 20:10:05Z edwin $
SUBDIRS = . loop @ARCH_DIR@
sets.h \
parseRT.c \
parseRTprint.h \
- parseRTstats.c
+ parseRTstats.c \
+ typecheck.c
noinst_HEADERS = \
parse.h \
noinst_LIBRARIES = libjit.a
-libjit_a_SOURCES = jit.c parse.c stack.c inline.c sets.c parseRT.c parseRTstats.c
+libjit_a_SOURCES = jit.c parse.c stack.c inline.c sets.c parseRT.c parseRTstats.c typecheck.c
all-local:
$(MAKE) $(AM_MAKEFLAGS) -C .. jit/@ARCH_DIR@/offsets.h
Authors: Andreas Krall
Reinhard Grafl
- $Id: jit.c 689 2003-12-05 18:03:47Z stefan $
+ $Id: jit.c 696 2003-12-06 20:10:05Z edwin $
*/
basicblock *last_block; /* points to the end of the BB list */
+bool regs_ok; /* true if registers have been allocated */
+
/* list of all classes used by the compiled method which have to be */
/* initialised (if not already done) before execution of this method */
chain *uninitializedclasses;
count_methods++;
intsDisable(); /* disable interrupts */
-
+
+ regs_ok = false;
/* mark start of dump memory area */
parse();
analyse_stack();
+#ifdef CACAO_TYPECHECK
+ typecheck();
+#endif
+
if (opt_loops) {
depthFirst();
analyseGraph();
#endif
regalloc();
+ regs_ok = true;
codegen();
/* intermediate and assembly code listings ********************************/
Changes: Christian Thalinger
- $Id: jit.h 665 2003-11-21 18:36:43Z jowenn $
+ $Id: jit.h 696 2003-12-06 20:10:05Z edwin $
*/
#include "toolbox/chain.h"
#include "global.h"
+#include "typeinfo.h"
/**************************** resolve typedef-cycles **************************/
/* slot types */
+/* XXX use TYPE_ADDRESS, ...? */
#define TYPE_INT 0 /* the stack slot types must numbered in the */
#define TYPE_LNG 1 /* same order as the ICMD_Ixxx to ICMD_Axxx */
#define TYPE_FLT 2 /* instructions (LOAD and STORE) */
struct stackelement {
stackptr prev; /* pointer to next element towards bottom */
int type; /* slot type of stack element */
+#ifdef CACAO_TYPECHECK
+ typeinfo typeinfo; /* info on reference types */
+#endif
int flags; /* flags (SAVED, INMEMORY) */
int varkind; /* kind of variable or register */
int varnum; /* number of variable */
#define BBUNDEF -1
#define BBREACHED 0
#define BBFINISHED 1
+#define BBTYPECHECK_UNDEF 2
+#define BBTYPECHECK_REACHED 3
#define BBTYPE_STD 0 /* standard basic block type */
#define BBTYPE_EXH 1 /* exception handler basic block type */
extern basicblock *last_block; /* points to the end of the BB list */
+extern bool regs_ok; /* true if registers have been allocated */
+
+
/* list of all classes used by the compiled method which have to be */
/* initialised (if not already done) before execution of this method */
extern chain *uninitializedclasses;
void removecompilerstub(u1 *stub);
void removenativestub(u1 *stub);
+/* debug helpers (in stack.c) */
+
+void icmd_print_stack(stackptr s);
+void show_icmd_block(basicblock *bptr);
+void show_icmd(instruction *iptr,bool deadcode);
+void show_icmd_method();
+
#endif /* _JIT_H */
Author: Andreas Krall
Changes: Carolyn Oates
+ Edwin Steiner
- $Id: parse.c 689 2003-12-05 18:03:47Z stefan $
+ $Id: parse.c 696 2003-12-06 20:10:05Z edwin $
*/
classinfo *cls = (classinfo*)class_getconstant(class, i, CONSTANT_Class);
if (cls->vftbl->arraydesc) {
/* array type cast-check */
- LOADCONST_A(cls->vftbl->arraydesc);
+ LOADCONST_A(cls->vftbl);
s_count++;
BUILTIN2((functionptr) asm_builtin_checkarraycast, TYPE_ADR);
}
classinfo *cls = (classinfo*)class_getconstant(class, i, CONSTANT_Class);
if (cls->vftbl->arraydesc) {
/* array type cast-check */
- LOADCONST_A(cls->vftbl->arraydesc);
+ LOADCONST_A(cls->vftbl);
s_count++;
#if defined(__I386__)
BUILTIN2((functionptr) asm_builtin_arrayinstanceof, TYPE_INT);
Authors: Andreas Krall
- $Id: stack.c 665 2003-11-21 18:36:43Z jowenn $
+ Changes: Edwin Steiner
+
+ $Id: stack.c 696 2003-12-06 20:10:05Z edwin $
*/
iptr[0].target = (void *) tbptr;
+ /* XXX This is a dirty hack. The typechecker
+ * needs it because the OP1_0ANY below
+ * overwrites iptr->dst.
+ */
+ iptr->val.a = (void*) iptr->dst;
+
tbptr->type=BBTYPE_SBR;
MARKREACHED(tbptr, copy);
OP1_0ANY;
}
-static void print_stack(stackptr s)
+void icmd_print_stack(stackptr s)
{
int i, j;
stackptr t;
printf(" ");
while (s) {
j--;
+ /* XXX remove */ /* printf("(%d)",s->flags); fflush(stdout); */
if (s->flags & SAVEDVAR)
switch (s->varkind) {
case TEMPVAR:
if (s->flags & INMEMORY)
- printf(" M%02d", s->regoff);
+ printf((regs_ok) ? " M%02d" : " M??", s->regoff);
else if ((s->type == TYPE_FLT) || (s->type == TYPE_DBL))
- printf(" F%02d", s->regoff);
- else
- printf(" %3s", regs[s->regoff]);
+ printf((regs_ok) ? " F%02d" : " F??", s->regoff);
+ else {
+ if (regs_ok) printf(" %3s",regs[s->regoff]); else printf(" ???");
+ }
break;
case STACKVAR:
printf(" I%02d", s->varnum);
switch (s->varkind) {
case TEMPVAR:
if (s->flags & INMEMORY)
- printf(" m%02d", s->regoff);
+ printf((regs_ok) ? " m%02d" : " m??", s->regoff);
else if ((s->type == TYPE_FLT) || (s->type == TYPE_DBL))
- printf(" f%02d", s->regoff);
- else
- printf(" %3s", regs[s->regoff]);
+ printf((regs_ok) ? " f%02d" : " f??", s->regoff);
+ else {
+ if (regs_ok) printf(" %3s",regs[s->regoff]); else printf(" ???");
+ }
break;
case STACKVAR:
printf(" i%02d", s->varnum);
#endif
-static char *builtin_name(functionptr bptr)
+char *icmd_builtin_name(functionptr bptr)
{
builtin_descriptor *bdesc = builtin_desc;
while ((bdesc->bptr != NULL) && (bdesc->bptr != bptr))
if (locals[i][j].type >= 0) {
printf(" (%s) ", jit_type[j]);
if (locals[i][j].flags & INMEMORY)
- printf("m%2d", locals[i][j].regoff);
+ printf((regs_ok) ? "m%2d" : "m??", locals[i][j].regoff);
else if ((j == TYPE_FLT) || (j == TYPE_DBL))
- printf("f%02d", locals[i][j].regoff);
- else
- printf("%3s", regs[locals[i][j].regoff]);
+ printf((regs_ok) ? "f%02d" : "f??", locals[i][j].regoff);
+ else {
+ if (regs_ok) printf("%3s",regs[locals[i][j].regoff]); else printf("???");
+ }
}
printf("\n");
}
printf(" (%s) ", jit_type[j]);
if (interfaces[i][j].flags & SAVEDVAR) {
if (interfaces[i][j].flags & INMEMORY)
- printf("M%2d", interfaces[i][j].regoff);
+ printf((regs_ok) ? "M%2d" : "M??", interfaces[i][j].regoff);
else if ((j == TYPE_FLT) || (j == TYPE_DBL))
- printf("F%02d", interfaces[i][j].regoff);
- else
- printf("%3s", regs[interfaces[i][j].regoff]);
+ printf((regs_ok) ? "F%02d" : "F??", interfaces[i][j].regoff);
+ else {
+ if (regs_ok) printf("%3s",regs[interfaces[i][j].regoff]); else printf("???");
+ }
}
else {
if (interfaces[i][j].flags & INMEMORY)
- printf("m%2d", interfaces[i][j].regoff);
+ printf((regs_ok) ? "m%2d" : "m??", interfaces[i][j].regoff);
else if ((j == TYPE_FLT) || (j == TYPE_DBL))
- printf("f%02d", interfaces[i][j].regoff);
- else
- printf("%3s", regs[interfaces[i][j].regoff]);
+ printf((regs_ok) ? "f%02d" : "f??", interfaces[i][j].regoff);
+ else {
+ if (regs_ok) printf("%3s",regs[interfaces[i][j].regoff]); else printf("???");
+ }
}
}
printf("\n");
for (bptr = block; bptr != NULL; bptr = bptr->next) {
+ show_icmd_block(bptr);
+ }
+}
+
+void
+show_icmd_block(basicblock *bptr)
+{
+ int i, j;
+ int deadcode;
+ s4 *s4ptr;
+ instruction *iptr;
+
if (bptr->flags != BBDELETED) {
deadcode = bptr->flags <= BBREACHED;
printf("[");
if (deadcode)
- for (j = maxstack; j > 0; j--)
+ for (j = method->maxstack; j > 0; j--)
printf(" ? ");
else
- print_stack(bptr->instack);
- printf("] L%03d(%d - %d):\n", bptr->debug_nr, bptr->icount, bptr->pre_count);
+ icmd_print_stack(bptr->instack);
+ printf("] L%03d(%d - %d) flags=%d:\n", bptr->debug_nr, bptr->icount, bptr->pre_count,bptr->flags);
iptr = bptr->iinstr;
for (i=0; i < bptr->icount; i++, iptr++) {
printf("[");
if (deadcode) {
- for (j = maxstack; j > 0; j--)
+ for (j = method->maxstack; j > 0; j--)
printf(" ? ");
}
else
- print_stack(iptr->dst);
- printf("] %4d %s", i, icmd_names[iptr->opc]);
- switch ((int) iptr->opc) {
+ icmd_print_stack(iptr->dst);
+ printf("] %4d ", i);
+ /* XXX remove */ /*fflush(stdout);*/
+ show_icmd(iptr,deadcode);
+ printf("\n");
+ }
+
+ if (showdisassemble && (!deadcode)) {
+#if defined(__I386__) || defined(__X86_64__)
+ u1 *u1ptr;
+ int a;
+
+ printf("\n");
+ i = bptr->mpc;
+ u1ptr = method->mcode + dseglen + i;
+
+ if (bptr->next != NULL) {
+ for (; i < bptr->next->mpc; i++, u1ptr++) {
+ a = disassinstr(u1ptr, i);
+ i += a;
+ u1ptr += a;
+ }
+ printf("\n");
+
+ } else {
+ for (; u1ptr < (u1 *) (method->mcode + method->mcodelength); i++, u1ptr++) {
+ a = disassinstr(u1ptr, i);
+ i += a;
+ u1ptr += a;
+ }
+ printf("\n");
+ }
+#else
+ printf("\n");
+ i = bptr->mpc;
+ s4ptr = (s4 *) (method->mcode + dseglen + i);
+
+ if (bptr->next != NULL) {
+ for (; i < bptr->next->mpc; i += 4, s4ptr++) {
+ disassinstr(*s4ptr, i);
+ }
+ printf("\n");
+ }
+ else {
+ for (; s4ptr < (s4 *) (method->mcode + method->mcodelength); i += 4, s4ptr++) {
+ disassinstr(*s4ptr, i);
+ }
+ printf("\n");
+ }
+#endif
+ }
+ }
+}
+
+void
+show_icmd(instruction *iptr,bool deadcode)
+{
+ int j;
+ s4 *s4ptr;
+ void **tptr;
+
+ printf("%s",icmd_names[iptr->opc]);
+ switch ((int) iptr->opc) {
case ICMD_IADDCONST:
case ICMD_ISUBCONST:
case ICMD_IMULCONST:
case ICMD_BUILTIN3:
case ICMD_BUILTIN2:
case ICMD_BUILTIN1:
- printf(" %s", builtin_name((functionptr) iptr->val.a));
+ printf(" %s", icmd_builtin_name((functionptr) iptr->val.a));
break;
case ICMD_INVOKEVIRTUAL:
case ICMD_INVOKESPECIAL:
case ICMD_IFGE:
case ICMD_IFGT:
case ICMD_IFLE:
- printf("(%d) L%03d", iptr->val.i, ((basicblock *) iptr->target)->debug_nr);
+ if (deadcode)
+ printf("(%d) op1=%d", iptr->val.i, iptr->op1);
+ else
+ printf("(%d) L%03d", iptr->val.i, ((basicblock *) iptr->target)->debug_nr);
break;
case ICMD_IF_LEQ:
case ICMD_IF_LNE:
case ICMD_IF_LGE:
case ICMD_IF_LGT:
case ICMD_IF_LLE:
- printf("(%lld) L%03d", iptr->val.l, ((basicblock *) iptr->target)->debug_nr);
+ if (deadcode)
+ printf("(%lld) op1=%d", iptr->val.l, iptr->op1);
+ else
+ printf("(%lld) L%03d", iptr->val.l, ((basicblock *) iptr->target)->debug_nr);
break;
case ICMD_JSR:
case ICMD_GOTO:
case ICMD_IF_LCMPLE:
case ICMD_IF_ACMPEQ:
case ICMD_IF_ACMPNE:
- printf(" L%03d", ((basicblock *) iptr->target)->debug_nr);
+ if (deadcode)
+ printf(" op1=%d", iptr->op1);
+ else
+ printf(" L%03d", ((basicblock *) iptr->target)->debug_nr);
break;
case ICMD_TABLESWITCH:
s4ptr = iptr->val.a;
- tptr = (void **) iptr->target;
-
- printf(" L%03d;", ((basicblock *) *tptr)->debug_nr);
- /* default */
- s4ptr++;
- tptr++;
+ if (deadcode) {
+ printf(" %d;", *s4ptr);
+ }
+ else {
+ tptr = (void **) iptr->target;
+ printf(" L%03d;", ((basicblock *) *tptr)->debug_nr);
+ tptr++;
+ }
+ s4ptr++; /* skip default */
j = *s4ptr++; /* low */
j = *s4ptr++ - j; /* high */
while (j >= 0) {
- printf(" L%03d", ((basicblock *) *tptr)->debug_nr);
- tptr++;
+ if (deadcode)
+ printf(" %d", *s4ptr++);
+ else {
+ printf(" L%03d", ((basicblock *) *tptr)->debug_nr);
+ tptr++;
+ }
j--;
}
break;
case ICMD_LOOKUPSWITCH:
s4ptr = iptr->val.a;
- tptr = (void **) iptr->target;
-
- printf(" L%03d", ((basicblock *) *tptr)->debug_nr);
- s4ptr++; /* default */
- j = *s4ptr; /* count */
- tptr++;
- while (--j >= 0) {
+ if (deadcode) {
+ printf(" %d;", *s4ptr);
+ }
+ else {
+ tptr = (void **) iptr->target;
printf(" L%03d", ((basicblock *) *tptr)->debug_nr);
tptr++;
}
- break;
- }
- printf("\n");
- }
-
- if (showdisassemble && (!deadcode)) {
-#if defined(__I386__) || defined(__X86_64__)
- u1 *u1ptr;
- int a;
-
- printf("\n");
- i = bptr->mpc;
- u1ptr = method->mcode + dseglen + i;
-
- if (bptr->next != NULL) {
- for (; i < bptr->next->mpc; i++, u1ptr++) {
- a = disassinstr(u1ptr, i);
- i += a;
- u1ptr += a;
- }
- printf("\n");
+ s4ptr++; /* default */
+ j = *s4ptr++; /* count */
- } else {
- for (; u1ptr < (u1 *) (method->mcode + method->mcodelength); i++, u1ptr++) {
- a = disassinstr(u1ptr, i);
- i += a;
- u1ptr += a;
+ while (--j >= 0) {
+ if (deadcode) {
+ s4ptr++; /* skip value */
+ printf(" %d",*s4ptr++);
+ }
+ else {
+ printf(" L%03d", ((basicblock *) *tptr)->debug_nr);
+ tptr++;
+ }
}
- printf("\n");
- }
-#else
- printf("\n");
- i = bptr->mpc;
- s4ptr = (s4 *) (method->mcode + dseglen + i);
-
- if (bptr->next != NULL) {
- for (; i < bptr->next->mpc; i += 4, s4ptr++) {
- disassinstr(*s4ptr, i);
- }
- printf("\n");
- }
- else {
- for (; s4ptr < (s4 *) (method->mcode + method->mcodelength); i += 4, s4ptr++) {
- disassinstr(*s4ptr, i);
- }
- printf("\n");
- }
-#endif
- }
- }
+ break;
}
}
-
/*
* These are local overrides for various environment variables in Emacs.
* Please do not remove this and leave it at the end of the file, where
--- /dev/null
+/* jit/typecheck.c - typechecking (part of bytecode verification)
+
+ Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
+ R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser,
+ M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck,
+ P. Tomsich, J. Wenninger
+
+ This file is part of CACAO.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+
+ Contact: cacao@complang.tuwien.ac.at
+
+ Authors: Edwin Steiner
+
+ $Id: typecheck.c 696 2003-12-06 20:10:05Z edwin $
+
+*/
+
+#include "global.h" /* must be here because of CACAO_TYPECHECK */
+
+#ifdef CACAO_TYPECHECK
+
+#include "jit.h"
+#include "builtin.h"
+#include "tables.h"
+#include "loader.h"
+#include "types.h"
+#include "toolbox/loging.h"
+#include "toolbox/memory.h"
+
+#define TOUCHED_YES 0x01
+#define TOUCHED_NO 0x02
+#define TOUCHED_MAYBE (TOUCHED_YES | TOUCHED_NO)
+
+#define REACH_STD 0
+#define REACH_JSR 1
+#define REACH_RET 2
+
+/****************************************************************************/
+/* DEBUG HELPERS */
+/****************************************************************************/
+
+#ifdef TYPECHECK_VERBOSE_OPT
+bool typecheckverbose = false;
+#define DOLOG(action) do { if (typecheckverbose) {action;} } while(0)
+#else
+#define DOLOG(action)
+#endif
+
+#ifdef TYPECHECK_VERBOSE
+#define TYPECHECK_VERBOSE_IMPORTANT
+#define LOG(str) DOLOG(log_text(str))
+#define LOG1(str,a) DOLOG(dolog(str,a))
+#define LOG2(str,a,b) DOLOG(dolog(str,a,b))
+#define LOG3(str,a,b,c) DOLOG(dolog(str,a,b,c))
+#define LOGIF(cond,str) DOLOG(do {if (cond) log_text(str);} while(0))
+#define LOGINFO(info) DOLOG(do {typeinfo_print_short(stdout,info);printf("\n");} while(0))
+#define LOGFLUSH DOLOG(fflush(stdout))
+#define LOGNL DOLOG(printf("\n"))
+#define LOGSTR(str) DOLOG(printf(str))
+#define LOGSTR1(str,a) DOLOG(printf(str,a))
+#define LOGSTR2(str,a,b) DOLOG(printf(str,a,b))
+#define LOGSTR3(str,a,b,c) DOLOG(printf(str,a,b,c))
+#define LOGSTRu(utf) DOLOG(utf_display(utf))
+#else
+#define LOG(str)
+#define LOG1(str,a)
+#define LOG2(str,a,b)
+#define LOG3(str,a,b,c)
+#define LOGIF(cond,str)
+#define LOGINFO(info)
+#define LOGFLUSH
+#define LOGNL
+#define LOGSTR(str)
+#define LOGSTR1(str,a)
+#define LOGSTR2(str,a,b)
+#define LOGSTR3(str,a,b,c)
+#endif
+
+#ifdef TYPECHECK_VERBOSE_IMPORTANT
+#define LOGimp(str) DOLOG(log_text(str))
+#define LOGimpSTR(str) DOLOG(printf(str))
+#define LOGimpSTRu(utf) DOLOG(utf_display(utf))
+#else
+#define LOGimp(str)
+#define LOGimpSTR(str)
+#define LOGimpSTRu(utf)
+#endif
+
+#if defined(TYPECHECK_VERBOSE) || defined(TYPECHECK_VERBOSE_IMPORTANT)
+
+static
+void
+typeinfo_print_locals(FILE *file,u1 *vtype,typeinfo *vinfo,u1 *touched,int num)
+{
+ int i;
+
+ for (i=0; i<num; ++i) {
+ if (touched)
+ fprintf(file," %d%s=",i,
+ (touched[i]==TOUCHED_YES) ? "*"
+ : ((touched[i]==TOUCHED_NO) ? "" : "~"));
+ else
+ fprintf(file," %d=",i);
+ typeinfo_print_type(file,vtype[i],vinfo+i);
+ }
+}
+
+static
+void
+typeinfo_print_stack(FILE *file,stackptr stack)
+{
+ while (stack) {
+ typeinfo_print_type(file,stack->type,&stack->typeinfo);
+ stack = stack->prev;
+ if (stack) fprintf(file," ");
+ }
+}
+
+static
+void
+typeinfo_print_block(FILE *file,stackptr instack,
+ u1 *vtype,typeinfo *vinfo,u1 *touched)
+{
+ fprintf(file,"Stack: ");
+ typeinfo_print_stack(file,instack);
+ fprintf(file," Locals:");
+ typeinfo_print_locals(file,vtype,vinfo,touched,maxlocals);
+}
+
+
+static
+void
+typeinfo_print_blocks(FILE *file,u1 *vtype,typeinfo *vinfo)
+{
+ int bi;
+ /* int j;*/
+
+ for (bi=0; bi<block_count; ++bi) {
+ fprintf(file,"%04d: (%3d) ",bi,block[bi].flags);
+ typeinfo_print_block(file,block[bi].instack,
+ vtype+maxlocals*bi,vinfo+maxlocals*bi,NULL);
+ fprintf(file,"\n");
+
+/* for (j=0; j<block[bi].icount; ++j) { */
+/* fprintf(file,"\t%s\n",icmd_names[block[bi].iinstr[j].opc]); */
+/* } */
+
+ show_icmd_block(block+bi);
+ }
+}
+
+#endif
+
+/****************************************************************************/
+/* INTERNAL DATA STRUCTURES */
+/****************************************************************************/
+
+typedef struct jsr_record jsr_record;
+
+/*
+ * For each basic block we store the chain of JSR instructions which
+ * were used to reach the block (usually zero or one). For more
+ * details on verifying JSR and RET instructions see the Java VM
+ * Specification.
+ *
+ * CAUTION: The fields starting with sbr_ are only valid for the
+ * 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 */
+};
+
+/****************************************************************************/
+/* MACROS USED INTERNALLY IN typecheck() */
+/****************************************************************************/
+
+#define TOUCH_VARIABLE(num) do {if (jsrchain) touched[num] = TOUCHED_YES;} while (0)
+#define TOUCH_TWOWORD(num) do {TOUCH_VARIABLE(num);TOUCH_VARIABLE((num)+1);} while (0)
+
+/* XXX should check num in range? */
+/* XXX invalidate two word variables on store in second half! */
+#define STORE_TYPE(num,type) do {vtype[(num)] = (type); TOUCH_VARIABLE(num);} while(0)
+#define STORE_INVALID(num) STORE_TYPE((num),TYPE_VOID)
+#define STORE_PRIMITIVE(num,type) STORE_TYPE((num),(type))
+#define STORE_TWOWORD(num,type) {STORE_PRIMITIVE((num),(type));STORE_INVALID((num)+1);}
+
+#define CHECKVARTYPE(num,type) \
+ {if (vtype[(num)] != (type)) panic("Variable type mismatch"); TOUCH_VARIABLE(num);}
+
+/* XXX maybe it's faster to copy always */
+#define COPYTYPE(source,dest) \
+ {if ((source)->type == TYPE_ADR) \
+ TYPEINFO_COPY((source)->typeinfo,(dest)->typeinfo);}
+
+#define ISBUILTIN(v) (iptr->val.a == (functionptr)(v))
+
+/* TYPECHECK_COPYVARS: copy the types and typeinfos of the current local
+ * variables to the local variables of the target block.
+ * Input:
+ * vtype......current local variable types
+ * vinfo......current local variable typeinfos
+ * ttype......local variable types of target block
+ * tinfo......local variable typeinfos of target block
+ * maxlocals..number of local variables
+ * Used:
+ * macro_i
+ */
+#define TYPECHECK_COPYVARS \
+ LOG("TYPECHECK_COPYVARS"); \
+ for (macro_i=0; macro_i<maxlocals; ++macro_i) { \
+ if ((ttype[macro_i] = vtype[macro_i]) == TYPE_ADR) \
+ TYPEINFO_CLONE(vinfo[macro_i],tinfo[macro_i]); \
+ }
+
+/* TYPECHECK_MERGEVARS: merge the local variables of the target block
+ * with the current local variables.
+ * Input:
+ * vtype......current local variable types
+ * vinfo......current local variable typeinfos
+ * ttype......local variable types of target block
+ * tinfo......local variable typeinfos of target block
+ * maxlocals..number of local variables
+ * Ouput:
+ * changed....set to true if any typeinfo has changed
+ * Used:
+ * macro_i
+ */
+#define TYPECHECK_MERGEVARS \
+ LOG("TYPECHECK_MERGEVARS"); \
+ for (macro_i=0; macro_i<maxlocals; ++macro_i) { \
+ if ((ttype[macro_i] != TYPE_VOID) && (vtype[macro_i] != ttype[macro_i])) { \
+ LOG3("var %d: type %d + type %d = void",macro_i,ttype[macro_i],vtype[macro_i]); \
+ ttype[macro_i] = TYPE_VOID; \
+ changed = true; \
+ } else if (ttype[macro_i] == TYPE_ADR) { \
+ if ( ((TYPEINFO_IS_PRIMITIVE(tinfo[macro_i])) ? 1 : 0) \
+ ^ \
+ ((TYPEINFO_IS_PRIMITIVE(vinfo[macro_i])) ? 1 : 0)) { \
+ LOG1("var %d: primitive + reference merge",macro_i); \
+ ttype[macro_i] = TYPE_VOID; \
+ changed = true; \
+ } \
+ else { \
+ LOG1("var %d:",macro_i); \
+ LOGINFO(tinfo+macro_i); \
+ LOGINFO(vinfo+macro_i); \
+ changed |= typeinfo_merge(tinfo+macro_i,vinfo+macro_i); \
+ LOGINFO(tinfo+macro_i); \
+ LOGIF(changed,"vars have changed"); \
+ } \
+ }; \
+ }
+
+/* TYPECHECK_MERGEJSR:
+ *
+ * Input:
+ * Ouput:
+ * tbptr......target block
+ * changed....set to true if any typeinfo has changed
+ * maxlocals..number of local variables
+ * touched....current touched flags of local variables
+ * Used:
+ * macro_i, jsrtemp, jsrtemp2
+ */
+#define TYPECHECK_MERGEJSR \
+ do { \
+ LOG("TYPECHECK_MERGEJSR"); \
+ jsrtemp = jsrbuffer[tbptr-block]; \
+ jsrtemp2 = jsrchain; \
+ while (jsrtemp || jsrtemp2) { \
+ if (!jsrtemp || !jsrtemp2) \
+ panic("Merging JSR subroutines of different depth"); \
+ if (jsrtemp->target != jsrtemp2->target) \
+ panic("Merging different JSR subroutines"); \
+ jsrtemp = jsrtemp->next; \
+ jsrtemp2 = jsrtemp2->next; \
+ } \
+ jsrtemp = jsrbuffer[tbptr-block]; \
+ if (jsrtemp) \
+ for (macro_i=0; macro_i<maxlocals; ++macro_i) { \
+ jsrtemp->touched[i] |= touched[i]; \
+ } } while (0)
+
+/* TYPECHECK_COPYSTACK: copy the typeinfos of the current stack to
+ * the input stack of the target block.
+ * Input:
+ * srcstack...current stack
+ * dststack...input stack of target block
+ */
+#define TYPECHECK_COPYSTACK \
+ LOG("TYPECHECK_COPYSTACK"); \
+ while (srcstack) { \
+ LOG1("copy %d",srcstack->type); \
+ if (!dststack) panic("Stack depth mismatch"); \
+ if (srcstack->type != dststack->type) \
+ panic("Type mismatch on stack"); \
+ if (srcstack->type == TYPE_ADR) { \
+ TYPEINFO_CLONE(srcstack->typeinfo,dststack->typeinfo); \
+ } \
+ dststack = dststack->prev; \
+ srcstack = srcstack->prev; \
+ } \
+ if (dststack) panic("Stack depth mismatch");
+
+/* TYPECHECK_MERGESTACK: merge the input stack of the target block
+ * with the current stack.
+ * Input:
+ * srcstack...current stack
+ * dststack...input stack of target block
+ * Ouput:
+ * changed....set to true if any typeinfo has changed
+ */
+#define TYPECHECK_MERGESTACK \
+ LOG("TYPECHECK_MERGESTACK"); \
+ while (srcstack) { \
+ if (!dststack) panic("Stack depth mismatch"); \
+ if (srcstack->type != dststack->type) \
+ panic("Type mismatch on stack"); \
+ if (srcstack->type == TYPE_ADR) { \
+ LOGINFO(&dststack->typeinfo); \
+ LOGINFO(&srcstack->typeinfo); LOGFLUSH; \
+ changed |= typeinfo_merge(&dststack->typeinfo, \
+ &srcstack->typeinfo); \
+ LOGINFO(&dststack->typeinfo); \
+ LOG((changed)?"CHANGED!\n":"not changed.\n"); \
+ } \
+ dststack = dststack->prev; \
+ srcstack = srcstack->prev; \
+ } \
+ if (dststack) panic("Stack depth mismatch");
+
+
+/* TYPECHECK_CHECK_JSR_CHAIN: checks if the target block is reached by
+ * the same JSR targets on all control paths.
+ *
+ * Input:
+ * tbptr......target block
+ * jsrchain...current JSR target chain
+ * jsrbuffer..JSR target chain for each basic block
+ * Output:
+ * panic if the JSR target chains don't match
+ * Used:
+ * jsrtemp, jsrtemp2
+ */
+#define TYPECHECK_CHECK_JSR_CHAIN \
+ do { \
+ jsrtemp = jsrbuffer[tbptr-block]; \
+ if (!jsrtemp) panic("non-subroutine called by JSR"); \
+ if (jsrtemp->target != tbptr) \
+ panic("Merging different JSR subroutines"); \
+ jsrtemp = jsrtemp->next; \
+ jsrtemp2 = jsrchain; \
+ while (jsrtemp || jsrtemp2) { \
+ if (!jsrtemp || !jsrtemp2) \
+ panic("Merging JSR subroutines of different depth"); \
+ if (jsrtemp->target != jsrtemp2->target) \
+ panic("Merging different JSR subroutines"); \
+ jsrtemp = jsrtemp->next; \
+ jsrtemp2 = jsrtemp2->next; \
+ } } while (0)
+
+/* TYPECHECK_ADD_JSR: add a JSR target to the current JSR target chain
+ * and store the resulting chain in the target block.
+ *
+ * Input:
+ * jsrchain...current JSR target chain
+ * tbptr.....the basic block targeted by the JSR
+ * maxlocals..number of local variables
+ * jsrbuffer..JSR target chain for each basic block
+ * Used:
+ * jsrtemp
+ */
+#define TYPECHECK_ADD_JSR \
+ do { \
+ LOG1("adding JSR to block %04d",(tbptr)-block); \
+ jsrtemp = (jsr_record *) dump_alloc(sizeof(jsr_record)+(maxlocals-1)*sizeof(u1)); \
+ jsrtemp->target = (tbptr); \
+ jsrtemp->next = jsrchain; \
+ jsrtemp->sbr_touched = NULL; \
+ memset(&jsrtemp->touched,TOUCHED_NO,sizeof(u1)*maxlocals); \
+ jsrbuffer[tbptr-block] = jsrtemp; \
+ } while (0)
+
+/* TYPECHECK_COPYJSR: copy the current JSR chain to the target block.
+ *
+ * Input:
+ * chain......current JSR target chain
+ * tbptr.....the basic block targeted by the JSR
+ * maxlocals..number of local variables
+ * jsrbuffer..JSR target chain for each basic block
+ * touched....current touched flags of local variables
+ * Used:
+ * jsrtemp
+ */
+#define TYPECHECK_COPYJSR(chain) \
+ do { \
+ LOG("TYPECHECK_COPYJSR"); \
+ if (chain) { \
+ jsrtemp = (jsr_record *) dump_alloc(sizeof(jsr_record)+(maxlocals-1)*sizeof(u1)); \
+ jsrtemp->target = (chain)->target; \
+ jsrtemp->next = (chain)->next; \
+ jsrtemp->sbr_touched = NULL; \
+ memcpy(&jsrtemp->touched,touched,sizeof(u1)*maxlocals); \
+ jsrbuffer[tbptr-block] = jsrtemp; \
+ } \
+ else \
+ jsrbuffer[tbptr-block] = NULL; \
+ } while (0)
+
+/* TYPECHECK_REACH: executed, when the target block (tbptr) can be reached
+ * from the current block (bptr). The types of local variables and
+ * stack slots are propagated to the target block.
+ * Input:
+ * bptr.......current block
+ * tbptr......target block
+ * dst........current output stack pointer
+ * vtype......current local variable types
+ * vinfo......current local variable typeinfos
+ * jsrchain...current JSR target chain
+ * jsrbuffer..JSR target chain for each basic block
+ * way........in which way the block is reached (REACH_ constant)
+ * touched....current touched flags of local variables
+ * Output:
+ * repeat.....changed to true if a block before the current
+ * block has changed
+ * Used:
+ * ttype, tinfo, srcstack, dststack, changed, macro_i
+ */
+#define TYPECHECK_REACH(way) \
+ LOG1("reaching block %04d",tbptr-block); \
+ srcstack = dst; \
+ dststack = tbptr->instack; \
+ ttype = vartype + maxlocals*(tbptr-block); \
+ tinfo = vartypeinfo + maxlocals*(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 { \
+ TYPECHECK_COPYJSR(jsrchain); \
+ TYPECHECK_COPYVARS; \
+ } \
+ TYPECHECK_COPYSTACK; \
+ changed = true; \
+ } else { \
+ /* This block has been reached before */ \
+ changed = false; \
+ if (way == REACH_JSR) \
+ TYPECHECK_CHECK_JSR_CHAIN; \
+ else \
+ TYPECHECK_MERGEJSR; \
+ LOGIF(changed,"changed jsr"); \
+ TYPECHECK_MERGEVARS; \
+ LOGIF(changed,"changed vars"); \
+ TYPECHECK_MERGESTACK; \
+ LOGIF(changed,"changed stack"); \
+ } \
+ if (changed) { \
+ LOG("REACHED!"); \
+ tbptr->flags = BBTYPECHECK_REACHED; \
+ if (tbptr <= bptr) {repeat = true; LOG("MUST REPEAT!");} \
+ } LOG("done.");
+
+/****************************************************************************/
+/* typecheck() */
+/****************************************************************************/
+
+#define MAXPARAMS 255
+
+/* typecheck is called directly after analyse_stack */
+void
+typecheck()
+{
+ int b_count, b_index;
+ stackptr curstack; /* input stack top for current instruction */
+ stackptr srcstack; /* source stack for copying and merging */
+ stackptr dststack; /* target stack for copying and merging */
+ int opcode, macro_i, len, i;
+ bool superblockend; /* true if no fallthrough to next block */
+ bool repeat; /* if true, blocks are iterated over again */
+ bool changed;
+ instruction *iptr = instr; /* pointer to current instruction */
+ basicblock *bptr; /* pointer to current basic block */
+ basicblock *tbptr;
+ 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 */
+ typeinfo tempinfo; /* temporary */
+ int returntype; /* return type of current method */
+ typeinfo returntypeinfo; /* typeinfo for return type */
+ 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 */
+ int changeddepth; /* depth to which the stack has changed */ /* XXX */
+ bool fulltypecheck; /* false == check only changed types */ /* XXX */
+ basicblock **tptr; /* pointer into target list of switch instructions */
+ jsr_record **jsrbuffer; /* JSR target chain for each basic block */
+ jsr_record *jsrchain; /* JSR chain for current block */
+ jsr_record *jsrtemp,*jsrtemp2,*jsrold; /* temporary variables */
+ jsr_record *subroutine; /* jsr_record of the current subroutine */
+ u1 *touched; /* touched flags for local variables */
+
+ LOGSTR("\n==============================================================================\n");
+ DOLOG(show_icmd_method());
+ LOGSTR("\n==============================================================================\n");
+ LOGimpSTR("Entering typecheck: ");
+ LOGimpSTRu(method->name);
+ LOGimpSTR(" ");
+ LOGimpSTRu(method->descriptor);
+ LOGimpSTR(" (class ");
+ LOGimpSTRu(method->class->name);
+ LOGimpSTR(")\n");
+
+ /* XXX allocate buffers for method arguments */
+ ptype = DMNEW(u1,MAXPARAMS);
+ pinfo = DMNEW(typeinfo,MAXPARAMS);
+
+ LOG("Buffer allocated.\n");
+
+ /* reset all BBFINISHED blocks to BBTYPECHECK_UNDEF. */
+ b_count = block_count;
+ bptr = block;
+ while (--b_count >= 0) {
+#ifdef TYPECHECK_DEBUG
+ if (bptr->flags != BBFINISHED && bptr->flags != BBDELETED
+ && bptr->flags != BBUNDEF)
+ {
+ show_icmd_method();
+ LOGSTR1("block flags: %d\n",bptr->flags); LOGFLUSH;
+ panic("Internal error: Unexpected block flags in typecheck()");
+ }
+#endif
+ if (bptr->flags >= BBFINISHED) {
+ bptr->flags = BBTYPECHECK_UNDEF;
+ }
+ bptr++;
+ }
+
+ /* The first block is always reached */
+ if (block_count && block[0].flags == BBTYPECHECK_UNDEF)
+ block[0].flags = BBTYPECHECK_REACHED;
+
+ LOG("Blocks reset.\n");
+
+ /* allocate the buffers for local variables */
+ vartype = DMNEW(u1,maxlocals * (block_count+1));
+ vartypeinfo = DMNEW(typeinfo,maxlocals * (block_count+1));
+ touched = DMNEW(u1,maxlocals);
+ vtype = vartype + maxlocals * block_count;
+ vinfo = vartypeinfo + maxlocals * block_count;
+ memset(vartype,TYPE_VOID,maxlocals * (block_count+1) * sizeof(typeinfo));
+ memset(vartypeinfo,0,maxlocals * (block_count+1) * sizeof(typeinfo));
+
+ LOG("Variable buffer initialized.\n");
+
+ /* allocate the buffer for storing JSR target chains */
+ jsrbuffer = DMNEW(jsr_record*,block_count);
+ memset(jsrbuffer,0,block_count * sizeof(jsr_record*));
+ jsrchain = NULL;
+
+ LOG("jsrbuffer initialized.\n");
+
+ /* initialize the variable types of the first block */
+ /* to the types of the arguments */
+ ttype = vartype;
+ tinfo = vartypeinfo;
+
+ /* if this is an instance method initialize the "this" ref type */
+ if (!(method->flags & ACC_STATIC)) {
+ *ttype++ = TYPE_ADDRESS;
+ TYPEINFO_INIT_CLASSINFO(*tinfo,class);
+ tinfo++;
+ }
+
+ LOG("'this' argument set.\n");
+
+ /* the rest of the arguments and the return type */
+ typeinfo_init_from_method_args(method->descriptor,ttype,tinfo,
+ maxlocals - (tinfo-vartypeinfo),
+ true, /* two word types use two slots */
+ &returntype,&returntypeinfo);
+
+ LOG("Arguments set.\n");
+
+ /* loop while there are still blocks to be checked */
+ fulltypecheck = true; /* XXX */
+ do {
+
+ repeat = false;
+
+ b_count = block_count;
+ bptr = block;
+
+ while (--b_count >= 0) {
+ LOGSTR1("---- BLOCK %04d, ",bptr-block);
+ LOGSTR1("blockflags: %d\n",bptr->flags);
+ LOGFLUSH;
+
+ if (bptr->flags == BBTYPECHECK_REACHED) {
+ LOGSTR1("\n---- BLOCK %04d ------------------------------------------------\n",bptr-block);
+ LOGFLUSH;
+
+ superblockend = false;
+ bptr->flags = BBFINISHED;
+ b_index = bptr - block;
+
+ /* init stack at the start of this block */
+ curstack = bptr->instack;
+
+ /* init variable types at the start of this block */
+ for (i=0; i<maxlocals; ++i) {
+ vtype[i] = vartype[maxlocals*b_index + i];
+ TYPEINFO_COPY(vartypeinfo[maxlocals*b_index + i],vinfo[i]);
+ }
+
+ /* init JSR target chain */
+ if ((jsrchain = jsrbuffer[b_index]) != NULL) {
+#ifdef TYPECHECK_VERBOSE
+ if (typecheckverbose) {
+ LOGSTR("jsr chain:");
+ jsrtemp = jsrchain;
+ while (jsrtemp) {
+ LOGSTR1(" L%03d",jsrtemp->target->debug_nr);
+ jsrtemp = jsrtemp->next;
+ }
+ LOGNL;
+ LOGFLUSH;
+ }
+#endif
+
+ subroutine = jsrbuffer[jsrchain->target - block];
+ memcpy(touched,jsrchain->touched,sizeof(u1)*maxlocals);
+ }
+ else
+ subroutine = NULL;
+#ifdef TYPECHECK_VERBOSE
+ if (typecheckverbose) {
+ if (subroutine) {LOGSTR1("subroutine L%03d\n",subroutine->target->debug_nr);LOGFLUSH;}
+ typeinfo_print_block(stdout,curstack,vtype,vinfo,(jsrchain) ? touched : NULL);
+ LOGNL; LOGFLUSH;
+ }
+#endif
+
+ /* loop over the instructions */
+ len = bptr->icount;
+ iptr = bptr->iinstr;
+ while (--len >= 0) {
+ DOLOG(show_icmd(iptr,false));
+ LOGNL;
+ LOGFLUSH;
+
+ opcode = iptr->opc;
+ dst = iptr->dst;
+
+ switch (opcode) {
+
+ /****************************************/
+ /* STACK MANIPULATIONS */
+
+ /* We just need to copy the typeinfo */
+ /* for slots containing addresses. */
+
+ case ICMD_DUP:
+ COPYTYPE(curstack,dst);
+ break;
+
+ case ICMD_DUP_X1:
+ COPYTYPE(curstack,dst);
+ COPYTYPE(curstack,dst-2);
+ COPYTYPE(curstack->prev,dst-1);
+ break;
+
+ case ICMD_DUP_X2:
+ COPYTYPE(curstack,dst);
+ COPYTYPE(curstack,dst-3);
+ COPYTYPE(curstack->prev,dst-1);
+ COPYTYPE(curstack->prev->prev,dst-2);
+ break;
+
+ case ICMD_DUP2:
+ COPYTYPE(curstack,dst);
+ COPYTYPE(curstack->prev,dst-1);
+ break;
+
+ case ICMD_DUP2_X1:
+ COPYTYPE(curstack,dst);
+ COPYTYPE(curstack->prev,dst-1);
+ COPYTYPE(curstack,dst-3);
+ COPYTYPE(curstack->prev,dst-4);
+ COPYTYPE(curstack->prev->prev,dst-2);
+ break;
+
+ case ICMD_DUP2_X2:
+ COPYTYPE(curstack,dst);
+ COPYTYPE(curstack->prev,dst-1);
+ COPYTYPE(curstack,dst-4);
+ COPYTYPE(curstack->prev,dst-5);
+ COPYTYPE(curstack->prev->prev,dst-2);
+ COPYTYPE(curstack->prev->prev->prev,dst-3);
+ break;
+
+ case ICMD_SWAP:
+ COPYTYPE(curstack,dst-1);
+ COPYTYPE(curstack->prev,dst);
+ break;
+
+ /* XXX only add these cases in debug mode? */
+ case ICMD_POP:
+ break;
+
+ case ICMD_POP2:
+ break;
+
+ /****************************************/
+ /* LOADING ADDRESS FROM VARIABLE */
+
+ case ICMD_ALOAD:
+ CHECKVARTYPE(iptr->op1,TYPE_ADR);
+
+ /* loading a returnAddress is not allowed */
+ if (TYPEINFO_IS_PRIMITIVE(vinfo[iptr->op1]))
+ panic("illegal instruction: ALOAD loading returnAddress");
+
+ TYPEINFO_COPY(vinfo[iptr->op1],dst->typeinfo);
+ break;
+
+ /****************************************/
+ /* STORING ADDRESS TO VARIABLE */
+
+ case ICMD_ASTORE:
+ /* TYPE_ADR has already been checked. */
+ STORE_TYPE(iptr->op1,TYPE_ADDRESS);
+ TYPEINFO_COPY(curstack->typeinfo,vinfo[iptr->op1]);
+ break;
+
+ /****************************************/
+ /* LOADING ADDRESS FROM ARRAY */
+
+ case ICMD_AALOAD:
+ if (!TYPEINFO_MAYBE_ARRAY_OF_REFS(curstack->prev->typeinfo))
+ panic("illegal instruction: AALOAD on non-reference array");
+
+ typeinfo_init_component(&curstack->prev->typeinfo,&dst->typeinfo);
+ break;
+
+ /****************************************/
+ /* STORING ADDRESS TO ARRAY */
+
+ case ICMD_AASTORE:
+ /* XXX also handled by builtin3 */
+ if (!TYPEINFO_MAYBE_ARRAY_OF_REFS(curstack->prev->prev->typeinfo))
+ panic("illegal instruction: AASTORE to non-reference array");
+
+ /* XXX optimize */
+ /*
+ typeinfo_init_component(&curstack->prev->prev->typeinfo,&tempinfo);
+ if (!typeinfo_is_assignable(&curstack->typeinfo,&tempinfo))
+ panic("illegal instruction: AASTORE to incompatible type");
+ */
+ break;
+
+ /****************************************/
+ /* FIELD ACCESS */
+
+ case ICMD_PUTFIELD:
+ if (!TYPEINFO_IS_REFERENCE(curstack->prev->typeinfo))
+ panic("illegal instruction: PUTFIELD on non-reference");
+ if (TYPEINFO_IS_ARRAY(curstack->prev->typeinfo)) /* XXX arraystub */
+ panic("illegal instruction: PUTFIELD on array");
+
+
+ /* XXX */
+ break;
+
+ case ICMD_PUTSTATIC:
+ /* XXX */
+ break;
+
+ case ICMD_GETFIELD:
+ if (!TYPEINFO_IS_REFERENCE(curstack->typeinfo))
+ panic("illegal instruction: GETFIELD on non-reference");
+ if (TYPEINFO_IS_ARRAY(curstack->typeinfo))
+ panic("illegal instruction: GETFIELD on array");
+
+ {
+ fieldinfo *fi = (fieldinfo *)(iptr->val.a);
+ /* XXX check non-static? */
+ if (dst->type == TYPE_ADR) {
+ TYPEINFO_INIT_FROM_FIELDINFO(dst->typeinfo,fi);
+ }
+ else {
+ TYPEINFO_INIT_PRIMITIVE(dst->typeinfo);
+ }
+ }
+ break;
+
+ case ICMD_GETSTATIC:
+ {
+ fieldinfo *fi = (fieldinfo *)(iptr->val.a);
+ /* XXX check static? */
+ if (dst->type == TYPE_ADR) {
+ TYPEINFO_INIT_FROM_FIELDINFO(dst->typeinfo,fi);
+ }
+ else {
+ TYPEINFO_INIT_PRIMITIVE(dst->typeinfo);
+ }
+ }
+ break;
+
+ /****************************************/
+ /* PRIMITIVE ARRAY ACCESS */
+
+ case ICMD_ARRAYLENGTH:
+ /* XXX should this also work on arraystubs? */
+ if (!TYPEINFO_MAYBE_ARRAY(curstack->typeinfo))
+ panic("illegal instruction: ARRAYLENGTH on non-array");
+ break;
+
+ case ICMD_BALOAD:
+ if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(curstack->prev->typeinfo,ARRAYTYPE_BOOLEAN)
+ && !TYPEINFO_MAYBE_PRIMITIVE_ARRAY(curstack->prev->typeinfo,ARRAYTYPE_BYTE))
+ panic("Array type mismatch");
+ break;
+ case ICMD_CALOAD:
+ if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(curstack->prev->typeinfo,ARRAYTYPE_CHAR))
+ panic("Array type mismatch");
+ break;
+ case ICMD_DALOAD:
+ if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(curstack->prev->typeinfo,ARRAYTYPE_DOUBLE))
+ panic("Array type mismatch");
+ break;
+ case ICMD_FALOAD:
+ if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(curstack->prev->typeinfo,ARRAYTYPE_FLOAT))
+ panic("Array type mismatch");
+ break;
+ case ICMD_IALOAD:
+ if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(curstack->prev->typeinfo,ARRAYTYPE_INT))
+ panic("Array type mismatch");
+ break;
+ case ICMD_SALOAD:
+ if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(curstack->prev->typeinfo,ARRAYTYPE_SHORT))
+ panic("Array type mismatch");
+ break;
+ case ICMD_LALOAD:
+ if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(curstack->prev->typeinfo,ARRAYTYPE_LONG))
+ panic("Array type mismatch");
+ break;
+
+ case ICMD_BASTORE:
+ if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(curstack->prev->prev->typeinfo,ARRAYTYPE_BOOLEAN)
+ && !TYPEINFO_MAYBE_PRIMITIVE_ARRAY(curstack->prev->prev->typeinfo,ARRAYTYPE_BYTE))
+ panic("Array type mismatch");
+ break;
+ case ICMD_CASTORE:
+ if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(curstack->prev->prev->typeinfo,ARRAYTYPE_CHAR))
+ panic("Array type mismatch");
+ break;
+ case ICMD_DASTORE:
+ if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(curstack->prev->prev->typeinfo,ARRAYTYPE_DOUBLE))
+ panic("Array type mismatch");
+ break;
+ case ICMD_FASTORE:
+ if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(curstack->prev->prev->typeinfo,ARRAYTYPE_FLOAT))
+ panic("Array type mismatch");
+ break;
+ case ICMD_IASTORE:
+ if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(curstack->prev->prev->typeinfo,ARRAYTYPE_INT))
+ panic("Array type mismatch");
+ break;
+ case ICMD_SASTORE:
+ if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(curstack->prev->prev->typeinfo,ARRAYTYPE_SHORT))
+ panic("Array type mismatch");
+ break;
+ case ICMD_LASTORE:
+ if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(curstack->prev->prev->typeinfo,ARRAYTYPE_LONG))
+ panic("Array type mismatch");
+ break;
+
+ /****************************************/
+ /* OPERATIONS WITH UNCHECKED INPUT */
+
+ case ICMD_CHECKCAST:
+ /* returnAddress is not allowed */
+ if (!TYPEINFO_IS_REFERENCE(curstack->typeinfo))
+ panic("Illegal instruction: INSTANCEOF on non-reference");
+
+ /* XXX check if the cast can be done statically */
+ TYPEINFO_INIT_CLASSINFO(dst->typeinfo,(classinfo *)iptr[0].val.a);
+ /* XXX */
+ break;
+
+ case ICMD_INSTANCEOF:
+ /* returnAddress is not allowed */
+ if (!TYPEINFO_IS_REFERENCE(curstack->typeinfo))
+ panic("Illegal instruction: INSTANCEOF on non-reference");
+
+ /* XXX */
+ 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_GOTO:
+ superblockend = true;
+ /* FALLTHROUGH! */
+ case ICMD_IFNULL:
+ case ICMD_IFNONNULL:
+ case ICMD_IFEQ:
+ case ICMD_IFNE:
+ case ICMD_IFLT:
+ case ICMD_IFGE:
+ case ICMD_IFGT:
+ case ICMD_IFLE:
+ case ICMD_IF_ICMPEQ:
+ case ICMD_IF_ICMPNE:
+ case ICMD_IF_ICMPLT:
+ case ICMD_IF_ICMPGE:
+ case ICMD_IF_ICMPGT:
+ case ICMD_IF_ICMPLE:
+ case ICMD_IF_ACMPEQ:
+ case ICMD_IF_ACMPNE:
+ case ICMD_IF_LEQ:
+ case ICMD_IF_LNE:
+ case ICMD_IF_LLT:
+ case ICMD_IF_LGE:
+ case ICMD_IF_LGT:
+ case ICMD_IF_LLE:
+ case ICMD_IF_LCMPEQ:
+ case ICMD_IF_LCMPNE:
+ case ICMD_IF_LCMPLT:
+ case ICMD_IF_LCMPGE:
+ case ICMD_IF_LCMPGT:
+ case ICMD_IF_LCMPLE:
+ tbptr = (basicblock *) iptr->target;
+
+ /* propagate stack and variables to the target block */
+ TYPECHECK_REACH(REACH_STD);
+ /* XXX */
+ break;
+
+ /****************************************/
+ /* SWITCHES */
+
+ case ICMD_TABLESWITCH:
+ {
+ s4 *s4ptr = iptr->val.a;
+ 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 */
+ }
+ switch_instruction_tail:
+ tptr = (basicblock **)iptr->target;
+
+ while (--i >= 0) {
+ tbptr = *tptr++;
+ LOG2("target %d is block %04d",(tptr-(basicblock **)iptr->target)-1,tbptr-block);
+ TYPECHECK_REACH(REACH_STD);
+ }
+ LOG("switch done");
+ superblockend = true;
+ break;
+
+ /****************************************/
+ /* RETURNS AND THROW */
+
+ case ICMD_ATHROW:
+ TYPEINFO_INIT_CLASSINFO(tempinfo,class_java_lang_Throwable);
+ if (!typeinfo_is_assignable(&curstack->typeinfo,&tempinfo))
+ panic("illegal instruction: ATHROW on non-Throwable");
+ superblockend = true;
+ break;
+
+ case ICMD_ARETURN:
+ if (!TYPEINFO_IS_REFERENCE(curstack->typeinfo))
+ panic("illegal instruction: ARETURN on non-reference");
+
+ if (returntype != TYPE_ADDRESS
+ || !typeinfo_is_assignable(&curstack->typeinfo,&returntypeinfo))
+ panic("Return type mismatch");
+
+ superblockend = true;
+ break;
+
+ case ICMD_IRETURN:
+ if (returntype != TYPE_INT)
+ panic("Return type mismatch");
+ superblockend = true;
+ break;
+ case ICMD_LRETURN:
+ if (returntype != TYPE_LONG)
+ panic("Return type mismatch");
+ superblockend = true;
+ break;
+ case ICMD_FRETURN:
+ if (returntype != TYPE_FLOAT)
+ panic("Return type mismatch");
+ superblockend = true;
+ break;
+ case ICMD_DRETURN:
+ if (returntype != TYPE_DOUBLE)
+ panic("Return type mismatch");
+ superblockend = true;
+ break;
+ case ICMD_RETURN:
+ if (returntype != TYPE_VOID)
+ panic("Return type mismatch");
+ superblockend = true;
+ break;
+
+ /****************************************/
+ /* SUBROUTINE INSTRUCTIONS */
+
+ case ICMD_JSR:
+ LOG("jsr");
+
+ /* XXX This is a dirty hack. It is needed
+ * because of the special handling of ICMD_JSR in stack.c
+ */
+ dst = (stackptr) iptr->val.a;
+
+ /* push return address */
+ TYPEINFO_INIT_PRIMITIVE(dst->typeinfo);
+
+ 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 */
+ /* XXX We assume (as in stack.c) that the
+ * subroutine returns the stack as it was
+ * before the JSR instruction. Is this
+ * correct?
+ */
+ dst = iptr->dst;
+
+ /* Find the jsr_record of the called subroutine */
+ jsrtemp = jsrbuffer[tbptr - block];
+
+ /* Check if we already calculated (at least
+ * for one RET) which variables the
+ * subroutine touches.
+ */
+ if (jsrtemp->sbr_touched) {
+ /* Calculate the local variables after the subroutine call */
+ for (i=0; i<maxlocals; ++i)
+ if (jsrtemp->sbr_touched[i] != TOUCHED_NO) {
+ TOUCH_VARIABLE(i);
+ if ((vtype[i] = jsrtemp->sbr_vtype[i]) == TYPE_ADR)
+ TYPEINFO_CLONE(jsrtemp->sbr_vinfo[i],vinfo[i]);
+ }
+
+ /* continue after the JSR call */
+ superblockend = false;
+ }
+ else {
+ /* We cannot proceed until the subroutine has been typechecked. */
+ /* XXX actually we would not have to check this block again */
+ bptr->flags = BBTYPECHECK_REACHED;
+ repeat = true;
+ superblockend = true;
+ }
+ break;
+
+ case ICMD_RET:
+ /* check returnAddress variable */
+ CHECKVARTYPE(iptr->op1,TYPE_ADR);
+
+ if (!TYPEINFO_IS_PRIMITIVE(vinfo[iptr->op1]))
+ panic("illegal instruction: RET using non-returnAddress variable");
+
+ /* check if we are inside a subroutine */
+ if (!subroutine)
+ panic("RET outside of subroutine");
+
+ /* determine which variables are touched by this subroutine */
+ /* and their types */
+ if (subroutine->sbr_touched) {
+ for (i=0; i<maxlocals; ++i)
+ subroutine->sbr_touched[i] |= touched[i];
+ ttype = subroutine->sbr_vtype;
+ tinfo = subroutine->sbr_vinfo;
+ TYPECHECK_MERGEVARS;
+ }
+ else {
+ subroutine->sbr_touched = DMNEW(u1,maxlocals);
+ memcpy(subroutine->sbr_touched,touched,sizeof(u1)*maxlocals);
+ subroutine->sbr_vtype = DMNEW(u1,maxlocals);
+ memcpy(subroutine->sbr_vtype,vtype,sizeof(u1)*maxlocals);
+ subroutine->sbr_vinfo = DMNEW(typeinfo,maxlocals);
+ for (i=0; i<maxlocals; ++i)
+ if (vtype[i] == TYPE_ADR)
+ TYPEINFO_CLONE(vinfo[i],subroutine->sbr_vinfo[i]);
+ }
+
+ LOGSTR("subroutine touches:");
+ DOLOG(typeinfo_print_locals(stdout,subroutine->sbr_vtype,subroutine->sbr_vinfo,
+ subroutine->sbr_touched,maxlocals));
+ LOGNL; LOGFLUSH;
+
+ /* reach blocks after JSR statements */
+ for (i=0; i<block_count; ++i) {
+ tbptr = block + i;
+ if (tbptr->iinstr[tbptr->icount - 1].opc != ICMD_JSR)
+ continue;
+ if ((basicblock*) tbptr->iinstr[tbptr->icount - 1].target != jsrold->target)
+ continue;
+ tbptr++;
+
+ LOG1("RET reaches block %04d",tbptr-block);
+
+ /*TYPECHECK_REACH(REACH_RET);*/
+ }
+
+ superblockend = true;
+ break;
+
+ /****************************************/
+ /* INVOKATIONS */
+
+ case ICMD_INVOKEVIRTUAL:
+ case ICMD_INVOKESPECIAL:
+ case ICMD_INVOKESTATIC:
+ case ICMD_INVOKEINTERFACE:
+ {
+ /* XXX check access rights */
+
+ methodinfo *mi = (methodinfo*) iptr->val.a;
+ /* XXX might use dst->typeinfo directly if non void */
+ typeinfo_init_from_method_args(mi->descriptor,ptype,pinfo,MAXPARAMS,false,
+ &rtype,&rinfo);
+
+ /* XXX compare rtype and dst->type? */
+ if (rtype != TYPE_VOID) {
+ TYPEINFO_COPY(rinfo,dst->typeinfo);
+ }
+ }
+ break;
+
+ case ICMD_MULTIANEWARRAY:
+ /* check the array lengths on the stack */
+ i = iptr[0].op1;
+ if (i<1) panic("MULTIANEWARRAY with dimensions < 1");
+ srcstack = curstack;
+ while (i--) {
+ if (!srcstack)
+ panic("MULTIANEWARRAY missing array length");
+ if (srcstack->type != TYPE_INT)
+ panic("MULTIANEWARRAY using non-int as array length");
+ srcstack = srcstack->prev;
+ }
+
+ /* set the array type of the result */
+ TYPEINFO_INIT_CLASSINFO(dst->typeinfo,((vftbl *)iptr[0].val.a)->class);
+ break;
+
+ case ICMD_BUILTIN3:
+ if (ISBUILTIN(asm_builtin_aastore)) {
+ /* XXX also handled by ICMD_AASTORE */
+ if (!TYPEINFO_MAYBE_ARRAY_OF_REFS(curstack->prev->prev->typeinfo))
+ panic("illegal instruction: AASTORE to non-reference array");
+
+ /* XXX optimize */
+ /*
+ typeinfo_init_component(&curstack->prev->prev->typeinfo,&tempinfo);
+ if (!typeinfo_is_assignable(&curstack->typeinfo,&tempinfo))
+ panic("illegal instruction: AASTORE to incompatible type");
+ */
+ }
+ /* XXX check for missed builtins in debug mode? */
+ break;
+
+ case ICMD_BUILTIN2:
+ if (
+#if defined(__I386__)
+ ISBUILTIN(asm_builtin_newarray)
+#else
+ ISBUILTIN(builtin_newarray)
+#endif
+ )
+ {
+ if (iptr[-1].opc != ICMD_ACONST)
+ panic("illegal instruction: builtin_newarray without classinfo");
+ TYPEINFO_INIT_CLASSINFO(dst->typeinfo,((vftbl *)iptr[-1].val.a)->class);
+ }
+ else if (ISBUILTIN(asm_builtin_checkarraycast)) {
+ if (iptr[-1].opc != ICMD_ACONST)
+ panic("illegal instruction: asm_builtin_checkarraycast without classinfo");
+ TYPEINFO_INIT_CLASSINFO(dst->typeinfo,((vftbl *)iptr[-1].val.a)->class);
+ }
+ /* XXX check for missed builtins in debug mode? */
+ break;
+
+ case ICMD_BUILTIN1:
+ if (ISBUILTIN(builtin_new)) {
+ if (iptr[-1].opc != ICMD_ACONST)
+ panic("illegal instruction: builtin_new without classinfo");
+ TYPEINFO_INIT_CLASSINFO(dst->typeinfo,(classinfo *)iptr[-1].val.a);
+ }
+ else if (ISBUILTIN(builtin_newarray_boolean)) {
+ TYPEINFO_INIT_PRIMITIVE_ARRAY(dst->typeinfo,ARRAYTYPE_BOOLEAN);
+ }
+ else if (ISBUILTIN(builtin_newarray_char)) {
+ TYPEINFO_INIT_PRIMITIVE_ARRAY(dst->typeinfo,ARRAYTYPE_CHAR);
+ }
+ else if (ISBUILTIN(builtin_newarray_float)) {
+ TYPEINFO_INIT_PRIMITIVE_ARRAY(dst->typeinfo,ARRAYTYPE_FLOAT);
+ }
+ else if (ISBUILTIN(builtin_newarray_double)) {
+ TYPEINFO_INIT_PRIMITIVE_ARRAY(dst->typeinfo,ARRAYTYPE_DOUBLE);
+ }
+ else if (ISBUILTIN(builtin_newarray_byte)) {
+ TYPEINFO_INIT_PRIMITIVE_ARRAY(dst->typeinfo,ARRAYTYPE_BYTE);
+ }
+ else if (ISBUILTIN(builtin_newarray_short)) {
+ TYPEINFO_INIT_PRIMITIVE_ARRAY(dst->typeinfo,ARRAYTYPE_SHORT);
+ }
+ else if (ISBUILTIN(builtin_newarray_int)) {
+ TYPEINFO_INIT_PRIMITIVE_ARRAY(dst->typeinfo,ARRAYTYPE_INT);
+ }
+ else if (ISBUILTIN(builtin_newarray_long)) {
+ TYPEINFO_INIT_PRIMITIVE_ARRAY(dst->typeinfo,ARRAYTYPE_LONG);
+ }
+ /* XXX check for missed builtins in debug mode? */
+ break;
+
+ /****************************************/
+ /* PRIMITIVE VARIABLE ACCESS */
+
+ case ICMD_ILOAD: CHECKVARTYPE(iptr->op1,TYPE_INT); break;
+ case ICMD_LLOAD: CHECKVARTYPE(iptr->op1,TYPE_LONG); break;
+ case ICMD_FLOAD: CHECKVARTYPE(iptr->op1,TYPE_FLOAT); break;
+ case ICMD_DLOAD: CHECKVARTYPE(iptr->op1,TYPE_DOUBLE); break;
+ case ICMD_IINC: CHECKVARTYPE(iptr->op1,TYPE_INT); /*TOUCH_VARIABLE(iptr->op1);*/ break;
+
+ case ICMD_FSTORE: STORE_PRIMITIVE(iptr->op1,TYPE_FLOAT); break;
+ case ICMD_ISTORE: STORE_PRIMITIVE(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 */
+
+ case ICMD_NEW:
+ case ICMD_NEWARRAY:
+ case ICMD_ANEWARRAY:
+ case ICMD_MONITORENTER:
+ case ICMD_MONITOREXIT:
+ /* XXX only check this in debug mode? */
+ LOGSTR2("ICMD %d at %d\n", iptr->opc, (int)(iptr-instr));
+ 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_CHECKASIZE: /* XXX ? */
+ case ICMD_NULLCHECKPOP: /* XXX ? */
+ case ICMD_READONLY_ARG: /* XXX ? */
+ case ICMD_CLEAR_ARGREN: /* XXX ? */
+ break;
+
+ /****************************************/
+ /* ARITHMETIC AND CONVERSION */
+
+ /* These instructions are typechecked in analyse_stack. */
+ /* XXX only add cases for them in debug mode? */
+
+ case ICMD_IADD:
+ case ICMD_ISUB:
+ case ICMD_IMUL:
+ case ICMD_IDIV:
+ case ICMD_IREM:
+ case ICMD_INEG:
+ case ICMD_IAND:
+ case ICMD_IOR:
+ case ICMD_IXOR:
+ case ICMD_ISHL:
+ case ICMD_ISHR:
+ case ICMD_IUSHR:
+ case ICMD_LADD:
+ case ICMD_LSUB:
+ case ICMD_LMUL:
+ case ICMD_LDIV:
+ case ICMD_LREM:
+ case ICMD_LNEG:
+ case ICMD_LAND:
+ case ICMD_LOR:
+ case ICMD_LXOR:
+ case ICMD_LSHL:
+ case ICMD_LSHR:
+ case ICMD_LUSHR:
+ case ICMD_IREM0X10001:
+ case ICMD_LREM0X10001:
+ case ICMD_IDIVPOW2:
+ case ICMD_LDIVPOW2:
+ case ICMD_IADDCONST:
+ case ICMD_ISUBCONST:
+ case ICMD_IMULCONST:
+ case ICMD_IANDCONST:
+ case ICMD_IORCONST:
+ case ICMD_IXORCONST:
+ case ICMD_ISHLCONST:
+ case ICMD_ISHRCONST:
+ case ICMD_IUSHRCONST:
+ case ICMD_IREMPOW2:
+ case ICMD_LADDCONST:
+ case ICMD_LSUBCONST:
+ case ICMD_LMULCONST:
+ case ICMD_LANDCONST:
+ case ICMD_LORCONST:
+ case ICMD_LXORCONST:
+ case ICMD_LSHLCONST:
+ case ICMD_LSHRCONST:
+ case ICMD_LUSHRCONST:
+ case ICMD_LREMPOW2:
+
+ case ICMD_LCMP:
+ case ICMD_LCMPCONST:
+ case ICMD_FCMPL:
+ case ICMD_FCMPG:
+ case ICMD_DCMPL:
+ case ICMD_DCMPG:
+
+ case ICMD_FADD:
+ case ICMD_DADD:
+ case ICMD_FSUB:
+ case ICMD_DSUB:
+ case ICMD_FMUL:
+ case ICMD_DMUL:
+ case ICMD_FDIV:
+ case ICMD_DDIV:
+ case ICMD_FREM:
+ case ICMD_DREM:
+ case ICMD_FNEG:
+ case ICMD_DNEG:
+
+ case ICMD_I2L:
+ case ICMD_I2F:
+ case ICMD_I2D:
+ case ICMD_L2I:
+ case ICMD_L2F:
+ case ICMD_L2D:
+ case ICMD_F2I:
+ case ICMD_F2L:
+ case ICMD_F2D:
+ case ICMD_D2I:
+ case ICMD_D2L:
+ case ICMD_D2F:
+ case ICMD_INT2BYTE:
+ case ICMD_INT2CHAR:
+ case ICMD_INT2SHORT:
+
+ case ICMD_ICONST:
+ case ICMD_LCONST:
+ case ICMD_FCONST:
+ case ICMD_DCONST:
+
+ case ICMD_IFEQ_ICONST:
+ case ICMD_IFNE_ICONST:
+ case ICMD_IFLT_ICONST:
+ case ICMD_IFGE_ICONST:
+ case ICMD_IFGT_ICONST:
+ case ICMD_IFLE_ICONST:
+ case ICMD_ELSE_ICONST:
+
+ break;
+
+ /****************************************/
+
+ default:
+ LOGSTR2("ICMD %d at %d\n", iptr->opc, (int)(iptr-instr));
+ panic("Missing ICMD code during typecheck");
+ }
+
+ /* the output of this instruction becomes the current stack */
+ curstack = dst;
+
+ iptr++;
+ } /* while instructions */
+
+ LOG("instructions done");
+ LOGSTR("RESULT=> ");
+ DOLOG(typeinfo_print_block(stdout,curstack,vtype,vinfo,(jsrchain) ? touched : NULL));
+ LOGNL; LOGFLUSH;
+
+ /* propagate stack and variables to the following block */
+ if (!superblockend) {
+ LOG("reaching following block");
+ tbptr = bptr + 1;
+ while (tbptr->flags == BBDELETED) {
+ tbptr++;
+#ifdef TYPECHECK_DEBUG
+ if ((tbptr-block) >= block_count)
+ panic("Control flow falls off the last block");
+#endif
+ }
+ TYPECHECK_REACH(REACH_STD);
+ }
+
+ } /* if block has to be checked */
+ bptr++;
+ } /* while blocks */
+
+ /* the following iterations only check if any types changed */
+ fulltypecheck = false; /* XXX */
+
+ LOGIF(repeat,"repeat=true");
+ } while (repeat);
+
+ /* XXX reset BB... to BBFINISHED */
+
+ /* XXX free vartype */
+ /* XXX free vartypeinfo */
+ /* XXX free buffers for method arguments. */
+
+ /* XXX add debug check if all non-dead blocks have been checked */
+
+ LOGimp("exiting typecheck");
+}
+
+#undef COPYTYPE
+
+#endif /* CACAO_TYPECHECK */
-/********************************* typeinfo.c *********************************
+/* typeinfo.c - type system used by the type checker
- Copyright (c) 2003 ? XXX
+ Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
+ R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser,
+ M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck,
+ P. Tomsich, J. Wenninger
- See file COPYRIGHT for information on usage and disclaimer of warranties
+ This file is part of CACAO.
- functions for the compiler's type system
-
- Authors: Edwin Steiner
-
- Last Change:
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
-*******************************************************************************/
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+
+ Contact: cacao@complang.tuwien.ac.at
+
+ Authors: Edwin Steiner
+
+ $Id: typeinfo.c 696 2003-12-06 20:10:05Z edwin $
+
+*/
#include "typeinfo.h"
#include "tables.h"
cls = value->typeclass;
/* DEBUG CHECK: dest must not have a merged list. */
-#ifdef DEBUG_TYPES
+#ifdef TYPEINFO_DEBUG
if (dest->merged)
panic("Internal error: typeinfo_is_assignable on merged destination.");
#endif
/* The following functions fill in uninitialized typeinfo structures. */
/**********************************************************************/
-/* XXX delete */
-#if 0
-void
-typeinfo_init_from_arraydescriptor(typeinfo *info,
- constant_arraydescriptor *desc)
-{
- int dim = 1;
-
- /* Arrays are instances of the pseudo class Array. */
- info->typeclass = pseudo_class_Array; /* XXX */
- info->merged = NULL;
-
- /* Handle multidimensional arrays */
- while (desc->arraytype == ARRAYTYPE_ARRAY) {
- dim++;
- desc = desc->elementdescriptor;
- }
-
- info->dimension = dim;
-
- if ((info->elementtype = desc->arraytype) == ARRAYTYPE_OBJECT) {
- info->elementclass = desc->objectclass;
- }
- else {
- info->elementclass = NULL;
- }
-}
-#endif
-
void
typeinfo_init_from_descriptor(typeinfo *info,char *utf_ptr,char *end_ptr)
{
cls = class_from_descriptor(utf_ptr,end_pos,&utf_ptr,CLASSLOAD_NEW);
if (!cls)
panic("Invalid method descriptor.");
-
+
switch (c) {
case 'B':
case 'C':
if (twoword) {
if (++args > buflen)
panic("Buffer too small for method arguments.");
+ if (typebuf)
+ *typebuf++ = TYPE_VOID;
TYPEINFO_INIT_PRIMITIVE(*infobuf);
infobuf++;
}
*typebuf++ = TYPE_ADDRESS;
TYPEINFO_INIT_CLASSINFO(*infobuf,cls);
- /* XXX remove */ /* utf_display(cls->name); */
infobuf++;
break;
typeinfo_init_component(typeinfo *srcarray,typeinfo *dst)
{
vftbl *comp = NULL;
+
+ if (TYPEINFO_IS_NULLTYPE(*srcarray)) {
+ TYPEINFO_INIT_NULLTYPE(*dst);
+ return;
+ }
/* XXX find component class */
if (!TYPEINFO_IS_ARRAY(*srcarray))
int count;
classinfo **srclist,**destlist;
-#ifdef DEBUG_TYPES
+#ifdef TYPEINFO_DEBUG
if (src == dest)
panic("Internal error: typeinfo_clone with src==dest");
#endif
static
void
typeinfo_merge_error(char *str,typeinfo *x,typeinfo *y) {
-#ifdef DEBUG_TYPES
+#ifdef TYPEINFO_DEBUG
fprintf(stderr,"Error in typeinfo_merge: %s\n",str);
fprintf(stderr,"Typeinfo x:\n");
typeinfo_print(stderr,x,1);
TYPEINFO_ALLOCMERGED(dest->merged,2);
dest->merged->count = 2;
-#ifdef DEBUG_TYPES
+#ifdef TYPEINFO_DEBUG
if (clsx == clsy)
panic("Internal error: typeinfo_merge_two called with clsx==clsy.");
#endif
/* {The new mergedlist will have count entries.} */
- if (y->count == count) {
+ if ((x->count != count) && (y->count == count)) {
temp = x; x = y; y = temp;
}
/* {If one of x,y is already the result it is x.} */
/* XXX remove */
/*
-#ifdef DEBUG_TYPES
+#ifdef TYPEINFO_DEBUG
typeinfo dbgx,dbgy;
printf("typeinfo_merge_nonarrays:\n");
TYPEINFO_INIT_CLASSINFO(dbgx,clsx);
/* {common == nearest common anchestor of clsx and clsy.} */
- /* XXX remove */ /* printf("common: "); utf_display(common->name); printf("\n"); */
-
/* If clsx==common and x is a whole class (not a merge of subclasses)
* then the result of the merge is clsx.
*/
/* XXX remove */
/*
-#ifdef DEBUG_TYPES
+#ifdef TYPEINFO_DEBUG
typeinfo_print(stdout,dest,4);
typeinfo_print(stdout,y,4);
#endif
*/
- /* This function cannot be used to merge primitive types. */
+ /* Merging two returnAddress types is ok. */
+ if (!dest->typeclass && !y->typeclass)
+ return false;
+
+ /* Primitive types cannot be merged with reference types */
if (!dest->typeclass || !y->typeclass)
typeinfo_merge_error("Trying to merge primitive types.",dest,y);
-#ifdef DEBUG_TYPES
+#ifdef TYPEINFO_DEBUG
if (dest == y)
panic("Internal error: typeinfo_merge with dest==y");
/* DEBUGGING HELPERS */
/**********************************************************************/
-#ifdef DEBUG_TYPES
+#ifdef TYPEINFO_DEBUG
#include "tables.h"
#include "loader.h"
typeinfo_testmerge(typeinfo *a,typeinfo *b,typeinfo *result,int *failed)
{
typeinfo dest;
+ bool changed,changed_should_be;
TYPEINFO_CLONE(*a,dest);
typeinfo_print_short(stdout,b);
printf("\n");
- typeinfo_merge(&dest,b);
+ changed = (typeinfo_merge(&dest,b)) ? 1 : 0;
+ changed_should_be = (!typeinfo_equal(&dest,a)) ? 1 : 0;
+
+ printf(" %s\n",(changed) ? "changed" : "=");
if (typeinfo_equal(&dest,result)) {
printf("OK ");
typeinfo_print_short(stdout,&dest);
printf("\n");
+ if (changed != changed_should_be) {
+ printf("WRONG RETURN VALUE!\n");
+ (*failed)++;
+ }
}
else {
printf("RESULT ");
char bufa[TYPEINFO_TEST_BUFLEN];
char bufb[TYPEINFO_TEST_BUFLEN];
char bufc[TYPEINFO_TEST_BUFLEN];
- typeinfo a,b,c,a2,b2;
+ typeinfo a,b,c;
int maxdim;
int failed = 0;
FILE *file = fopen(filename,"rt");
utf_fprint(file,info->typeclass->name);
- /* XXX remove */
-#if 0
- if (TYPEINFO_IS_ARRAY(*info)) {
- fprintf(file,"[%d]",info->dimension);
- switch (info->elementtype) {
- case ARRAYTYPE_INT : fprintf(file,"int"); break;
- case ARRAYTYPE_LONG : fprintf(file,"long"); break;
- case ARRAYTYPE_FLOAT : fprintf(file,"float"); break;
- case ARRAYTYPE_DOUBLE : fprintf(file,"double"); break;
- case ARRAYTYPE_BYTE : fprintf(file,"byte"); break;
- case ARRAYTYPE_CHAR : fprintf(file,"char"); break;
- case ARRAYTYPE_SHORT : fprintf(file,"short"); break;
- case ARRAYTYPE_BOOLEAN : fprintf(file,"boolean"); break;
-
- case ARRAYTYPE_OBJECT:
- fprintf(file,"object(");
- utf_fprint(file,info->elementclass->name);
- fprintf(file,")");
- break;
-
- default:
- fprintf(file,"INVALID ARRAYTYPE!");
- }
- }
-#endif
-
if (info->merged) {
fprintf(file,"{");
for (i=0; i<info->merged->count; ++i) {
if (TYPEINFO_IS_PRIMITIVE(*info))
fprintf(file,"R"); /* returnAddress */
else {
- fprintf(file,"L");
typeinfo_print_short(file,info);
- fprintf(file,";");
}
break;
}
}
-#endif // DEBUG_TYPES
+#endif // TYPEINFO_DEBUG
-/********************************* typeinfo.h **********************************
+/* typeinfo.h - type system used by the type checker
- Copyright (c) 2003 ? XXX
+ Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
+ R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser,
+ M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck,
+ P. Tomsich, J. Wenninger
- See file COPYRIGHT for information on usage and disclaimer of warranties
+ This file is part of CACAO.
- defininitions for the compiler's type system
-
- Authors: Edwin Steiner
-
- Last Change:
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
-*******************************************************************************/
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+
+ Contact: cacao@complang.tuwien.ac.at
+
+ Authors: Edwin Steiner
+
+ $Id: typeinfo.h 696 2003-12-06 20:10:05Z edwin $
+
+*/
#ifndef __typeinfo_h_
#define __typeinfo_h_
-/* #define DEBUG_TYPES */ /* XXX */
-
#include "global.h"
/* resolve typedef cycles *****************************************************/
* and java.io.Serializable. This pseudo class is used internally
* to represent such results. (They are *not* considered arrays!)
*
- * pseudo_class_Array XXX delete?
- * (extends pseudo_class_Arraystub)
- *
- * This pseudo class is used internally as the class of all arrays
- * to distinguish them from arbitrary Objects.
- *
* pseudo_class_Null
*
* This pseudo class is used internally to represent the
/* MACROS */
/****************************************************************************/
+/* XXX wrap macro blocks in do { } while(0) */
+
/* NOTE: These macros take typeinfo *structs* not pointers as arguments.
* You have to dereference any pointers.
*/
/* internally used macros ***************************************************/
/* internal, don't use this explicitly! */
-/* XXX change to GC? */
#define TYPEINFO_ALLOCMERGED(mergedlist,count) \
{(mergedlist) = (typeinfo_mergedlist*)dump_alloc( \
sizeof(typeinfo_mergedlist) \
+ ((count)-1)*sizeof(classinfo*));}
/* internal, don't use this explicitly! */
-/* XXX change to GC? */
-#if 0
-#define TYPEINFO_FREEMERGED(mergedlist) \
- {mem_free((mergedlist),sizeof(typeinfo_mergedlist) \
- + ((mergedlist)->count - 1)*sizeof(classinfo*));}
-#endif
#define TYPEINFO_FREEMERGED(mergedlist)
/* internal, don't use this explicitly! */
-#define TYPEINFO_FREEMERGED_IF_ANY(mergedlist) \
- {if (mergedlist) TYPEINFO_FREEMERGED(mergedlist);}
+#define TYPEINFO_FREEMERGED_IF_ANY(mergedlist)
/* macros for type queries **************************************************/
( TYPEINFO_IS_ARRAY(info) \
&& TYPEINFO_IS_ARRAY_OF_REFS_NOCHECK(info) )
+/* queries allowing null types **********************************************/
+
+#define TYPEINFO_MAYBE_ARRAY(info) \
+ (TYPEINFO_IS_ARRAY(info) || TYPEINFO_IS_NULLTYPE(info))
+
+#define TYPEINFO_MAYBE_PRIMITIVE_ARRAY(info,at) \
+ (TYPEINFO_IS_PRIMITIVE_ARRAY(info,at) || TYPEINFO_IS_NULLTYPE(info))
+
+#define TYPEINFO_MAYBE_ARRAY_OF_REFS(info) \
+ (TYPEINFO_IS_ARRAY_OF_REFS(info) || TYPEINFO_IS_NULLTYPE(info))
+
+
/* macros for initializing typeinfo structures ******************************/
#define TYPEINFO_INIT_PRIMITIVE(info) \
#define TYPEINFO_INIT_NULLTYPE(info) \
TYPEINFO_INIT_CLASSINFO(info,pseudo_class_Null)
-/* XXX delete */
-#if 0
-#define TYPEINFO_INIT_ARRAY(info,dim,elmtype,elmcinfo) \
- {(info).typeclass = pseudo_class_Array; \
- (info).elementclass = (elmcinfo); \
- (info).merged = NULL; \
- (info).dimension = (dim); \
- (info).elementtype = (elmtype);}
-#endif
-
-/* XXX delete? */
-#define TYPEINFO_INIT_ARRAY(info,cls) \
- {(info).typeclass = cls; \
- if (cls->vftbl->arraydesc->elementvftbl) \
- (info).elementclass = cls->vftbl->arraydesc->elementvftbl->class; \
- else \
- (info).elementclass = NULL; \
- (info).merged = NULL; \
- (info).dimension = cls->vftbl->arraydesc->dimension; \
- (info).elementtype = cls->vftbl->arraydesc->elementtype;}
+#define TYPEINFO_INIT_PRIMITIVE_ARRAY(info,arraytype) \
+ TYPEINFO_INIT_CLASSINFO(info,primitivetype_table[arraytype].arrayclass);
#define TYPEINFO_INIT_CLASSINFO(info,cls) \
- {if (((info).typeclass = cls)->vftbl->arraydesc) { \
- if (cls->vftbl->arraydesc->elementvftbl) \
- (info).elementclass = cls->vftbl->arraydesc->elementvftbl->class; \
+ {if (((info).typeclass = (cls))->vftbl->arraydesc) { \
+ if ((cls)->vftbl->arraydesc->elementvftbl) \
+ (info).elementclass = (cls)->vftbl->arraydesc->elementvftbl->class; \
else \
(info).elementclass = NULL; \
- (info).dimension = cls->vftbl->arraydesc->dimension; \
- (info).elementtype = cls->vftbl->arraydesc->elementtype;\
+ (info).dimension = (cls)->vftbl->arraydesc->dimension; \
+ (info).elementtype = (cls)->vftbl->arraydesc->elementtype;\
} \
else { \
(info).elementclass = NULL; \
} \
(info).merged = NULL;}
-/* XXX */
-#define TYPEINFO_INC_DIMENSION(info) \
- (info).dimension++
-
#define TYPEINFO_INIT_FROM_FIELDINFO(info,fi) \
typeinfo_init_from_descriptor(&(info), \
(fi)->descriptor->text,utf_end((fi)->descriptor));
#define TYPEINFO_PUT_NON_ARRAY_CLASSINFO(info,cinfo) \
{(info).typeclass = (cinfo);}
-/* XXX delete */
-#if 0
-#define TYPEINFO_PUT_ARRAY(info,dim,elmtype) \
- {(info).typeclass = pseudo_class_Array; \
- (info).dimension = (dim); \
- (info).elementtype = (elmtype);}
-#endif
-
-/* XXX delete? */
-#define TYPEINFO_PUT_ARRAY(info,cls) \
- {(info).typeclass = cls; \
- if (cls->vftbl->arraydesc->elementvftbl) \
- (info).elementclass = cls->vftbl->arraydesc->elementvftbl->class; \
- (info).dimension = cls->vftbl->arraydesc->dimension; \
- (info).elementtype = cls->vftbl->arraydesc->elementtype;}
-
#define TYPEINFO_PUT_CLASSINFO(info,cls) \
- {if (((info).typeclass = cls)->vftbl->arraydesc) { \
- if (cls->vftbl->arraydesc->elementvftbl) \
- (info).elementclass = cls->vftbl->arraydesc->elementvftbl->class; \
- (info).dimension = cls->vftbl->arraydesc->dimension; \
- (info).elementtype = cls->vftbl->arraydesc->elementtype; \
+ {if (((info).typeclass = (cls))->vftbl->arraydesc) { \
+ if ((cls)->vftbl->arraydesc->elementvftbl) \
+ (info).elementclass = (cls)->vftbl->arraydesc->elementvftbl->class; \
+ (info).dimension = (cls)->vftbl->arraydesc->dimension; \
+ (info).elementtype = (cls)->vftbl->arraydesc->elementtype; \
}}
-/* XXX delete */
-#if 0
-#define TYPEINFO_PUT_OBJECT_ARRAY(info,dim,elmcinfo) \
- {TYPEINFO_PUT_ARRAY(info,dim,ARRAYTYPE_OBJECT); \
- (info).elementclass = (elmcinfo);}
-#endif
-
/* srcarray must be an array (not checked) */
#define TYPEINFO_PUT_COMPONENT(srcarray,dst) \
{typeinfo_put_component(&(srcarray),&(dst));}
/* debugging helpers ********************************************************/
-#ifdef DEBUG_TYPES
+#ifdef TYPEINFO_DEBUG
void typeinfo_test();
void typeinfo_init_from_fielddescriptor(typeinfo *info,char *desc);
void typeinfo_print_short(FILE *file,typeinfo *info);
void typeinfo_print_type(FILE *file,int type,typeinfo *info);
-#endif // DEBUG_TYPES
+#endif // TYPEINFO_DEBUG
#endif
Changes: Andreas Krall
Roman Obermaiser
Mark Probst
+ Edwin Steiner
- $Id: loader.c 693 2003-12-05 19:00:58Z jowenn $
+ $Id: loader.c 696 2003-12-06 20:10:05Z edwin $
*/
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);
m -> jcode = NULL;
m -> exceptiontable = NULL;
methodinfo *clone;
int namelen;
+ /* XXX remove */ /* dolog("class_new_array: %s",c->name->text); */
+
/* Array classes are not loaded from classfiles. */
list_remove (&unloadedclasses, c);
c->super = class_java_lang_Object;
c->interfacescount = 2;
- c->interfaces = MNEW(classinfo*,2);
+ c->interfaces = MNEW(classinfo*,2); /* XXX use GC? */
c->interfaces[0] = class_java_lang_Cloneable;
c->interfaces[1] = class_java_io_Serializable;
c->methodscount = 1;
- c->methods = MNEW (methodinfo, c->methodscount);
+ c->methods = MNEW (methodinfo, c->methodscount); /* XXX use GC? */
clone = c->methods;
memset(clone,0,sizeof(methodinfo));
char *start = utf_ptr;
bool error = false;
utf *name;
-
+
SKIP_FIELDDESCRIPTOR_SAFE(utf_ptr,end_ptr,error);
if (error) return NULL;
if (next) *next = utf_ptr;
-/* loader.c - class loader header
+/* loader.h - class loader header
Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser,
Authors: Reinhard Grafl
- $Id: loader.h 669 2003-11-23 14:04:20Z edwin $
+ $Id: loader.h 696 2003-12-06 20:10:05Z edwin $
*/
#define CLASSLOAD_SKIP 0
#define CLASSLOAD_NEW 1
#define CLASSLOAD_LOAD 2
+
+#if 0
+#define CLASSLOAD_NEW 0x0000 /* default */
+#define CLASSLOAD_LOAD 0x0001
+#define CLASSLOAD_SKIP 0x0002
+#define CLASSLOAD_PANIC 0x0000 /* default */
+#define CLASSLOAD_NOPANIC 0x0010
+#define CLASSLOAD_PRIMITIVE 0x0000 /* default */
+#define CLASSLOAD_VOID 0x0000 /* default */
+#define CLASSLOAD_NOVOID 0x0020
+#endif
+
classinfo *class_from_descriptor(char *utf_ptr,char *end_ptr,char **next,int mode);
/* (used by class_new, don't use directly) */
-/********************************* typeinfo.c *********************************
+/* typeinfo.c - type system used by the type checker
- Copyright (c) 2003 ? XXX
+ Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
+ R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser,
+ M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck,
+ P. Tomsich, J. Wenninger
- See file COPYRIGHT for information on usage and disclaimer of warranties
+ This file is part of CACAO.
- functions for the compiler's type system
-
- Authors: Edwin Steiner
-
- Last Change:
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
-*******************************************************************************/
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+
+ Contact: cacao@complang.tuwien.ac.at
+
+ Authors: Edwin Steiner
+
+ $Id: typeinfo.c 696 2003-12-06 20:10:05Z edwin $
+
+*/
#include "typeinfo.h"
#include "tables.h"
cls = value->typeclass;
/* DEBUG CHECK: dest must not have a merged list. */
-#ifdef DEBUG_TYPES
+#ifdef TYPEINFO_DEBUG
if (dest->merged)
panic("Internal error: typeinfo_is_assignable on merged destination.");
#endif
/* The following functions fill in uninitialized typeinfo structures. */
/**********************************************************************/
-/* XXX delete */
-#if 0
-void
-typeinfo_init_from_arraydescriptor(typeinfo *info,
- constant_arraydescriptor *desc)
-{
- int dim = 1;
-
- /* Arrays are instances of the pseudo class Array. */
- info->typeclass = pseudo_class_Array; /* XXX */
- info->merged = NULL;
-
- /* Handle multidimensional arrays */
- while (desc->arraytype == ARRAYTYPE_ARRAY) {
- dim++;
- desc = desc->elementdescriptor;
- }
-
- info->dimension = dim;
-
- if ((info->elementtype = desc->arraytype) == ARRAYTYPE_OBJECT) {
- info->elementclass = desc->objectclass;
- }
- else {
- info->elementclass = NULL;
- }
-}
-#endif
-
void
typeinfo_init_from_descriptor(typeinfo *info,char *utf_ptr,char *end_ptr)
{
cls = class_from_descriptor(utf_ptr,end_pos,&utf_ptr,CLASSLOAD_NEW);
if (!cls)
panic("Invalid method descriptor.");
-
+
switch (c) {
case 'B':
case 'C':
if (twoword) {
if (++args > buflen)
panic("Buffer too small for method arguments.");
+ if (typebuf)
+ *typebuf++ = TYPE_VOID;
TYPEINFO_INIT_PRIMITIVE(*infobuf);
infobuf++;
}
*typebuf++ = TYPE_ADDRESS;
TYPEINFO_INIT_CLASSINFO(*infobuf,cls);
- /* XXX remove */ /* utf_display(cls->name); */
infobuf++;
break;
typeinfo_init_component(typeinfo *srcarray,typeinfo *dst)
{
vftbl *comp = NULL;
+
+ if (TYPEINFO_IS_NULLTYPE(*srcarray)) {
+ TYPEINFO_INIT_NULLTYPE(*dst);
+ return;
+ }
/* XXX find component class */
if (!TYPEINFO_IS_ARRAY(*srcarray))
int count;
classinfo **srclist,**destlist;
-#ifdef DEBUG_TYPES
+#ifdef TYPEINFO_DEBUG
if (src == dest)
panic("Internal error: typeinfo_clone with src==dest");
#endif
static
void
typeinfo_merge_error(char *str,typeinfo *x,typeinfo *y) {
-#ifdef DEBUG_TYPES
+#ifdef TYPEINFO_DEBUG
fprintf(stderr,"Error in typeinfo_merge: %s\n",str);
fprintf(stderr,"Typeinfo x:\n");
typeinfo_print(stderr,x,1);
TYPEINFO_ALLOCMERGED(dest->merged,2);
dest->merged->count = 2;
-#ifdef DEBUG_TYPES
+#ifdef TYPEINFO_DEBUG
if (clsx == clsy)
panic("Internal error: typeinfo_merge_two called with clsx==clsy.");
#endif
/* {The new mergedlist will have count entries.} */
- if (y->count == count) {
+ if ((x->count != count) && (y->count == count)) {
temp = x; x = y; y = temp;
}
/* {If one of x,y is already the result it is x.} */
/* XXX remove */
/*
-#ifdef DEBUG_TYPES
+#ifdef TYPEINFO_DEBUG
typeinfo dbgx,dbgy;
printf("typeinfo_merge_nonarrays:\n");
TYPEINFO_INIT_CLASSINFO(dbgx,clsx);
/* {common == nearest common anchestor of clsx and clsy.} */
- /* XXX remove */ /* printf("common: "); utf_display(common->name); printf("\n"); */
-
/* If clsx==common and x is a whole class (not a merge of subclasses)
* then the result of the merge is clsx.
*/
/* XXX remove */
/*
-#ifdef DEBUG_TYPES
+#ifdef TYPEINFO_DEBUG
typeinfo_print(stdout,dest,4);
typeinfo_print(stdout,y,4);
#endif
*/
- /* This function cannot be used to merge primitive types. */
+ /* Merging two returnAddress types is ok. */
+ if (!dest->typeclass && !y->typeclass)
+ return false;
+
+ /* Primitive types cannot be merged with reference types */
if (!dest->typeclass || !y->typeclass)
typeinfo_merge_error("Trying to merge primitive types.",dest,y);
-#ifdef DEBUG_TYPES
+#ifdef TYPEINFO_DEBUG
if (dest == y)
panic("Internal error: typeinfo_merge with dest==y");
/* DEBUGGING HELPERS */
/**********************************************************************/
-#ifdef DEBUG_TYPES
+#ifdef TYPEINFO_DEBUG
#include "tables.h"
#include "loader.h"
typeinfo_testmerge(typeinfo *a,typeinfo *b,typeinfo *result,int *failed)
{
typeinfo dest;
+ bool changed,changed_should_be;
TYPEINFO_CLONE(*a,dest);
typeinfo_print_short(stdout,b);
printf("\n");
- typeinfo_merge(&dest,b);
+ changed = (typeinfo_merge(&dest,b)) ? 1 : 0;
+ changed_should_be = (!typeinfo_equal(&dest,a)) ? 1 : 0;
+
+ printf(" %s\n",(changed) ? "changed" : "=");
if (typeinfo_equal(&dest,result)) {
printf("OK ");
typeinfo_print_short(stdout,&dest);
printf("\n");
+ if (changed != changed_should_be) {
+ printf("WRONG RETURN VALUE!\n");
+ (*failed)++;
+ }
}
else {
printf("RESULT ");
char bufa[TYPEINFO_TEST_BUFLEN];
char bufb[TYPEINFO_TEST_BUFLEN];
char bufc[TYPEINFO_TEST_BUFLEN];
- typeinfo a,b,c,a2,b2;
+ typeinfo a,b,c;
int maxdim;
int failed = 0;
FILE *file = fopen(filename,"rt");
utf_fprint(file,info->typeclass->name);
- /* XXX remove */
-#if 0
- if (TYPEINFO_IS_ARRAY(*info)) {
- fprintf(file,"[%d]",info->dimension);
- switch (info->elementtype) {
- case ARRAYTYPE_INT : fprintf(file,"int"); break;
- case ARRAYTYPE_LONG : fprintf(file,"long"); break;
- case ARRAYTYPE_FLOAT : fprintf(file,"float"); break;
- case ARRAYTYPE_DOUBLE : fprintf(file,"double"); break;
- case ARRAYTYPE_BYTE : fprintf(file,"byte"); break;
- case ARRAYTYPE_CHAR : fprintf(file,"char"); break;
- case ARRAYTYPE_SHORT : fprintf(file,"short"); break;
- case ARRAYTYPE_BOOLEAN : fprintf(file,"boolean"); break;
-
- case ARRAYTYPE_OBJECT:
- fprintf(file,"object(");
- utf_fprint(file,info->elementclass->name);
- fprintf(file,")");
- break;
-
- default:
- fprintf(file,"INVALID ARRAYTYPE!");
- }
- }
-#endif
-
if (info->merged) {
fprintf(file,"{");
for (i=0; i<info->merged->count; ++i) {
if (TYPEINFO_IS_PRIMITIVE(*info))
fprintf(file,"R"); /* returnAddress */
else {
- fprintf(file,"L");
typeinfo_print_short(file,info);
- fprintf(file,";");
}
break;
}
}
-#endif // DEBUG_TYPES
+#endif // TYPEINFO_DEBUG
-/********************************* typeinfo.h **********************************
+/* typeinfo.h - type system used by the type checker
- Copyright (c) 2003 ? XXX
+ Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
+ R. Grafl, A. Krall, C. Kruegel, C. Oates, R. Obermaisser,
+ M. Probst, S. Ring, E. Steiner, C. Thalinger, D. Thuernbeck,
+ P. Tomsich, J. Wenninger
- See file COPYRIGHT for information on usage and disclaimer of warranties
+ This file is part of CACAO.
- defininitions for the compiler's type system
-
- Authors: Edwin Steiner
-
- Last Change:
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2, or (at
+ your option) any later version.
-*******************************************************************************/
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ 02111-1307, USA.
+
+ Contact: cacao@complang.tuwien.ac.at
+
+ Authors: Edwin Steiner
+
+ $Id: typeinfo.h 696 2003-12-06 20:10:05Z edwin $
+
+*/
#ifndef __typeinfo_h_
#define __typeinfo_h_
-/* #define DEBUG_TYPES */ /* XXX */
-
#include "global.h"
/* resolve typedef cycles *****************************************************/
* and java.io.Serializable. This pseudo class is used internally
* to represent such results. (They are *not* considered arrays!)
*
- * pseudo_class_Array XXX delete?
- * (extends pseudo_class_Arraystub)
- *
- * This pseudo class is used internally as the class of all arrays
- * to distinguish them from arbitrary Objects.
- *
* pseudo_class_Null
*
* This pseudo class is used internally to represent the
/* MACROS */
/****************************************************************************/
+/* XXX wrap macro blocks in do { } while(0) */
+
/* NOTE: These macros take typeinfo *structs* not pointers as arguments.
* You have to dereference any pointers.
*/
/* internally used macros ***************************************************/
/* internal, don't use this explicitly! */
-/* XXX change to GC? */
#define TYPEINFO_ALLOCMERGED(mergedlist,count) \
{(mergedlist) = (typeinfo_mergedlist*)dump_alloc( \
sizeof(typeinfo_mergedlist) \
+ ((count)-1)*sizeof(classinfo*));}
/* internal, don't use this explicitly! */
-/* XXX change to GC? */
-#if 0
-#define TYPEINFO_FREEMERGED(mergedlist) \
- {mem_free((mergedlist),sizeof(typeinfo_mergedlist) \
- + ((mergedlist)->count - 1)*sizeof(classinfo*));}
-#endif
#define TYPEINFO_FREEMERGED(mergedlist)
/* internal, don't use this explicitly! */
-#define TYPEINFO_FREEMERGED_IF_ANY(mergedlist) \
- {if (mergedlist) TYPEINFO_FREEMERGED(mergedlist);}
+#define TYPEINFO_FREEMERGED_IF_ANY(mergedlist)
/* macros for type queries **************************************************/
( TYPEINFO_IS_ARRAY(info) \
&& TYPEINFO_IS_ARRAY_OF_REFS_NOCHECK(info) )
+/* queries allowing null types **********************************************/
+
+#define TYPEINFO_MAYBE_ARRAY(info) \
+ (TYPEINFO_IS_ARRAY(info) || TYPEINFO_IS_NULLTYPE(info))
+
+#define TYPEINFO_MAYBE_PRIMITIVE_ARRAY(info,at) \
+ (TYPEINFO_IS_PRIMITIVE_ARRAY(info,at) || TYPEINFO_IS_NULLTYPE(info))
+
+#define TYPEINFO_MAYBE_ARRAY_OF_REFS(info) \
+ (TYPEINFO_IS_ARRAY_OF_REFS(info) || TYPEINFO_IS_NULLTYPE(info))
+
+
/* macros for initializing typeinfo structures ******************************/
#define TYPEINFO_INIT_PRIMITIVE(info) \
#define TYPEINFO_INIT_NULLTYPE(info) \
TYPEINFO_INIT_CLASSINFO(info,pseudo_class_Null)
-/* XXX delete */
-#if 0
-#define TYPEINFO_INIT_ARRAY(info,dim,elmtype,elmcinfo) \
- {(info).typeclass = pseudo_class_Array; \
- (info).elementclass = (elmcinfo); \
- (info).merged = NULL; \
- (info).dimension = (dim); \
- (info).elementtype = (elmtype);}
-#endif
-
-/* XXX delete? */
-#define TYPEINFO_INIT_ARRAY(info,cls) \
- {(info).typeclass = cls; \
- if (cls->vftbl->arraydesc->elementvftbl) \
- (info).elementclass = cls->vftbl->arraydesc->elementvftbl->class; \
- else \
- (info).elementclass = NULL; \
- (info).merged = NULL; \
- (info).dimension = cls->vftbl->arraydesc->dimension; \
- (info).elementtype = cls->vftbl->arraydesc->elementtype;}
+#define TYPEINFO_INIT_PRIMITIVE_ARRAY(info,arraytype) \
+ TYPEINFO_INIT_CLASSINFO(info,primitivetype_table[arraytype].arrayclass);
#define TYPEINFO_INIT_CLASSINFO(info,cls) \
- {if (((info).typeclass = cls)->vftbl->arraydesc) { \
- if (cls->vftbl->arraydesc->elementvftbl) \
- (info).elementclass = cls->vftbl->arraydesc->elementvftbl->class; \
+ {if (((info).typeclass = (cls))->vftbl->arraydesc) { \
+ if ((cls)->vftbl->arraydesc->elementvftbl) \
+ (info).elementclass = (cls)->vftbl->arraydesc->elementvftbl->class; \
else \
(info).elementclass = NULL; \
- (info).dimension = cls->vftbl->arraydesc->dimension; \
- (info).elementtype = cls->vftbl->arraydesc->elementtype;\
+ (info).dimension = (cls)->vftbl->arraydesc->dimension; \
+ (info).elementtype = (cls)->vftbl->arraydesc->elementtype;\
} \
else { \
(info).elementclass = NULL; \
} \
(info).merged = NULL;}
-/* XXX */
-#define TYPEINFO_INC_DIMENSION(info) \
- (info).dimension++
-
#define TYPEINFO_INIT_FROM_FIELDINFO(info,fi) \
typeinfo_init_from_descriptor(&(info), \
(fi)->descriptor->text,utf_end((fi)->descriptor));
#define TYPEINFO_PUT_NON_ARRAY_CLASSINFO(info,cinfo) \
{(info).typeclass = (cinfo);}
-/* XXX delete */
-#if 0
-#define TYPEINFO_PUT_ARRAY(info,dim,elmtype) \
- {(info).typeclass = pseudo_class_Array; \
- (info).dimension = (dim); \
- (info).elementtype = (elmtype);}
-#endif
-
-/* XXX delete? */
-#define TYPEINFO_PUT_ARRAY(info,cls) \
- {(info).typeclass = cls; \
- if (cls->vftbl->arraydesc->elementvftbl) \
- (info).elementclass = cls->vftbl->arraydesc->elementvftbl->class; \
- (info).dimension = cls->vftbl->arraydesc->dimension; \
- (info).elementtype = cls->vftbl->arraydesc->elementtype;}
-
#define TYPEINFO_PUT_CLASSINFO(info,cls) \
- {if (((info).typeclass = cls)->vftbl->arraydesc) { \
- if (cls->vftbl->arraydesc->elementvftbl) \
- (info).elementclass = cls->vftbl->arraydesc->elementvftbl->class; \
- (info).dimension = cls->vftbl->arraydesc->dimension; \
- (info).elementtype = cls->vftbl->arraydesc->elementtype; \
+ {if (((info).typeclass = (cls))->vftbl->arraydesc) { \
+ if ((cls)->vftbl->arraydesc->elementvftbl) \
+ (info).elementclass = (cls)->vftbl->arraydesc->elementvftbl->class; \
+ (info).dimension = (cls)->vftbl->arraydesc->dimension; \
+ (info).elementtype = (cls)->vftbl->arraydesc->elementtype; \
}}
-/* XXX delete */
-#if 0
-#define TYPEINFO_PUT_OBJECT_ARRAY(info,dim,elmcinfo) \
- {TYPEINFO_PUT_ARRAY(info,dim,ARRAYTYPE_OBJECT); \
- (info).elementclass = (elmcinfo);}
-#endif
-
/* srcarray must be an array (not checked) */
#define TYPEINFO_PUT_COMPONENT(srcarray,dst) \
{typeinfo_put_component(&(srcarray),&(dst));}
/* debugging helpers ********************************************************/
-#ifdef DEBUG_TYPES
+#ifdef TYPEINFO_DEBUG
void typeinfo_test();
void typeinfo_init_from_fielddescriptor(typeinfo *info,char *desc);
void typeinfo_print_short(FILE *file,typeinfo *info);
void typeinfo_print_type(FILE *file,int type,typeinfo *info);
-#endif // DEBUG_TYPES
+#endif // TYPEINFO_DEBUG
#endif