* src/vm/jit/verify/icmds.cpp,
authorAndreas HUBERT <andreas.hubert@gmx.at>
Tue, 14 Oct 2008 08:32:46 +0000 (10:32 +0200)
committerAndreas HUBERT <andreas.hubert@gmx.at>
Tue, 14 Oct 2008 08:32:46 +0000 (10:32 +0200)
  src/vm/jit/verify/typecheck-common.cpp,
  src/vm/jit/verify/typecheck-common.hpp,
  src/vm/jit/verify/typecheck-stackbased.cpp,
  src/vm/jit/verify/typecheck-typeinferer.cpp,
  src/vm/jit/verify/typecheck-typeinferer.hpp,
  src/vm/jit/verify/typecheck.cpp,
  src/vm/jit/verify/typecheck.hpp,
  src/vm/jit/verify/typeinfo.cpp,
  src/vm/jit/verify/typeinfo.hpp: Moved to C++.

--HG--
rename : src/vm/jit/verify/icmds.c => src/vm/jit/verify/icmds.cpp
rename : src/vm/jit/verify/typecheck-common.c => src/vm/jit/verify/typecheck-common.cpp
rename : src/vm/jit/verify/typecheck-common.h => src/vm/jit/verify/typecheck-common.hpp
rename : src/vm/jit/verify/typecheck-stackbased.c => src/vm/jit/verify/typecheck-stackbased.cpp
rename : src/vm/jit/verify/typecheck-typeinferer.c => src/vm/jit/verify/typecheck-typeinferer.cpp
rename : src/vm/jit/verify/typecheck-typeinferer.h => src/vm/jit/verify/typecheck-typeinferer.hpp
rename : src/vm/jit/verify/typecheck.c => src/vm/jit/verify/typecheck.cpp
rename : src/vm/jit/verify/typecheck.h => src/vm/jit/verify/typecheck.hpp
rename : src/vm/jit/verify/typeinfo.c => src/vm/jit/verify/typeinfo.cpp
rename : src/vm/jit/verify/typeinfo.h => src/vm/jit/verify/typeinfo.hpp

27 files changed:
src/vm/jit/inline/inline.cpp
src/vm/jit/jit.cpp
src/vm/jit/jit.hpp
src/vm/jit/reg.h
src/vm/jit/verify/Makefile.am
src/vm/jit/verify/icmds.c [deleted file]
src/vm/jit/verify/icmds.cpp [new file with mode: 0644]
src/vm/jit/verify/typecheck-common.c [deleted file]
src/vm/jit/verify/typecheck-common.cpp [new file with mode: 0644]
src/vm/jit/verify/typecheck-common.h [deleted file]
src/vm/jit/verify/typecheck-common.hpp [new file with mode: 0644]
src/vm/jit/verify/typecheck-stackbased.c [deleted file]
src/vm/jit/verify/typecheck-stackbased.cpp [new file with mode: 0644]
src/vm/jit/verify/typecheck-typeinferer.c [deleted file]
src/vm/jit/verify/typecheck-typeinferer.cpp [new file with mode: 0644]
src/vm/jit/verify/typecheck-typeinferer.h [deleted file]
src/vm/jit/verify/typecheck-typeinferer.hpp [new file with mode: 0644]
src/vm/jit/verify/typecheck.c [deleted file]
src/vm/jit/verify/typecheck.cpp [new file with mode: 0644]
src/vm/jit/verify/typecheck.h [deleted file]
src/vm/jit/verify/typecheck.hpp [new file with mode: 0644]
src/vm/jit/verify/typeinfo.c [deleted file]
src/vm/jit/verify/typeinfo.cpp [new file with mode: 0644]
src/vm/jit/verify/typeinfo.h [deleted file]
src/vm/jit/verify/typeinfo.hpp [new file with mode: 0644]
src/vm/resolve.cpp
src/vm/resolve.hpp

index 6ceffa01b8cba5538822f927f375ca765c87d1a5..2ba9156c2181739cdad0fd9409a9f7ea3b853a65 100644 (file)
@@ -57,7 +57,7 @@
 #include "vm/jit/inline/inline.hpp"
 #include "vm/jit/loop/loop.h"
 
-#include "vm/jit/verify/typecheck.h"
+#include "vm/jit/verify/typecheck.hpp"
 
 
 /* algorithm tuning constants *************************************************/
index c218f05e8d14685568a3e157b3849a05e136fd28..9817434123bc731352d8e634a7fa397eb926807b 100644 (file)
 # include "vm/jit/python.h"
 #endif
 
-#include "vm/jit/verify/typecheck.h"
+#include "vm/jit/verify/typecheck.hpp"
 
 
 /* debug macros ***************************************************************/
index 838e330287b31000cf0ebb36a0105bf454ca5096..ecbb865cf24c3e297a1d196a7c4f117c0e78b761 100644 (file)
@@ -68,7 +68,7 @@ typedef struct exception_entry exception_entry;
 # include "vm/jit/allocator/lsra.h"
 #endif
 
-#include "vm/jit/verify/typeinfo.h"
+#include "vm/jit/verify/typeinfo.hpp"
 
 
 /* common jit/codegen macros **************************************************/
index 9dc637b3f12df8b3d866bc2f2a315cdb509f4d60..5235e1b119ea9356d388263f47c88e6b0e84dcc9 100644 (file)
@@ -38,7 +38,7 @@ typedef struct registerdata registerdata;
 #include "arch.h"
 
 #include "vm/jit/jit.hpp"
-#include "vm/jit/verify/typeinfo.h"
+#include "vm/jit/verify/typeinfo.hpp"
 
 
 /************************* pseudo variable structure **************************/
index 8be3839e3a1ae3c916c7df1fd1c917bea5bbad69..c9e3a632e3992d2316c33b4977cb204970014417 100644 (file)
@@ -37,22 +37,22 @@ LIBS =
 noinst_LTLIBRARIES = libverify.la
 
 libverify_la_SOURCES = \
-       typecheck.c \
-       typecheck.h \
-       typecheck-common.c \
-       typecheck-common.h \
+       typecheck.cpp \
+       typecheck.hpp \
+       typecheck-common.cpp \
+       typecheck-common.hpp \
        typecheck-builtins.inc \
        typecheck-fields.inc \
        typecheck-invoke.inc \
        typecheck-multianewarray.inc \
-       typecheck-stackbased.c \
-       typecheck-typeinferer.c \
-       typecheck-typeinferer.h \
+       typecheck-stackbased.cpp \
+       typecheck-typeinferer.cpp \
+       typecheck-typeinferer.hpp \
        typecheck-stackbased-gen.inc \
        typecheck-variablesbased-gen.inc \
        typecheck-typeinferer-gen.inc \
-       typeinfo.c \
-       typeinfo.h
+       typeinfo.cpp \
+       typeinfo.hpp
 
 
 ## Local variables:
diff --git a/src/vm/jit/verify/icmds.c b/src/vm/jit/verify/icmds.c
deleted file mode 100644 (file)
index 65adf81..0000000
+++ /dev/null
@@ -1,779 +0,0 @@
-/* src/vm/jit/verify/icmds.c - ICMD-specific type checking code
-
-   Copyright (C) 1996-2005, 2006, 2007, 2008
-   CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
-
-   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., 51 Franklin Street, Fifth Floor, Boston, MA
-   02110-1301, USA.
-
-*/
-
-#if 0 /* (needed for code examples in the following comment) */
-/******************************************************************************/
-/* This file contains ICMD-specific code for type checking and type
- * inference. It is an input file for the verifier generator
- * (src/vm/jit/verify/generate.pl). The verifier generator creates
- * code for three compiler passes:
- *     - stack-based type-infering verification
- *     - vasiables-based type-infering verification
- *     - type inference pass (no verification - used for optimizing compiler)
- *
- * The rest of this file must consist of "case" clauses starting in
- * the first column. Each clause can be marked with tags like this:
- *
- */          case ICMD_CONSTANT: /* {TAG, TAG, ...} */
-/*
- * This must be on one line. The following tags are defined:
- *     STACKBASED..........use this clause for the stack-based verifier
- *     VARIABLESBASED......use this clause for the variables-based verifier
- *     TYPEINFERER.........use this clause for the type inference pass
- *     ALL.................use for all passes
- *
- * If no tag is specified, {STACKBASED,VARIABLESBASED} is assumed.
- *
- * There are also tags that can be used inside a clause like this:
- *
- */          /* {TAG} */
-/*
- * The following tags are defined within clauses:
- *     RESULTNOW...........generate code for modelling the stack action
- *                         _before_ the user-defined code in the clause
- *                         (Default is to model the stack action afterwards.)
- *
- * The following macros are pre-defined:
- *
- *     TYPECHECK_STACKBASED.......iff compiling the stack-based verifier
- *     TYPECHECK_VARIABLESBASED...iff compiling the variables-based verifier
- *     TYPECHECK_TYPEINFERER......iff compiling the type inference pass
- *
-/******************************************************************************/
-#endif /* (end #if 0) */
-
-
-/* this marker is needed by generate.pl: */
-/* {START_OF_CODE} */
-
-       /****************************************/
-       /* MOVE/COPY                            */
-
-       /* We just need to copy the typeinfo */
-       /* for slots containing addresses.   */
-
-       /* (These are only used by the variables based verifier.) */
-
-case ICMD_MOVE: /* {VARIABLESBASED,TYPEINFERER} */
-case ICMD_COPY: /* {VARIABLESBASED,TYPEINFERER} */
-       TYPECHECK_COUNT(stat_ins_stack);
-       COPYTYPE(IPTR->s1, IPTR->dst);
-       DST->type = OP1->type;
-       break;
-
-       /****************************************/
-       /* LOADING ADDRESS FROM VARIABLE        */
-
-case ICMD_ALOAD: /* {ALL} */
-       TYPECHECK_COUNT(stat_ins_aload);
-
-#if !defined(TYPECHECK_TYPEINFERER)
-       /* loading a returnAddress is not allowed */
-       if (!TYPEDESC_IS_REFERENCE(*OP1)) {
-               VERIFY_ERROR("illegal instruction: ALOAD loading non-reference");
-       }
-#endif
-       TYPEINFO_COPY(OP1->typeinfo,DST->typeinfo);
-       break;
-
-       /****************************************/
-       /* STORING ADDRESS TO VARIABLE          */
-
-case ICMD_ASTORE: /* {ALL} */
-       TYPEINFO_COPY(OP1->typeinfo, DST->typeinfo);
-       break;
-
-       /****************************************/
-       /* LOADING ADDRESS FROM ARRAY           */
-
-case ICMD_AALOAD: /* {ALL} */
-#if !defined(TYPECHECK_TYPEINFERER)
-       if (!TYPEINFO_MAYBE_ARRAY_OF_REFS(OP1->typeinfo))
-               VERIFY_ERROR("illegal instruction: AALOAD on non-reference array");
-#endif
-
-       if (!typeinfo_init_component(&OP1->typeinfo,&DST->typeinfo))
-               EXCEPTION;
-       break;
-
-       /****************************************/
-       /* FIELD ACCESS                         */
-
-case ICMD_PUTFIELD: /* {STACKBASED} */
-       CHECK_STACK_DEPTH(2);
-       if (!IS_CAT1(stack[0])) {
-               CHECK_STACK_DEPTH(3);
-               stack -= 1;
-       }
-       CHECK_STACK_TYPE(stack[-1], TYPE_ADR);
-       stack = typecheck_stackbased_verify_fieldaccess(STATE, stack-1, stack, stack-2);
-       if (stack == NULL)
-               EXCEPTION;
-       break;
-
-case ICMD_PUTSTATIC: /* {STACKBASED} */
-       CHECK_STACK_DEPTH(1);
-       if (!IS_CAT1(stack[0])) {
-               /* (stack depth >= 2 is guaranteed) */
-               stack -= 1;
-       }
-       stack = typecheck_stackbased_verify_fieldaccess(STATE, NULL, stack, stack-1);
-       if (stack == NULL)
-               EXCEPTION;
-       break;
-
-case ICMD_GETFIELD: /* {STACKBASED} */
-       CHECK_STACK_TYPE(stack[0], TYPE_ADR);
-       stack = typecheck_stackbased_verify_fieldaccess(STATE, stack, NULL, stack-1);
-       if (stack == NULL)
-               EXCEPTION;
-       break;
-
-case ICMD_GETSTATIC:      /* {STACKBASED} */
-       stack = typecheck_stackbased_verify_fieldaccess(STATE, NULL, NULL, stack);
-       if (stack == NULL)
-               EXCEPTION;
-       break;
-
-case ICMD_PUTFIELD:       /* {VARIABLESBASED} */
-       if (!handle_fieldaccess(state, VAROP(iptr->s1), VAROP(iptr->sx.s23.s2)))
-               return false;
-       maythrow = true;
-       break;
-
-case ICMD_PUTSTATIC:      /* {VARIABLESBASED} */
-       if (!handle_fieldaccess(state, NULL, VAROP(iptr->s1)))
-               return false;
-       maythrow = true;
-       break;
-
-case ICMD_PUTFIELDCONST:  /* {VARIABLESBASED} */
-       /* XXX this mess will go away with const operands */
-       INSTRUCTION_GET_FIELDREF(state->iptr, fieldref);
-       constvalue.type = fieldref->parseddesc.fd->type;
-       if (IS_ADR_TYPE(constvalue.type)) {
-               if (state->iptr->sx.val.anyptr) {
-                       classinfo *cc = (state->iptr->flags.bits & INS_FLAG_CLASS)
-                               ? class_java_lang_Class : class_java_lang_String;
-                       assert(cc);
-                       assert(cc->state & CLASS_LINKED);
-                       typeinfo_init_classinfo(&(constvalue.typeinfo), cc);
-               }
-               else {
-                       TYPEINFO_INIT_NULLTYPE(constvalue.typeinfo);
-               }
-       }
-       if (!handle_fieldaccess(state, VAROP(iptr->s1), &constvalue))
-               return false;
-       maythrow = true;
-       break;
-
-case ICMD_PUTSTATICCONST: /* {VARIABLESBASED} */
-       /* XXX this mess will go away with const operands */
-       INSTRUCTION_GET_FIELDREF(state->iptr, fieldref);
-       constvalue.type = fieldref->parseddesc.fd->type;
-       if (IS_ADR_TYPE(constvalue.type)) {
-               if (state->iptr->sx.val.anyptr) {
-                       classinfo *cc = (state->iptr->flags.bits & INS_FLAG_CLASS)
-                               ? class_java_lang_Class : class_java_lang_String;
-                       assert(cc);
-                       assert(cc->state & CLASS_LINKED);
-                       typeinfo_init_classinfo(&(constvalue.typeinfo), cc);
-               }
-               else {
-                       TYPEINFO_INIT_NULLTYPE(constvalue.typeinfo);
-               }
-       }
-       if (!handle_fieldaccess(state, NULL, &constvalue))
-               return false;
-       maythrow = true;
-       break;
-
-case ICMD_GETFIELD:       /* {VARIABLESBASED,TYPEINFERER} */
-       if (!handle_fieldaccess(state, VAROP(iptr->s1), NULL))
-               return false;
-       maythrow = true;
-       break;
-
-case ICMD_GETSTATIC:      /* {VARIABLESBASED,TYPEINFERER} */
-       if (!handle_fieldaccess(state, NULL, NULL))
-               return false;
-       maythrow = true;
-       break;
-
-       /****************************************/
-       /* PRIMITIVE ARRAY ACCESS               */
-
-case ICMD_ARRAYLENGTH:
-       if (!TYPEINFO_MAYBE_ARRAY(OP1->typeinfo)
-                       && OP1->typeinfo.typeclass.cls != pseudo_class_Arraystub)
-               VERIFY_ERROR("illegal instruction: ARRAYLENGTH on non-array");
-       break;
-
-case ICMD_BALOAD:
-       if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(OP1->typeinfo,ARRAYTYPE_BOOLEAN)
-                       && !TYPEINFO_MAYBE_PRIMITIVE_ARRAY(OP1->typeinfo,ARRAYTYPE_BYTE))
-               VERIFY_ERROR("Array type mismatch");
-       break;
-
-case ICMD_CALOAD:
-       if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(OP1->typeinfo,ARRAYTYPE_CHAR))
-               VERIFY_ERROR("Array type mismatch");
-       break;
-
-case ICMD_DALOAD:
-       if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(OP1->typeinfo,ARRAYTYPE_DOUBLE))
-               VERIFY_ERROR("Array type mismatch");
-       break;
-
-case ICMD_FALOAD:
-       if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(OP1->typeinfo,ARRAYTYPE_FLOAT))
-               VERIFY_ERROR("Array type mismatch");
-       break;
-
-case ICMD_IALOAD:
-       if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(OP1->typeinfo,ARRAYTYPE_INT))
-               VERIFY_ERROR("Array type mismatch");
-       break;
-
-case ICMD_SALOAD:
-       if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(OP1->typeinfo,ARRAYTYPE_SHORT))
-               VERIFY_ERROR("Array type mismatch");
-       break;
-
-case ICMD_LALOAD:
-       if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(OP1->typeinfo,ARRAYTYPE_LONG))
-               VERIFY_ERROR("Array type mismatch");
-       break;
-
-case ICMD_BASTORE:
-       if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(OP1->typeinfo,ARRAYTYPE_BOOLEAN)
-                       && !TYPEINFO_MAYBE_PRIMITIVE_ARRAY(OP1->typeinfo,ARRAYTYPE_BYTE))
-               VERIFY_ERROR("Array type mismatch");
-       break;
-
-case ICMD_CASTORE:
-       if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(OP1->typeinfo,ARRAYTYPE_CHAR))
-               VERIFY_ERROR("Array type mismatch");
-       break;
-
-case ICMD_DASTORE:
-       if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(OP1->typeinfo,ARRAYTYPE_DOUBLE))
-               VERIFY_ERROR("Array type mismatch");
-       break;
-
-case ICMD_FASTORE:
-       if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(OP1->typeinfo,ARRAYTYPE_FLOAT))
-               VERIFY_ERROR("Array type mismatch");
-       break;
-
-case ICMD_IASTORE:
-       if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(OP1->typeinfo,ARRAYTYPE_INT))
-               VERIFY_ERROR("Array type mismatch");
-       break;
-
-case ICMD_SASTORE:
-       if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(OP1->typeinfo,ARRAYTYPE_SHORT))
-               VERIFY_ERROR("Array type mismatch");
-       break;
-
-case ICMD_LASTORE:
-       if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(OP1->typeinfo,ARRAYTYPE_LONG))
-               VERIFY_ERROR("Array type mismatch");
-       break;
-
-case ICMD_AASTORE:
-       /* we just check the basic input types and that the           */
-       /* destination is an array of references. Assignability to    */
-       /* the actual array must be checked at runtime, each time the */
-       /* instruction is performed. (See builtin_canstore.)          */
-       if (!TYPEINFO_MAYBE_ARRAY_OF_REFS(OP1->typeinfo))
-               VERIFY_ERROR("illegal instruction: AASTORE to non-reference array");
-       break;
-
-case ICMD_IASTORECONST:
-       if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(OP1->typeinfo, ARRAYTYPE_INT))
-               VERIFY_ERROR("Array type mismatch");
-       break;
-
-case ICMD_LASTORECONST:
-       if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(OP1->typeinfo, ARRAYTYPE_LONG))
-               VERIFY_ERROR("Array type mismatch");
-       break;
-
-case ICMD_BASTORECONST:
-       if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(OP1->typeinfo, ARRAYTYPE_BOOLEAN)
-                       && !TYPEINFO_MAYBE_PRIMITIVE_ARRAY(OP1->typeinfo, ARRAYTYPE_BYTE))
-               VERIFY_ERROR("Array type mismatch");
-       break;
-
-case ICMD_CASTORECONST:
-       if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(OP1->typeinfo, ARRAYTYPE_CHAR))
-               VERIFY_ERROR("Array type mismatch");
-       break;
-
-case ICMD_SASTORECONST:
-       if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(OP1->typeinfo, ARRAYTYPE_SHORT))
-               VERIFY_ERROR("Array type mismatch");
-       break;
-
-       /****************************************/
-       /* ADDRESS CONSTANTS                    */
-
-case ICMD_ACONST: /* {ALL} */
-       if (IPTR->flags.bits & INS_FLAG_CLASS) {
-               /* a java.lang.Class reference */
-               TYPEINFO_INIT_JAVA_LANG_CLASS(DST->typeinfo,IPTR->sx.val.c);
-       }
-       else {
-               if (IPTR->sx.val.anyptr == NULL)
-                       TYPEINFO_INIT_NULLTYPE(DST->typeinfo);
-               else {
-                       /* string constant (or constant for builtin function) */
-                       typeinfo_init_classinfo(&(DST->typeinfo),class_java_lang_String);
-               }
-       }
-       break;
-
-       /****************************************/
-       /* CHECKCAST AND INSTANCEOF             */
-
-case ICMD_CHECKCAST: /* {ALL} */
-#if !defined(TYPECHECK_TYPEINFERER)
-       /* returnAddress is not allowed */
-       if (!TYPEINFO_IS_REFERENCE(OP1->typeinfo))
-               VERIFY_ERROR("Illegal instruction: CHECKCAST on non-reference");
-#endif
-
-    /* XXX only if narrower */
-       if (!typeinfo_init_class(&(DST->typeinfo),IPTR->sx.s23.s3.c))
-               EXCEPTION;
-       break;
-
-case ICMD_INSTANCEOF:
-       /* returnAddress is not allowed */
-       if (!TYPEINFO_IS_REFERENCE(OP1->typeinfo))
-               VERIFY_ERROR("Illegal instruction: INSTANCEOF on non-reference");
-
-       /* XXX should propagate type information to the following if-branches */
-       break;
-
-       /****************************************/
-       /* BRANCH INSTRUCTIONS                  */
-
-case ICMD_GOTO:            /* {ALL} */
-case ICMD_IFNULL:          /* {ALL} */
-case ICMD_IFNONNULL:       /* {ALL} */
-case ICMD_IFEQ:            /* {ALL} */
-case ICMD_IFNE:            /* {ALL} */
-case ICMD_IFLT:            /* {ALL} */
-case ICMD_IFGE:            /* {ALL} */
-case ICMD_IFGT:            /* {ALL} */
-case ICMD_IFLE:            /* {ALL} */
-case ICMD_IF_ICMPEQ:       /* {ALL} */
-case ICMD_IF_ICMPNE:       /* {ALL} */
-case ICMD_IF_ICMPLT:       /* {ALL} */
-case ICMD_IF_ICMPGE:       /* {ALL} */
-case ICMD_IF_ICMPGT:       /* {ALL} */
-case ICMD_IF_ICMPLE:       /* {ALL} */
-case ICMD_IF_ACMPEQ:       /* {ALL} */
-case ICMD_IF_ACMPNE:       /* {ALL} */
-
-case ICMD_IF_LEQ:          /* {ALL} */
-case ICMD_IF_LNE:          /* {ALL} */
-case ICMD_IF_LLT:          /* {ALL} */
-case ICMD_IF_LGE:          /* {ALL} */
-case ICMD_IF_LGT:          /* {ALL} */
-case ICMD_IF_LLE:          /* {ALL} */
-
-case ICMD_IF_LCMPEQ:       /* {ALL} */
-case ICMD_IF_LCMPNE:       /* {ALL} */
-case ICMD_IF_LCMPLT:       /* {ALL} */
-case ICMD_IF_LCMPGE:       /* {ALL} */
-case ICMD_IF_LCMPGT:       /* {ALL} */
-case ICMD_IF_LCMPLE:       /* {ALL} */
-       /* {RESULTNOW} */
-       TYPECHECK_COUNT(stat_ins_branch);
-
-       /* propagate stack and variables to the target block */
-       REACH(IPTR->dst);
-       break;
-
-       /****************************************/
-       /* SWITCHES                             */
-
-case ICMD_TABLESWITCH:     /* {ALL} */
-       /* {RESULTNOW} */
-       TYPECHECK_COUNT(stat_ins_switch);
-
-       table = IPTR->dst.table;
-       i = IPTR->sx.s23.s3.tablehigh
-       - IPTR->sx.s23.s2.tablelow + 1 + 1; /* plus default */
-
-       while (--i >= 0) {
-               REACH(*table);
-               table++;
-       }
-
-       LOG("switch done");
-       break;
-
-case ICMD_LOOKUPSWITCH:    /* {ALL} */
-       /* {RESULTNOW} */
-       TYPECHECK_COUNT(stat_ins_switch);
-
-       lookup = IPTR->dst.lookup;
-       i = IPTR->sx.s23.s2.lookupcount;
-       REACH(IPTR->sx.s23.s3.lookupdefault);
-
-       while (--i >= 0) {
-               REACH(lookup->target);
-               lookup++;
-       }
-
-       LOG("switch done");
-       break;
-
-
-       /****************************************/
-       /* ADDRESS RETURNS AND THROW            */
-
-case ICMD_ATHROW:
-       TYPECHECK_COUNT(stat_ins_athrow);
-       r = typeinfo_is_assignable_to_class(&OP1->typeinfo,
-                       CLASSREF_OR_CLASSINFO(class_java_lang_Throwable));
-       if (r == typecheck_FALSE)
-               VERIFY_ERROR("illegal instruction: ATHROW on non-Throwable");
-       if (r == typecheck_FAIL)
-               EXCEPTION;
-       if (r == typecheck_MAYBE) {
-               /* the check has to be postponed. we need a patcher */
-               TYPECHECK_COUNT(stat_ins_athrow_unresolved);
-               IPTR->sx.s23.s2.uc = create_unresolved_class(
-                               METHOD,
-                               /* XXX make this more efficient, use class_java_lang_Throwable
-                                * directly */
-                               class_get_classref(METHOD->clazz,utf_java_lang_Throwable),
-                               &OP1->typeinfo);
-               IPTR->flags.bits |= INS_FLAG_UNRESOLVED;
-       }
-       break;
-
-case ICMD_ARETURN:
-       TYPECHECK_COUNT(stat_ins_areturn);
-       if (!TYPEINFO_IS_REFERENCE(OP1->typeinfo))
-               VERIFY_ERROR("illegal instruction: ARETURN on non-reference");
-
-       if (STATE->returntype.type != TYPE_ADR
-                       || (r = typeinfo_is_assignable(&OP1->typeinfo,&(STATE->returntype.typeinfo)))
-                       == typecheck_FALSE)
-               VERIFY_ERROR("Return type mismatch");
-       if (r == typecheck_FAIL)
-               EXCEPTION;
-       if (r == typecheck_MAYBE) {
-               /* the check has to be postponed, we need a patcher */
-               TYPECHECK_COUNT(stat_ins_areturn_unresolved);
-               IPTR->sx.s23.s2.uc = create_unresolved_class(
-                               METHOD,
-                               METHOD->parseddesc->returntype.classref,
-                               &OP1->typeinfo);
-               IPTR->flags.bits |= INS_FLAG_UNRESOLVED;
-       }
-       goto return_tail;
-
-       /****************************************/
-       /* PRIMITIVE RETURNS                    */
-
-case ICMD_IRETURN:
-       if (STATE->returntype.type != TYPE_INT)
-               VERIFY_ERROR("Return type mismatch");
-       goto return_tail;
-
-case ICMD_LRETURN:
-       if (STATE->returntype.type != TYPE_LNG)
-               VERIFY_ERROR("Return type mismatch");
-       goto return_tail;
-
-case ICMD_FRETURN:
-       if (STATE->returntype.type != TYPE_FLT)
-               VERIFY_ERROR("Return type mismatch");
-       goto return_tail;
-
-case ICMD_DRETURN:
-       if (STATE->returntype.type != TYPE_DBL)
-               VERIFY_ERROR("Return type mismatch");
-       goto return_tail;
-
-case ICMD_RETURN:
-       if (STATE->returntype.type != TYPE_VOID)
-               VERIFY_ERROR("Return type mismatch");
-
-return_tail:
-       TYPECHECK_COUNT(stat_ins_primitive_return);
-
-       if (STATE->initmethod && METHOD->clazz != class_java_lang_Object) {
-               /* Check if the 'this' instance has been initialized. */
-               LOG("Checking <init> marker");
-#if defined(TYPECHECK_VARIABLESBASED)
-               if (!typevector_checktype(jd->var,STATE->numlocals-1,TYPE_INT))
-#else
-               if (STATE->locals[STATE->numlocals-1].type != TYPE_INT)
-#endif
-                       VERIFY_ERROR("<init> method does not initialize 'this'");
-       }
-       break;
-
-       /****************************************/
-       /* SUBROUTINE INSTRUCTIONS              */
-
-case ICMD_JSR: /* {VARIABLESBASED,TYPEINFERER} */
-       TYPEINFO_INIT_RETURNADDRESS(DST->typeinfo, BPTR->next);
-       REACH(IPTR->sx.s23.s3.jsrtarget);
-       break;
-
-case ICMD_JSR: /* {STACKBASED} */
-       /* {RESULTNOW} */
-       tbptr = IPTR->sx.s23.s3.jsrtarget.block;
-
-       TYPEINFO_INIT_RETURNADDRESS(stack[0].typeinfo, tbptr);
-       REACH_BLOCK(tbptr);
-
-       stack = typecheck_stackbased_jsr(STATE, stack, stackfloor);
-       if (stack == NULL)
-               EXCEPTION;
-       break;
-
-case ICMD_RET: /* {VARIABLESBASED,TYPEINFERER} */
-#if !defined(TYPECHECK_TYPEINFERER)
-       /* check returnAddress variable */
-       if (!typevector_checkretaddr(jd->var,IPTR->s1.varindex))
-               VERIFY_ERROR("illegal instruction: RET using non-returnAddress variable");
-#endif
-       REACH(IPTR->dst);
-       break;
-
-case ICMD_RET: /* {STACKBASED} */
-       /* {RESULTNOW} */
-       CHECK_LOCAL_TYPE(IPTR->s1.varindex, TYPE_RET);
-       if (!TYPEINFO_IS_PRIMITIVE(STATE->locals[IPTR->s1.varindex].typeinfo))
-               VERIFY_ERROR("illegal instruction: RET using non-returnAddress variable");
-
-       if (!typecheck_stackbased_ret(STATE, stack, stackfloor))
-               EXCEPTION;
-       break;
-
-       /****************************************/
-       /* INVOKATIONS                          */
-
-case ICMD_INVOKEVIRTUAL:   /* {VARIABLESBASED,TYPEINFERER} */
-case ICMD_INVOKESPECIAL:   /* {VARIABLESBASED,TYPEINFERER} */
-case ICMD_INVOKESTATIC:    /* {VARIABLESBASED,TYPEINFERER} */
-case ICMD_INVOKEINTERFACE: /* {VARIABLESBASED,TYPEINFERER} */
-       TYPECHECK_COUNT(stat_ins_invoke);
-       if (!handle_invocation(state))
-               EXCEPTION;
-       TYPECHECK_COUNTIF(INSTRUCTION_IS_UNRESOLVED(IPTR), stat_ins_invoke_unresolved);
-       break;
-
-case ICMD_INVOKEVIRTUAL:   /* {STACKBASED} */
-case ICMD_INVOKESPECIAL:   /* {STACKBASED} */
-case ICMD_INVOKESTATIC:    /* {STACKBASED} */
-case ICMD_INVOKEINTERFACE: /* {STACKBASED} */
-       TYPECHECK_COUNT(stat_ins_invoke);
-
-       INSTRUCTION_GET_METHODDESC(IPTR, md);
-       CHECK_STACK_DEPTH(md->paramslots);
-
-       if (!typecheck_stackbased_verify_invocation(STATE, stack, stackfloor))
-               EXCEPTION;
-
-       stack -= md->paramslots;
-
-       if (md->returntype.type != TYPE_VOID) {
-               if (IS_2_WORD_TYPE(md->returntype.type)) {
-                       CHECK_STACK_SPACE(2);
-                       stack += 2;
-                       stack[0].type = TYPE_VOID;
-                       stack[-1].type = md->returntype.type;
-               }
-               else {
-                       CHECK_STACK_SPACE(1);
-                       stack += 1;
-                       stack[0].type = md->returntype.type;
-               }
-       }
-       TYPECHECK_COUNTIF(INSTRUCTION_IS_UNRESOLVED(IPTR), stat_ins_invoke_unresolved);
-       break;
-
-       /****************************************/
-       /* MULTIANEWARRAY                       */
-
-case ICMD_MULTIANEWARRAY: /* {VARIABLESBASED,TYPEINFERER} */
-       if (!handle_multianewarray(STATE))
-               EXCEPTION;
-       break;
-
-case ICMD_MULTIANEWARRAY: /* {STACKBASED} */
-       if (!typecheck_stackbased_multianewarray(STATE, stack, stackfloor))
-               EXCEPTION;
-       stack -= (IPTR->s1.argcount - 1);
-       stack[0].type = TYPE_ADR;
-       break;
-
-       /****************************************/
-       /* BUILTINS                             */
-
-case ICMD_BUILTIN: /* {VARIABLESBASED,TYPEINFERER} */
-       TYPECHECK_COUNT(stat_ins_builtin);
-       if (!handle_builtin(state))
-               EXCEPTION;
-       break;
-
-case ICMD_BUILTIN: /* {STACKBASED} */
-       TYPECHECK_COUNT(stat_ins_builtin);
-       if (!typecheck_stackbased_verify_builtin(STATE, stack, stackfloor))
-               EXCEPTION;
-
-       /* pop operands and push return value */
-       {
-               u1 rtype = IPTR->sx.s23.s3.bte->md->returntype.type;
-               stack -=  IPTR->sx.s23.s3.bte->md->paramslots;
-               if (rtype != TYPE_VOID) {
-                       if (IS_2_WORD_TYPE(rtype))
-                               stack += 2;
-                       else
-                               stack += 1;
-               }
-       }
-       break;
-
-/* the following code is only used by the stackbased verifier */
-
-case ICMD_POP: /* {STACKBASED} */
-       /* we pop 1 */
-       CHECK_CAT1(stack[0]);
-       break;
-
-case ICMD_POP2: /* {STACKBASED} */
-       /* we pop either 11 or 2 */
-       if (IS_CAT1(stack[0]))
-               CHECK_CAT1(stack[-1]);
-       break;
-
-case ICMD_SWAP: /* {STACKBASED} */
-       CHECK_CAT1(stack[0]);
-       CHECK_CAT1(stack[-1]);
-
-       COPY_SLOT(stack[ 0], temp     );
-       COPY_SLOT(stack[-1], stack[ 0]);
-       COPY_SLOT(temp     , stack[-1]);
-       break;
-
-case ICMD_DUP: /* {STACKBASED} */
-       /* we dup 1 */
-       CHECK_CAT1(stack[0]);
-
-       COPY_SLOT(stack[ 0], stack[ 1]);
-       break;
-
-case ICMD_DUP_X1: /* {STACKBASED} */
-       /* we dup 1 */
-       CHECK_CAT1(stack[0]);
-       /* we skip 1 */
-       CHECK_CAT1(stack[-1]);
-
-       COPY_SLOT(stack[ 0], stack[ 1]);
-       COPY_SLOT(stack[-1], stack[ 0]);
-       COPY_SLOT(stack[ 1], stack[-1]);
-       break;
-
-case ICMD_DUP_X2: /* {STACKBASED} */
-       /* we dup 1 */
-       CHECK_CAT1(stack[0]);
-       /* we skip either 11 or 2 */
-       if (IS_CAT1(stack[-1]))
-               CHECK_CAT1(stack[-2]);
-
-       COPY_SLOT(stack[ 0], stack[ 1]);
-       COPY_SLOT(stack[-1], stack[ 0]);
-       COPY_SLOT(stack[-2], stack[-1]);
-       COPY_SLOT(stack[ 1], stack[-2]);
-       break;
-
-case ICMD_DUP2: /* {STACKBASED} */
-       /* we dup either 11 or 2 */
-       if (IS_CAT1(stack[0]))
-               CHECK_CAT1(stack[-1]);
-
-       COPY_SLOT(stack[ 0], stack[ 2]);
-       COPY_SLOT(stack[-1], stack[ 1]);
-       break;
-
-case ICMD_DUP2_X1: /* {STACKBASED} */
-       /* we dup either 11 or 2 */
-       if (IS_CAT1(stack[0]))
-               CHECK_CAT1(stack[-1]);
-       /* we skip 1 */
-       CHECK_CAT1(stack[-2]);
-
-       COPY_SLOT(stack[ 0], stack[ 2]);
-       COPY_SLOT(stack[-1], stack[ 1]);
-       COPY_SLOT(stack[-2], stack[ 0]);
-       COPY_SLOT(stack[ 2], stack[-1]);
-       COPY_SLOT(stack[ 1], stack[-2]);
-       break;
-
-case ICMD_DUP2_X2: /* {STACKBASED} */
-       /* we dup either 11 or 2 */
-       if (IS_CAT1(stack[0]))
-               CHECK_CAT1(stack[-1]);
-       /* we skip either 11 or 2 */
-       if (IS_CAT1(stack[-2]))
-               CHECK_CAT1(stack[-3]);
-
-       COPY_SLOT(stack[ 0], stack[ 2]);
-       COPY_SLOT(stack[-1], stack[ 1]);
-       COPY_SLOT(stack[-2], stack[ 0]);
-       COPY_SLOT(stack[-3], stack[-1]);
-       COPY_SLOT(stack[ 2], stack[-2]);
-       COPY_SLOT(stack[ 1], stack[-3]);
-       break;
-
-
-/* this marker is needed by generate.pl: */
-/* {END_OF_CODE} */
-
-/*
- * 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
- * Emacs will automagically detect them.
- * ---------------------------------------------------------------------
- * Local variables:
- * mode: c
- * indent-tabs-mode: t
- * c-basic-offset: 4
- * tab-width: 4
- * End:
- * vim:noexpandtab:sw=4:ts=4:
- */
diff --git a/src/vm/jit/verify/icmds.cpp b/src/vm/jit/verify/icmds.cpp
new file mode 100644 (file)
index 0000000..65adf81
--- /dev/null
@@ -0,0 +1,779 @@
+/* src/vm/jit/verify/icmds.c - ICMD-specific type checking code
+
+   Copyright (C) 1996-2005, 2006, 2007, 2008
+   CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
+
+   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., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301, USA.
+
+*/
+
+#if 0 /* (needed for code examples in the following comment) */
+/******************************************************************************/
+/* This file contains ICMD-specific code for type checking and type
+ * inference. It is an input file for the verifier generator
+ * (src/vm/jit/verify/generate.pl). The verifier generator creates
+ * code for three compiler passes:
+ *     - stack-based type-infering verification
+ *     - vasiables-based type-infering verification
+ *     - type inference pass (no verification - used for optimizing compiler)
+ *
+ * The rest of this file must consist of "case" clauses starting in
+ * the first column. Each clause can be marked with tags like this:
+ *
+ */          case ICMD_CONSTANT: /* {TAG, TAG, ...} */
+/*
+ * This must be on one line. The following tags are defined:
+ *     STACKBASED..........use this clause for the stack-based verifier
+ *     VARIABLESBASED......use this clause for the variables-based verifier
+ *     TYPEINFERER.........use this clause for the type inference pass
+ *     ALL.................use for all passes
+ *
+ * If no tag is specified, {STACKBASED,VARIABLESBASED} is assumed.
+ *
+ * There are also tags that can be used inside a clause like this:
+ *
+ */          /* {TAG} */
+/*
+ * The following tags are defined within clauses:
+ *     RESULTNOW...........generate code for modelling the stack action
+ *                         _before_ the user-defined code in the clause
+ *                         (Default is to model the stack action afterwards.)
+ *
+ * The following macros are pre-defined:
+ *
+ *     TYPECHECK_STACKBASED.......iff compiling the stack-based verifier
+ *     TYPECHECK_VARIABLESBASED...iff compiling the variables-based verifier
+ *     TYPECHECK_TYPEINFERER......iff compiling the type inference pass
+ *
+/******************************************************************************/
+#endif /* (end #if 0) */
+
+
+/* this marker is needed by generate.pl: */
+/* {START_OF_CODE} */
+
+       /****************************************/
+       /* MOVE/COPY                            */
+
+       /* We just need to copy the typeinfo */
+       /* for slots containing addresses.   */
+
+       /* (These are only used by the variables based verifier.) */
+
+case ICMD_MOVE: /* {VARIABLESBASED,TYPEINFERER} */
+case ICMD_COPY: /* {VARIABLESBASED,TYPEINFERER} */
+       TYPECHECK_COUNT(stat_ins_stack);
+       COPYTYPE(IPTR->s1, IPTR->dst);
+       DST->type = OP1->type;
+       break;
+
+       /****************************************/
+       /* LOADING ADDRESS FROM VARIABLE        */
+
+case ICMD_ALOAD: /* {ALL} */
+       TYPECHECK_COUNT(stat_ins_aload);
+
+#if !defined(TYPECHECK_TYPEINFERER)
+       /* loading a returnAddress is not allowed */
+       if (!TYPEDESC_IS_REFERENCE(*OP1)) {
+               VERIFY_ERROR("illegal instruction: ALOAD loading non-reference");
+       }
+#endif
+       TYPEINFO_COPY(OP1->typeinfo,DST->typeinfo);
+       break;
+
+       /****************************************/
+       /* STORING ADDRESS TO VARIABLE          */
+
+case ICMD_ASTORE: /* {ALL} */
+       TYPEINFO_COPY(OP1->typeinfo, DST->typeinfo);
+       break;
+
+       /****************************************/
+       /* LOADING ADDRESS FROM ARRAY           */
+
+case ICMD_AALOAD: /* {ALL} */
+#if !defined(TYPECHECK_TYPEINFERER)
+       if (!TYPEINFO_MAYBE_ARRAY_OF_REFS(OP1->typeinfo))
+               VERIFY_ERROR("illegal instruction: AALOAD on non-reference array");
+#endif
+
+       if (!typeinfo_init_component(&OP1->typeinfo,&DST->typeinfo))
+               EXCEPTION;
+       break;
+
+       /****************************************/
+       /* FIELD ACCESS                         */
+
+case ICMD_PUTFIELD: /* {STACKBASED} */
+       CHECK_STACK_DEPTH(2);
+       if (!IS_CAT1(stack[0])) {
+               CHECK_STACK_DEPTH(3);
+               stack -= 1;
+       }
+       CHECK_STACK_TYPE(stack[-1], TYPE_ADR);
+       stack = typecheck_stackbased_verify_fieldaccess(STATE, stack-1, stack, stack-2);
+       if (stack == NULL)
+               EXCEPTION;
+       break;
+
+case ICMD_PUTSTATIC: /* {STACKBASED} */
+       CHECK_STACK_DEPTH(1);
+       if (!IS_CAT1(stack[0])) {
+               /* (stack depth >= 2 is guaranteed) */
+               stack -= 1;
+       }
+       stack = typecheck_stackbased_verify_fieldaccess(STATE, NULL, stack, stack-1);
+       if (stack == NULL)
+               EXCEPTION;
+       break;
+
+case ICMD_GETFIELD: /* {STACKBASED} */
+       CHECK_STACK_TYPE(stack[0], TYPE_ADR);
+       stack = typecheck_stackbased_verify_fieldaccess(STATE, stack, NULL, stack-1);
+       if (stack == NULL)
+               EXCEPTION;
+       break;
+
+case ICMD_GETSTATIC:      /* {STACKBASED} */
+       stack = typecheck_stackbased_verify_fieldaccess(STATE, NULL, NULL, stack);
+       if (stack == NULL)
+               EXCEPTION;
+       break;
+
+case ICMD_PUTFIELD:       /* {VARIABLESBASED} */
+       if (!handle_fieldaccess(state, VAROP(iptr->s1), VAROP(iptr->sx.s23.s2)))
+               return false;
+       maythrow = true;
+       break;
+
+case ICMD_PUTSTATIC:      /* {VARIABLESBASED} */
+       if (!handle_fieldaccess(state, NULL, VAROP(iptr->s1)))
+               return false;
+       maythrow = true;
+       break;
+
+case ICMD_PUTFIELDCONST:  /* {VARIABLESBASED} */
+       /* XXX this mess will go away with const operands */
+       INSTRUCTION_GET_FIELDREF(state->iptr, fieldref);
+       constvalue.type = fieldref->parseddesc.fd->type;
+       if (IS_ADR_TYPE(constvalue.type)) {
+               if (state->iptr->sx.val.anyptr) {
+                       classinfo *cc = (state->iptr->flags.bits & INS_FLAG_CLASS)
+                               ? class_java_lang_Class : class_java_lang_String;
+                       assert(cc);
+                       assert(cc->state & CLASS_LINKED);
+                       typeinfo_init_classinfo(&(constvalue.typeinfo), cc);
+               }
+               else {
+                       TYPEINFO_INIT_NULLTYPE(constvalue.typeinfo);
+               }
+       }
+       if (!handle_fieldaccess(state, VAROP(iptr->s1), &constvalue))
+               return false;
+       maythrow = true;
+       break;
+
+case ICMD_PUTSTATICCONST: /* {VARIABLESBASED} */
+       /* XXX this mess will go away with const operands */
+       INSTRUCTION_GET_FIELDREF(state->iptr, fieldref);
+       constvalue.type = fieldref->parseddesc.fd->type;
+       if (IS_ADR_TYPE(constvalue.type)) {
+               if (state->iptr->sx.val.anyptr) {
+                       classinfo *cc = (state->iptr->flags.bits & INS_FLAG_CLASS)
+                               ? class_java_lang_Class : class_java_lang_String;
+                       assert(cc);
+                       assert(cc->state & CLASS_LINKED);
+                       typeinfo_init_classinfo(&(constvalue.typeinfo), cc);
+               }
+               else {
+                       TYPEINFO_INIT_NULLTYPE(constvalue.typeinfo);
+               }
+       }
+       if (!handle_fieldaccess(state, NULL, &constvalue))
+               return false;
+       maythrow = true;
+       break;
+
+case ICMD_GETFIELD:       /* {VARIABLESBASED,TYPEINFERER} */
+       if (!handle_fieldaccess(state, VAROP(iptr->s1), NULL))
+               return false;
+       maythrow = true;
+       break;
+
+case ICMD_GETSTATIC:      /* {VARIABLESBASED,TYPEINFERER} */
+       if (!handle_fieldaccess(state, NULL, NULL))
+               return false;
+       maythrow = true;
+       break;
+
+       /****************************************/
+       /* PRIMITIVE ARRAY ACCESS               */
+
+case ICMD_ARRAYLENGTH:
+       if (!TYPEINFO_MAYBE_ARRAY(OP1->typeinfo)
+                       && OP1->typeinfo.typeclass.cls != pseudo_class_Arraystub)
+               VERIFY_ERROR("illegal instruction: ARRAYLENGTH on non-array");
+       break;
+
+case ICMD_BALOAD:
+       if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(OP1->typeinfo,ARRAYTYPE_BOOLEAN)
+                       && !TYPEINFO_MAYBE_PRIMITIVE_ARRAY(OP1->typeinfo,ARRAYTYPE_BYTE))
+               VERIFY_ERROR("Array type mismatch");
+       break;
+
+case ICMD_CALOAD:
+       if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(OP1->typeinfo,ARRAYTYPE_CHAR))
+               VERIFY_ERROR("Array type mismatch");
+       break;
+
+case ICMD_DALOAD:
+       if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(OP1->typeinfo,ARRAYTYPE_DOUBLE))
+               VERIFY_ERROR("Array type mismatch");
+       break;
+
+case ICMD_FALOAD:
+       if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(OP1->typeinfo,ARRAYTYPE_FLOAT))
+               VERIFY_ERROR("Array type mismatch");
+       break;
+
+case ICMD_IALOAD:
+       if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(OP1->typeinfo,ARRAYTYPE_INT))
+               VERIFY_ERROR("Array type mismatch");
+       break;
+
+case ICMD_SALOAD:
+       if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(OP1->typeinfo,ARRAYTYPE_SHORT))
+               VERIFY_ERROR("Array type mismatch");
+       break;
+
+case ICMD_LALOAD:
+       if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(OP1->typeinfo,ARRAYTYPE_LONG))
+               VERIFY_ERROR("Array type mismatch");
+       break;
+
+case ICMD_BASTORE:
+       if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(OP1->typeinfo,ARRAYTYPE_BOOLEAN)
+                       && !TYPEINFO_MAYBE_PRIMITIVE_ARRAY(OP1->typeinfo,ARRAYTYPE_BYTE))
+               VERIFY_ERROR("Array type mismatch");
+       break;
+
+case ICMD_CASTORE:
+       if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(OP1->typeinfo,ARRAYTYPE_CHAR))
+               VERIFY_ERROR("Array type mismatch");
+       break;
+
+case ICMD_DASTORE:
+       if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(OP1->typeinfo,ARRAYTYPE_DOUBLE))
+               VERIFY_ERROR("Array type mismatch");
+       break;
+
+case ICMD_FASTORE:
+       if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(OP1->typeinfo,ARRAYTYPE_FLOAT))
+               VERIFY_ERROR("Array type mismatch");
+       break;
+
+case ICMD_IASTORE:
+       if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(OP1->typeinfo,ARRAYTYPE_INT))
+               VERIFY_ERROR("Array type mismatch");
+       break;
+
+case ICMD_SASTORE:
+       if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(OP1->typeinfo,ARRAYTYPE_SHORT))
+               VERIFY_ERROR("Array type mismatch");
+       break;
+
+case ICMD_LASTORE:
+       if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(OP1->typeinfo,ARRAYTYPE_LONG))
+               VERIFY_ERROR("Array type mismatch");
+       break;
+
+case ICMD_AASTORE:
+       /* we just check the basic input types and that the           */
+       /* destination is an array of references. Assignability to    */
+       /* the actual array must be checked at runtime, each time the */
+       /* instruction is performed. (See builtin_canstore.)          */
+       if (!TYPEINFO_MAYBE_ARRAY_OF_REFS(OP1->typeinfo))
+               VERIFY_ERROR("illegal instruction: AASTORE to non-reference array");
+       break;
+
+case ICMD_IASTORECONST:
+       if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(OP1->typeinfo, ARRAYTYPE_INT))
+               VERIFY_ERROR("Array type mismatch");
+       break;
+
+case ICMD_LASTORECONST:
+       if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(OP1->typeinfo, ARRAYTYPE_LONG))
+               VERIFY_ERROR("Array type mismatch");
+       break;
+
+case ICMD_BASTORECONST:
+       if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(OP1->typeinfo, ARRAYTYPE_BOOLEAN)
+                       && !TYPEINFO_MAYBE_PRIMITIVE_ARRAY(OP1->typeinfo, ARRAYTYPE_BYTE))
+               VERIFY_ERROR("Array type mismatch");
+       break;
+
+case ICMD_CASTORECONST:
+       if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(OP1->typeinfo, ARRAYTYPE_CHAR))
+               VERIFY_ERROR("Array type mismatch");
+       break;
+
+case ICMD_SASTORECONST:
+       if (!TYPEINFO_MAYBE_PRIMITIVE_ARRAY(OP1->typeinfo, ARRAYTYPE_SHORT))
+               VERIFY_ERROR("Array type mismatch");
+       break;
+
+       /****************************************/
+       /* ADDRESS CONSTANTS                    */
+
+case ICMD_ACONST: /* {ALL} */
+       if (IPTR->flags.bits & INS_FLAG_CLASS) {
+               /* a java.lang.Class reference */
+               TYPEINFO_INIT_JAVA_LANG_CLASS(DST->typeinfo,IPTR->sx.val.c);
+       }
+       else {
+               if (IPTR->sx.val.anyptr == NULL)
+                       TYPEINFO_INIT_NULLTYPE(DST->typeinfo);
+               else {
+                       /* string constant (or constant for builtin function) */
+                       typeinfo_init_classinfo(&(DST->typeinfo),class_java_lang_String);
+               }
+       }
+       break;
+
+       /****************************************/
+       /* CHECKCAST AND INSTANCEOF             */
+
+case ICMD_CHECKCAST: /* {ALL} */
+#if !defined(TYPECHECK_TYPEINFERER)
+       /* returnAddress is not allowed */
+       if (!TYPEINFO_IS_REFERENCE(OP1->typeinfo))
+               VERIFY_ERROR("Illegal instruction: CHECKCAST on non-reference");
+#endif
+
+    /* XXX only if narrower */
+       if (!typeinfo_init_class(&(DST->typeinfo),IPTR->sx.s23.s3.c))
+               EXCEPTION;
+       break;
+
+case ICMD_INSTANCEOF:
+       /* returnAddress is not allowed */
+       if (!TYPEINFO_IS_REFERENCE(OP1->typeinfo))
+               VERIFY_ERROR("Illegal instruction: INSTANCEOF on non-reference");
+
+       /* XXX should propagate type information to the following if-branches */
+       break;
+
+       /****************************************/
+       /* BRANCH INSTRUCTIONS                  */
+
+case ICMD_GOTO:            /* {ALL} */
+case ICMD_IFNULL:          /* {ALL} */
+case ICMD_IFNONNULL:       /* {ALL} */
+case ICMD_IFEQ:            /* {ALL} */
+case ICMD_IFNE:            /* {ALL} */
+case ICMD_IFLT:            /* {ALL} */
+case ICMD_IFGE:            /* {ALL} */
+case ICMD_IFGT:            /* {ALL} */
+case ICMD_IFLE:            /* {ALL} */
+case ICMD_IF_ICMPEQ:       /* {ALL} */
+case ICMD_IF_ICMPNE:       /* {ALL} */
+case ICMD_IF_ICMPLT:       /* {ALL} */
+case ICMD_IF_ICMPGE:       /* {ALL} */
+case ICMD_IF_ICMPGT:       /* {ALL} */
+case ICMD_IF_ICMPLE:       /* {ALL} */
+case ICMD_IF_ACMPEQ:       /* {ALL} */
+case ICMD_IF_ACMPNE:       /* {ALL} */
+
+case ICMD_IF_LEQ:          /* {ALL} */
+case ICMD_IF_LNE:          /* {ALL} */
+case ICMD_IF_LLT:          /* {ALL} */
+case ICMD_IF_LGE:          /* {ALL} */
+case ICMD_IF_LGT:          /* {ALL} */
+case ICMD_IF_LLE:          /* {ALL} */
+
+case ICMD_IF_LCMPEQ:       /* {ALL} */
+case ICMD_IF_LCMPNE:       /* {ALL} */
+case ICMD_IF_LCMPLT:       /* {ALL} */
+case ICMD_IF_LCMPGE:       /* {ALL} */
+case ICMD_IF_LCMPGT:       /* {ALL} */
+case ICMD_IF_LCMPLE:       /* {ALL} */
+       /* {RESULTNOW} */
+       TYPECHECK_COUNT(stat_ins_branch);
+
+       /* propagate stack and variables to the target block */
+       REACH(IPTR->dst);
+       break;
+
+       /****************************************/
+       /* SWITCHES                             */
+
+case ICMD_TABLESWITCH:     /* {ALL} */
+       /* {RESULTNOW} */
+       TYPECHECK_COUNT(stat_ins_switch);
+
+       table = IPTR->dst.table;
+       i = IPTR->sx.s23.s3.tablehigh
+       - IPTR->sx.s23.s2.tablelow + 1 + 1; /* plus default */
+
+       while (--i >= 0) {
+               REACH(*table);
+               table++;
+       }
+
+       LOG("switch done");
+       break;
+
+case ICMD_LOOKUPSWITCH:    /* {ALL} */
+       /* {RESULTNOW} */
+       TYPECHECK_COUNT(stat_ins_switch);
+
+       lookup = IPTR->dst.lookup;
+       i = IPTR->sx.s23.s2.lookupcount;
+       REACH(IPTR->sx.s23.s3.lookupdefault);
+
+       while (--i >= 0) {
+               REACH(lookup->target);
+               lookup++;
+       }
+
+       LOG("switch done");
+       break;
+
+
+       /****************************************/
+       /* ADDRESS RETURNS AND THROW            */
+
+case ICMD_ATHROW:
+       TYPECHECK_COUNT(stat_ins_athrow);
+       r = typeinfo_is_assignable_to_class(&OP1->typeinfo,
+                       CLASSREF_OR_CLASSINFO(class_java_lang_Throwable));
+       if (r == typecheck_FALSE)
+               VERIFY_ERROR("illegal instruction: ATHROW on non-Throwable");
+       if (r == typecheck_FAIL)
+               EXCEPTION;
+       if (r == typecheck_MAYBE) {
+               /* the check has to be postponed. we need a patcher */
+               TYPECHECK_COUNT(stat_ins_athrow_unresolved);
+               IPTR->sx.s23.s2.uc = create_unresolved_class(
+                               METHOD,
+                               /* XXX make this more efficient, use class_java_lang_Throwable
+                                * directly */
+                               class_get_classref(METHOD->clazz,utf_java_lang_Throwable),
+                               &OP1->typeinfo);
+               IPTR->flags.bits |= INS_FLAG_UNRESOLVED;
+       }
+       break;
+
+case ICMD_ARETURN:
+       TYPECHECK_COUNT(stat_ins_areturn);
+       if (!TYPEINFO_IS_REFERENCE(OP1->typeinfo))
+               VERIFY_ERROR("illegal instruction: ARETURN on non-reference");
+
+       if (STATE->returntype.type != TYPE_ADR
+                       || (r = typeinfo_is_assignable(&OP1->typeinfo,&(STATE->returntype.typeinfo)))
+                       == typecheck_FALSE)
+               VERIFY_ERROR("Return type mismatch");
+       if (r == typecheck_FAIL)
+               EXCEPTION;
+       if (r == typecheck_MAYBE) {
+               /* the check has to be postponed, we need a patcher */
+               TYPECHECK_COUNT(stat_ins_areturn_unresolved);
+               IPTR->sx.s23.s2.uc = create_unresolved_class(
+                               METHOD,
+                               METHOD->parseddesc->returntype.classref,
+                               &OP1->typeinfo);
+               IPTR->flags.bits |= INS_FLAG_UNRESOLVED;
+       }
+       goto return_tail;
+
+       /****************************************/
+       /* PRIMITIVE RETURNS                    */
+
+case ICMD_IRETURN:
+       if (STATE->returntype.type != TYPE_INT)
+               VERIFY_ERROR("Return type mismatch");
+       goto return_tail;
+
+case ICMD_LRETURN:
+       if (STATE->returntype.type != TYPE_LNG)
+               VERIFY_ERROR("Return type mismatch");
+       goto return_tail;
+
+case ICMD_FRETURN:
+       if (STATE->returntype.type != TYPE_FLT)
+               VERIFY_ERROR("Return type mismatch");
+       goto return_tail;
+
+case ICMD_DRETURN:
+       if (STATE->returntype.type != TYPE_DBL)
+               VERIFY_ERROR("Return type mismatch");
+       goto return_tail;
+
+case ICMD_RETURN:
+       if (STATE->returntype.type != TYPE_VOID)
+               VERIFY_ERROR("Return type mismatch");
+
+return_tail:
+       TYPECHECK_COUNT(stat_ins_primitive_return);
+
+       if (STATE->initmethod && METHOD->clazz != class_java_lang_Object) {
+               /* Check if the 'this' instance has been initialized. */
+               LOG("Checking <init> marker");
+#if defined(TYPECHECK_VARIABLESBASED)
+               if (!typevector_checktype(jd->var,STATE->numlocals-1,TYPE_INT))
+#else
+               if (STATE->locals[STATE->numlocals-1].type != TYPE_INT)
+#endif
+                       VERIFY_ERROR("<init> method does not initialize 'this'");
+       }
+       break;
+
+       /****************************************/
+       /* SUBROUTINE INSTRUCTIONS              */
+
+case ICMD_JSR: /* {VARIABLESBASED,TYPEINFERER} */
+       TYPEINFO_INIT_RETURNADDRESS(DST->typeinfo, BPTR->next);
+       REACH(IPTR->sx.s23.s3.jsrtarget);
+       break;
+
+case ICMD_JSR: /* {STACKBASED} */
+       /* {RESULTNOW} */
+       tbptr = IPTR->sx.s23.s3.jsrtarget.block;
+
+       TYPEINFO_INIT_RETURNADDRESS(stack[0].typeinfo, tbptr);
+       REACH_BLOCK(tbptr);
+
+       stack = typecheck_stackbased_jsr(STATE, stack, stackfloor);
+       if (stack == NULL)
+               EXCEPTION;
+       break;
+
+case ICMD_RET: /* {VARIABLESBASED,TYPEINFERER} */
+#if !defined(TYPECHECK_TYPEINFERER)
+       /* check returnAddress variable */
+       if (!typevector_checkretaddr(jd->var,IPTR->s1.varindex))
+               VERIFY_ERROR("illegal instruction: RET using non-returnAddress variable");
+#endif
+       REACH(IPTR->dst);
+       break;
+
+case ICMD_RET: /* {STACKBASED} */
+       /* {RESULTNOW} */
+       CHECK_LOCAL_TYPE(IPTR->s1.varindex, TYPE_RET);
+       if (!TYPEINFO_IS_PRIMITIVE(STATE->locals[IPTR->s1.varindex].typeinfo))
+               VERIFY_ERROR("illegal instruction: RET using non-returnAddress variable");
+
+       if (!typecheck_stackbased_ret(STATE, stack, stackfloor))
+               EXCEPTION;
+       break;
+
+       /****************************************/
+       /* INVOKATIONS                          */
+
+case ICMD_INVOKEVIRTUAL:   /* {VARIABLESBASED,TYPEINFERER} */
+case ICMD_INVOKESPECIAL:   /* {VARIABLESBASED,TYPEINFERER} */
+case ICMD_INVOKESTATIC:    /* {VARIABLESBASED,TYPEINFERER} */
+case ICMD_INVOKEINTERFACE: /* {VARIABLESBASED,TYPEINFERER} */
+       TYPECHECK_COUNT(stat_ins_invoke);
+       if (!handle_invocation(state))
+               EXCEPTION;
+       TYPECHECK_COUNTIF(INSTRUCTION_IS_UNRESOLVED(IPTR), stat_ins_invoke_unresolved);
+       break;
+
+case ICMD_INVOKEVIRTUAL:   /* {STACKBASED} */
+case ICMD_INVOKESPECIAL:   /* {STACKBASED} */
+case ICMD_INVOKESTATIC:    /* {STACKBASED} */
+case ICMD_INVOKEINTERFACE: /* {STACKBASED} */
+       TYPECHECK_COUNT(stat_ins_invoke);
+
+       INSTRUCTION_GET_METHODDESC(IPTR, md);
+       CHECK_STACK_DEPTH(md->paramslots);
+
+       if (!typecheck_stackbased_verify_invocation(STATE, stack, stackfloor))
+               EXCEPTION;
+
+       stack -= md->paramslots;
+
+       if (md->returntype.type != TYPE_VOID) {
+               if (IS_2_WORD_TYPE(md->returntype.type)) {
+                       CHECK_STACK_SPACE(2);
+                       stack += 2;
+                       stack[0].type = TYPE_VOID;
+                       stack[-1].type = md->returntype.type;
+               }
+               else {
+                       CHECK_STACK_SPACE(1);
+                       stack += 1;
+                       stack[0].type = md->returntype.type;
+               }
+       }
+       TYPECHECK_COUNTIF(INSTRUCTION_IS_UNRESOLVED(IPTR), stat_ins_invoke_unresolved);
+       break;
+
+       /****************************************/
+       /* MULTIANEWARRAY                       */
+
+case ICMD_MULTIANEWARRAY: /* {VARIABLESBASED,TYPEINFERER} */
+       if (!handle_multianewarray(STATE))
+               EXCEPTION;
+       break;
+
+case ICMD_MULTIANEWARRAY: /* {STACKBASED} */
+       if (!typecheck_stackbased_multianewarray(STATE, stack, stackfloor))
+               EXCEPTION;
+       stack -= (IPTR->s1.argcount - 1);
+       stack[0].type = TYPE_ADR;
+       break;
+
+       /****************************************/
+       /* BUILTINS                             */
+
+case ICMD_BUILTIN: /* {VARIABLESBASED,TYPEINFERER} */
+       TYPECHECK_COUNT(stat_ins_builtin);
+       if (!handle_builtin(state))
+               EXCEPTION;
+       break;
+
+case ICMD_BUILTIN: /* {STACKBASED} */
+       TYPECHECK_COUNT(stat_ins_builtin);
+       if (!typecheck_stackbased_verify_builtin(STATE, stack, stackfloor))
+               EXCEPTION;
+
+       /* pop operands and push return value */
+       {
+               u1 rtype = IPTR->sx.s23.s3.bte->md->returntype.type;
+               stack -=  IPTR->sx.s23.s3.bte->md->paramslots;
+               if (rtype != TYPE_VOID) {
+                       if (IS_2_WORD_TYPE(rtype))
+                               stack += 2;
+                       else
+                               stack += 1;
+               }
+       }
+       break;
+
+/* the following code is only used by the stackbased verifier */
+
+case ICMD_POP: /* {STACKBASED} */
+       /* we pop 1 */
+       CHECK_CAT1(stack[0]);
+       break;
+
+case ICMD_POP2: /* {STACKBASED} */
+       /* we pop either 11 or 2 */
+       if (IS_CAT1(stack[0]))
+               CHECK_CAT1(stack[-1]);
+       break;
+
+case ICMD_SWAP: /* {STACKBASED} */
+       CHECK_CAT1(stack[0]);
+       CHECK_CAT1(stack[-1]);
+
+       COPY_SLOT(stack[ 0], temp     );
+       COPY_SLOT(stack[-1], stack[ 0]);
+       COPY_SLOT(temp     , stack[-1]);
+       break;
+
+case ICMD_DUP: /* {STACKBASED} */
+       /* we dup 1 */
+       CHECK_CAT1(stack[0]);
+
+       COPY_SLOT(stack[ 0], stack[ 1]);
+       break;
+
+case ICMD_DUP_X1: /* {STACKBASED} */
+       /* we dup 1 */
+       CHECK_CAT1(stack[0]);
+       /* we skip 1 */
+       CHECK_CAT1(stack[-1]);
+
+       COPY_SLOT(stack[ 0], stack[ 1]);
+       COPY_SLOT(stack[-1], stack[ 0]);
+       COPY_SLOT(stack[ 1], stack[-1]);
+       break;
+
+case ICMD_DUP_X2: /* {STACKBASED} */
+       /* we dup 1 */
+       CHECK_CAT1(stack[0]);
+       /* we skip either 11 or 2 */
+       if (IS_CAT1(stack[-1]))
+               CHECK_CAT1(stack[-2]);
+
+       COPY_SLOT(stack[ 0], stack[ 1]);
+       COPY_SLOT(stack[-1], stack[ 0]);
+       COPY_SLOT(stack[-2], stack[-1]);
+       COPY_SLOT(stack[ 1], stack[-2]);
+       break;
+
+case ICMD_DUP2: /* {STACKBASED} */
+       /* we dup either 11 or 2 */
+       if (IS_CAT1(stack[0]))
+               CHECK_CAT1(stack[-1]);
+
+       COPY_SLOT(stack[ 0], stack[ 2]);
+       COPY_SLOT(stack[-1], stack[ 1]);
+       break;
+
+case ICMD_DUP2_X1: /* {STACKBASED} */
+       /* we dup either 11 or 2 */
+       if (IS_CAT1(stack[0]))
+               CHECK_CAT1(stack[-1]);
+       /* we skip 1 */
+       CHECK_CAT1(stack[-2]);
+
+       COPY_SLOT(stack[ 0], stack[ 2]);
+       COPY_SLOT(stack[-1], stack[ 1]);
+       COPY_SLOT(stack[-2], stack[ 0]);
+       COPY_SLOT(stack[ 2], stack[-1]);
+       COPY_SLOT(stack[ 1], stack[-2]);
+       break;
+
+case ICMD_DUP2_X2: /* {STACKBASED} */
+       /* we dup either 11 or 2 */
+       if (IS_CAT1(stack[0]))
+               CHECK_CAT1(stack[-1]);
+       /* we skip either 11 or 2 */
+       if (IS_CAT1(stack[-2]))
+               CHECK_CAT1(stack[-3]);
+
+       COPY_SLOT(stack[ 0], stack[ 2]);
+       COPY_SLOT(stack[-1], stack[ 1]);
+       COPY_SLOT(stack[-2], stack[ 0]);
+       COPY_SLOT(stack[-3], stack[-1]);
+       COPY_SLOT(stack[ 2], stack[-2]);
+       COPY_SLOT(stack[ 1], stack[-3]);
+       break;
+
+
+/* this marker is needed by generate.pl: */
+/* {END_OF_CODE} */
+
+/*
+ * 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
+ * Emacs will automagically detect them.
+ * ---------------------------------------------------------------------
+ * Local variables:
+ * mode: c
+ * indent-tabs-mode: t
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ * vim:noexpandtab:sw=4:ts=4:
+ */
diff --git a/src/vm/jit/verify/typecheck-common.c b/src/vm/jit/verify/typecheck-common.c
deleted file mode 100644 (file)
index 7b2cdd1..0000000
+++ /dev/null
@@ -1,552 +0,0 @@
-/* src/vm/jit/verify/typecheck-common.c - shared verifier code
-
-   Copyright (C) 1996-2005, 2006, 2008
-   CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
-
-   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., 51 Franklin Street, Fifth Floor, Boston, MA
-   02110-1301, USA.
-
-*/
-
-
-#include "config.h"
-#include "vm/types.h"
-#include "vm/global.h"
-
-#include <assert.h>
-
-#include "vm/exceptions.hpp"
-#include "vm/globals.hpp"
-
-#include "vm/jit/show.hpp"
-
-#include "typecheck-common.h"
-
-
-/****************************************************************************/
-/* DEBUG HELPERS                                                            */
-/****************************************************************************/
-
-#ifdef TYPECHECK_VERBOSE_OPT
-bool opt_typecheckverbose = false;
-#endif
-
-#if defined(TYPECHECK_VERBOSE) || defined(TYPECHECK_VERBOSE_IMPORTANT)
-
-void typecheck_print_var(FILE *file, jitdata *jd, s4 index)
-{
-       varinfo *var;
-
-       assert(index >= 0 && index < jd->varcount);
-       var = VAR(index);
-       typeinfo_print_type(file, var->type, &(var->typeinfo));
-}
-
-void typecheck_print_vararray(FILE *file, jitdata *jd, s4 *vars, int len)
-{
-       s4 i;
-
-       for (i=0; i<len; ++i) {
-               if (i)
-                       fputc(' ', file);
-               typecheck_print_var(file, jd, *vars++);
-       }
-}
-
-#endif /* defined(TYPECHECK_VERBOSE) || defined(TYPECHECK_VERBOSE_IMPORTANT) */
-
-
-/****************************************************************************/
-/* STATISTICS                                                               */
-/****************************************************************************/
-
-#if defined(TYPECHECK_STATISTICS)
-int stat_typechecked = 0;
-int stat_methods_with_handlers = 0;
-int stat_methods_maythrow = 0;
-int stat_iterations[STAT_ITERATIONS+1] = { 0 };
-int stat_reached = 0;
-int stat_copied = 0;
-int stat_merged = 0;
-int stat_merging_changed = 0;
-int stat_blocks[STAT_BLOCKS+1] = { 0 };
-int stat_locals[STAT_LOCALS+1] = { 0 };
-int stat_ins = 0;
-int stat_ins_maythrow = 0;
-int stat_ins_stack = 0;
-int stat_ins_field = 0;
-int stat_ins_field_unresolved = 0;
-int stat_ins_field_uninitialized = 0;
-int stat_ins_invoke = 0;
-int stat_ins_invoke_unresolved = 0;
-int stat_ins_primload = 0;
-int stat_ins_aload = 0;
-int stat_ins_builtin = 0;
-int stat_ins_builtin_gen = 0;
-int stat_ins_branch = 0;
-int stat_ins_switch = 0;
-int stat_ins_primitive_return = 0;
-int stat_ins_areturn = 0;
-int stat_ins_areturn_unresolved = 0;
-int stat_ins_athrow = 0;
-int stat_ins_athrow_unresolved = 0;
-int stat_ins_unchecked = 0;
-int stat_handlers_reached = 0;
-int stat_savedstack = 0;
-
-static void print_freq(FILE *file,int *array,int limit)
-{
-       int i;
-       for (i=0; i<limit; ++i)
-               fprintf(file,"      %3d: %8d\n",i,array[i]);
-       fprintf(file,"    >=%3d: %8d\n",limit,array[limit]);
-}
-
-void typecheck_print_statistics(FILE *file) {
-       fprintf(file,"typechecked methods: %8d\n",stat_typechecked);
-       fprintf(file,"    with handler(s): %8d\n",stat_methods_with_handlers);
-       fprintf(file,"    with throw(s)  : %8d\n",stat_methods_maythrow);
-       fprintf(file,"reached blocks     : %8d\n",stat_reached);
-       fprintf(file,"copied states      : %8d\n",stat_copied);
-       fprintf(file,"merged states      : %8d\n",stat_merged);
-       fprintf(file,"merging changed    : %8d\n",stat_merging_changed);
-       fprintf(file,"handlers reached   : %8d\n",stat_handlers_reached);
-       fprintf(file,"saved stack (times): %8d\n",stat_savedstack);
-       fprintf(file,"instructions       : %8d\n",stat_ins);
-       fprintf(file,"    stack          : %8d\n",stat_ins_stack);
-       fprintf(file,"    field access   : %8d\n",stat_ins_field);
-       fprintf(file,"      (unresolved) : %8d\n",stat_ins_field_unresolved);
-       fprintf(file,"      (uninit.)    : %8d\n",stat_ins_field_uninitialized);
-       fprintf(file,"    invocations    : %8d\n",stat_ins_invoke);
-       fprintf(file,"      (unresolved) : %8d\n",stat_ins_invoke_unresolved);
-       fprintf(file,"    load primitive : (currently not counted) %8d\n",stat_ins_primload);
-       fprintf(file,"    load address   : %8d\n",stat_ins_aload);
-       fprintf(file,"    builtins       : %8d\n",stat_ins_builtin);
-       fprintf(file,"        generic    : %8d\n",stat_ins_builtin_gen);
-       fprintf(file,"    branches       : %8d\n",stat_ins_branch);
-       fprintf(file,"    switches       : %8d\n",stat_ins_switch);
-       fprintf(file,"    prim. return   : %8d\n",stat_ins_primitive_return);
-       fprintf(file,"    areturn        : %8d\n",stat_ins_areturn);
-       fprintf(file,"      (unresolved) : %8d\n",stat_ins_areturn_unresolved);
-       fprintf(file,"    athrow         : %8d\n",stat_ins_athrow);
-       fprintf(file,"      (unresolved) : %8d\n",stat_ins_athrow_unresolved);
-       fprintf(file,"    unchecked      : %8d\n",stat_ins_unchecked);
-       fprintf(file,"    maythrow       : %8d\n",stat_ins_maythrow);
-       fprintf(file,"iterations used:\n");
-       print_freq(file,stat_iterations,STAT_ITERATIONS);
-       fprintf(file,"basic blocks per method / 10:\n");
-       print_freq(file,stat_blocks,STAT_BLOCKS);
-       fprintf(file,"locals:\n");
-       print_freq(file,stat_locals,STAT_LOCALS);
-}
-#endif /* defined(TYPECHECK_STATISTICS) */
-
-
-/* typecheck_init_flags ********************************************************
-   Initialize the basic block flags for the following CFG traversal.
-  
-   IN:
-       state............the current state of the verifier
-       minflags.........minimum flags value of blocks that should be
-                        considered
-
-*******************************************************************************/
-
-void typecheck_init_flags(verifier_state *state, s4 minflags)
-{
-       basicblock *block;
-
-    /* set all BBFINISHED blocks to BBTYPECHECK_UNDEF. */
-       
-    for (block = state->basicblocks; block; block = block->next) {
-               
-#ifdef TYPECHECK_DEBUG
-               /* check for invalid flags */
-        if (block->flags != BBFINISHED && block->flags != BBDELETED && block->flags != BBUNDEF)
-        {
-            LOGSTR1("block flags: %d\n",block->flags); LOGFLUSH;
-                       TYPECHECK_ASSERT(false);
-        }
-#endif
-
-        if (block->flags >= minflags) {
-            block->flags = BBTYPECHECK_UNDEF;
-        }
-    }
-
-    /* the first block is always reached */
-       
-    if (state->basicblockcount && state->basicblocks[0].flags == BBTYPECHECK_UNDEF)
-        state->basicblocks[0].flags = BBTYPECHECK_REACHED;
-}
-
-
-/* typecheck_reset_flags *******************************************************
-   Reset the flags of basic blocks we have not reached.
-  
-   IN:
-       state............the current state of the verifier
-
-*******************************************************************************/
-
-void typecheck_reset_flags(verifier_state *state)
-{
-       basicblock *block;
-
-       /* check for invalid flags at exit */
-       
-#ifdef TYPECHECK_DEBUG
-       for (block = state->basicblocks; block; block = block->next) {
-               if (block->flags != BBDELETED
-                       && block->flags != BBUNDEF
-                       && block->flags != BBFINISHED
-                       && block->flags != BBTYPECHECK_UNDEF) /* typecheck may never reach
-                                                                                                        * some exception handlers,
-                                                                                                        * that's ok. */
-               {
-                       LOG2("block L%03d has invalid flags after typecheck: %d",
-                                block->nr,block->flags);
-                       TYPECHECK_ASSERT(false);
-               }
-       }
-#endif
-       
-       /* Delete blocks we never reached */
-       
-       for (block = state->basicblocks; block; block = block->next) {
-               if (block->flags == BBTYPECHECK_UNDEF)
-                       block->flags = BBDELETED;
-       }
-}
-
-
-/****************************************************************************/
-/* TYPESTACK MACROS AND FUNCTIONS                                           */
-/*                                                                          */
-/* These macros and functions act on the 'type stack', which is a shorthand */
-/* for the types of the stackslots of the current stack. The type of a      */
-/* stack slot is usually described by a TYPE_* constant and -- for TYPE_ADR */
-/* -- by the typeinfo of the slot. The only thing that makes the type stack */
-/* more complicated are returnAddresses of local subroutines, because a     */
-/* single stack slot may contain a set of more than one possible return     */
-/* address. This is handled by 'return address sets'. A return address set  */
-/* is kept as a linked list dangling off the typeinfo of the stack slot.    */
-/****************************************************************************/
-
-/* typecheck_copy_types ********************************************************
-
-   Copy the types of the source variables to the destination variables.
-
-   IN:
-          state............current verifier state
-          srcvars..........array of variable indices to copy
-          dstvars..........array of the destination variables
-          n................number of variables to copy
-
-   RETURN VALUE:
-       true.............success
-          false............an exception has been thrown
-
-*******************************************************************************/
-
-bool typecheck_copy_types(verifier_state *state, s4 *srcvars, s4 *dstvars, s4 n)
-{
-       s4 i;
-       varinfo *sv;
-       varinfo *dv;
-       jitdata *jd = state->jd;
-
-       for (i=0; i < n; ++i, ++srcvars, ++dstvars) {
-               sv = VAR(*srcvars);
-               dv = VAR(*dstvars);
-
-               dv->type = sv->type;
-               if (dv->type == TYPE_ADR) {
-                       TYPEINFO_CLONE(sv->typeinfo,dv->typeinfo);
-               }
-       }
-       return true;
-}
-
-
-/* typecheck_merge_types *******************************************************
-
-   Merge the types of the source variables into the destination variables.
-
-   IN:
-       state............current state of the verifier
-          srcvars..........source variable indices
-          dstvars..........destination variable indices
-          n................number of variables
-
-   RETURN VALUE:
-       typecheck_TRUE...the destination variables have been modified
-          typecheck_FALSE..the destination variables are unchanged
-          typecheck_FAIL...an exception has been thrown
-
-*******************************************************************************/
-
-typecheck_result typecheck_merge_types(verifier_state *state,
-                                                                          s4 *srcvars,
-                                                                          s4 *dstvars,
-                                                                          s4 n)
-{
-       s4 i;
-       varinfo *sv;
-       varinfo *dv;
-       jitdata *jd = state->jd;
-       typecheck_result r;
-       bool changed = false;
-
-       for (i=0; i < n; ++i, ++srcvars, ++dstvars) {
-               sv = VAR(*srcvars);
-               dv = VAR(*dstvars);
-
-               if (dv->type != sv->type) {
-                       exceptions_throw_verifyerror(state->m,"Stack type mismatch");
-                       return typecheck_FAIL;
-               }
-               if (dv->type == TYPE_ADR) {
-                       if (TYPEINFO_IS_PRIMITIVE(dv->typeinfo)) {
-                               /* dv has returnAddress type */
-                               if (!TYPEINFO_IS_PRIMITIVE(sv->typeinfo)) {
-                                       exceptions_throw_verifyerror(state->m,"Merging returnAddress with reference");
-                                       return typecheck_FAIL;
-                               }
-                       }
-                       else {
-                               /* dv has reference type */
-                               if (TYPEINFO_IS_PRIMITIVE(sv->typeinfo)) {
-                                       exceptions_throw_verifyerror(state->m,"Merging reference with returnAddress");
-                                       return typecheck_FAIL;
-                               }
-                               r = typeinfo_merge(state->m,&(dv->typeinfo),&(sv->typeinfo));
-                               if (r == typecheck_FAIL)
-                                       return r;
-                               changed |= r;
-                       }
-               }
-       }
-       return changed;
-}
-
-
-/* typestate_merge *************************************************************
-
-   Merge the types of one state into the destination state.
-
-   IN:
-       state............current state of the verifier
-          dstvars..........indices of the destinations invars
-          dstlocals........the destinations inlocals
-          srcvars..........indices of the source's outvars
-          srclocals........the source locals
-          n................number of invars (== number of outvars)
-
-   RETURN VALUE:
-       typecheck_TRUE...destination state has been modified
-          typecheck_FALSE..destination state has not been modified
-          typecheck_FAIL...an exception has been thrown
-
-*******************************************************************************/
-
-typecheck_result typestate_merge(verifier_state *state,
-                                                s4 *srcvars, varinfo *srclocals,
-                                                s4 *dstvars, varinfo *dstlocals,
-                                                s4 n)
-{
-       bool changed = false;
-       typecheck_result r;
-
-       /* The stack is always merged. If there are returnAddresses on
-        * the stack they are ignored in this step. */
-
-       r = typecheck_merge_types(state, srcvars, dstvars, n);
-       if (r == typecheck_FAIL)
-               return r;
-       changed |= r;
-
-       /* merge the locals */
-
-       r = typevector_merge(state->m, dstlocals, srclocals, state->numlocals);
-       if (r == typecheck_FAIL)
-               return r;
-       return changed | r;
-}
-
-
-/* typestate_reach *************************************************************
-
-   Reach a destination block and propagate stack and local variable types
-
-   IN:
-       state............current state of the verifier
-          destblock........destination basic block
-          srcvars..........variable indices of the outvars to propagate
-          srclocals........local variables to propagate
-          n................number of srcvars
-
-   OUT:
-       state->repeat....set to true if the verifier must iterate again
-                           over the basic blocks
-
-   RETURN VALUE:
-       true.............success
-          false............an exception has been thrown
-
-*******************************************************************************/
-
-bool typestate_reach(verifier_state *state,
-                                        basicblock *destblock,
-                                        s4 *srcvars, varinfo *srclocals, s4 n)
-{
-       varinfo *destloc;
-       bool changed = false;
-       typecheck_result r;
-
-       LOG1("reaching block L%03d",destblock->nr);
-       TYPECHECK_COUNT(stat_reached);
-
-       destloc = destblock->inlocals;
-
-       if (destblock->flags == BBTYPECHECK_UNDEF) {
-               /* The destblock has never been reached before */
-
-               TYPECHECK_COUNT(stat_copied);
-               LOG1("block L%03d reached first time",destblock->nr);
-
-               if (!typecheck_copy_types(state, srcvars, destblock->invars, n))
-                       return false;
-               typevector_copy_inplace(srclocals, destloc, state->numlocals);
-               changed = true;
-       }
-       else {
-               /* The destblock has already been reached before */
-
-               TYPECHECK_COUNT(stat_merged);
-               LOG1("block L%03d reached before", destblock->nr);
-
-               r = typestate_merge(state, srcvars, srclocals,
-                               destblock->invars, destblock->inlocals, n);
-               if (r == typecheck_FAIL)
-                       return false;
-               changed = r;
-               TYPECHECK_COUNTIF(changed,stat_merging_changed);
-       }
-
-       if (changed) {
-               LOG("changed!");
-               destblock->flags = BBTYPECHECK_REACHED;
-               if (destblock->nr <= state->bptr->nr) {
-                       LOG("REPEAT!");
-                       state->repeat = true;
-               }
-       }
-       return true;
-}
-
-
-/* typecheck_init_locals *******************************************************
-
-   Initialize the local variables in the verifier state.
-
-   IN:
-       state............the current state of the verifier
-          newthis..........if true, mark the instance in <init> methods as
-                           uninitialized object.
-
-   RETURN VALUE:
-       true.............success,
-          false............an exception has been thrown.
-
-*******************************************************************************/
-
-bool typecheck_init_locals(verifier_state *state, bool newthis)
-{
-       int i;
-       int varindex;
-       varinfo *locals;
-       varinfo *v;
-       jitdata *jd = state->jd;
-       int skip = 0;
-
-       locals = state->basicblocks[0].inlocals;
-
-       /* allocate parameter descriptors if necessary */
-
-       if (!state->m->parseddesc->params)
-               if (!descriptor_params_from_paramtypes(state->m->parseddesc,state->m->flags))
-                       return false;
-
-       /* pre-initialize variables as TYPE_VOID */
-
-       i = state->numlocals;
-       v = locals;
-       while (i--) {
-               v->type = TYPE_VOID;
-               v++;
-       }
-
-    /* if this is an instance method initialize the "this" ref type */
-
-    if (!(state->m->flags & ACC_STATIC)) {
-               varindex = jd->local_map[5*0 + TYPE_ADR];
-               if (varindex != UNUSED) {
-                       if (state->validlocals < 1)
-                               TYPECHECK_VERIFYERROR_bool("Not enough local variables for method arguments");
-                       v = locals + varindex;
-                       v->type = TYPE_ADR;
-                       if (state->initmethod && newthis)
-                               TYPEINFO_INIT_NEWOBJECT(v->typeinfo, NULL);
-                       else
-                               typeinfo_init_classinfo(&(v->typeinfo), state->m->clazz);
-               }
-
-               skip = 1;
-    }
-
-    LOG("'this' argument set.\n");
-
-    /* the rest of the arguments and the return type */
-
-    if (!typeinfo_init_varinfos_from_methoddesc(locals, state->m->parseddesc,
-                                                                                         state->validlocals,
-                                                                                         skip, /* skip 'this' pointer */
-                                                                                         jd->local_map,
-                                                                                         &state->returntype))
-               return false;
-
-    LOG("Arguments set.\n");
-       return true;
-}
-
-
-/*
- * 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
- * Emacs will automagically detect them.
- * ---------------------------------------------------------------------
- * Local variables:
- * mode: c
- * indent-tabs-mode: t
- * c-basic-offset: 4
- * tab-width: 4
- * End:
- * vim:noexpandtab:sw=4:ts=4:
- */
diff --git a/src/vm/jit/verify/typecheck-common.cpp b/src/vm/jit/verify/typecheck-common.cpp
new file mode 100644 (file)
index 0000000..62818a1
--- /dev/null
@@ -0,0 +1,558 @@
+/* src/vm/jit/verify/typecheck-common.c - shared verifier code
+
+   Copyright (C) 1996-2005, 2006, 2008
+   CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
+
+   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., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301, USA.
+
+*/
+
+
+#include "config.h"
+#include "vm/types.h"
+#include "vm/global.h"
+
+#include <assert.h>
+
+#include "vm/exceptions.hpp"
+#include "vm/globals.hpp"
+
+#include "vm/jit/show.hpp"
+
+#include "typecheck-common.hpp"
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/****************************************************************************/
+/* DEBUG HELPERS                                                            */
+/****************************************************************************/
+
+#ifdef TYPECHECK_VERBOSE_OPT
+bool opt_typecheckverbose = false;
+#endif
+
+#if defined(TYPECHECK_VERBOSE) || defined(TYPECHECK_VERBOSE_IMPORTANT)
+
+void typecheck_print_var(FILE *file, jitdata *jd, s4 index)
+{
+       varinfo *var;
+
+       assert(index >= 0 && index < jd->varcount);
+       var = VAR(index);
+       typeinfo_print_type(file, var->type, &(var->typeinfo));
+}
+
+void typecheck_print_vararray(FILE *file, jitdata *jd, s4 *vars, int len)
+{
+       s4 i;
+
+       for (i=0; i<len; ++i) {
+               if (i)
+                       fputc(' ', file);
+               typecheck_print_var(file, jd, *vars++);
+       }
+}
+
+#endif /* defined(TYPECHECK_VERBOSE) || defined(TYPECHECK_VERBOSE_IMPORTANT) */
+
+
+/****************************************************************************/
+/* STATISTICS                                                               */
+/****************************************************************************/
+
+#if defined(TYPECHECK_STATISTICS)
+int stat_typechecked = 0;
+int stat_methods_with_handlers = 0;
+int stat_methods_maythrow = 0;
+int stat_iterations[STAT_ITERATIONS+1] = { 0 };
+int stat_reached = 0;
+int stat_copied = 0;
+int stat_merged = 0;
+int stat_merging_changed = 0;
+int stat_blocks[STAT_BLOCKS+1] = { 0 };
+int stat_locals[STAT_LOCALS+1] = { 0 };
+int stat_ins = 0;
+int stat_ins_maythrow = 0;
+int stat_ins_stack = 0;
+int stat_ins_field = 0;
+int stat_ins_field_unresolved = 0;
+int stat_ins_field_uninitialized = 0;
+int stat_ins_invoke = 0;
+int stat_ins_invoke_unresolved = 0;
+int stat_ins_primload = 0;
+int stat_ins_aload = 0;
+int stat_ins_builtin = 0;
+int stat_ins_builtin_gen = 0;
+int stat_ins_branch = 0;
+int stat_ins_switch = 0;
+int stat_ins_primitive_return = 0;
+int stat_ins_areturn = 0;
+int stat_ins_areturn_unresolved = 0;
+int stat_ins_athrow = 0;
+int stat_ins_athrow_unresolved = 0;
+int stat_ins_unchecked = 0;
+int stat_handlers_reached = 0;
+int stat_savedstack = 0;
+
+static void print_freq(FILE *file,int *array,int limit)
+{
+       int i;
+       for (i=0; i<limit; ++i)
+               fprintf(file,"      %3d: %8d\n",i,array[i]);
+       fprintf(file,"    >=%3d: %8d\n",limit,array[limit]);
+}
+
+void typecheck_print_statistics(FILE *file) {
+       fprintf(file,"typechecked methods: %8d\n",stat_typechecked);
+       fprintf(file,"    with handler(s): %8d\n",stat_methods_with_handlers);
+       fprintf(file,"    with throw(s)  : %8d\n",stat_methods_maythrow);
+       fprintf(file,"reached blocks     : %8d\n",stat_reached);
+       fprintf(file,"copied states      : %8d\n",stat_copied);
+       fprintf(file,"merged states      : %8d\n",stat_merged);
+       fprintf(file,"merging changed    : %8d\n",stat_merging_changed);
+       fprintf(file,"handlers reached   : %8d\n",stat_handlers_reached);
+       fprintf(file,"saved stack (times): %8d\n",stat_savedstack);
+       fprintf(file,"instructions       : %8d\n",stat_ins);
+       fprintf(file,"    stack          : %8d\n",stat_ins_stack);
+       fprintf(file,"    field access   : %8d\n",stat_ins_field);
+       fprintf(file,"      (unresolved) : %8d\n",stat_ins_field_unresolved);
+       fprintf(file,"      (uninit.)    : %8d\n",stat_ins_field_uninitialized);
+       fprintf(file,"    invocations    : %8d\n",stat_ins_invoke);
+       fprintf(file,"      (unresolved) : %8d\n",stat_ins_invoke_unresolved);
+       fprintf(file,"    load primitive : (currently not counted) %8d\n",stat_ins_primload);
+       fprintf(file,"    load address   : %8d\n",stat_ins_aload);
+       fprintf(file,"    builtins       : %8d\n",stat_ins_builtin);
+       fprintf(file,"        generic    : %8d\n",stat_ins_builtin_gen);
+       fprintf(file,"    branches       : %8d\n",stat_ins_branch);
+       fprintf(file,"    switches       : %8d\n",stat_ins_switch);
+       fprintf(file,"    prim. return   : %8d\n",stat_ins_primitive_return);
+       fprintf(file,"    areturn        : %8d\n",stat_ins_areturn);
+       fprintf(file,"      (unresolved) : %8d\n",stat_ins_areturn_unresolved);
+       fprintf(file,"    athrow         : %8d\n",stat_ins_athrow);
+       fprintf(file,"      (unresolved) : %8d\n",stat_ins_athrow_unresolved);
+       fprintf(file,"    unchecked      : %8d\n",stat_ins_unchecked);
+       fprintf(file,"    maythrow       : %8d\n",stat_ins_maythrow);
+       fprintf(file,"iterations used:\n");
+       print_freq(file,stat_iterations,STAT_ITERATIONS);
+       fprintf(file,"basic blocks per method / 10:\n");
+       print_freq(file,stat_blocks,STAT_BLOCKS);
+       fprintf(file,"locals:\n");
+       print_freq(file,stat_locals,STAT_LOCALS);
+}
+#endif /* defined(TYPECHECK_STATISTICS) */
+
+
+/* typecheck_init_flags ********************************************************
+   Initialize the basic block flags for the following CFG traversal.
+  
+   IN:
+       state............the current state of the verifier
+       minflags.........minimum flags value of blocks that should be
+                        considered
+
+*******************************************************************************/
+
+void typecheck_init_flags(verifier_state *state, s4 minflags)
+{
+       basicblock *block;
+
+    /* set all BBFINISHED blocks to BBTYPECHECK_UNDEF. */
+       
+    for (block = state->basicblocks; block; block = block->next) {
+               
+#ifdef TYPECHECK_DEBUG
+               /* check for invalid flags */
+        if (block->flags != BBFINISHED && block->flags != BBDELETED && block->flags != BBUNDEF)
+        {
+            LOGSTR1("block flags: %d\n",block->flags); LOGFLUSH;
+                       TYPECHECK_ASSERT(false);
+        }
+#endif
+
+        if (block->flags >= minflags) {
+            block->flags = BBTYPECHECK_UNDEF;
+        }
+    }
+
+    /* the first block is always reached */
+       
+    if (state->basicblockcount && state->basicblocks[0].flags == BBTYPECHECK_UNDEF)
+        state->basicblocks[0].flags = BBTYPECHECK_REACHED;
+}
+
+
+/* typecheck_reset_flags *******************************************************
+   Reset the flags of basic blocks we have not reached.
+  
+   IN:
+       state............the current state of the verifier
+
+*******************************************************************************/
+
+void typecheck_reset_flags(verifier_state *state)
+{
+       basicblock *block;
+
+       /* check for invalid flags at exit */
+       
+#ifdef TYPECHECK_DEBUG
+       for (block = state->basicblocks; block; block = block->next) {
+               if (block->flags != BBDELETED
+                       && block->flags != BBUNDEF
+                       && block->flags != BBFINISHED
+                       && block->flags != BBTYPECHECK_UNDEF) /* typecheck may never reach
+                                                                                                        * some exception handlers,
+                                                                                                        * that's ok. */
+               {
+                       LOG2("block L%03d has invalid flags after typecheck: %d",
+                                block->nr,block->flags);
+                       TYPECHECK_ASSERT(false);
+               }
+       }
+#endif
+       
+       /* Delete blocks we never reached */
+       
+       for (block = state->basicblocks; block; block = block->next) {
+               if (block->flags == BBTYPECHECK_UNDEF)
+                       block->flags = BBDELETED;
+       }
+}
+
+
+/****************************************************************************/
+/* TYPESTACK MACROS AND FUNCTIONS                                           */
+/*                                                                          */
+/* These macros and functions act on the 'type stack', which is a shorthand */
+/* for the types of the stackslots of the current stack. The type of a      */
+/* stack slot is usually described by a TYPE_* constant and -- for TYPE_ADR */
+/* -- by the typeinfo of the slot. The only thing that makes the type stack */
+/* more complicated are returnAddresses of local subroutines, because a     */
+/* single stack slot may contain a set of more than one possible return     */
+/* address. This is handled by 'return address sets'. A return address set  */
+/* is kept as a linked list dangling off the typeinfo of the stack slot.    */
+/****************************************************************************/
+
+/* typecheck_copy_types ********************************************************
+
+   Copy the types of the source variables to the destination variables.
+
+   IN:
+          state............current verifier state
+          srcvars..........array of variable indices to copy
+          dstvars..........array of the destination variables
+          n................number of variables to copy
+
+   RETURN VALUE:
+       true.............success
+          false............an exception has been thrown
+
+*******************************************************************************/
+
+bool typecheck_copy_types(verifier_state *state, s4 *srcvars, s4 *dstvars, s4 n)
+{
+       s4 i;
+       varinfo *sv;
+       varinfo *dv;
+       jitdata *jd = state->jd;
+
+       for (i=0; i < n; ++i, ++srcvars, ++dstvars) {
+               sv = VAR(*srcvars);
+               dv = VAR(*dstvars);
+
+               dv->type = sv->type;
+               if (dv->type == TYPE_ADR) {
+                       TYPEINFO_CLONE(sv->typeinfo,dv->typeinfo);
+               }
+       }
+       return true;
+}
+
+
+/* typecheck_merge_types *******************************************************
+
+   Merge the types of the source variables into the destination variables.
+
+   IN:
+       state............current state of the verifier
+          srcvars..........source variable indices
+          dstvars..........destination variable indices
+          n................number of variables
+
+   RETURN VALUE:
+       typecheck_TRUE...the destination variables have been modified
+          typecheck_FALSE..the destination variables are unchanged
+          typecheck_FAIL...an exception has been thrown
+
+*******************************************************************************/
+
+typecheck_result typecheck_merge_types(verifier_state *state,
+                                                                          s4 *srcvars,
+                                                                          s4 *dstvars,
+                                                                          s4 n)
+{
+       s4 i;
+       varinfo *sv;
+       varinfo *dv;
+       jitdata *jd = state->jd;
+       typecheck_result r;
+       bool changed = false;
+
+       for (i=0; i < n; ++i, ++srcvars, ++dstvars) {
+               sv = VAR(*srcvars);
+               dv = VAR(*dstvars);
+
+               if (dv->type != sv->type) {
+                       exceptions_throw_verifyerror(state->m,"Stack type mismatch");
+                       return typecheck_FAIL;
+               }
+               if (dv->type == TYPE_ADR) {
+                       if (TYPEINFO_IS_PRIMITIVE(dv->typeinfo)) {
+                               /* dv has returnAddress type */
+                               if (!TYPEINFO_IS_PRIMITIVE(sv->typeinfo)) {
+                                       exceptions_throw_verifyerror(state->m,"Merging returnAddress with reference");
+                                       return typecheck_FAIL;
+                               }
+                       }
+                       else {
+                               /* dv has reference type */
+                               if (TYPEINFO_IS_PRIMITIVE(sv->typeinfo)) {
+                                       exceptions_throw_verifyerror(state->m,"Merging reference with returnAddress");
+                                       return typecheck_FAIL;
+                               }
+                               r = typeinfo_merge(state->m,&(dv->typeinfo),&(sv->typeinfo));
+                               if (r == typecheck_FAIL)
+                                       return r;
+                               changed |= r;
+                       }
+               }
+       }
+       return (typecheck_result) changed;
+}
+
+
+/* typestate_merge *************************************************************
+
+   Merge the types of one state into the destination state.
+
+   IN:
+       state............current state of the verifier
+          dstvars..........indices of the destinations invars
+          dstlocals........the destinations inlocals
+          srcvars..........indices of the source's outvars
+          srclocals........the source locals
+          n................number of invars (== number of outvars)
+
+   RETURN VALUE:
+       typecheck_TRUE...destination state has been modified
+          typecheck_FALSE..destination state has not been modified
+          typecheck_FAIL...an exception has been thrown
+
+*******************************************************************************/
+
+typecheck_result typestate_merge(verifier_state *state,
+                                                s4 *srcvars, varinfo *srclocals,
+                                                s4 *dstvars, varinfo *dstlocals,
+                                                s4 n)
+{
+       bool changed = false;
+       typecheck_result r;
+
+       /* The stack is always merged. If there are returnAddresses on
+        * the stack they are ignored in this step. */
+
+       r = typecheck_merge_types(state, srcvars, dstvars, n);
+       if (r == typecheck_FAIL)
+               return r;
+       changed |= r;
+
+       /* merge the locals */
+
+       r = typevector_merge(state->m, dstlocals, srclocals, state->numlocals);
+       if (r == typecheck_FAIL)
+               return r;
+       return (typecheck_result) (changed | r);
+}
+
+
+/* typestate_reach *************************************************************
+
+   Reach a destination block and propagate stack and local variable types
+
+   IN:
+       state............current state of the verifier
+          destblock........destination basic block
+          srcvars..........variable indices of the outvars to propagate
+          srclocals........local variables to propagate
+          n................number of srcvars
+
+   OUT:
+       state->repeat....set to true if the verifier must iterate again
+                           over the basic blocks
+
+   RETURN VALUE:
+       true.............success
+          false............an exception has been thrown
+
+*******************************************************************************/
+
+bool typestate_reach(verifier_state *state,
+                                        basicblock *destblock,
+                                        s4 *srcvars, varinfo *srclocals, s4 n)
+{
+       varinfo *destloc;
+       bool changed = false;
+       typecheck_result r;
+
+       LOG1("reaching block L%03d",destblock->nr);
+       TYPECHECK_COUNT(stat_reached);
+
+       destloc = destblock->inlocals;
+
+       if (destblock->flags == BBTYPECHECK_UNDEF) {
+               /* The destblock has never been reached before */
+
+               TYPECHECK_COUNT(stat_copied);
+               LOG1("block L%03d reached first time",destblock->nr);
+
+               if (!typecheck_copy_types(state, srcvars, destblock->invars, n))
+                       return false;
+               typevector_copy_inplace(srclocals, destloc, state->numlocals);
+               changed = true;
+       }
+       else {
+               /* The destblock has already been reached before */
+
+               TYPECHECK_COUNT(stat_merged);
+               LOG1("block L%03d reached before", destblock->nr);
+
+               r = typestate_merge(state, srcvars, srclocals,
+                               destblock->invars, destblock->inlocals, n);
+               if (r == typecheck_FAIL)
+                       return false;
+               changed = r;
+               TYPECHECK_COUNTIF(changed,stat_merging_changed);
+       }
+
+       if (changed) {
+               LOG("changed!");
+               destblock->flags = BBTYPECHECK_REACHED;
+               if (destblock->nr <= state->bptr->nr) {
+                       LOG("REPEAT!");
+                       state->repeat = true;
+               }
+       }
+       return true;
+}
+
+
+/* typecheck_init_locals *******************************************************
+
+   Initialize the local variables in the verifier state.
+
+   IN:
+       state............the current state of the verifier
+          newthis..........if true, mark the instance in <init> methods as
+                           uninitialized object.
+
+   RETURN VALUE:
+       true.............success,
+          false............an exception has been thrown.
+
+*******************************************************************************/
+
+bool typecheck_init_locals(verifier_state *state, bool newthis)
+{
+       int i;
+       int varindex;
+       varinfo *locals;
+       varinfo *v;
+       jitdata *jd = state->jd;
+       int skip = 0;
+
+       locals = state->basicblocks[0].inlocals;
+
+       /* allocate parameter descriptors if necessary */
+
+       if (!state->m->parseddesc->params)
+               if (!descriptor_params_from_paramtypes(state->m->parseddesc,state->m->flags))
+                       return false;
+
+       /* pre-initialize variables as TYPE_VOID */
+
+       i = state->numlocals;
+       v = locals;
+       while (i--) {
+               v->type = TYPE_VOID;
+               v++;
+       }
+
+    /* if this is an instance method initialize the "this" ref type */
+
+    if (!(state->m->flags & ACC_STATIC)) {
+               varindex = jd->local_map[5*0 + TYPE_ADR];
+               if (varindex != UNUSED) {
+                       if (state->validlocals < 1)
+                               TYPECHECK_VERIFYERROR_bool("Not enough local variables for method arguments");
+                       v = locals + varindex;
+                       v->type = TYPE_ADR;
+                       if (state->initmethod && newthis)
+                               TYPEINFO_INIT_NEWOBJECT(v->typeinfo, NULL);
+                       else
+                               typeinfo_init_classinfo(&(v->typeinfo), state->m->clazz);
+               }
+
+               skip = 1;
+    }
+
+    LOG("'this' argument set.\n");
+
+    /* the rest of the arguments and the return type */
+
+    if (!typeinfo_init_varinfos_from_methoddesc(locals, state->m->parseddesc,
+                                                                                         state->validlocals,
+                                                                                         skip, /* skip 'this' pointer */
+                                                                                         jd->local_map,
+                                                                                         &state->returntype))
+               return false;
+
+    LOG("Arguments set.\n");
+       return true;
+}
+
+#if defined(__cplusplus)
+}
+#endif
+
+/*
+ * 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
+ * Emacs will automagically detect them.
+ * ---------------------------------------------------------------------
+ * Local variables:
+ * mode: c
+ * indent-tabs-mode: t
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ * vim:noexpandtab:sw=4:ts=4:
+ */
diff --git a/src/vm/jit/verify/typecheck-common.h b/src/vm/jit/verify/typecheck-common.h
deleted file mode 100644 (file)
index 226113f..0000000
+++ /dev/null
@@ -1,308 +0,0 @@
-/* src/vm/jit/verify/typecheck-common.h - internal header for the type checker
-
-   Copyright (C) 1996-2005, 2006, 2008
-   CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
-
-   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., 51 Franklin Street, Fifth Floor, Boston, MA
-   02110-1301, USA.
-
-*/
-
-
-#ifndef _TYPECHECK_COMMON_H
-#define _TYPECHECK_COMMON_H
-
-#include "config.h"
-#include "vm/types.h"
-#include "vm/global.h"
-
-#include <assert.h>
-
-#include "vm/jit/jit.hpp"
-
-
-/****************************************************************************/
-/* DEBUG HELPERS                                                            */
-/****************************************************************************/
-
-#ifdef TYPECHECK_DEBUG
-#define TYPECHECK_ASSERT(cond)  assert(cond)
-#else
-#define TYPECHECK_ASSERT(cond)
-#endif
-
-#ifdef TYPECHECK_VERBOSE_OPT
-extern bool opt_typecheckverbose;
-#define DOLOG(action)  do { if (opt_typecheckverbose) {action;} } while(0)
-#else
-#define DOLOG(action)
-#endif
-
-#ifdef TYPECHECK_VERBOSE
-#define TYPECHECK_VERBOSE_IMPORTANT
-#define LOGNL              DOLOG(puts(""))
-#define LOG(str)           DOLOG(puts(str);)
-#define LOG1(str,a)        DOLOG(printf(str,a); LOGNL)
-#define LOG2(str,a,b)      DOLOG(printf(str,a,b); LOGNL)
-#define LOG3(str,a,b,c)    DOLOG(printf(str,a,b,c); LOGNL)
-#define LOGIF(cond,str)    DOLOG(do {if (cond) { puts(str); }} while(0))
-#ifdef  TYPEINFO_DEBUG
-#define LOGINFO(info)      DOLOG(do {typeinfo_print_short(stdout,(info)); LOGNL;} while(0))
-#else
-#define LOGINFO(info)
-#define typevector_print(x,y,z)
-#endif
-#define LOGFLUSH           DOLOG(fflush(stdout))
-#define LOGSTR(str)        DOLOG(printf("%s", 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 LOGNAME(c)         DOLOG(class_classref_or_classinfo_print(c))
-#define LOGMETHOD(str,m)   DOLOG(printf("%s", str); method_println(m);)
-#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)
-#define LOGNAME(c)
-#define LOGMETHOD(str,m)
-#endif
-
-#ifdef TYPECHECK_VERBOSE_IMPORTANT
-#define LOGimp(str)     DOLOG(puts(str);LOGNL)
-#define LOGimpSTR(str)  DOLOG(puts(str))
-#else
-#define LOGimp(str)
-#define LOGimpSTR(str)
-#endif
-
-#if defined(TYPECHECK_VERBOSE) || defined(TYPECHECK_VERBOSE_IMPORTANT)
-#include <stdio.h>
-void typecheck_print_var(FILE *file, jitdata *jd, s4 index);
-void typecheck_print_vararray(FILE *file, jitdata *jd, s4 *vars, int len);
-#endif
-
-
-/****************************************************************************/
-/* STATISTICS                                                               */
-/****************************************************************************/
-
-#if defined(TYPECHECK_DEBUG) && !defined(TYPECHECK_NO_STATISTICS)
-/*#define TYPECHECK_STATISTICS*/
-#endif
-
-#ifdef TYPECHECK_STATISTICS
-#define STAT_ITERATIONS  10
-#define STAT_BLOCKS      10
-#define STAT_LOCALS      16
-
-extern int stat_typechecked;
-extern int stat_methods_with_handlers;
-extern int stat_methods_maythrow;
-extern int stat_iterations[STAT_ITERATIONS+1];
-extern int stat_reached;
-extern int stat_copied;
-extern int stat_merged;
-extern int stat_merging_changed;
-extern int stat_blocks[STAT_BLOCKS+1];
-extern int stat_locals[STAT_LOCALS+1];
-extern int stat_ins;
-extern int stat_ins_maythrow;
-extern int stat_ins_stack;
-extern int stat_ins_field;
-extern int stat_ins_field_unresolved;
-extern int stat_ins_field_uninitialized;
-extern int stat_ins_invoke;
-extern int stat_ins_invoke_unresolved;
-extern int stat_ins_primload;
-extern int stat_ins_aload;
-extern int stat_ins_builtin;
-extern int stat_ins_builtin_gen;
-extern int stat_ins_branch;
-extern int stat_ins_switch;
-extern int stat_ins_primitive_return;
-extern int stat_ins_areturn;
-extern int stat_ins_areturn_unresolved;
-extern int stat_ins_athrow;
-extern int stat_ins_athrow_unresolved;
-extern int stat_ins_unchecked;
-extern int stat_handlers_reached;
-extern int stat_savedstack;
-
-#define TYPECHECK_MARK(var)   ((var) = true)
-#define TYPECHECK_COUNT(cnt)  (cnt)++
-#define TYPECHECK_COUNTIF(cond,cnt)  do{if(cond) (cnt)++;} while(0)
-#define TYPECHECK_COUNT_FREQ(array,val,limit) \
-       do {                                                                      \
-               if ((val) < (limit)) (array)[val]++;  \
-               else (array)[limit]++;                            \
-       } while (0)
-
-void typecheck_print_statistics(FILE *file);
-
-#else /* !defined(TYPECHECK_STATISTICS) */
-                                                  
-#define TYPECHECK_COUNT(cnt)
-#define TYPECHECK_MARK(var)
-#define TYPECHECK_COUNTIF(cond,cnt)
-#define TYPECHECK_COUNT_FREQ(array,val,limit)
-
-#endif /* defined(TYPECHECK_STATISTICS) */
-
-
-/****************************************************************************/
-/* MACROS FOR THROWING EXCEPTIONS                                           */
-/****************************************************************************/
-
-#define TYPECHECK_VERIFYERROR_ret(m,msg,retval)                      \
-    do {                                                             \
-        exceptions_throw_verifyerror((m), (msg));                    \
-        return (retval);                                             \
-    } while (0)
-
-#define TYPECHECK_VERIFYERROR_main(msg)  TYPECHECK_VERIFYERROR_ret(state.m,(msg),NULL)
-#define TYPECHECK_VERIFYERROR_bool(msg)  TYPECHECK_VERIFYERROR_ret(state->m,(msg),false)
-
-
-/****************************************************************************/
-/* MISC MACROS                                                              */
-/****************************************************************************/
-
-#define COPYTYPE(source,dest)                                        \
-    {if (VAROP(source)->type == TYPE_ADR)                            \
-            TYPEINFO_COPY(VAROP(source)->typeinfo,VAROP(dest)->typeinfo);}
-
-
-/****************************************************************************/
-/* JSR VERIFICATION (stack-based verifier)                                  */
-/****************************************************************************/
-
-typedef struct typecheck_jsr_t typecheck_jsr_t;
-typedef struct typecheck_jsr_caller_t typecheck_jsr_caller_t;
-
-struct typecheck_jsr_caller_t {
-       typecheck_jsr_caller_t *next;                   /* next in linked list */
-       basicblock *callblock;             /* block containing the calling JSR */
-};
-
-struct typecheck_jsr_t {
-       typecheck_jsr_t *next;               /* next (lower) in the call chain */
-       basicblock  *start;                                   /* for debugging */
-       typecheck_jsr_caller_t *callers;  /* list of callers (blocks with JSR) */
-       basicblock  *retblock;              /* block with the RET for this sub */
-       bool         active;           /* true if this sub is currently active */
-       char        *blockflags;   /* saved block flags when JSR was traversed */
-       char        *usedlocals;       /* != 0 for each local used in this sub */
-       typedescriptor_t *retlocals;                 /* locals on the RET edge */
-       typedescriptor_t *retstack;                   /* stack on the RET edge */
-       s4              retdepth;               /* stack depth on the RET edge */
-};
-
-/****************************************************************************/
-/* VERIFIER STATE STRUCT                                                    */
-/****************************************************************************/
-
-/* verifier_state - This structure keeps the current state of the      */
-/* bytecode verifier for passing it between verifier functions.        */
-
-typedef struct verifier_state {
-    instruction *iptr;               /* pointer to current instruction */
-    basicblock *bptr;                /* pointer to current basic block */
-
-       methodinfo *m;                               /* the current method */
-       jitdata *jd;                         /* jitdata for current method */
-       codegendata *cd;                 /* codegendata for current method */
-
-       basicblock *basicblocks;
-       s4 basicblockcount;
-       
-       s4 numlocals;                         /* number of local variables */
-       s4 validlocals;                /* number of Java-accessible locals */
-       
-       typedescriptor_t returntype;  /* return type of the current method */
-
-       s4 *savedindices;
-       s4 *savedinvars;                            /* saved invar pointer */
-
-       s4 exinvars;
-       
-    exception_entry **handlers;           /* active exception handlers */
-       
-    bool repeat;            /* if true, blocks are iterated over again */
-    bool initmethod;             /* true if this is an "<init>" method */
-
-#ifdef TYPECHECK_STATISTICS
-       bool stat_maythrow;          /* at least one instruction may throw */
-#endif
-
-       /* the following fields are used by the stackbased verifier only:  */
-
-       typedescriptor_t *locals;               /* current local variables */
-       typedescriptor_t *startlocals;/* locals at the start of each block */
-       typedescriptor_t *startstack;  /* stack at the start of each block */
-       s4               *indepth;                /* stack depth at --''-- */
-       typedescriptor_t *stackceiling;    /* upper edge of verifier stack */
-
-       typecheck_jsr_t *topjsr;        /* most recently called subroutine */
-       typecheck_jsr_t **jsrinfos;      /* subroutine info for each block */
-} verifier_state;
-
-void typecheck_init_flags(verifier_state *state, s4 minflags);
-void typecheck_reset_flags(verifier_state *state);
-
-bool typecheck_copy_types(verifier_state *state,
-                                                 s4 *srcvars, s4 *dstvars, s4 n);
-
-typecheck_result typecheck_merge_types(verifier_state *state,
-                                                                          s4 *srcvars,
-                                                                          s4 *dstvars,
-                                                                          s4 n);
-
-typecheck_result typestate_merge(verifier_state *state,
-                                                s4 *srcvars, varinfo *srclocals,
-                                                s4 *dstvars, varinfo *dstlocals,
-                                                s4 n);
-
-bool typestate_reach(verifier_state *state,
-                                        basicblock *destblock,
-                                        s4 *srcvars, varinfo *srclocals, s4 n);
-
-bool typecheck_init_locals(verifier_state *state, bool newthis);
-
-#endif /* _TYPECHECK_COMMON_H */
-
-/*
- * 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
- * Emacs will automagically detect them.
- * ---------------------------------------------------------------------
- * Local variables:
- * mode: c
- * indent-tabs-mode: t
- * c-basic-offset: 4
- * tab-width: 4
- * End:
- * vim:noexpandtab:sw=4:ts=4:
- */
diff --git a/src/vm/jit/verify/typecheck-common.hpp b/src/vm/jit/verify/typecheck-common.hpp
new file mode 100644 (file)
index 0000000..bc47e37
--- /dev/null
@@ -0,0 +1,315 @@
+/* src/vm/jit/verify/typecheck-common.h - internal header for the type checker
+
+   Copyright (C) 1996-2005, 2006, 2008
+   CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
+
+   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., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301, USA.
+
+*/
+
+
+#ifndef _TYPECHECK_COMMON_H
+#define _TYPECHECK_COMMON_H
+
+#include "config.h"
+#include "vm/types.h"
+#include "vm/global.h"
+
+#include <assert.h>
+
+#include "vm/jit/jit.hpp"
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/****************************************************************************/
+/* DEBUG HELPERS                                                            */
+/****************************************************************************/
+
+#ifdef TYPECHECK_DEBUG
+#define TYPECHECK_ASSERT(cond)  assert(cond)
+#else
+#define TYPECHECK_ASSERT(cond)
+#endif
+
+#ifdef TYPECHECK_VERBOSE_OPT
+extern bool opt_typecheckverbose;
+#define DOLOG(action)  do { if (opt_typecheckverbose) {action;} } while(0)
+#else
+#define DOLOG(action)
+#endif
+
+#ifdef TYPECHECK_VERBOSE
+#define TYPECHECK_VERBOSE_IMPORTANT
+#define LOGNL              DOLOG(puts(""))
+#define LOG(str)           DOLOG(puts(str);)
+#define LOG1(str,a)        DOLOG(printf(str,a); LOGNL)
+#define LOG2(str,a,b)      DOLOG(printf(str,a,b); LOGNL)
+#define LOG3(str,a,b,c)    DOLOG(printf(str,a,b,c); LOGNL)
+#define LOGIF(cond,str)    DOLOG(do {if (cond) { puts(str); }} while(0))
+#ifdef  TYPEINFO_DEBUG
+#define LOGINFO(info)      DOLOG(do {typeinfo_print_short(stdout,(info)); LOGNL;} while(0))
+#else
+#define LOGINFO(info)
+#define typevector_print(x,y,z)
+#endif
+#define LOGFLUSH           DOLOG(fflush(stdout))
+#define LOGSTR(str)        DOLOG(printf("%s", 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 LOGNAME(c)         DOLOG(class_classref_or_classinfo_print(c))
+#define LOGMETHOD(str,m)   DOLOG(printf("%s", str); method_println(m);)
+#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)
+#define LOGNAME(c)
+#define LOGMETHOD(str,m)
+#endif
+
+#ifdef TYPECHECK_VERBOSE_IMPORTANT
+#define LOGimp(str)     DOLOG(puts(str);LOGNL)
+#define LOGimpSTR(str)  DOLOG(puts(str))
+#else
+#define LOGimp(str)
+#define LOGimpSTR(str)
+#endif
+
+#if defined(TYPECHECK_VERBOSE) || defined(TYPECHECK_VERBOSE_IMPORTANT)
+#include <stdio.h>
+void typecheck_print_var(FILE *file, jitdata *jd, s4 index);
+void typecheck_print_vararray(FILE *file, jitdata *jd, s4 *vars, int len);
+#endif
+
+
+/****************************************************************************/
+/* STATISTICS                                                               */
+/****************************************************************************/
+
+#if defined(TYPECHECK_DEBUG) && !defined(TYPECHECK_NO_STATISTICS)
+/*#define TYPECHECK_STATISTICS*/
+#endif
+
+#ifdef TYPECHECK_STATISTICS
+#define STAT_ITERATIONS  10
+#define STAT_BLOCKS      10
+#define STAT_LOCALS      16
+
+extern int stat_typechecked;
+extern int stat_methods_with_handlers;
+extern int stat_methods_maythrow;
+extern int stat_iterations[STAT_ITERATIONS+1];
+extern int stat_reached;
+extern int stat_copied;
+extern int stat_merged;
+extern int stat_merging_changed;
+extern int stat_blocks[STAT_BLOCKS+1];
+extern int stat_locals[STAT_LOCALS+1];
+extern int stat_ins;
+extern int stat_ins_maythrow;
+extern int stat_ins_stack;
+extern int stat_ins_field;
+extern int stat_ins_field_unresolved;
+extern int stat_ins_field_uninitialized;
+extern int stat_ins_invoke;
+extern int stat_ins_invoke_unresolved;
+extern int stat_ins_primload;
+extern int stat_ins_aload;
+extern int stat_ins_builtin;
+extern int stat_ins_builtin_gen;
+extern int stat_ins_branch;
+extern int stat_ins_switch;
+extern int stat_ins_primitive_return;
+extern int stat_ins_areturn;
+extern int stat_ins_areturn_unresolved;
+extern int stat_ins_athrow;
+extern int stat_ins_athrow_unresolved;
+extern int stat_ins_unchecked;
+extern int stat_handlers_reached;
+extern int stat_savedstack;
+
+#define TYPECHECK_MARK(var)   ((var) = true)
+#define TYPECHECK_COUNT(cnt)  (cnt)++
+#define TYPECHECK_COUNTIF(cond,cnt)  do{if(cond) (cnt)++;} while(0)
+#define TYPECHECK_COUNT_FREQ(array,val,limit) \
+       do {                                                                      \
+               if ((val) < (limit)) (array)[val]++;  \
+               else (array)[limit]++;                            \
+       } while (0)
+
+void typecheck_print_statistics(FILE *file);
+
+#else /* !defined(TYPECHECK_STATISTICS) */
+                                                  
+#define TYPECHECK_COUNT(cnt)
+#define TYPECHECK_MARK(var)
+#define TYPECHECK_COUNTIF(cond,cnt)
+#define TYPECHECK_COUNT_FREQ(array,val,limit)
+
+#endif /* defined(TYPECHECK_STATISTICS) */
+
+
+/****************************************************************************/
+/* MACROS FOR THROWING EXCEPTIONS                                           */
+/****************************************************************************/
+
+#define TYPECHECK_VERIFYERROR_ret(m,msg,retval)                      \
+    do {                                                             \
+        exceptions_throw_verifyerror((m), (msg));                    \
+        return (retval);                                             \
+    } while (0)
+
+#define TYPECHECK_VERIFYERROR_main(msg)  TYPECHECK_VERIFYERROR_ret(state.m,(msg),NULL)
+#define TYPECHECK_VERIFYERROR_bool(msg)  TYPECHECK_VERIFYERROR_ret(state->m,(msg),false)
+
+
+/****************************************************************************/
+/* MISC MACROS                                                              */
+/****************************************************************************/
+
+#define COPYTYPE(source,dest)                                        \
+    {if (VAROP(source)->type == TYPE_ADR)                            \
+            TYPEINFO_COPY(VAROP(source)->typeinfo,VAROP(dest)->typeinfo);}
+
+
+/****************************************************************************/
+/* JSR VERIFICATION (stack-based verifier)                                  */
+/****************************************************************************/
+
+typedef struct typecheck_jsr_t typecheck_jsr_t;
+typedef struct typecheck_jsr_caller_t typecheck_jsr_caller_t;
+
+struct typecheck_jsr_caller_t {
+       typecheck_jsr_caller_t *next;                   /* next in linked list */
+       basicblock *callblock;             /* block containing the calling JSR */
+};
+
+struct typecheck_jsr_t {
+       typecheck_jsr_t *next;               /* next (lower) in the call chain */
+       basicblock  *start;                                   /* for debugging */
+       typecheck_jsr_caller_t *callers;  /* list of callers (blocks with JSR) */
+       basicblock  *retblock;              /* block with the RET for this sub */
+       bool         active;           /* true if this sub is currently active */
+       char        *blockflags;   /* saved block flags when JSR was traversed */
+       char        *usedlocals;       /* != 0 for each local used in this sub */
+       typedescriptor_t *retlocals;                 /* locals on the RET edge */
+       typedescriptor_t *retstack;                   /* stack on the RET edge */
+       s4              retdepth;               /* stack depth on the RET edge */
+};
+
+/****************************************************************************/
+/* VERIFIER STATE STRUCT                                                    */
+/****************************************************************************/
+
+/* verifier_state - This structure keeps the current state of the      */
+/* bytecode verifier for passing it between verifier functions.        */
+
+typedef struct verifier_state {
+    instruction *iptr;               /* pointer to current instruction */
+    basicblock *bptr;                /* pointer to current basic block */
+
+       methodinfo *m;                               /* the current method */
+       jitdata *jd;                         /* jitdata for current method */
+       codegendata *cd;                 /* codegendata for current method */
+
+       basicblock *basicblocks;
+       s4 basicblockcount;
+       
+       s4 numlocals;                         /* number of local variables */
+       s4 validlocals;                /* number of Java-accessible locals */
+       
+       typedescriptor_t returntype;  /* return type of the current method */
+
+       s4 *savedindices;
+       s4 *savedinvars;                            /* saved invar pointer */
+
+       s4 exinvars;
+       
+    exception_entry **handlers;           /* active exception handlers */
+       
+    bool repeat;            /* if true, blocks are iterated over again */
+    bool initmethod;             /* true if this is an "<init>" method */
+
+#ifdef TYPECHECK_STATISTICS
+       bool stat_maythrow;          /* at least one instruction may throw */
+#endif
+
+       /* the following fields are used by the stackbased verifier only:  */
+
+       typedescriptor_t *locals;               /* current local variables */
+       typedescriptor_t *startlocals;/* locals at the start of each block */
+       typedescriptor_t *startstack;  /* stack at the start of each block */
+       s4               *indepth;                /* stack depth at --''-- */
+       typedescriptor_t *stackceiling;    /* upper edge of verifier stack */
+
+       typecheck_jsr_t *topjsr;        /* most recently called subroutine */
+       typecheck_jsr_t **jsrinfos;      /* subroutine info for each block */
+} verifier_state;
+
+void typecheck_init_flags(verifier_state *state, s4 minflags);
+void typecheck_reset_flags(verifier_state *state);
+
+bool typecheck_copy_types(verifier_state *state,
+                                                 s4 *srcvars, s4 *dstvars, s4 n);
+
+typecheck_result typecheck_merge_types(verifier_state *state,
+                                                                          s4 *srcvars,
+                                                                          s4 *dstvars,
+                                                                          s4 n);
+
+typecheck_result typestate_merge(verifier_state *state,
+                                                s4 *srcvars, varinfo *srclocals,
+                                                s4 *dstvars, varinfo *dstlocals,
+                                                s4 n);
+
+bool typestate_reach(verifier_state *state,
+                                        basicblock *destblock,
+                                        s4 *srcvars, varinfo *srclocals, s4 n);
+
+bool typecheck_init_locals(verifier_state *state, bool newthis);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* _TYPECHECK_COMMON_H */
+
+/*
+ * 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
+ * Emacs will automagically detect them.
+ * ---------------------------------------------------------------------
+ * Local variables:
+ * mode: c
+ * indent-tabs-mode: t
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ * vim:noexpandtab:sw=4:ts=4:
+ */
diff --git a/src/vm/jit/verify/typecheck-stackbased.c b/src/vm/jit/verify/typecheck-stackbased.c
deleted file mode 100644 (file)
index 7056142..0000000
+++ /dev/null
@@ -1,1027 +0,0 @@
-/* src/vm/jit/verify/typecheck-stackbased.c - stack-based verifier
-
-   Copyright (C) 1996-2005, 2006, 2007, 2008
-   CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
-
-   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., 51 Franklin Street, Fifth Floor, Boston, MA
-   02110-1301, USA.
-
-*/
-
-
-#include "config.h"
-
-#include <assert.h>
-
-#include "vm/types.h"
-
-#include "vm/jit/builtin.hpp"
-#include "mm/memory.h"
-
-#include "vm/array.hpp"
-#include "vm/exceptions.hpp"
-#include "vm/global.h"
-#include "vm/globals.hpp"
-#include "vm/primitive.hpp"
-
-#include "vm/jit/parse.hpp"
-#include "vm/jit/show.hpp"
-#include "vm/jit/stack.h"
-#include "vm/jit/verify/typecheck-common.h"
-
-
-/* this #if runs over the whole file: */
-#if defined(ENABLE_VERIFIER)
-
-typedef typedescriptor_t verifier_slot_t;
-
-#if defined(TYPECHECK_VERBOSE)
-static void typecheck_stackbased_show_state(verifier_state *state,
-                                                                                       typedescriptor *stack,
-                                                                                       typedescriptor *stackfloor,
-                                                                                       bool showins);
-#endif
-
-
-#define CHECK_STACK_DEPTH(d)                                         \
-    if (((u1*)stack - (u1*)stackfloor)                               \
-            < (((d)-1) * (int)sizeof(verifier_slot_t)))              \
-        goto throw_stack_underflow;
-
-/* XXX don't need to check against ACONST for every ICMD */
-#define CHECK_STACK_SPACE(d)                                         \
-    if (((u1*)STATE->stackceiling - (u1*)stack)                      \
-            < (((d)+1) * (int)sizeof(verifier_slot_t)))              \
-        if (STATE->iptr->opc != ICMD_ACONST                          \
-                || INSTRUCTION_MUST_CHECK(STATE->iptr))              \
-            goto throw_stack_overflow;
-
-#define CHECK_STACK_TYPE(s, t)                                       \
-    if ((s).type != (t))                                             \
-        goto throw_stack_type_error;
-
-/* XXX inefficient */
-#define CHECK_LOCAL_TYPE(index, t)                                   \
-    do {                                                             \
-        if (state.locals[(index)].type != (t))                       \
-            goto throw_local_type_error;                             \
-        if (STATE->topjsr)                                           \
-            STATE->topjsr->usedlocals[(index)] = 1;                  \
-        if (STATE->topjsr && IS_2_WORD_TYPE(t))                      \
-            STATE->topjsr->usedlocals[(index) + 1] = 1;              \
-    } while(0)
-
-/* XXX inefficient */
-#define STORE_LOCAL(t, index)                                        \
-    do {                                                             \
-        state.locals[(index)].type = (t);                            \
-        if ((index) && IS_2_WORD_TYPE(state.locals[(index)-1].type)) \
-            state.locals[(index-1)].type = TYPE_VOID;                \
-        if (STATE->topjsr)                                           \
-            STATE->topjsr->usedlocals[(index)] = 1;                  \
-    } while (0)
-
-/* XXX inefficient */
-#define STORE_LOCAL_2_WORD(t, index)                                 \
-    do {                                                             \
-        STORE_LOCAL(t, index);                                       \
-        state.locals[(index)+1].type = TYPE_VOID;                    \
-        if (STATE->topjsr)                                           \
-            STATE->topjsr->usedlocals[(index)] = 1;                  \
-    } while (0)
-
-#define VERIFY_ERROR(msg)                                            \
-    do {                                                             \
-        LOG1("VerifyError: %s", msg);                                \
-        exceptions_throw_verifyerror(STATE->m, msg);                 \
-        return false;                                                \
-    } while (0)
-
-#define IS_CAT1(slot)                                                \
-    ((slot).type != TYPE_VOID && !IS_2_WORD_TYPE((slot).type))
-
-#define IS_CAT2(slot)                                                \
-    ((slot).type != TYPE_VOID && IS_2_WORD_TYPE((slot).type))
-
-#define CHECK_CAT1(slot)                                             \
-    do {                                                             \
-        if (!IS_CAT1(slot))                                          \
-            goto throw_stack_category_error;                         \
-    } while (0)
-
-#define CHECK_CAT2(slot)                                             \
-    do {                                                             \
-        if (!IS_CAT2(slot))                                          \
-            goto throw_stack_category_error;                         \
-    } while (0)
-
-#define COPY_SLOT(s, d)                                              \
-    do { (d) = (s); } while (0)
-
-#define REACH_BLOCK(target)                                          \
-    do {                                                             \
-        if (!typecheck_stackbased_reach(STATE, (target), stack,      \
-                    (stack - stackfloor) + 1))                       \
-            return false;                                            \
-    } while (0)
-
-#define REACH(target)                                                \
-    do {                                                             \
-        REACH_BLOCK((target).block);                                 \
-    } while (0)
-
-#undef TYPECHECK_INT
-#undef TYPECHECK_LNG
-#undef TYPECHECK_FLT
-#undef TYPECHECK_DBL
-#undef TYPECHECK_ADR
-
-/* XXX should reuse typevector code */
-static typecheck_result typecheck_stackbased_merge_locals(methodinfo *m,
-                                                                                                                 typedescriptor_t *dst,
-                                                                                                                 typedescriptor_t *y,
-                                                                                                                 int size)
-{
-       bool changed = false;
-       typecheck_result r;
-
-       typedescriptor_t *a = dst;
-       typedescriptor_t *b = y;
-       while (size--) {
-               if (a->type != TYPE_VOID && a->type != b->type) {
-                       a->type = TYPE_VOID;
-                       changed = true;
-               }
-               else if (a->type == TYPE_ADR) {
-                       if (TYPEINFO_IS_PRIMITIVE(a->typeinfo)) {
-                               /* 'a' is a returnAddress */
-                               if (!TYPEINFO_IS_PRIMITIVE(b->typeinfo)
-                                       || (TYPEINFO_RETURNADDRESS(a->typeinfo)
-                                               != TYPEINFO_RETURNADDRESS(b->typeinfo)))
-                               {
-                                       a->type = TYPE_VOID;
-                                       changed = true;
-                               }
-                       }
-                       else {
-                               /* 'a' is a reference */
-                               if (TYPEINFO_IS_PRIMITIVE(b->typeinfo)) {
-                                       a->type = TYPE_VOID;
-                                       changed = true;
-                               }
-                               else {
-                                       /* two reference types are merged. There cannot be */
-                                       /* a merge error. In the worst case we get j.l.O.  */
-                                       r = typeinfo_merge(m,&(a->typeinfo),&(b->typeinfo));
-                                       if (r == typecheck_FAIL)
-                                               return r;
-                                       changed |= r;
-                               }
-                       }
-               }
-               a++;
-               b++;
-       }
-       return changed;
-}
-
-static typecheck_result typecheck_stackbased_merge(verifier_state *state,
-                                                                                                  basicblock *destblock,
-                                                                                                  typedescriptor_t *stack,
-                                                                                                  s4 stackdepth)
-{
-       s4 i;
-       s4 destidx;
-       typedescriptor_t *stackfloor;
-       typedescriptor_t *sp;
-       typedescriptor_t *dp;
-       typecheck_result r;
-       bool changed = false;
-
-       destidx = destblock->nr;
-
-       if (stackdepth != state->indepth[destidx]) {
-               exceptions_throw_verifyerror(state->m, "Stack depth mismatch");
-               return typecheck_FAIL;
-       }
-
-       stackfloor = stack - (stackdepth - 1);
-
-       sp = stackfloor;
-       dp = state->startstack + (destidx * state->m->maxstack);
-
-       for (i=0; i<stackdepth; ++i, ++sp, ++dp) {
-               if (sp->type != dp->type) {
-                       exceptions_throw_verifyerror(state->m, "Mismatched stack types");
-                       return typecheck_FAIL;
-               }
-               if (dp->type == TYPE_ADR) {
-                       if (TYPEINFO_IS_PRIMITIVE(dp->typeinfo)) {
-                               /* dp has returnAddress type */
-                               if (TYPEINFO_IS_PRIMITIVE(sp->typeinfo)) {
-                                       if (TYPEINFO_RETURNADDRESS(dp->typeinfo) != TYPEINFO_RETURNADDRESS(sp->typeinfo)) {
-                                               exceptions_throw_verifyerror(state->m, "Mismatched stack types");
-                                               return typecheck_FAIL;
-                                       }
-                               }
-                               else {
-                                       exceptions_throw_verifyerror(state->m,"Merging returnAddress with reference");
-                                       return typecheck_FAIL;
-                               }
-                       }
-                       else {
-                               /* dp has reference type */
-                               if (TYPEINFO_IS_PRIMITIVE(sp->typeinfo)) {
-                                       exceptions_throw_verifyerror(state->m,"Merging reference with returnAddress");
-                                       return typecheck_FAIL;
-                               }
-                               r = typeinfo_merge(state->m,&(dp->typeinfo),&(sp->typeinfo));
-                               if (r == typecheck_FAIL)
-                                       return r;
-                               changed |= r;
-                       }
-               }
-       }
-
-       dp = state->startlocals + (destidx * state->numlocals);
-       r = typecheck_stackbased_merge_locals(state->m, dp, state->locals, state->numlocals);
-       if (r == typecheck_FAIL)
-               return r;
-       changed |= r;
-
-       return changed;
-}
-
-static bool typecheck_stackbased_reach(verifier_state *state,
-                                                                          basicblock *destblock,
-                                                                          typedescriptor_t *stack,
-                                                                          s4 stackdepth)
-{
-       bool changed = false;
-       typecheck_result r;
-
-       assert(destblock);
-
-       if (destblock->flags == BBTYPECHECK_UNDEF) {
-               /* The destblock has never been reached before */
-
-               TYPECHECK_COUNT(stat_copied);
-               LOG1("block L%03d reached first time",destblock->nr); LOGSTR("\t");
-               DOLOG( typecheck_stackbased_show_state(state, stack, stack - (stackdepth - 1), false); );
-
-               state->indepth[destblock->nr] = stackdepth;
-
-               MCOPY(state->startstack + (destblock->nr * state->m->maxstack),
-                         stack - (stackdepth - 1),
-                         typedescriptor_t,
-                         stackdepth);
-
-               MCOPY(state->startlocals + (destblock->nr * state->numlocals),
-                         state->locals,
-                         typedescriptor_t,
-                         state->numlocals);
-
-               changed = true;
-       }
-       else {
-               /* The destblock has already been reached before */
-
-               TYPECHECK_COUNT(stat_merged);
-               LOG1("block L%03d reached before", destblock->nr); LOGSTR("\t");
-               DOLOG( typecheck_stackbased_show_state(state, stack, stack - (stackdepth - 1), false); );
-
-               r = typecheck_stackbased_merge(state, destblock, stack, stackdepth);
-               if (r == typecheck_FAIL)
-                       return false;
-               changed = r;
-
-               TYPECHECK_COUNTIF(changed,stat_merging_changed);
-       }
-
-       if (changed) {
-               LOG("\tchanged!");
-               destblock->flags = BBTYPECHECK_REACHED;
-               /* XXX is this check ok? */
-               if (destblock->nr <= state->bptr->nr) {
-                       LOG("\tREPEAT!");
-                       state->repeat = true;
-               }
-       }
-       return true;
-}
-
-
-/* typecheck_stackbased_verify_fieldaccess *************************************
-
-   Verify an ICMD_{GET,PUT}{STATIC,FIELD}
-
-   IN:
-       state............the current state of the verifier
-          instance.........the instance slot, or NULL
-          value............the value slot, or NULL
-          stack............stack after popping the arguments
-
-   RETURN VALUE:
-       stack pointer....successful verification,
-          NULL.............an exception has been thrown.
-
-*******************************************************************************/
-
-static typedescriptor_t *typecheck_stackbased_verify_fieldaccess(
-               verifier_state *state,
-               typedescriptor_t *instance,
-               typedescriptor_t *value,
-               typedescriptor_t *stack)
-{
-       jitdata *jd;
-
-       jd = state->jd;
-
-#define TYPECHECK_STACKBASED
-#define EXCEPTION  do { return NULL; } while (0)
-#define STATE  state
-#include <typecheck-fields.inc>
-#undef  EXCEPTION
-#undef  STATE
-#undef  TYPECHECK_STACKBASED
-
-       return stack;
-
-throw_stack_overflow:
-       LOG("STACK OVERFLOW!");
-       exceptions_throw_verifyerror(state->m, "Stack size too large");
-       return NULL;
-}
-
-static bool typecheck_stackbased_verify_invocation(verifier_state *state,
-                                                                                                  typedescriptor_t *stack,
-                                                                                                  typedescriptor_t *stackfloor)
-{
-       s4 paramslots;
-       methoddesc *md;
-       typedescriptor_t *dv;
-
-       /* check stack depth */
-
-       /* XXX parse params */
-
-       INSTRUCTION_GET_METHODDESC(state->iptr, md);
-
-       paramslots = md->paramslots;
-
-       if ((stack - stackfloor) + 1 < paramslots) {
-               exceptions_throw_verifyerror(state->m, 
-                               "Trying to pop operand of an empty stack");
-               return false;
-       }
-
-       dv = stack - (paramslots - 1);
-
-#define TYPECHECK_STACKBASED
-#define OP1   dv
-#include <typecheck-invoke.inc>
-#undef  OP1
-#undef  TYPECHECK_STACKBASED
-
-       return true;
-}
-
-static bool typecheck_stackbased_verify_builtin(verifier_state *state,
-                                                                                               typedescriptor_t *stack,
-                                                                                               typedescriptor_t *stackfloor)
-{
-       s4 paramslots;
-       typedescriptor_t *dv;
-
-       /* check stack depth */
-
-       /* XXX parse params */
-
-       paramslots = state->iptr->sx.s23.s3.bte->md->paramslots;
-
-       if ((stack - stackfloor) + 1 < paramslots) {
-               exceptions_throw_verifyerror(state->m, 
-                               "Trying to pop operand of an empty stack");
-               return false;
-       }
-
-       dv = stack - (paramslots - 1);
-
-#define TYPECHECK_STACKBASED
-#define OP1   dv
-#define TYPECHECK_INT(s)  CHECK_STACK_TYPE(*(s), TYPE_INT)
-#define TYPECHECK_ADR(s)  CHECK_STACK_TYPE(*(s), TYPE_ADR)
-#define TYPECHECK_LNG(s)  CHECK_STACK_TYPE(*(s), TYPE_LNG)
-#define TYPECHECK_FLT(s)  CHECK_STACK_TYPE(*(s), TYPE_FLT)
-#define TYPECHECK_DBL(s)  CHECK_STACK_TYPE(*(s), TYPE_DBL)
-#include <typecheck-builtins.inc>
-#undef  OP1
-#undef  TYPECHECK_STACKBASED
-
-       return true;
-
-throw_stack_type_error:
-       exceptions_throw_verifyerror(state->m, "Wrong type on stack"); /* XXX */
-       return false;
-}
-
-static bool typecheck_stackbased_multianewarray(verifier_state *state,
-                                                                                               typedescriptor_t *stack,
-                                                                                               typedescriptor_t *stackfloor)
-{
-       /* XXX recombine with verify_multianewarray */
-
-       classinfo *arrayclass;
-       arraydescriptor *desc;
-       s4 i;
-       typedescriptor_t *sp;
-       typedescriptor_t *dst;
-
-       /* destination slot */
-
-       i = state->iptr->s1.argcount;
-
-       dst = stack - (i-1);
-
-       /* check the array lengths on the stack */
-
-       if ((stack - stackfloor) + 1 < i) {
-               exceptions_throw_verifyerror(state->m, 
-                               "Trying to pop operand of an empty stack");
-               return false;
-       }
-
-       if (i < 1)
-               TYPECHECK_VERIFYERROR_bool("Illegal dimension argument");
-
-       for (sp = dst; sp <= stack; ++sp) {
-               if (sp->type != TYPE_INT) {
-                       exceptions_throw_verifyerror_for_stack(state->m, TYPE_INT);
-                       return false;
-               }
-       }
-
-       /* check array descriptor */
-
-       if (INSTRUCTION_IS_RESOLVED(state->iptr)) {
-               /* the array class reference has already been resolved */
-               arrayclass = state->iptr->sx.s23.s3.c.cls;
-               if (!arrayclass)
-                       TYPECHECK_VERIFYERROR_bool("MULTIANEWARRAY with unlinked class");
-               if ((desc = arrayclass->vftbl->arraydesc) == NULL)
-                       TYPECHECK_VERIFYERROR_bool("MULTIANEWARRAY with non-array class");
-               if (desc->dimension < state->iptr->s1.argcount)
-                       TYPECHECK_VERIFYERROR_bool("MULTIANEWARRAY dimension to high");
-
-               /* set the array type of the result */
-               typeinfo_init_classinfo(&(dst->typeinfo), arrayclass);
-       }
-       else {
-               const char *p;
-               constant_classref *cr;
-
-               /* the array class reference is still unresolved */
-               /* check that the reference indicates an array class of correct dimension */
-               cr = state->iptr->sx.s23.s3.c.ref;
-               i = 0;
-               p = cr->name->text;
-               while (p[i] == '[')
-                       i++;
-               /* { the dimension of the array class == i } */
-               if (i < 1)
-                       TYPECHECK_VERIFYERROR_bool("MULTIANEWARRAY with non-array class");
-               if (i < state->iptr->s1.argcount)
-                       TYPECHECK_VERIFYERROR_bool("MULTIANEWARRAY dimension to high");
-
-               /* set the array type of the result */
-               if (!typeinfo_init_class(&(dst->typeinfo),CLASSREF_OR_CLASSINFO(cr)))
-                       return false;
-       }
-
-       /* everything ok */
-       return true;
-
-}
-
-static void typecheck_stackbased_add_jsr_caller(typecheck_jsr_t *jsr,
-                                                                                               basicblock *bptr)
-{
-       typecheck_jsr_caller_t *jc;
-
-       for (jc = jsr->callers; jc; jc = jc->next)
-               if (jc->callblock == bptr)
-                       return;
-
-       jc = DNEW(typecheck_jsr_caller_t);
-       jc->next = jsr->callers;
-       jc->callblock = bptr;
-       jsr->callers = jc;
-}
-
-static typedescriptor_t *typecheck_stackbased_jsr(verifier_state *state,
-                                                                                               typedescriptor_t *stack,
-                                                                                               typedescriptor_t *stackfloor)
-{
-       typecheck_jsr_t *jsr;
-       basicblock *tbptr;
-       jitdata *jd;
-       s4 i;
-
-       jd = state->jd;
-
-       tbptr = state->iptr->sx.s23.s3.jsrtarget.block;
-       jsr = state->jsrinfos[tbptr->nr];
-
-       if (jsr && tbptr->flags == BBFINISHED) {
-
-               LOG1("another JSR to analysed subroutine L%03d", tbptr->nr);
-               if (jsr->active) {
-                       exceptions_throw_verifyerror(state->m, "Recursive JSR");
-                       return NULL;
-               }
-
-               assert(jsr->callers);
-               assert(jsr->callers->callblock);
-
-               /* copy the stack of the RET edge */
-
-               MCOPY(stackfloor, jsr->retstack, typedescriptor_t, jsr->retdepth);
-               stack = stackfloor + (jsr->retdepth - 1);
-
-               /* copy variables that were used in the subroutine from the RET edge */
-
-               for (i=0; i<state->numlocals; ++i)
-                       if (jsr->usedlocals[i])
-                               state->locals[i] = jsr->retlocals[i];
-
-               /* reach the following block */
-
-               if (!typecheck_stackbased_reach(state, state->bptr->next, stack, 
-                                       (stack - stackfloor) + 1))
-                       return NULL;
-       }
-       else {
-               if (!jsr) {
-                       LOG1("first JSR to block L%03d", tbptr->nr);
-
-                       jsr = DNEW(typecheck_jsr_t);
-                       state->jsrinfos[tbptr->nr] = jsr;
-                       jsr->callers = NULL;
-                       jsr->blockflags = DMNEW(char, state->basicblockcount);
-                       jsr->retblock = NULL;
-                       jsr->start = tbptr;
-                       jsr->usedlocals = DMNEW(char, state->numlocals);
-                       MZERO(jsr->usedlocals, char, state->numlocals);
-                       jsr->retlocals = DMNEW(typedescriptor_t, state->numlocals);
-                       jsr->retstack = DMNEW(typedescriptor_t, state->m->maxstack);
-                       jsr->retdepth = 0;
-               }
-               else {
-                       LOG1("re-analysing JSR to block L%03d", tbptr->nr);
-               }
-
-               jsr->active = true;
-               jsr->next = state->topjsr;
-               state->topjsr = jsr;
-
-               assert(state->iptr->sx.s23.s3.jsrtarget.block->flags == BBTYPECHECK_REACHED);
-
-               tbptr->flags = BBFINISHED;
-
-               for (tbptr = state->basicblocks; tbptr != NULL; tbptr = tbptr->next) {
-                       jsr->blockflags[tbptr->nr] = tbptr->flags;
-
-                       if (tbptr->flags == BBTYPECHECK_REACHED)
-                               tbptr->flags = BBFINISHED;
-               }
-
-               state->iptr->sx.s23.s3.jsrtarget.block->flags = BBTYPECHECK_REACHED;
-       }
-
-       /* register this block as a caller, if not already done */
-
-       typecheck_stackbased_add_jsr_caller(jsr, state->bptr);
-
-       return stack;
-}
-
-static bool typecheck_stackbased_ret(verifier_state *state,
-                                                                        typedescriptor_t *stack,
-                                                                        typedescriptor_t *stackfloor)
-{
-       basicblock *tbptr;
-       typecheck_jsr_caller_t *jsrcaller;
-       typecheck_jsr_t *jsr;
-       s4 i;
-
-       /* get the subroutine we are RETurning from */
-
-       tbptr = TYPEINFO_RETURNADDRESS(state->locals[state->iptr->s1.varindex].typeinfo);
-       if (tbptr == NULL) {
-               exceptions_throw_verifyerror(state->m, "Illegal RET");
-               return false;
-       }
-
-       LOG1("RET from subroutine L%03d", tbptr->nr);
-       jsr = state->jsrinfos[tbptr->nr];
-       assert(jsr);
-
-       /* check against recursion */
-
-       if (!jsr->active) {
-               exceptions_throw_verifyerror(state->m, "RET outside of local subroutine");
-               return false;
-       }
-
-       /* check against multiple RETs for one subroutine */
-
-       if (jsr->retblock && jsr->retblock != state->bptr) {
-               exceptions_throw_verifyerror(state->m, "Multiple RETs from local subroutine");
-               return false;
-       }
-
-       /* store data-flow of the RET edge */
-
-       jsr->retblock = state->bptr;
-       jsr->retdepth = (stack - stackfloor) + 1;
-       MCOPY(jsr->retstack, stackfloor, typedescriptor_t, jsr->retdepth);
-       MCOPY(jsr->retlocals, state->locals, typedescriptor_t, state->numlocals);
-
-       /* invalidate the returnAddress used by this RET */
-       /* XXX should we also invalidate the returnAddresses of JSRs that are skipped by this RET? */
-
-       for (i=0; i<state->numlocals; ++i) {
-               typedescriptor_t *lc = &(jsr->retlocals[i]);
-               if (TYPE_IS_RETURNADDRESS(lc->type, lc->typeinfo))
-                       if (TYPEINFO_RETURNADDRESS(lc->typeinfo) == tbptr) {
-                               LOG1("invalidating returnAddress in local %d", i);
-                               TYPEINFO_INIT_RETURNADDRESS(lc->typeinfo, NULL);
-                       }
-       }
-
-       /* touch all callers of the subroutine, so they are analysed again */
-
-       for (jsrcaller = jsr->callers; jsrcaller != NULL; jsrcaller = jsrcaller->next) {
-               tbptr = jsrcaller->callblock;
-               LOG1("touching caller L%03d from RET", tbptr->nr);
-               assert(jsr->blockflags[tbptr->nr] >= BBFINISHED);
-               jsr->blockflags[tbptr->nr] = BBTYPECHECK_REACHED; /* XXX repeat? */
-       }
-
-       return true;
-}
-
-bool typecheck_stackbased(jitdata *jd)
-{
-       register verifier_slot_t *stack;
-       verifier_slot_t *stackfloor;
-       s4 len;
-       methoddesc *md;
-       bool maythrow;
-       bool superblockend;
-       verifier_slot_t temp;
-       branch_target_t *table;
-       lookup_target_t *lookup;
-       s4 i;
-       typecheck_result r;
-       verifier_slot_t *dst;
-       verifier_state state;
-       basicblock *tbptr;
-       exception_entry *ex;
-       typedescriptor_t exstack;
-       s4 skip = 0;
-
-       DOLOG( show_method(jd, SHOW_PARSE); );
-
-       /* initialize verifier state */
-
-       state.jd = jd;
-       state.m = jd->m;
-       state.cd = jd->cd;
-       state.basicblocks = jd->basicblocks;
-       state.basicblockcount = jd->basicblockcount;
-       state.topjsr = NULL;
-#   define STATE (&state)
-
-       /* check that the basicblock numbers are valid */
-
-#if !defined(NDEBUG)
-       jit_check_basicblock_numbers(jd);
-#endif
-
-       /* check if this method is an instance initializer method */
-
-    state.initmethod = (state.m->name == utf_init);
-
-       /* allocate parameter descriptors if necessary */
-
-       if (!state.m->parseddesc->params)
-               if (!descriptor_params_from_paramtypes(state.m->parseddesc,state.m->flags))
-                       return false;
-
-       /* allocate the stack buffers */
-
-       stackfloor = DMNEW(verifier_slot_t, state.m->maxstack + 1);
-       state.stackceiling = stackfloor + state.m->maxstack;
-       stack = stackfloor - 1;
-       state.indepth = DMNEW(s4, state.basicblockcount);
-       state.startstack = DMNEW(verifier_slot_t, state.m->maxstack * state.basicblockcount);
-
-       /* allocate the local variables buffers */
-
-       state.numlocals = state.m->maxlocals;
-       state.validlocals = state.m->maxlocals;
-    if (state.initmethod)
-               state.numlocals++; /* extra marker variable */
-
-       state.locals = DMNEW(verifier_slot_t, state.numlocals);
-       state.startlocals = DMNEW(verifier_slot_t, state.numlocals * state.basicblockcount);
-
-    /* allocate the buffer of active exception handlers */
-
-    state.handlers = DMNEW(exception_entry*, state.jd->exceptiontablelength + 1);
-
-    /* initialize instack of exception handlers */
-
-       exstack.type = TYPE_ADR;
-       typeinfo_init_classinfo(&(exstack.typeinfo),
-                                                       class_java_lang_Throwable); /* changed later */
-
-    LOG("Exception handler stacks set.\n");
-
-       /* initialize jsr info buffer */
-
-       state.jsrinfos = DMNEW(typecheck_jsr_t *, state.basicblockcount);
-       MZERO(state.jsrinfos, typecheck_jsr_t *, state.basicblockcount);
-
-       /* initialize stack of first block */
-
-       state.indepth[0] = 0;
-
-       /* initialize locals of first block */
-
-    /* if this is an instance method initialize the "this" ref type */
-
-    if (!(state.m->flags & ACC_STATIC)) {
-               if (state.validlocals < 1)
-                       VERIFY_ERROR("Not enough local variables for method arguments");
-               dst = state.startlocals;
-               dst->type = TYPE_ADR;
-               if (state.initmethod)
-                       TYPEINFO_INIT_NEWOBJECT(dst->typeinfo, NULL);
-               else
-                       typeinfo_init_classinfo(&(dst->typeinfo), state.m->clazz);
-
-               skip = 1;
-    }
-
-    LOG("'this' argument set.\n");
-
-       len = typedescriptors_init_from_methoddesc(state.startlocals + skip,
-                       state.m->parseddesc,
-                       state.validlocals, true, skip, &state.returntype);
-       if (len < 0)
-               return false;
-
-       /* set remaining locals to void */
-
-       for (i = skip + len; i<state.numlocals; ++i)
-               state.startlocals[i].type = TYPE_VOID;
-
-       /* initialize block flags */
-
-       typecheck_init_flags(&state, BBUNDEF);
-
-       /* iterate until fixpoint reached */
-
-       do {
-
-               state.repeat = false;
-
-               /* iterate over the basic blocks */
-
-               for (state.bptr = state.basicblocks; state.bptr != NULL; state.bptr = state.bptr->next) {
-
-                       if (state.bptr->flags != BBTYPECHECK_REACHED)
-                               continue;
-
-                       DOLOG( show_basicblock(jd, state.bptr, SHOW_PARSE); );
-
-                       /* mark this block as analysed */
-
-                       state.bptr->flags = BBFINISHED;
-
-                       /* determine the active exception handlers for this block */
-                       /* XXX could use a faster algorithm with sorted lists or  */
-                       /* something?                                             */
-                       /* XXX reuse code from variables based verifer? */
-                       len = 0;
-                       for (ex = STATE->jd->exceptiontable; ex ; ex = ex->down) {
-                               if ((ex->start->nr <= STATE->bptr->nr) && (ex->end->nr > STATE->bptr->nr)) {
-                                       LOG1("\tactive handler L%03d", ex->handler->nr);
-                                       STATE->handlers[len++] = ex;
-                               }
-                       }
-                       STATE->handlers[len] = NULL;
-
-                       /* initialize the locals */
-
-                       MCOPY(state.locals,
-                                 state.startlocals + (state.bptr->nr * state.numlocals),
-                                 verifier_slot_t, state.numlocals);
-
-                       /* initialize the stack */
-
-                       len = state.indepth[state.bptr->nr];
-
-                       MCOPY(stackfloor,
-                                 state.startstack + (state.bptr->nr * state.m->maxstack),
-                                 verifier_slot_t, len);
-
-                       stack = stackfloor + (len - 1);
-
-                       /* iterate over the instructions in this block */
-
-                       state.iptr = state.bptr->iinstr;
-                       len = state.bptr->icount;
-
-                       superblockend = false;
-
-                       for (; len--; state.iptr++) {
-
-                               maythrow = false;
-
-                               LOGNL;
-                               DOLOG( typecheck_stackbased_show_state(&state, stack, stackfloor, true); );
-
-                               switch (state.iptr->opc) {
-#define TYPECHECK_STACKBASED 1
-#define STATE (&state)
-#define IPTR state.iptr
-#define BPTR state.bptr
-#define METHOD state.m
-#define LOCAL_SLOT(index)  (state.locals + (index))
-#define EXCEPTION                                                    \
-    do {                                                             \
-        LOG("EXCEPTION THROWN!\n");                                  \
-        return false;                                                \
-    } while (0)
-
-#include <typecheck-stackbased-gen.inc>
-#undef  TYPECHECK_STACKBASED
-                               }
-
-                               /* reach exception handlers for this instruction */
-
-                               if (maythrow) {
-                                       TYPECHECK_COUNT(stat_ins_maythrow);
-                                       TYPECHECK_MARK(STATE->stat_maythrow);
-                                       LOG("\treaching exception handlers");
-                                       i = 0;
-                                       while (STATE->handlers[i]) {
-                                               TYPECHECK_COUNT(stat_handlers_reached);
-                                               if (STATE->handlers[i]->catchtype.any)
-                                                       exstack.typeinfo.typeclass = STATE->handlers[i]->catchtype;
-                                               else
-                                                       exstack.typeinfo.typeclass.cls = class_java_lang_Throwable;
-                                               if (!typecheck_stackbased_reach(
-                                                               STATE,
-                                                               STATE->handlers[i]->handler,
-                                                               &exstack, 1))
-                                                       EXCEPTION;
-                                               i++;
-                                       }
-                               }
-                       }
-
-                       /* propagate types to the following block */
-
-                       if (!superblockend) {
-                               if (!typecheck_stackbased_reach(&state, state.bptr->next,
-                                                                                               stack, stack - stackfloor + 1))
-                                       EXCEPTION;
-                       }
-               } /* end loop over blocks */
-
-               while (!state.repeat && state.topjsr) {
-                       LOG1("done analysing subroutine L%03d", state.topjsr->start->nr);
-
-                       /* propagate down used locals */
-
-                       if (state.topjsr->next) {
-                               for (i=0; i<state.numlocals; ++i)
-                                       state.topjsr->next->usedlocals[i] |= state.topjsr->usedlocals[i];
-                       }
-
-                       /* restore REACHED flags */
-
-                       for (tbptr = state.basicblocks; tbptr != NULL; tbptr = tbptr->next) {
-                               assert(tbptr->flags != BBTYPECHECK_REACHED);
-                               if (state.topjsr->blockflags[tbptr->nr] == BBTYPECHECK_REACHED) {
-                                       tbptr->flags = BBTYPECHECK_REACHED;
-                                       state.repeat = true;
-                               }
-                       }
-
-                       /* dactivate the subroutine */
-
-                       state.topjsr->active = false;
-                       state.topjsr = state.topjsr->next;
-               }
-       } while (state.repeat);
-
-       /* reset block flags */
-
-       typecheck_reset_flags(&state);
-
-       LOG("typecheck_stackbased successful");
-
-       return true;
-
-throw_stack_underflow:
-       LOG("STACK UNDERFLOW!");
-       exceptions_throw_verifyerror(state.m, "Unable to pop operand off an empty stack");
-       return false;
-
-throw_stack_overflow:
-       LOG("STACK OVERFLOW!");
-       exceptions_throw_verifyerror(state.m, "Stack size too large");
-       return false;
-
-throw_stack_type_error:
-       LOG("STACK TYPE ERROR!");
-       exceptions_throw_verifyerror(state.m, "Mismatched stack types");
-       return false;
-
-throw_local_type_error:
-       LOG("LOCAL TYPE ERROR!");
-       exceptions_throw_verifyerror(state.m, "Local variable type mismatch");
-       return false;
-
-throw_stack_category_error:
-       LOG("STACK CATEGORY ERROR!");
-       exceptions_throw_verifyerror(state.m, "Attempt to split long or double on the stack");
-       return false;
-}
-
-
-#if defined(TYPECHECK_VERBOSE)
-static void typecheck_stackbased_show_state(verifier_state *state,
-                                                                                       typedescriptor_t *stack,
-                                                                                       typedescriptor_t *stackfloor,
-                                                                                       bool showins)
-{
-       typedescriptor_t *sp;
-       s4 i;
-
-       LOGSTR1("stackdepth %d stack [", (stack - stackfloor) + 1);
-       for (sp=stackfloor; sp <= stack; sp++) {
-               LOGSTR(" ");
-               DOLOG( typedescriptor_print(stdout, sp); );
-       }
-       LOGSTR(" ] locals [");
-       for (i=0; i<state->numlocals; ++i) {
-               LOGSTR(" ");
-               DOLOG( typedescriptor_print(stdout, state->locals + i); );
-       }
-       LOGSTR(" ]");
-       LOGNL;
-       if (showins && state->iptr < (state->bptr->iinstr + state->bptr->icount)) {
-               LOGSTR("\t");
-               DOLOG( show_icmd(state->jd, state->iptr, false, SHOW_PARSE); );
-               LOGNL;
-       }
-}
-#endif
-
-#endif /* defined(ENABLE_VERIFIER) */
-
-
-/*
- * 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
- * Emacs will automagically detect them.
- * ---------------------------------------------------------------------
- * Local variables:
- * mode: c
- * indent-tabs-mode: t
- * c-basic-offset: 4
- * tab-width: 4
- * End:
- * vim:noexpandtab:sw=4:ts=4:
- */
-
diff --git a/src/vm/jit/verify/typecheck-stackbased.cpp b/src/vm/jit/verify/typecheck-stackbased.cpp
new file mode 100644 (file)
index 0000000..ceb27be
--- /dev/null
@@ -0,0 +1,1034 @@
+/* src/vm/jit/verify/typecheck-stackbased.c - stack-based verifier
+
+   Copyright (C) 1996-2005, 2006, 2007, 2008
+   CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
+
+   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., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301, USA.
+
+*/
+
+
+#include "config.h"
+
+#include <assert.h>
+
+#include "vm/types.h"
+
+#include "vm/jit/builtin.hpp"
+#include "mm/memory.h"
+
+#include "vm/array.hpp"
+#include "vm/exceptions.hpp"
+#include "vm/global.h"
+#include "vm/globals.hpp"
+#include "vm/primitive.hpp"
+
+#include "vm/jit/parse.hpp"
+#include "vm/jit/show.hpp"
+#include "vm/jit/stack.h"
+#include "vm/jit/verify/typecheck-common.hpp"
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/* this #if runs over the whole file: */
+#if defined(ENABLE_VERIFIER)
+
+typedef typedescriptor_t verifier_slot_t;
+
+#if defined(TYPECHECK_VERBOSE)
+static void typecheck_stackbased_show_state(verifier_state *state,
+                                                                                       typedescriptor *stack,
+                                                                                       typedescriptor *stackfloor,
+                                                                                       bool showins);
+#endif
+
+
+#define CHECK_STACK_DEPTH(d)                                         \
+    if (((u1*)stack - (u1*)stackfloor)                               \
+            < (((d)-1) * (int)sizeof(verifier_slot_t)))              \
+        goto throw_stack_underflow;
+
+/* XXX don't need to check against ACONST for every ICMD */
+#define CHECK_STACK_SPACE(d)                                         \
+    if (((u1*)STATE->stackceiling - (u1*)stack)                      \
+            < (((d)+1) * (int)sizeof(verifier_slot_t)))              \
+        if (STATE->iptr->opc != ICMD_ACONST                          \
+                || INSTRUCTION_MUST_CHECK(STATE->iptr))              \
+            goto throw_stack_overflow;
+
+#define CHECK_STACK_TYPE(s, t)                                       \
+    if ((s).type != (t))                                             \
+        goto throw_stack_type_error;
+
+/* XXX inefficient */
+#define CHECK_LOCAL_TYPE(index, t)                                   \
+    do {                                                             \
+        if (state.locals[(index)].type != (t))                       \
+            goto throw_local_type_error;                             \
+        if (STATE->topjsr)                                           \
+            STATE->topjsr->usedlocals[(index)] = 1;                  \
+        if (STATE->topjsr && IS_2_WORD_TYPE(t))                      \
+            STATE->topjsr->usedlocals[(index) + 1] = 1;              \
+    } while(0)
+
+/* XXX inefficient */
+#define STORE_LOCAL(t, index)                                        \
+    do {                                                             \
+        state.locals[(index)].type = (t);                            \
+        if ((index) && IS_2_WORD_TYPE(state.locals[(index)-1].type)) \
+            state.locals[(index-1)].type = TYPE_VOID;                \
+        if (STATE->topjsr)                                           \
+            STATE->topjsr->usedlocals[(index)] = 1;                  \
+    } while (0)
+
+/* XXX inefficient */
+#define STORE_LOCAL_2_WORD(t, index)                                 \
+    do {                                                             \
+        STORE_LOCAL(t, index);                                       \
+        state.locals[(index)+1].type = TYPE_VOID;                    \
+        if (STATE->topjsr)                                           \
+            STATE->topjsr->usedlocals[(index)] = 1;                  \
+    } while (0)
+
+#define VERIFY_ERROR(msg)                                            \
+    do {                                                             \
+        LOG1("VerifyError: %s", msg);                                \
+        exceptions_throw_verifyerror(STATE->m, msg);                 \
+        return false;                                                \
+    } while (0)
+
+#define IS_CAT1(slot)                                                \
+    ((slot).type != TYPE_VOID && !IS_2_WORD_TYPE((slot).type))
+
+#define IS_CAT2(slot)                                                \
+    ((slot).type != TYPE_VOID && IS_2_WORD_TYPE((slot).type))
+
+#define CHECK_CAT1(slot)                                             \
+    do {                                                             \
+        if (!IS_CAT1(slot))                                          \
+            goto throw_stack_category_error;                         \
+    } while (0)
+
+#define CHECK_CAT2(slot)                                             \
+    do {                                                             \
+        if (!IS_CAT2(slot))                                          \
+            goto throw_stack_category_error;                         \
+    } while (0)
+
+#define COPY_SLOT(s, d)                                              \
+    do { (d) = (s); } while (0)
+
+#define REACH_BLOCK(target)                                          \
+    do {                                                             \
+        if (!typecheck_stackbased_reach(STATE, (target), stack,      \
+                    (stack - stackfloor) + 1))                       \
+            return false;                                            \
+    } while (0)
+
+#define REACH(target)                                                \
+    do {                                                             \
+        REACH_BLOCK((target).block);                                 \
+    } while (0)
+
+#undef TYPECHECK_INT
+#undef TYPECHECK_LNG
+#undef TYPECHECK_FLT
+#undef TYPECHECK_DBL
+#undef TYPECHECK_ADR
+
+/* XXX should reuse typevector code */
+static typecheck_result typecheck_stackbased_merge_locals(methodinfo *m,
+                                                                                                                 typedescriptor_t *dst,
+                                                                                                                 typedescriptor_t *y,
+                                                                                                                 int size)
+{
+       bool changed = false;
+       typecheck_result r;
+
+       typedescriptor_t *a = dst;
+       typedescriptor_t *b = y;
+       while (size--) {
+               if (a->type != TYPE_VOID && a->type != b->type) {
+                       a->type = TYPE_VOID;
+                       changed = true;
+               }
+               else if (a->type == TYPE_ADR) {
+                       if (TYPEINFO_IS_PRIMITIVE(a->typeinfo)) {
+                               /* 'a' is a returnAddress */
+                               if (!TYPEINFO_IS_PRIMITIVE(b->typeinfo)
+                                       || (TYPEINFO_RETURNADDRESS(a->typeinfo)
+                                               != TYPEINFO_RETURNADDRESS(b->typeinfo)))
+                               {
+                                       a->type = TYPE_VOID;
+                                       changed = true;
+                               }
+                       }
+                       else {
+                               /* 'a' is a reference */
+                               if (TYPEINFO_IS_PRIMITIVE(b->typeinfo)) {
+                                       a->type = TYPE_VOID;
+                                       changed = true;
+                               }
+                               else {
+                                       /* two reference types are merged. There cannot be */
+                                       /* a merge error. In the worst case we get j.l.O.  */
+                                       r = typeinfo_merge(m,&(a->typeinfo),&(b->typeinfo));
+                                       if (r == typecheck_FAIL)
+                                               return r;
+                                       changed |= r;
+                               }
+                       }
+               }
+               a++;
+               b++;
+       }
+       return (typecheck_result) changed;
+}
+
+static typecheck_result typecheck_stackbased_merge(verifier_state *state,
+                                                                                                  basicblock *destblock,
+                                                                                                  typedescriptor_t *stack,
+                                                                                                  s4 stackdepth)
+{
+       s4 i;
+       s4 destidx;
+       typedescriptor_t *stackfloor;
+       typedescriptor_t *sp;
+       typedescriptor_t *dp;
+       typecheck_result r;
+       bool changed = false;
+
+       destidx = destblock->nr;
+
+       if (stackdepth != state->indepth[destidx]) {
+               exceptions_throw_verifyerror(state->m, "Stack depth mismatch");
+               return typecheck_FAIL;
+       }
+
+       stackfloor = stack - (stackdepth - 1);
+
+       sp = stackfloor;
+       dp = state->startstack + (destidx * state->m->maxstack);
+
+       for (i=0; i<stackdepth; ++i, ++sp, ++dp) {
+               if (sp->type != dp->type) {
+                       exceptions_throw_verifyerror(state->m, "Mismatched stack types");
+                       return typecheck_FAIL;
+               }
+               if (dp->type == TYPE_ADR) {
+                       if (TYPEINFO_IS_PRIMITIVE(dp->typeinfo)) {
+                               /* dp has returnAddress type */
+                               if (TYPEINFO_IS_PRIMITIVE(sp->typeinfo)) {
+                                       if (TYPEINFO_RETURNADDRESS(dp->typeinfo) != TYPEINFO_RETURNADDRESS(sp->typeinfo)) {
+                                               exceptions_throw_verifyerror(state->m, "Mismatched stack types");
+                                               return typecheck_FAIL;
+                                       }
+                               }
+                               else {
+                                       exceptions_throw_verifyerror(state->m,"Merging returnAddress with reference");
+                                       return typecheck_FAIL;
+                               }
+                       }
+                       else {
+                               /* dp has reference type */
+                               if (TYPEINFO_IS_PRIMITIVE(sp->typeinfo)) {
+                                       exceptions_throw_verifyerror(state->m,"Merging reference with returnAddress");
+                                       return typecheck_FAIL;
+                               }
+                               r = typeinfo_merge(state->m,&(dp->typeinfo),&(sp->typeinfo));
+                               if (r == typecheck_FAIL)
+                                       return r;
+                               changed |= r;
+                       }
+               }
+       }
+
+       dp = state->startlocals + (destidx * state->numlocals);
+       r = typecheck_stackbased_merge_locals(state->m, dp, state->locals, state->numlocals);
+       if (r == typecheck_FAIL)
+               return r;
+       changed |= r;
+
+       return (typecheck_result) changed;
+}
+
+static bool typecheck_stackbased_reach(verifier_state *state,
+                                                                          basicblock *destblock,
+                                                                          typedescriptor_t *stack,
+                                                                          s4 stackdepth)
+{
+       bool changed = false;
+       typecheck_result r;
+
+       assert(destblock);
+
+       if (destblock->flags == BBTYPECHECK_UNDEF) {
+               /* The destblock has never been reached before */
+
+               TYPECHECK_COUNT(stat_copied);
+               LOG1("block L%03d reached first time",destblock->nr); LOGSTR("\t");
+               DOLOG( typecheck_stackbased_show_state(state, stack, stack - (stackdepth - 1), false); );
+
+               state->indepth[destblock->nr] = stackdepth;
+
+               MCOPY(state->startstack + (destblock->nr * state->m->maxstack),
+                         stack - (stackdepth - 1),
+                         typedescriptor_t,
+                         stackdepth);
+
+               MCOPY(state->startlocals + (destblock->nr * state->numlocals),
+                         state->locals,
+                         typedescriptor_t,
+                         state->numlocals);
+
+               changed = true;
+       }
+       else {
+               /* The destblock has already been reached before */
+
+               TYPECHECK_COUNT(stat_merged);
+               LOG1("block L%03d reached before", destblock->nr); LOGSTR("\t");
+               DOLOG( typecheck_stackbased_show_state(state, stack, stack - (stackdepth - 1), false); );
+
+               r = typecheck_stackbased_merge(state, destblock, stack, stackdepth);
+               if (r == typecheck_FAIL)
+                       return false;
+               changed = r;
+
+               TYPECHECK_COUNTIF(changed,stat_merging_changed);
+       }
+
+       if (changed) {
+               LOG("\tchanged!");
+               destblock->flags = BBTYPECHECK_REACHED;
+               /* XXX is this check ok? */
+               if (destblock->nr <= state->bptr->nr) {
+                       LOG("\tREPEAT!");
+                       state->repeat = true;
+               }
+       }
+       return true;
+}
+
+
+/* typecheck_stackbased_verify_fieldaccess *************************************
+
+   Verify an ICMD_{GET,PUT}{STATIC,FIELD}
+
+   IN:
+       state............the current state of the verifier
+          instance.........the instance slot, or NULL
+          value............the value slot, or NULL
+          stack............stack after popping the arguments
+
+   RETURN VALUE:
+       stack pointer....successful verification,
+          NULL.............an exception has been thrown.
+
+*******************************************************************************/
+
+static typedescriptor_t *typecheck_stackbased_verify_fieldaccess(
+               verifier_state *state,
+               typedescriptor_t *instance,
+               typedescriptor_t *value,
+               typedescriptor_t *stack)
+{
+       jitdata *jd;
+
+       jd = state->jd;
+
+#define TYPECHECK_STACKBASED
+#define EXCEPTION  do { return NULL; } while (0)
+#define STATE  state
+#include <typecheck-fields.inc>
+#undef  EXCEPTION
+#undef  STATE
+#undef  TYPECHECK_STACKBASED
+
+       return stack;
+
+throw_stack_overflow:
+       LOG("STACK OVERFLOW!");
+       exceptions_throw_verifyerror(state->m, "Stack size too large");
+       return NULL;
+}
+
+static bool typecheck_stackbased_verify_invocation(verifier_state *state,
+                                                                                                  typedescriptor_t *stack,
+                                                                                                  typedescriptor_t *stackfloor)
+{
+       s4 paramslots;
+       methoddesc *md;
+       typedescriptor_t *dv;
+
+       /* check stack depth */
+
+       /* XXX parse params */
+
+       INSTRUCTION_GET_METHODDESC(state->iptr, md);
+
+       paramslots = md->paramslots;
+
+       if ((stack - stackfloor) + 1 < paramslots) {
+               exceptions_throw_verifyerror(state->m, 
+                               "Trying to pop operand of an empty stack");
+               return false;
+       }
+
+       dv = stack - (paramslots - 1);
+
+#define TYPECHECK_STACKBASED
+#define OP1   dv
+#include <typecheck-invoke.inc>
+#undef  OP1
+#undef  TYPECHECK_STACKBASED
+
+       return true;
+}
+
+static bool typecheck_stackbased_verify_builtin(verifier_state *state,
+                                                                                               typedescriptor_t *stack,
+                                                                                               typedescriptor_t *stackfloor)
+{
+       s4 paramslots;
+       typedescriptor_t *dv;
+
+       /* check stack depth */
+
+       /* XXX parse params */
+
+       paramslots = state->iptr->sx.s23.s3.bte->md->paramslots;
+
+       if ((stack - stackfloor) + 1 < paramslots) {
+               exceptions_throw_verifyerror(state->m, 
+                               "Trying to pop operand of an empty stack");
+               return false;
+       }
+
+       dv = stack - (paramslots - 1);
+
+#define TYPECHECK_STACKBASED
+#define OP1   dv
+#define TYPECHECK_INT(s)  CHECK_STACK_TYPE(*(s), TYPE_INT)
+#define TYPECHECK_ADR(s)  CHECK_STACK_TYPE(*(s), TYPE_ADR)
+#define TYPECHECK_LNG(s)  CHECK_STACK_TYPE(*(s), TYPE_LNG)
+#define TYPECHECK_FLT(s)  CHECK_STACK_TYPE(*(s), TYPE_FLT)
+#define TYPECHECK_DBL(s)  CHECK_STACK_TYPE(*(s), TYPE_DBL)
+#include <typecheck-builtins.inc>
+#undef  OP1
+#undef  TYPECHECK_STACKBASED
+
+       return true;
+
+throw_stack_type_error:
+       exceptions_throw_verifyerror(state->m, "Wrong type on stack"); /* XXX */
+       return false;
+}
+
+static bool typecheck_stackbased_multianewarray(verifier_state *state,
+                                                                                               typedescriptor_t *stack,
+                                                                                               typedescriptor_t *stackfloor)
+{
+       /* XXX recombine with verify_multianewarray */
+
+       classinfo *arrayclass;
+       arraydescriptor *desc;
+       s4 i;
+       typedescriptor_t *sp;
+       typedescriptor_t *dst;
+
+       /* destination slot */
+
+       i = state->iptr->s1.argcount;
+
+       dst = stack - (i-1);
+
+       /* check the array lengths on the stack */
+
+       if ((stack - stackfloor) + 1 < i) {
+               exceptions_throw_verifyerror(state->m, 
+                               "Trying to pop operand of an empty stack");
+               return false;
+       }
+
+       if (i < 1)
+               TYPECHECK_VERIFYERROR_bool("Illegal dimension argument");
+
+       for (sp = dst; sp <= stack; ++sp) {
+               if (sp->type != TYPE_INT) {
+                       exceptions_throw_verifyerror_for_stack(state->m, TYPE_INT);
+                       return false;
+               }
+       }
+
+       /* check array descriptor */
+
+       if (INSTRUCTION_IS_RESOLVED(state->iptr)) {
+               /* the array class reference has already been resolved */
+               arrayclass = state->iptr->sx.s23.s3.c.cls;
+               if (!arrayclass)
+                       TYPECHECK_VERIFYERROR_bool("MULTIANEWARRAY with unlinked class");
+               if ((desc = arrayclass->vftbl->arraydesc) == NULL)
+                       TYPECHECK_VERIFYERROR_bool("MULTIANEWARRAY with non-array class");
+               if (desc->dimension < state->iptr->s1.argcount)
+                       TYPECHECK_VERIFYERROR_bool("MULTIANEWARRAY dimension to high");
+
+               /* set the array type of the result */
+               typeinfo_init_classinfo(&(dst->typeinfo), arrayclass);
+       }
+       else {
+               const char *p;
+               constant_classref *cr;
+
+               /* the array class reference is still unresolved */
+               /* check that the reference indicates an array class of correct dimension */
+               cr = state->iptr->sx.s23.s3.c.ref;
+               i = 0;
+               p = cr->name->text;
+               while (p[i] == '[')
+                       i++;
+               /* { the dimension of the array class == i } */
+               if (i < 1)
+                       TYPECHECK_VERIFYERROR_bool("MULTIANEWARRAY with non-array class");
+               if (i < state->iptr->s1.argcount)
+                       TYPECHECK_VERIFYERROR_bool("MULTIANEWARRAY dimension to high");
+
+               /* set the array type of the result */
+               if (!typeinfo_init_class(&(dst->typeinfo),CLASSREF_OR_CLASSINFO(cr)))
+                       return false;
+       }
+
+       /* everything ok */
+       return true;
+
+}
+
+static void typecheck_stackbased_add_jsr_caller(typecheck_jsr_t *jsr,
+                                                                                               basicblock *bptr)
+{
+       typecheck_jsr_caller_t *jc;
+
+       for (jc = jsr->callers; jc; jc = jc->next)
+               if (jc->callblock == bptr)
+                       return;
+
+       jc = (typecheck_jsr_caller_t*) DumpMemory::allocate(sizeof(typecheck_jsr_caller_t));
+       jc->next = jsr->callers;
+       jc->callblock = bptr;
+       jsr->callers = jc;
+}
+
+static typedescriptor_t *typecheck_stackbased_jsr(verifier_state *state,
+                                                                                               typedescriptor_t *stack,
+                                                                                               typedescriptor_t *stackfloor)
+{
+       typecheck_jsr_t *jsr;
+       basicblock *tbptr;
+       jitdata *jd;
+       s4 i;
+
+       jd = state->jd;
+
+       tbptr = state->iptr->sx.s23.s3.jsrtarget.block;
+       jsr = state->jsrinfos[tbptr->nr];
+
+       if (jsr && tbptr->flags == BBFINISHED) {
+
+               LOG1("another JSR to analysed subroutine L%03d", tbptr->nr);
+               if (jsr->active) {
+                       exceptions_throw_verifyerror(state->m, "Recursive JSR");
+                       return NULL;
+               }
+
+               assert(jsr->callers);
+               assert(jsr->callers->callblock);
+
+               /* copy the stack of the RET edge */
+
+               MCOPY(stackfloor, jsr->retstack, typedescriptor_t, jsr->retdepth);
+               stack = stackfloor + (jsr->retdepth - 1);
+
+               /* copy variables that were used in the subroutine from the RET edge */
+
+               for (i=0; i<state->numlocals; ++i)
+                       if (jsr->usedlocals[i])
+                               state->locals[i] = jsr->retlocals[i];
+
+               /* reach the following block */
+
+               if (!typecheck_stackbased_reach(state, state->bptr->next, stack, 
+                                       (stack - stackfloor) + 1))
+                       return NULL;
+       }
+       else {
+               if (!jsr) {
+                       LOG1("first JSR to block L%03d", tbptr->nr);
+
+                       jsr = (typecheck_jsr_t*) DumpMemory::allocate(sizeof(typecheck_jsr_t));
+                       state->jsrinfos[tbptr->nr] = jsr;
+                       jsr->callers = NULL;
+                       jsr->blockflags = (char*) DumpMemory::allocate(sizeof(char) * state->basicblockcount);
+                       jsr->retblock = NULL;
+                       jsr->start = tbptr;
+                       jsr->usedlocals = (char*) DumpMemory::allocate(sizeof(char) * state->numlocals);
+                       MZERO(jsr->usedlocals, char, state->numlocals);
+                       jsr->retlocals = (typedescriptor_t*) DumpMemory::allocate(sizeof(typedescriptor_t) * state->numlocals);
+                       jsr->retstack = (typedescriptor_t*) DumpMemory::allocate(sizeof(typedescriptor_t) * state->m->maxstack);
+                       jsr->retdepth = 0;
+               }
+               else {
+                       LOG1("re-analysing JSR to block L%03d", tbptr->nr);
+               }
+
+               jsr->active = true;
+               jsr->next = state->topjsr;
+               state->topjsr = jsr;
+
+               assert(state->iptr->sx.s23.s3.jsrtarget.block->flags == BBTYPECHECK_REACHED);
+
+               tbptr->flags = BBFINISHED;
+
+               for (tbptr = state->basicblocks; tbptr != NULL; tbptr = tbptr->next) {
+                       jsr->blockflags[tbptr->nr] = tbptr->flags;
+
+                       if (tbptr->flags == BBTYPECHECK_REACHED)
+                               tbptr->flags = BBFINISHED;
+               }
+
+               state->iptr->sx.s23.s3.jsrtarget.block->flags = BBTYPECHECK_REACHED;
+       }
+
+       /* register this block as a caller, if not already done */
+
+       typecheck_stackbased_add_jsr_caller(jsr, state->bptr);
+
+       return stack;
+}
+
+static bool typecheck_stackbased_ret(verifier_state *state,
+                                                                        typedescriptor_t *stack,
+                                                                        typedescriptor_t *stackfloor)
+{
+       basicblock *tbptr;
+       typecheck_jsr_caller_t *jsrcaller;
+       typecheck_jsr_t *jsr;
+       s4 i;
+
+       /* get the subroutine we are RETurning from */
+
+       tbptr = (basicblock*) TYPEINFO_RETURNADDRESS(state->locals[state->iptr->s1.varindex].typeinfo);
+       if (tbptr == NULL) {
+               exceptions_throw_verifyerror(state->m, "Illegal RET");
+               return false;
+       }
+
+       LOG1("RET from subroutine L%03d", tbptr->nr);
+       jsr = state->jsrinfos[tbptr->nr];
+       assert(jsr);
+
+       /* check against recursion */
+
+       if (!jsr->active) {
+               exceptions_throw_verifyerror(state->m, "RET outside of local subroutine");
+               return false;
+       }
+
+       /* check against multiple RETs for one subroutine */
+
+       if (jsr->retblock && jsr->retblock != state->bptr) {
+               exceptions_throw_verifyerror(state->m, "Multiple RETs from local subroutine");
+               return false;
+       }
+
+       /* store data-flow of the RET edge */
+
+       jsr->retblock = state->bptr;
+       jsr->retdepth = (stack - stackfloor) + 1;
+       MCOPY(jsr->retstack, stackfloor, typedescriptor_t, jsr->retdepth);
+       MCOPY(jsr->retlocals, state->locals, typedescriptor_t, state->numlocals);
+
+       /* invalidate the returnAddress used by this RET */
+       /* XXX should we also invalidate the returnAddresses of JSRs that are skipped by this RET? */
+
+       for (i=0; i<state->numlocals; ++i) {
+               typedescriptor_t *lc = &(jsr->retlocals[i]);
+               if (TYPE_IS_RETURNADDRESS(lc->type, lc->typeinfo))
+                       if (TYPEINFO_RETURNADDRESS(lc->typeinfo) == tbptr) {
+                               LOG1("invalidating returnAddress in local %d", i);
+                               TYPEINFO_INIT_RETURNADDRESS(lc->typeinfo, NULL);
+                       }
+       }
+
+       /* touch all callers of the subroutine, so they are analysed again */
+
+       for (jsrcaller = jsr->callers; jsrcaller != NULL; jsrcaller = jsrcaller->next) {
+               tbptr = jsrcaller->callblock;
+               LOG1("touching caller L%03d from RET", tbptr->nr);
+               assert(jsr->blockflags[tbptr->nr] >= BBFINISHED);
+               jsr->blockflags[tbptr->nr] = BBTYPECHECK_REACHED; /* XXX repeat? */
+       }
+
+       return true;
+}
+
+bool typecheck_stackbased(jitdata *jd)
+{
+       register verifier_slot_t *stack;
+       verifier_slot_t *stackfloor;
+       s4 len;
+       methoddesc *md;
+       bool maythrow;
+       bool superblockend;
+       verifier_slot_t temp;
+       branch_target_t *table;
+       lookup_target_t *lookup;
+       s4 i;
+       typecheck_result r;
+       verifier_slot_t *dst;
+       verifier_state state;
+       basicblock *tbptr;
+       exception_entry *ex;
+       typedescriptor_t exstack;
+       s4 skip = 0;
+
+       DOLOG( show_method(jd, SHOW_PARSE); );
+
+       /* initialize verifier state */
+
+       state.jd = jd;
+       state.m = jd->m;
+       state.cd = jd->cd;
+       state.basicblocks = jd->basicblocks;
+       state.basicblockcount = jd->basicblockcount;
+       state.topjsr = NULL;
+#   define STATE (&state)
+
+       /* check that the basicblock numbers are valid */
+
+#if !defined(NDEBUG)
+       jit_check_basicblock_numbers(jd);
+#endif
+
+       /* check if this method is an instance initializer method */
+
+    state.initmethod = (state.m->name == utf_init);
+
+       /* allocate parameter descriptors if necessary */
+
+       if (!state.m->parseddesc->params)
+               if (!descriptor_params_from_paramtypes(state.m->parseddesc,state.m->flags))
+                       return false;
+
+       /* allocate the stack buffers */
+
+       stackfloor = (verifier_slot_t*) DumpMemory::allocate(sizeof(verifier_slot_t) * (state.m->maxstack + 1));
+       state.stackceiling = stackfloor + state.m->maxstack;
+       stack = stackfloor - 1;
+       state.indepth = (s4*) DumpMemory::allocate(sizeof(s4) * state.basicblockcount);
+       state.startstack = (verifier_slot_t*) DumpMemory::allocate(sizeof(verifier_slot_t) * state.m->maxstack * state.basicblockcount);
+
+       /* allocate the local variables buffers */
+
+       state.numlocals = state.m->maxlocals;
+       state.validlocals = state.m->maxlocals;
+    if (state.initmethod)
+               state.numlocals++; /* extra marker variable */
+
+       state.locals = (verifier_slot_t*) DumpMemory::allocate(sizeof(verifier_slot_t) * state.numlocals);
+       state.startlocals = (verifier_slot_t*) DumpMemory::allocate(sizeof(verifier_slot_t) * state.numlocals * state.basicblockcount);
+
+    /* allocate the buffer of active exception handlers */
+
+    state.handlers = (exception_entry**) DumpMemory::allocate(sizeof(exception_entry*) * (state.jd->exceptiontablelength + 1));
+
+    /* initialize instack of exception handlers */
+
+       exstack.type = TYPE_ADR;
+       typeinfo_init_classinfo(&(exstack.typeinfo),
+                                                       class_java_lang_Throwable); /* changed later */
+
+    LOG("Exception handler stacks set.\n");
+
+       /* initialize jsr info buffer */
+
+       state.jsrinfos = (typecheck_jsr_t**) DumpMemory::allocate(sizeof(typecheck_jsr_t*) * state.basicblockcount);
+       MZERO(state.jsrinfos, typecheck_jsr_t *, state.basicblockcount);
+
+       /* initialize stack of first block */
+
+       state.indepth[0] = 0;
+
+       /* initialize locals of first block */
+
+    /* if this is an instance method initialize the "this" ref type */
+
+    if (!(state.m->flags & ACC_STATIC)) {
+               if (state.validlocals < 1)
+                       VERIFY_ERROR("Not enough local variables for method arguments");
+               dst = state.startlocals;
+               dst->type = TYPE_ADR;
+               if (state.initmethod)
+                       TYPEINFO_INIT_NEWOBJECT(dst->typeinfo, NULL);
+               else
+                       typeinfo_init_classinfo(&(dst->typeinfo), state.m->clazz);
+
+               skip = 1;
+    }
+
+    LOG("'this' argument set.\n");
+
+       len = typedescriptors_init_from_methoddesc(state.startlocals + skip,
+                       state.m->parseddesc,
+                       state.validlocals, true, skip, &state.returntype);
+       if (len < 0)
+               return false;
+
+       /* set remaining locals to void */
+
+       for (i = skip + len; i<state.numlocals; ++i)
+               state.startlocals[i].type = TYPE_VOID;
+
+       /* initialize block flags */
+
+       typecheck_init_flags(&state, BBUNDEF);
+
+       /* iterate until fixpoint reached */
+
+       do {
+
+               state.repeat = false;
+
+               /* iterate over the basic blocks */
+
+               for (state.bptr = state.basicblocks; state.bptr != NULL; state.bptr = state.bptr->next) {
+
+                       if (state.bptr->flags != BBTYPECHECK_REACHED)
+                               continue;
+
+                       DOLOG( show_basicblock(jd, state.bptr, SHOW_PARSE); );
+
+                       /* mark this block as analysed */
+
+                       state.bptr->flags = BBFINISHED;
+
+                       /* determine the active exception handlers for this block */
+                       /* XXX could use a faster algorithm with sorted lists or  */
+                       /* something?                                             */
+                       /* XXX reuse code from variables based verifer? */
+                       len = 0;
+                       for (ex = STATE->jd->exceptiontable; ex ; ex = ex->down) {
+                               if ((ex->start->nr <= STATE->bptr->nr) && (ex->end->nr > STATE->bptr->nr)) {
+                                       LOG1("\tactive handler L%03d", ex->handler->nr);
+                                       STATE->handlers[len++] = ex;
+                               }
+                       }
+                       STATE->handlers[len] = NULL;
+
+                       /* initialize the locals */
+
+                       MCOPY(state.locals,
+                                 state.startlocals + (state.bptr->nr * state.numlocals),
+                                 verifier_slot_t, state.numlocals);
+
+                       /* initialize the stack */
+
+                       len = state.indepth[state.bptr->nr];
+
+                       MCOPY(stackfloor,
+                                 state.startstack + (state.bptr->nr * state.m->maxstack),
+                                 verifier_slot_t, len);
+
+                       stack = stackfloor + (len - 1);
+
+                       /* iterate over the instructions in this block */
+
+                       state.iptr = state.bptr->iinstr;
+                       len = state.bptr->icount;
+
+                       superblockend = false;
+
+                       for (; len--; state.iptr++) {
+
+                               maythrow = false;
+
+                               LOGNL;
+                               DOLOG( typecheck_stackbased_show_state(&state, stack, stackfloor, true); );
+
+                               switch (state.iptr->opc) {
+#define TYPECHECK_STACKBASED 1
+#define STATE (&state)
+#define IPTR state.iptr
+#define BPTR state.bptr
+#define METHOD state.m
+#define LOCAL_SLOT(index)  (state.locals + (index))
+#define EXCEPTION                                                    \
+    do {                                                             \
+        LOG("EXCEPTION THROWN!\n");                                  \
+        return false;                                                \
+    } while (0)
+
+#include <typecheck-stackbased-gen.inc>
+#undef  TYPECHECK_STACKBASED
+                               }
+
+                               /* reach exception handlers for this instruction */
+
+                               if (maythrow) {
+                                       TYPECHECK_COUNT(stat_ins_maythrow);
+                                       TYPECHECK_MARK(STATE->stat_maythrow);
+                                       LOG("\treaching exception handlers");
+                                       i = 0;
+                                       while (STATE->handlers[i]) {
+                                               TYPECHECK_COUNT(stat_handlers_reached);
+                                               if (STATE->handlers[i]->catchtype.any)
+                                                       exstack.typeinfo.typeclass = STATE->handlers[i]->catchtype;
+                                               else
+                                                       exstack.typeinfo.typeclass.cls = class_java_lang_Throwable;
+                                               if (!typecheck_stackbased_reach(
+                                                               STATE,
+                                                               STATE->handlers[i]->handler,
+                                                               &exstack, 1))
+                                                       EXCEPTION;
+                                               i++;
+                                       }
+                               }
+                       }
+
+                       /* propagate types to the following block */
+
+                       if (!superblockend) {
+                               if (!typecheck_stackbased_reach(&state, state.bptr->next,
+                                                                                               stack, stack - stackfloor + 1))
+                                       EXCEPTION;
+                       }
+               } /* end loop over blocks */
+
+               while (!state.repeat && state.topjsr) {
+                       LOG1("done analysing subroutine L%03d", state.topjsr->start->nr);
+
+                       /* propagate down used locals */
+
+                       if (state.topjsr->next) {
+                               for (i=0; i<state.numlocals; ++i)
+                                       state.topjsr->next->usedlocals[i] |= state.topjsr->usedlocals[i];
+                       }
+
+                       /* restore REACHED flags */
+
+                       for (tbptr = state.basicblocks; tbptr != NULL; tbptr = tbptr->next) {
+                               assert(tbptr->flags != BBTYPECHECK_REACHED);
+                               if (state.topjsr->blockflags[tbptr->nr] == BBTYPECHECK_REACHED) {
+                                       tbptr->flags = BBTYPECHECK_REACHED;
+                                       state.repeat = true;
+                               }
+                       }
+
+                       /* dactivate the subroutine */
+
+                       state.topjsr->active = false;
+                       state.topjsr = state.topjsr->next;
+               }
+       } while (state.repeat);
+
+       /* reset block flags */
+
+       typecheck_reset_flags(&state);
+
+       LOG("typecheck_stackbased successful");
+
+       return true;
+
+throw_stack_underflow:
+       LOG("STACK UNDERFLOW!");
+       exceptions_throw_verifyerror(state.m, "Unable to pop operand off an empty stack");
+       return false;
+
+throw_stack_overflow:
+       LOG("STACK OVERFLOW!");
+       exceptions_throw_verifyerror(state.m, "Stack size too large");
+       return false;
+
+throw_stack_type_error:
+       LOG("STACK TYPE ERROR!");
+       exceptions_throw_verifyerror(state.m, "Mismatched stack types");
+       return false;
+
+throw_local_type_error:
+       LOG("LOCAL TYPE ERROR!");
+       exceptions_throw_verifyerror(state.m, "Local variable type mismatch");
+       return false;
+
+throw_stack_category_error:
+       LOG("STACK CATEGORY ERROR!");
+       exceptions_throw_verifyerror(state.m, "Attempt to split long or double on the stack");
+       return false;
+}
+
+
+#if defined(TYPECHECK_VERBOSE)
+static void typecheck_stackbased_show_state(verifier_state *state,
+                                                                                       typedescriptor_t *stack,
+                                                                                       typedescriptor_t *stackfloor,
+                                                                                       bool showins)
+{
+       typedescriptor_t *sp;
+       s4 i;
+
+       LOGSTR1("stackdepth %d stack [", (stack - stackfloor) + 1);
+       for (sp=stackfloor; sp <= stack; sp++) {
+               LOGSTR(" ");
+               DOLOG( typedescriptor_print(stdout, sp); );
+       }
+       LOGSTR(" ] locals [");
+       for (i=0; i<state->numlocals; ++i) {
+               LOGSTR(" ");
+               DOLOG( typedescriptor_print(stdout, state->locals + i); );
+       }
+       LOGSTR(" ]");
+       LOGNL;
+       if (showins && state->iptr < (state->bptr->iinstr + state->bptr->icount)) {
+               LOGSTR("\t");
+               DOLOG( show_icmd(state->jd, state->iptr, false, SHOW_PARSE); );
+               LOGNL;
+       }
+}
+#endif
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* defined(ENABLE_VERIFIER) */
+
+
+/*
+ * 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
+ * Emacs will automagically detect them.
+ * ---------------------------------------------------------------------
+ * Local variables:
+ * mode: c
+ * indent-tabs-mode: t
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ * vim:noexpandtab:sw=4:ts=4:
+ */
+
diff --git a/src/vm/jit/verify/typecheck-typeinferer.c b/src/vm/jit/verify/typecheck-typeinferer.c
deleted file mode 100644 (file)
index 60af008..0000000
+++ /dev/null
@@ -1,485 +0,0 @@
-/* src/vm/jit/verify/typecheck-typeinferer.c - type inference pass
-
-   Copyright (C) 1996-2005, 2006, 2007, 2008
-   CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
-
-   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., 51 Franklin Street, Fifth Floor, Boston, MA
-   02110-1301, USA.
-
-*/
-
-#include "config.h"
-#include "vm/types.h"
-#include "vm/global.h"
-
-#include <assert.h>
-#include <string.h>
-
-#include "mm/memory.h"
-
-#include "native/native.hpp"
-
-#include "toolbox/logging.h"
-
-#include "vm/access.h"
-#include "vm/array.hpp"
-#include "vm/jit/builtin.hpp"
-#include "vm/exceptions.hpp"
-#include "vm/globals.hpp"
-#include "vm/loader.hpp"
-#include "vm/options.h"
-#include "vm/primitive.hpp"
-#include "vm/resolve.hpp"
-#include "vm/vm.hpp"
-
-#include "vm/jit/jit.hpp"
-#include "vm/jit/show.hpp"
-#include "vm/jit/parse.hpp"
-
-#include "vm/jit/verify/typecheck-typeinferer.h"
-
-#define TYPECHECK_NO_STATISTICS
-#include <typecheck-common.h>
-
-
-/* macros used by the generated code ******************************************/
-
-#define EXCEPTION          do { return false; } while (0)
-#define VERIFY_ERROR(msg)  assert(false)
-
-#define CHECK_LOCAL_TYPE(index, t)                                   \
-       assert(jd->var[(index)].type == (t));
-
-#define STORE_LOCAL(t, index)                                        \
-    do {                                                             \
-         typevector_store(jd->var, (index), (t), NULL);              \
-    } while (0)
-
-#define STORE_LOCAL_2_WORD(t, index)                                 \
-    do {                                                             \
-         typevector_store(jd->var, (index), (t), NULL);              \
-    } while (0)
-
-#define REACH_BLOCK(target)                                          \
-    do {                                                             \
-        if (!typestate_reach(state, (target),                        \
-                             state->bptr->outvars, jd->var,          \
-                             state->bptr->outdepth))                 \
-                return false;                                        \
-    } while (0)
-
-#define REACH(target)   REACH_BLOCK((target).block)
-
-#define TYPECHECK_INT(v)  assert(jd->var[(v)].type == TYPE_INT)
-#define TYPECHECK_ADR(v)  assert(jd->var[(v)].type == TYPE_ADR)
-
-
-/* handle_fieldaccess **********************************************************
-   Verify an ICMD_{GET,PUT}{STATIC,FIELD}(CONST)?
-  
-   IN:
-       state............the current state of the verifier
-
-   RETURN VALUE:
-       true.............successful verification,
-          false............an exception has been thrown.
-
-*******************************************************************************/
-
-static bool
-handle_fieldaccess(verifier_state *state, 
-                                  varinfo *instance,
-                                  varinfo *value)
-{
-       jitdata *jd;
-
-       jd = state->jd;
-
-#define TYPECHECK_TYPEINFERER
-#include <typecheck-fields.inc>
-#undef  TYPECHECK_TYPEINFERER
-
-       return true;
-}
-
-
-/* handle_invocation ***********************************************************
-   Verify an ICMD_INVOKE* instruction.
-  
-   IN:
-       state............the current state of the verifier
-
-   RETURN VALUE:
-       true.............successful verification,
-          false............an exception has been thrown.
-
-*******************************************************************************/
-
-static bool
-handle_invocation(verifier_state *state)
-{
-       jitdata *jd;
-    varinfo *dv;               /* output variable of current instruction */
-
-       jd = state->jd;
-       dv = VAROP(state->iptr->dst);
-
-#define TYPECHECK_TYPEINFERER
-#define OP1   VAR(state->iptr->sx.s23.s2.args[0])
-#include <typecheck-invoke.inc>
-#undef  OP1
-#undef  TYPECHECK_TYPEINFERER
-
-       return true;
-}
-
-
-/* handle_builtin **************************************************************
-   Verify the call of a builtin method.
-  
-   IN:
-       state............the current state of the verifier
-
-   RETURN VALUE:
-       true.............successful verification,
-          false............an exception has been thrown.
-
-*******************************************************************************/
-
-static bool
-handle_builtin(verifier_state *state)
-{
-       jitdata *jd;
-    varinfo *dv;               /* output variable of current instruction */
-
-       jd = state->jd;
-       dv = VAROP(state->iptr->dst);
-
-#define TYPECHECK_TYPEINFERER
-#define OP1   state->iptr->sx.s23.s2.args[0]
-#include <typecheck-builtins.inc>
-#undef  OP1
-#undef  TYPECHECK_TYPEINFERER
-
-       return true;
-}
-
-/* handle_multianewarray *******************************************************
-   Verify a MULTIANEWARRAY instruction.
-  
-   IN:
-       state............the current state of the verifier
-
-   RETURN VALUE:
-       true.............successful verification,
-          false............an exception has been thrown.
-
-*******************************************************************************/
-
-static bool
-handle_multianewarray(verifier_state *state)
-{
-       jitdata *jd;
-    varinfo *dv;               /* output variable of current instruction */
-
-       jd = state->jd;
-       dv = VAROP(state->iptr->dst);
-
-#define TYPECHECK_TYPEINFERER
-#include <typecheck-multianewarray.inc>
-#undef  TYPECHECK_TYPEINFERER
-
-       return true;
-}
-
-
-/* handle_basic_block **********************************************************
-   Perform bytecode verification of a basic block.
-  
-   IN:
-       state............the current state of the verifier
-
-   RETURN VALUE:
-       true.............successful verification,
-          false............an exception has been thrown.
-
-*******************************************************************************/
-
-static bool
-handle_basic_block(verifier_state *state)
-{
-    int opcode;                                      /* current opcode */
-    int len;                        /* for counting instructions, etc. */
-    bool superblockend;        /* true if no fallthrough to next block */
-       instruction *iptr;                      /* the current instruction */
-    basicblock *tbptr;                   /* temporary for target block */
-    bool maythrow;               /* true if this instruction may throw */
-       s4 i;
-       branch_target_t *table;
-       lookup_target_t *lookup;
-       jitdata *jd = state->jd;
-       exception_entry *ex;
-
-       LOGSTR1("\n---- BLOCK %04d ------------------------------------------------\n",state->bptr->nr);
-       LOGFLUSH;
-       DOLOG(show_basicblock(jd, state->bptr, SHOW_STACK));
-
-       superblockend = false;
-       state->bptr->flags = BBFINISHED;
-
-       /* prevent compiler warnings */
-
-
-       /* determine the active exception handlers for this block */
-       /* XXX could use a faster algorithm with sorted lists or  */
-       /* something?                                             */
-       len = 0;
-       for (ex = state->jd->exceptiontable; ex ; ex = ex->down) {
-               if ((ex->start->nr <= state->bptr->nr) && (ex->end->nr > state->bptr->nr)) {
-                       LOG1("active handler L%03d", ex->handler->nr);
-                       state->handlers[len++] = ex;
-               }
-       }
-       state->handlers[len] = NULL;
-
-       /* init variable types at the start of this block */
-       typevector_copy_inplace(state->bptr->inlocals, jd->var, state->numlocals);
-
-       DOLOG(typecheck_print_vararray(stdout, jd, state->bptr->invars, 
-                               state->bptr->indepth));
-       DOLOG(typevector_print(stdout, jd->var, state->numlocals));
-       LOGNL; LOGFLUSH;
-
-       /* loop over the instructions */
-       len = state->bptr->icount;
-       state->iptr = state->bptr->iinstr;
-       while (--len >= 0)  {
-               TYPECHECK_COUNT(stat_ins);
-
-               iptr = state->iptr;
-
-               DOLOG(typevector_print(stdout, jd->var, state->numlocals));
-               LOGNL; LOGFLUSH;
-               DOLOG(show_icmd(jd, state->iptr, false, SHOW_STACK)); LOGNL; LOGFLUSH;
-
-               opcode = iptr->opc;
-               maythrow = false;
-
-               switch (opcode) {
-
-                       /* include generated code for ICMDs verification */
-
-#define TYPECHECK_TYPEINFERER
-#define STATE  state
-#define METHOD (state->m)
-#define IPTR   iptr
-#define BPTR   (state->bptr)
-#include <typecheck-typeinferer-gen.inc>
-#undef  STATE
-#undef  METHOD
-#undef  IPTR
-#undef  BPTR
-#undef  TYPECHECK_TYPEINFERER
-
-                       default:
-                               vm_abort("missing ICMD in type inferer: %d\n", opcode);
-               }
-
-               /* reach exception handlers for this instruction */
-
-               if (maythrow) {
-                       TYPECHECK_COUNT(stat_ins_maythrow);
-                       TYPECHECK_MARK(state->stat_maythrow);
-                       LOG("reaching exception handlers");
-                       i = 0;
-                       while (state->handlers[i]) {
-                               TYPECHECK_COUNT(stat_handlers_reached);
-                               if (state->handlers[i]->catchtype.any)
-                                       VAR(state->exinvars)->typeinfo.typeclass = state->handlers[i]->catchtype;
-                               else
-                                       VAR(state->exinvars)->typeinfo.typeclass.cls = class_java_lang_Throwable;
-                               if (!typestate_reach(state,
-                                               state->handlers[i]->handler,
-                                               &(state->exinvars), jd->var, 1))
-                                       return false;
-                               i++;
-                       }
-               }
-
-               LOG("\t\tnext instruction");
-               state->iptr++;
-       } /* while instructions */
-
-       LOG("instructions done");
-       LOGSTR("RESULT=> ");
-       DOLOG(typecheck_print_vararray(stdout, jd, state->bptr->outvars,
-                               state->bptr->outdepth));
-       DOLOG(typevector_print(stdout, jd->var, state->numlocals));
-       LOGNL; LOGFLUSH;
-
-       /* propagate stack and variables to the following block */
-       if (!superblockend) {
-               LOG("reaching following block");
-               tbptr = state->bptr->next;
-               while (tbptr->flags == BBDELETED) {
-                       tbptr = tbptr->next;
-               }
-               if (!typestate_reach(state,tbptr,state->bptr->outvars, jd->var,
-                                       state->bptr->outdepth))
-                       return false;
-       }
-
-       return true;
-}
-
-
-bool typecheck_infer_types(jitdata *jd)
-{
-       methodinfo     *meth;
-       codegendata    *cd;
-       varinfo        *savedlocals;
-       verifier_state  state;             /* current state of the verifier */
-
-       /* get required compiler data */
-
-       meth = jd->m;
-       cd   = jd->cd;
-
-       /* some logging on entry */
-
-
-    LOGSTR("\n==============================================================================\n");
-    DOLOG( show_method(jd, SHOW_STACK) );
-    LOGSTR("\n==============================================================================\n");
-    LOGMETHOD("Entering type inference: ",cd->method);
-
-       /* initialize the verifier state */
-
-       state.m = meth;
-       state.jd = jd;
-       state.cd = cd;
-       state.basicblockcount = jd->basicblockcount;
-       state.basicblocks = jd->basicblocks;
-       state.savedindices = NULL;
-       state.savedinvars = NULL;
-
-       /* check that the basicblock numbers are valid */
-
-#if !defined(NDEBUG)
-       jit_check_basicblock_numbers(jd);
-#endif
-
-       /* check if this method is an instance initializer method */
-
-    state.initmethod = (state.m->name == utf_init);
-
-       /* initialize the basic block flags for the following CFG traversal */
-
-       typecheck_init_flags(&state, BBFINISHED);
-
-    /* number of local variables */
-    
-    /* In <init> methods we use an extra local variable to indicate whether */
-    /* the 'this' reference has been initialized.                           */
-       /*         TYPE_VOID...means 'this' has not been initialized,           */
-       /*         TYPE_INT....means 'this' has been initialized.               */
-
-    state.numlocals = state.jd->localcount;
-       state.validlocals = state.numlocals;
-    if (state.initmethod) 
-               state.numlocals++; /* VERIFIER_EXTRA_LOCALS */
-
-    /* allocate the buffer of active exception handlers */
-       
-    state.handlers = DMNEW(exception_entry*, state.jd->exceptiontablelength + 1);
-
-       /* save local variables */
-
-       savedlocals = DMNEW(varinfo, state.numlocals);
-       MCOPY(savedlocals, jd->var, varinfo, state.numlocals);
-
-       /* initialized local variables of first block */
-
-       if (!typecheck_init_locals(&state, false))
-               return false;
-
-    /* initialize invars of exception handlers */
-       
-       state.exinvars = state.numlocals;
-       VAR(state.exinvars)->type = TYPE_ADR;
-       typeinfo_init_classinfo(&(VAR(state.exinvars)->typeinfo),
-                                                       class_java_lang_Throwable); /* changed later */
-
-    LOG("Exception handler stacks set.\n");
-
-    /* loop while there are still blocks to be checked */
-    do {
-               TYPECHECK_COUNT(count_iterations);
-
-        state.repeat = false;
-        
-        state.bptr = state.basicblocks;
-
-        for (; state.bptr; state.bptr = state.bptr->next) {
-            LOGSTR1("---- BLOCK %04d, ",state.bptr->nr);
-            LOGSTR1("blockflags: %d\n",state.bptr->flags);
-            LOGFLUSH;
-            
-                   /* verify reached block */  
-            if (state.bptr->flags == BBTYPECHECK_REACHED) {
-                if (!handle_basic_block(&state))
-                                       return false;
-            }
-        } /* for blocks */
-
-        LOGIF(state.repeat,"state.repeat == true");
-    } while (state.repeat);
-
-       /* statistics */
-       
-       /* reset the flags of blocks we haven't reached */
-
-       typecheck_reset_flags(&state);
-
-       /* restore locals */
-
-       MCOPY(jd->var, savedlocals, varinfo, state.numlocals);
-
-       /* everything's ok */
-
-    LOGimp("exiting type inference");
-       return true;
-}
-
-/*
- * 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
- * Emacs will automagically detect them.
- * ---------------------------------------------------------------------
- * Local variables:
- * mode: c
- * indent-tabs-mode: t
- * c-basic-offset: 4
- * tab-width: 4
- * End:
- * vim:noexpandtab:sw=4:ts=4:
- */
diff --git a/src/vm/jit/verify/typecheck-typeinferer.cpp b/src/vm/jit/verify/typecheck-typeinferer.cpp
new file mode 100644 (file)
index 0000000..6f8ee53
--- /dev/null
@@ -0,0 +1,492 @@
+/* src/vm/jit/verify/typecheck-typeinferer.c - type inference pass
+
+   Copyright (C) 1996-2005, 2006, 2007, 2008
+   CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
+
+   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., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301, USA.
+
+*/
+
+#include "config.h"
+#include "vm/types.h"
+#include "vm/global.h"
+
+#include <assert.h>
+#include <string.h>
+
+#include "mm/memory.h"
+
+#include "native/native.hpp"
+
+#include "toolbox/logging.h"
+
+#include "vm/access.h"
+#include "vm/array.hpp"
+#include "vm/jit/builtin.hpp"
+#include "vm/exceptions.hpp"
+#include "vm/globals.hpp"
+#include "vm/loader.hpp"
+#include "vm/options.h"
+#include "vm/primitive.hpp"
+#include "vm/resolve.hpp"
+#include "vm/vm.hpp"
+
+#include "vm/jit/jit.hpp"
+#include "vm/jit/show.hpp"
+#include "vm/jit/parse.hpp"
+
+#include "vm/jit/verify/typecheck-typeinferer.hpp"
+
+#define TYPECHECK_NO_STATISTICS
+#include "vm/jit/verify/typecheck-common.hpp"
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/* macros used by the generated code ******************************************/
+
+#define EXCEPTION          do { return false; } while (0)
+#define VERIFY_ERROR(msg)  assert(false)
+
+#define CHECK_LOCAL_TYPE(index, t)                                   \
+       assert(jd->var[(index)].type == (t));
+
+#define STORE_LOCAL(t, index)                                        \
+    do {                                                             \
+         typevector_store(jd->var, (index), (t), NULL);              \
+    } while (0)
+
+#define STORE_LOCAL_2_WORD(t, index)                                 \
+    do {                                                             \
+         typevector_store(jd->var, (index), (t), NULL);              \
+    } while (0)
+
+#define REACH_BLOCK(target)                                          \
+    do {                                                             \
+        if (!typestate_reach(state, (target),                        \
+                             state->bptr->outvars, jd->var,          \
+                             state->bptr->outdepth))                 \
+                return false;                                        \
+    } while (0)
+
+#define REACH(target)   REACH_BLOCK((target).block)
+
+#define TYPECHECK_INT(v)  assert(jd->var[(v)].type == TYPE_INT)
+#define TYPECHECK_ADR(v)  assert(jd->var[(v)].type == TYPE_ADR)
+
+
+/* handle_fieldaccess **********************************************************
+   Verify an ICMD_{GET,PUT}{STATIC,FIELD}(CONST)?
+  
+   IN:
+       state............the current state of the verifier
+
+   RETURN VALUE:
+       true.............successful verification,
+          false............an exception has been thrown.
+
+*******************************************************************************/
+
+static bool
+handle_fieldaccess(verifier_state *state, 
+                                  varinfo *instance,
+                                  varinfo *value)
+{
+       jitdata *jd;
+
+       jd = state->jd;
+
+#define TYPECHECK_TYPEINFERER
+#include <typecheck-fields.inc>
+#undef  TYPECHECK_TYPEINFERER
+
+       return true;
+}
+
+
+/* handle_invocation ***********************************************************
+   Verify an ICMD_INVOKE* instruction.
+  
+   IN:
+       state............the current state of the verifier
+
+   RETURN VALUE:
+       true.............successful verification,
+          false............an exception has been thrown.
+
+*******************************************************************************/
+
+static bool
+handle_invocation(verifier_state *state)
+{
+       jitdata *jd;
+    varinfo *dv;               /* output variable of current instruction */
+
+       jd = state->jd;
+       dv = VAROP(state->iptr->dst);
+
+#define TYPECHECK_TYPEINFERER
+#define OP1   VAR(state->iptr->sx.s23.s2.args[0])
+#include <typecheck-invoke.inc>
+#undef  OP1
+#undef  TYPECHECK_TYPEINFERER
+
+       return true;
+}
+
+
+/* handle_builtin **************************************************************
+   Verify the call of a builtin method.
+  
+   IN:
+       state............the current state of the verifier
+
+   RETURN VALUE:
+       true.............successful verification,
+          false............an exception has been thrown.
+
+*******************************************************************************/
+
+static bool
+handle_builtin(verifier_state *state)
+{
+       jitdata *jd;
+    varinfo *dv;               /* output variable of current instruction */
+
+       jd = state->jd;
+       dv = VAROP(state->iptr->dst);
+
+#define TYPECHECK_TYPEINFERER
+#define OP1   state->iptr->sx.s23.s2.args[0]
+#include <typecheck-builtins.inc>
+#undef  OP1
+#undef  TYPECHECK_TYPEINFERER
+
+       return true;
+}
+
+/* handle_multianewarray *******************************************************
+   Verify a MULTIANEWARRAY instruction.
+  
+   IN:
+       state............the current state of the verifier
+
+   RETURN VALUE:
+       true.............successful verification,
+          false............an exception has been thrown.
+
+*******************************************************************************/
+
+static bool
+handle_multianewarray(verifier_state *state)
+{
+       jitdata *jd;
+    varinfo *dv;               /* output variable of current instruction */
+
+       jd = state->jd;
+       dv = VAROP(state->iptr->dst);
+
+#define TYPECHECK_TYPEINFERER
+#include <typecheck-multianewarray.inc>
+#undef  TYPECHECK_TYPEINFERER
+
+       return true;
+}
+
+
+/* handle_basic_block **********************************************************
+   Perform bytecode verification of a basic block.
+  
+   IN:
+       state............the current state of the verifier
+
+   RETURN VALUE:
+       true.............successful verification,
+          false............an exception has been thrown.
+
+*******************************************************************************/
+
+static bool
+handle_basic_block(verifier_state *state)
+{
+    int opcode;                                      /* current opcode */
+    int len;                        /* for counting instructions, etc. */
+    bool superblockend;        /* true if no fallthrough to next block */
+       instruction *iptr;                      /* the current instruction */
+    basicblock *tbptr;                   /* temporary for target block */
+    bool maythrow;               /* true if this instruction may throw */
+       s4 i;
+       branch_target_t *table;
+       lookup_target_t *lookup;
+       jitdata *jd = state->jd;
+       exception_entry *ex;
+
+       LOGSTR1("\n---- BLOCK %04d ------------------------------------------------\n",state->bptr->nr);
+       LOGFLUSH;
+       DOLOG(show_basicblock(jd, state->bptr, SHOW_STACK));
+
+       superblockend = false;
+       state->bptr->flags = BBFINISHED;
+
+       /* prevent compiler warnings */
+
+
+       /* determine the active exception handlers for this block */
+       /* XXX could use a faster algorithm with sorted lists or  */
+       /* something?                                             */
+       len = 0;
+       for (ex = state->jd->exceptiontable; ex ; ex = ex->down) {
+               if ((ex->start->nr <= state->bptr->nr) && (ex->end->nr > state->bptr->nr)) {
+                       LOG1("active handler L%03d", ex->handler->nr);
+                       state->handlers[len++] = ex;
+               }
+       }
+       state->handlers[len] = NULL;
+
+       /* init variable types at the start of this block */
+       typevector_copy_inplace(state->bptr->inlocals, jd->var, state->numlocals);
+
+       DOLOG(typecheck_print_vararray(stdout, jd, state->bptr->invars, 
+                               state->bptr->indepth));
+       DOLOG(typevector_print(stdout, jd->var, state->numlocals));
+       LOGNL; LOGFLUSH;
+
+       /* loop over the instructions */
+       len = state->bptr->icount;
+       state->iptr = state->bptr->iinstr;
+       while (--len >= 0)  {
+               TYPECHECK_COUNT(stat_ins);
+
+               iptr = state->iptr;
+
+               DOLOG(typevector_print(stdout, jd->var, state->numlocals));
+               LOGNL; LOGFLUSH;
+               DOLOG(show_icmd(jd, state->iptr, false, SHOW_STACK)); LOGNL; LOGFLUSH;
+
+               opcode = iptr->opc;
+               maythrow = false;
+
+               switch (opcode) {
+
+                       /* include generated code for ICMDs verification */
+
+#define TYPECHECK_TYPEINFERER
+#define STATE  state
+#define METHOD (state->m)
+#define IPTR   iptr
+#define BPTR   (state->bptr)
+#include <typecheck-typeinferer-gen.inc>
+#undef  STATE
+#undef  METHOD
+#undef  IPTR
+#undef  BPTR
+#undef  TYPECHECK_TYPEINFERER
+
+                       default:
+                               vm_abort("missing ICMD in type inferer: %d\n", opcode);
+               }
+
+               /* reach exception handlers for this instruction */
+
+               if (maythrow) {
+                       TYPECHECK_COUNT(stat_ins_maythrow);
+                       TYPECHECK_MARK(state->stat_maythrow);
+                       LOG("reaching exception handlers");
+                       i = 0;
+                       while (state->handlers[i]) {
+                               TYPECHECK_COUNT(stat_handlers_reached);
+                               if (state->handlers[i]->catchtype.any)
+                                       VAR(state->exinvars)->typeinfo.typeclass = state->handlers[i]->catchtype;
+                               else
+                                       VAR(state->exinvars)->typeinfo.typeclass.cls = class_java_lang_Throwable;
+                               if (!typestate_reach(state,
+                                               state->handlers[i]->handler,
+                                               &(state->exinvars), jd->var, 1))
+                                       return false;
+                               i++;
+                       }
+               }
+
+               LOG("\t\tnext instruction");
+               state->iptr++;
+       } /* while instructions */
+
+       LOG("instructions done");
+       LOGSTR("RESULT=> ");
+       DOLOG(typecheck_print_vararray(stdout, jd, state->bptr->outvars,
+                               state->bptr->outdepth));
+       DOLOG(typevector_print(stdout, jd->var, state->numlocals));
+       LOGNL; LOGFLUSH;
+
+       /* propagate stack and variables to the following block */
+       if (!superblockend) {
+               LOG("reaching following block");
+               tbptr = state->bptr->next;
+               while (tbptr->flags == BBDELETED) {
+                       tbptr = tbptr->next;
+               }
+               if (!typestate_reach(state,tbptr,state->bptr->outvars, jd->var,
+                                       state->bptr->outdepth))
+                       return false;
+       }
+
+       return true;
+}
+
+
+bool typecheck_infer_types(jitdata *jd)
+{
+       methodinfo     *meth;
+       codegendata    *cd;
+       varinfo        *savedlocals;
+       verifier_state  state;             /* current state of the verifier */
+
+       /* get required compiler data */
+
+       meth = jd->m;
+       cd   = jd->cd;
+
+       /* some logging on entry */
+
+
+    LOGSTR("\n==============================================================================\n");
+    DOLOG( show_method(jd, SHOW_STACK) );
+    LOGSTR("\n==============================================================================\n");
+    LOGMETHOD("Entering type inference: ",cd->method);
+
+       /* initialize the verifier state */
+
+       state.m = meth;
+       state.jd = jd;
+       state.cd = cd;
+       state.basicblockcount = jd->basicblockcount;
+       state.basicblocks = jd->basicblocks;
+       state.savedindices = NULL;
+       state.savedinvars = NULL;
+
+       /* check that the basicblock numbers are valid */
+
+#if !defined(NDEBUG)
+       jit_check_basicblock_numbers(jd);
+#endif
+
+       /* check if this method is an instance initializer method */
+
+    state.initmethod = (state.m->name == utf_init);
+
+       /* initialize the basic block flags for the following CFG traversal */
+
+       typecheck_init_flags(&state, BBFINISHED);
+
+    /* number of local variables */
+    
+    /* In <init> methods we use an extra local variable to indicate whether */
+    /* the 'this' reference has been initialized.                           */
+       /*         TYPE_VOID...means 'this' has not been initialized,           */
+       /*         TYPE_INT....means 'this' has been initialized.               */
+
+    state.numlocals = state.jd->localcount;
+       state.validlocals = state.numlocals;
+    if (state.initmethod) 
+               state.numlocals++; /* VERIFIER_EXTRA_LOCALS */
+
+    /* allocate the buffer of active exception handlers */
+       
+    state.handlers = (exception_entry**) DumpMemory::allocate(sizeof(exception_entry*) * (state.jd->exceptiontablelength + 1));
+
+       /* save local variables */
+
+       savedlocals = (varinfo*) DumpMemory::allocate(sizeof(varinfo) * state.numlocals);
+       MCOPY(savedlocals, jd->var, varinfo, state.numlocals);
+
+       /* initialized local variables of first block */
+
+       if (!typecheck_init_locals(&state, false))
+               return false;
+
+    /* initialize invars of exception handlers */
+       
+       state.exinvars = state.numlocals;
+       VAR(state.exinvars)->type = TYPE_ADR;
+       typeinfo_init_classinfo(&(VAR(state.exinvars)->typeinfo),
+                                                       class_java_lang_Throwable); /* changed later */
+
+    LOG("Exception handler stacks set.\n");
+
+    /* loop while there are still blocks to be checked */
+    do {
+               TYPECHECK_COUNT(count_iterations);
+
+        state.repeat = false;
+        
+        state.bptr = state.basicblocks;
+
+        for (; state.bptr; state.bptr = state.bptr->next) {
+            LOGSTR1("---- BLOCK %04d, ",state.bptr->nr);
+            LOGSTR1("blockflags: %d\n",state.bptr->flags);
+            LOGFLUSH;
+            
+                   /* verify reached block */  
+            if (state.bptr->flags == BBTYPECHECK_REACHED) {
+                if (!handle_basic_block(&state))
+                                       return false;
+            }
+        } /* for blocks */
+
+        LOGIF(state.repeat,"state.repeat == true");
+    } while (state.repeat);
+
+       /* statistics */
+       
+       /* reset the flags of blocks we haven't reached */
+
+       typecheck_reset_flags(&state);
+
+       /* restore locals */
+
+       MCOPY(jd->var, savedlocals, varinfo, state.numlocals);
+
+       /* everything's ok */
+
+    LOGimp("exiting type inference");
+       return true;
+}
+
+#if defined(__cplusplus)
+}
+#endif
+
+/*
+ * 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
+ * Emacs will automagically detect them.
+ * ---------------------------------------------------------------------
+ * Local variables:
+ * mode: c
+ * indent-tabs-mode: t
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ * vim:noexpandtab:sw=4:ts=4:
+ */
diff --git a/src/vm/jit/verify/typecheck-typeinferer.h b/src/vm/jit/verify/typecheck-typeinferer.h
deleted file mode 100644 (file)
index 6684ac9..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-/* src/vm/jit/verify/typecheck-typeinferer.h - type inference header
-
-   Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel,
-   C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
-   E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
-   J. Wenninger, Institut f. Computersprachen - TU Wien
-
-   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., 51 Franklin Street, Fifth Floor, Boston, MA
-   02110-1301, USA.
-
-   Contact: cacao@cacaojvm.org
-
-   Authors: Edwin Steiner
-
-
-*/
-
-
-#ifndef _TYPECHECK_TYPEINFERER_H
-#define _TYPECHECK_TYPEINFERER_H
-
-#include "config.h"
-
-#include "vm/global.h"
-#include "vm/jit/jit.hpp"
-
-
-/* function prototypes ********************************************************/
-
-#if defined(ENABLE_VERIFIER)
-bool typecheck_infer_types(jitdata *jd);
-#endif
-
-#endif /* _TYPECHECK_TYPEINFERER_H */
-
-
-/*
- * 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
- * Emacs will automagically detect them.
- * ---------------------------------------------------------------------
- * Local variables:
- * mode: c
- * indent-tabs-mode: t
- * c-basic-offset: 4
- * tab-width: 4
- * End:
- */
diff --git a/src/vm/jit/verify/typecheck-typeinferer.hpp b/src/vm/jit/verify/typecheck-typeinferer.hpp
new file mode 100644 (file)
index 0000000..7bffa52
--- /dev/null
@@ -0,0 +1,69 @@
+/* src/vm/jit/verify/typecheck-typeinferer.h - type inference header
+
+   Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel,
+   C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
+   E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
+   J. Wenninger, Institut f. Computersprachen - TU Wien
+
+   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., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301, USA.
+
+   Contact: cacao@cacaojvm.org
+
+   Authors: Edwin Steiner
+
+
+*/
+
+
+#ifndef _TYPECHECK_TYPEINFERER_H
+#define _TYPECHECK_TYPEINFERER_H
+
+#include "config.h"
+
+#include "vm/global.h"
+#include "vm/jit/jit.hpp"
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/* function prototypes ********************************************************/
+
+#if defined(ENABLE_VERIFIER)
+bool typecheck_infer_types(jitdata *jd);
+#endif
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* _TYPECHECK_TYPEINFERER_H */
+
+
+/*
+ * 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
+ * Emacs will automagically detect them.
+ * ---------------------------------------------------------------------
+ * Local variables:
+ * mode: c
+ * indent-tabs-mode: t
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ */
diff --git a/src/vm/jit/verify/typecheck.c b/src/vm/jit/verify/typecheck.c
deleted file mode 100644 (file)
index 00e3cfd..0000000
+++ /dev/null
@@ -1,833 +0,0 @@
-/* src/vm/jit/verify/typecheck.c - typechecking (part of bytecode verification)
-
-   Copyright (C) 1996-2005, 2006, 2007, 2008
-   CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
-
-   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., 51 Franklin Street, Fifth Floor, Boston, MA
-   02110-1301, USA.
-
-*/
-
-/*
-
-What's the purpose of the `typechecker`?
-----------------------------------------
-
-The typechecker analyses (the intermediate repr. of) the bytecode of
-each method and ensures that for each instruction the values on the
-stack and in local variables are of the correct type whenever the
-instruction is executed.
-
-type checking is a mandatory part of bytecode verification.
-
-
-How does the typechecker work?
-------------------------------
-
-The JVM stack and the local variables are not statically typed, so the
-typechecker has to *infer* the static types of stack slots and local
-variables at each point of the method. The JVM spec imposes a lot of
-restrictions on the bytecode in order to guarantee that this is always
-possible.
-
-Basically the typechecker solves the data flow equations of the method.
-This is done in the usual way for a forward data flow analysis: Starting
-from the entry point of the method the typechecker follows the CFG and
-records the type of each stack slot and local variable at each point[1].
-When two or more control flow paths merge at a point, the union of the
-types for each slot/variable is taken. The algorithm continues to follow
-all possible paths[2] until the recorded types do not change anymore (ie.
-the equations have been solved).
-
-If the solution has been reached and the resulting types are valid for
-all instructions, then type checking terminates with success, otherwise
-an exception is thrown.
-
-
-Why is this code so damn complicated?
--------------------------------------
-
-Short answer: The devil's in the details.
-
-While the basic operation of the typechecker is no big deal, there are
-many properties of Java bytecode which make type checking hard. Some of
-them are not even addressed in the JVM spec. Some problems and their
-solutions:
-
-*) Finding a good representation of the union of two reference types is
-difficult because of multiple inheritance of interfaces. 
-
-       Solution: The typeinfo system can represent such "merged" types by a
-       list of proper subclasses of a class. Example:
-
-               typeclass=java.lang.Object merged={ InterfaceA, InterfaceB }
-       
-       represents the result of merging two interface types "InterfaceA"
-       and "InterfaceB".
-
-*) When the code of a method is verified, there may still be unresolved
-references to classes/methods/fields in the code, which we may not force
-to be resolved eagerly. (A similar problem arises because of the special
-checks for protected members.)
-
-       Solution: The typeinfo system knows how to deal with unresolved
-       class references. Whenever a check has to be performed for an
-       unresolved type, the type is annotated with constraints representing
-       the check. Later, when the type is resolved, the constraints are
-       checked. (See the constrain_unresolved_... and the resolve_...
-       methods.)[3]
-
-*) Checks for uninitialized object instances are hard because after the
-invocation of <init> on an uninitialized object *all* slots/variables
-referring to this object (and exactly those slots/variables) must be
-marked as initialized.
-
-       Solution: The JVM spec describes a solution, which has been
-       implemented in this typechecker.
-
-Note that some checks mentioned in the JVM spec are unnecessary[4] and
-not performed by either the reference implementation, or this implementation.
-
-
---- Footnotes
-
-[1] Actually only the types of slots/variables at the start of each
-basic block are remembered. Within a basic block the algorithm only keeps
-the types of the slots/variables for the "current" instruction which is
-being analysed. 
-
-[2] Actually the algorithm iterates through the basic block list until
-there are no more changes. Theoretically it would be wise to sort the
-basic blocks topologically beforehand, but the number of average/max
-iterations observed is so low, that this was not deemed necessary.
-
-[3] This is similar to a method proposed by: Alessandro Coglio et al., A
-Formal Specification of Java Class Loading, Technical Report, Kestrel
-Institute April 2000, revised July 2000 
-http://www.kestrel.edu/home/people/coglio/loading.pdf
-An important difference is that Coglio's subtype constraints are checked
-after loading, while our constraints are checked when the field/method
-is accessed for the first time, so we can guarantee lexically correct
-error reporting.
-
-[4] Alessandro Coglio
-    Improving the official specification of Java bytecode verification
-    Proceedings of the 3rd ECOOP Workshop on Formal Techniques for Java Programs
-    June 2001
-    citeseer.ist.psu.edu/article/coglio03improving.html
-*/
-
-
-#include "config.h"
-
-#include <assert.h>
-#include <string.h>
-
-#include "vm/types.h"
-
-#ifdef ENABLE_VERIFIER
-
-#include "mm/memory.h"
-
-#include "native/native.hpp"
-
-#include "toolbox/logging.h"
-
-#include "vm/access.h"
-#include "vm/array.hpp"
-#include "vm/jit/builtin.hpp"
-#include "vm/exceptions.hpp"
-#include "vm/global.h"
-#include "vm/globals.hpp"
-#include "vm/loader.hpp"
-#include "vm/options.h"
-#include "vm/primitive.hpp"
-#include "vm/resolve.hpp"
-
-#include "vm/jit/jit.hpp"
-#include "vm/jit/parse.hpp"
-#include "vm/jit/show.hpp"
-
-#include <typecheck-common.h>
-
-
-/****************************************************************************/
-/* MACROS FOR VARIABLE TYPE CHECKING                                        */
-/****************************************************************************/
-
-#define TYPECHECK_CHECK_TYPE(i,tp,msg)                               \
-    do {                                                             \
-        if (VAR(i)->type != (tp)) {                                  \
-            exceptions_throw_verifyerror(state->m, (msg));           \
-            return false;                                            \
-        }                                                            \
-    } while (0)
-
-#define TYPECHECK_INT(i)                                             \
-    TYPECHECK_CHECK_TYPE(i,TYPE_INT,"Expected to find integer value")
-#define TYPECHECK_LNG(i)                                             \
-    TYPECHECK_CHECK_TYPE(i,TYPE_LNG,"Expected to find long value")
-#define TYPECHECK_FLT(i)                                             \
-    TYPECHECK_CHECK_TYPE(i,TYPE_FLT,"Expected to find float value")
-#define TYPECHECK_DBL(i)                                             \
-    TYPECHECK_CHECK_TYPE(i,TYPE_DBL,"Expected to find double value")
-#define TYPECHECK_ADR(i)                                             \
-    TYPECHECK_CHECK_TYPE(i,TYPE_ADR,"Expected to find object value")
-
-#define TYPECHECK_INT_OP(o)  TYPECHECK_INT((o).varindex)
-#define TYPECHECK_LNG_OP(o)  TYPECHECK_LNG((o).varindex)
-#define TYPECHECK_FLT_OP(o)  TYPECHECK_FLT((o).varindex)
-#define TYPECHECK_DBL_OP(o)  TYPECHECK_DBL((o).varindex)
-#define TYPECHECK_ADR_OP(o)  TYPECHECK_ADR((o).varindex)
-
-
-/* typestate_save_invars *******************************************************
-   Save the invars of the current basic block in the space reserved by
-   parse.
-
-   This function must be called before an instruction modifies a variable
-   that is an invar of the current block. In such cases the invars of the
-   block must be saved, and restored at the end of the analysis of this
-   basic block, so that the invars again reflect the *input* to this basic
-   block (and do not randomly contain types that appear within the block).
-
-   IN:
-       state............current state of the verifier
-
-*******************************************************************************/
-
-static void
-typestate_save_invars(verifier_state *state)
-{
-       s4 i, index;
-       s4 *pindex;
-       
-       LOG("saving invars");
-
-       if (!state->savedindices) {
-               LOG("allocating savedindices buffer");
-               pindex = DMNEW(s4, state->m->maxstack);
-               state->savedindices = pindex;
-               index = state->numlocals + VERIFIER_EXTRA_VARS;
-               for (i=0; i<state->m->maxstack; ++i)
-                       *pindex++ = index++;
-       }
-
-       /* save types */
-
-       typecheck_copy_types(state, state->bptr->invars, state->savedindices, 
-                       state->bptr->indepth);
-
-       /* set the invars of the block to the saved variables */
-       /* and remember the original invars                   */
-
-       state->savedinvars = state->bptr->invars;
-       state->bptr->invars = state->savedindices;
-}
-
-
-/* typestate_restore_invars  ***************************************************
-   Restore the invars of the current basic block that have been previously
-   saved by `typestate_save_invars`.
-
-   IN:
-       state............current state of the verifier
-
-*******************************************************************************/
-
-static void
-typestate_restore_invars(verifier_state *state)
-{
-       TYPECHECK_COUNT(stat_savedstack);
-       LOG("restoring saved invars");
-
-       /* restore the invars pointer */
-
-       state->bptr->invars = state->savedinvars;
-
-       /* copy the types back */
-
-       typecheck_copy_types(state, state->savedindices, state->bptr->invars,
-                       state->bptr->indepth);
-
-       /* mark that there are no saved invars currently */
-
-       state->savedinvars = NULL;
-}
-
-
-/* handle_fieldaccess **********************************************************
-   Verify an ICMD_{GET,PUT}{STATIC,FIELD}(CONST)?
-  
-   IN:
-       state............the current state of the verifier
-
-   RETURN VALUE:
-       true.............successful verification,
-          false............an exception has been thrown.
-
-*******************************************************************************/
-
-static bool
-handle_fieldaccess(verifier_state *state,
-                                  varinfo *instance,
-                                  varinfo *value)
-{
-       jitdata *jd;
-
-       jd = state->jd;
-
-#define TYPECHECK_VARIABLESBASED
-#define EXCEPTION  do { return false; } while (0)
-#define VERIFY_ERROR(msg)  TYPECHECK_VERIFYERROR_bool(msg)
-#include <typecheck-fields.inc>
-#undef  EXCEPTION
-#undef  VERIFY_ERROR
-#undef  TYPECHECK_VARIABLESBASED
-
-       return true;
-}
-
-
-/* handle_invocation ***********************************************************
-   Verify an ICMD_INVOKE* instruction.
-  
-   IN:
-       state............the current state of the verifier
-
-   RETURN VALUE:
-       true.............successful verification,
-          false............an exception has been thrown.
-
-*******************************************************************************/
-
-static bool
-handle_invocation(verifier_state *state)
-{
-       jitdata *jd;
-    varinfo *dv;               /* output variable of current instruction */
-
-       jd = state->jd;
-       dv = VAROP(state->iptr->dst);
-
-#define TYPECHECK_VARIABLESBASED
-#define OP1   VAR(state->iptr->sx.s23.s2.args[0])
-#include <typecheck-invoke.inc>
-#undef  OP1
-#undef  TYPECHECK_VARIABLESBASED
-
-       return true;
-}
-
-
-/* handle_builtin **************************************************************
-   Verify the call of a builtin method.
-  
-   IN:
-       state............the current state of the verifier
-
-   RETURN VALUE:
-       true.............successful verification,
-          false............an exception has been thrown.
-
-*******************************************************************************/
-
-static bool
-handle_builtin(verifier_state *state)
-{
-       jitdata *jd;
-    varinfo *dv;               /* output variable of current instruction */
-
-       jd = state->jd;
-       dv = VAROP(state->iptr->dst);
-
-#define TYPECHECK_VARIABLESBASED
-#define OP1   state->iptr->sx.s23.s2.args[0]
-#include <typecheck-builtins.inc>
-#undef  OP1
-#undef  TYPECHECK_VARIABLESBASED
-
-       return true;
-}
-
-/* handle_multianewarray *******************************************************
-   Verify a MULTIANEWARRAY instruction.
-  
-   IN:
-       state............the current state of the verifier
-
-   RETURN VALUE:
-       true.............successful verification,
-          false............an exception has been thrown.
-
-*******************************************************************************/
-
-static bool
-handle_multianewarray(verifier_state *state)
-{
-       jitdata *jd;
-    varinfo *dv;               /* output variable of current instruction */
-
-       jd = state->jd;
-       dv = VAROP(state->iptr->dst);
-
-#define TYPECHECK_VARIABLESBASED
-#define VERIFY_ERROR(msg)  TYPECHECK_VERIFYERROR_bool(msg)
-#include <typecheck-multianewarray.inc>
-#undef VERIFY_ERROR
-#undef  TYPECHECK_VARIABLESBASED
-
-       return true;
-}
-
-/* typecheck_invalidate_locals *************************************************
-   Invalidate locals that are overwritten by writing to the given local.
-  
-   IN:
-       state............the current state of the verifier
-          index............the index of the local that is written
-          twoword..........true, if a two-word type is written
-
-*******************************************************************************/
-
-static void typecheck_invalidate_locals(verifier_state *state, s4 index, bool twoword)
-{
-       s4 javaindex;
-       s4 t;
-       s4 varindex;
-       jitdata *jd = state->jd;
-       s4 *localmap = jd->local_map;
-       varinfo *vars = jd->var;
-
-       javaindex = jd->reverselocalmap[index];
-
-       /* invalidate locals of two-word type at index javaindex-1 */
-
-       if (javaindex > 0) {
-               localmap += 5 * (javaindex-1);
-               for (t=0; t<5; ++t) {
-                       varindex = *localmap++;
-                       if (varindex >= 0 && IS_2_WORD_TYPE(vars[varindex].type)) {
-                               LOG1("invalidate local %d", varindex);
-                               vars[varindex].type = TYPE_VOID;
-                       }
-               }
-       }
-       else {
-               localmap += 5 * javaindex;
-       }
-
-       /* invalidate locals at index javaindex */
-
-       for (t=0; t<5; ++t) {
-               varindex = *localmap++;
-               if (varindex >= 0) {
-                       LOG1("invalidate local %d", varindex);
-                       vars[varindex].type = TYPE_VOID;
-               }
-       }
-
-       /* if a two-word type is written, invalidate locals at index javaindex+1 */
-
-       if (twoword) {
-               for (t=0; t<5; ++t) {
-                       varindex = *localmap++;
-                       if (varindex >= 0) {
-                               LOG1("invalidate local %d", varindex);
-                               vars[varindex].type = TYPE_VOID;
-                       }
-               }
-       }
-}
-
-
-/* macros used by the generated code ******************************************/
-
-#define EXCEPTION          do { return false; } while (0)
-#define VERIFY_ERROR(msg)  TYPECHECK_VERIFYERROR_bool(msg)
-
-#define CHECK_LOCAL_TYPE(index, t)                                   \
-    do {                                                             \
-        if (!typevector_checktype(jd->var, (index), (t)))            \
-             VERIFY_ERROR("Local variable type mismatch");           \
-    } while (0)
-
-#define STORE_LOCAL(t, index)                                        \
-    do {                                                             \
-         s4 temp_t = (t);                                            \
-         typecheck_invalidate_locals(state, (index), false);         \
-         typevector_store(jd->var, (index), (temp_t), NULL);         \
-    } while (0)
-
-#define STORE_LOCAL_2_WORD(t, index)                                 \
-    do {                                                             \
-         s4 temp_t = (t);                                            \
-         typecheck_invalidate_locals(state, (index), true);          \
-         typevector_store(jd->var, (index), (temp_t), NULL);         \
-    } while (0)
-
-#define REACH_BLOCK(target)                                          \
-    do {                                                             \
-        if (!typestate_reach(state, (target),                        \
-                             state->bptr->outvars, jd->var,          \
-                             state->bptr->outdepth))                 \
-                return false;                                        \
-    } while (0)
-
-#define REACH(target)   REACH_BLOCK((target).block)
-
-
-/* handle_basic_block **********************************************************
-   Perform bytecode verification of a basic block.
-  
-   IN:
-       state............the current state of the verifier
-
-   RETURN VALUE:
-       true.............successful verification,
-          false............an exception has been thrown.
-
-*******************************************************************************/
-
-static bool
-handle_basic_block(verifier_state *state)
-{
-    int opcode;                                      /* current opcode */
-    int len;                        /* for counting instructions, etc. */
-    bool superblockend;        /* true if no fallthrough to next block */
-       instruction *iptr;                      /* the current instruction */
-    basicblock *tbptr;                   /* temporary for target block */
-    bool maythrow;               /* true if this instruction may throw */
-       s4 i;
-       typecheck_result r;
-       branch_target_t *table;
-       lookup_target_t *lookup;
-       jitdata *jd = state->jd;
-       exception_entry *ex;
-       varinfo constvalue;                               /* for PUT*CONST */
-       constant_FMIref *fieldref;
-
-       LOGSTR1("\n---- BLOCK %04d ------------------------------------------------\n",state->bptr->nr);
-       LOGFLUSH;
-
-       superblockend = false;
-       state->bptr->flags = BBFINISHED;
-
-       /* prevent compiler warnings */
-
-
-       /* determine the active exception handlers for this block */
-       /* XXX could use a faster algorithm with sorted lists or  */
-       /* something?                                             */
-       len = 0;
-       for (ex = state->jd->exceptiontable; ex ; ex = ex->down) {
-               if ((ex->start->nr <= state->bptr->nr) && (ex->end->nr > state->bptr->nr)) {
-                       LOG1("active handler L%03d", ex->handler->nr);
-                       state->handlers[len++] = ex;
-               }
-       }
-       state->handlers[len] = NULL;
-
-       /* init variable types at the start of this block */
-       typevector_copy_inplace(state->bptr->inlocals, jd->var, state->numlocals);
-
-       DOLOG(show_basicblock(jd, state->bptr, SHOW_STACK));
-       DOLOG(typecheck_print_vararray(stdout, jd, state->bptr->invars, 
-                               state->bptr->indepth));
-       DOLOG(typevector_print(stdout, jd->var, state->numlocals));
-       LOGNL; LOGFLUSH;
-
-       /* loop over the instructions */
-       len = state->bptr->icount;
-       state->iptr = state->bptr->iinstr;
-       while (--len >= 0)  {
-               TYPECHECK_COUNT(stat_ins);
-
-               iptr = state->iptr;
-
-               DOLOG(typevector_print(stdout, jd->var, state->numlocals));
-               LOGNL; LOGFLUSH;
-               DOLOG(show_icmd(jd, state->iptr, false, SHOW_STACK)); LOGNL; LOGFLUSH;
-
-               opcode = iptr->opc;
-               maythrow = false;
-
-               switch (opcode) {
-
-                       /* include generated code for ICMDs verification */
-
-#define TYPECHECK_VARIABLESBASED
-#define STATE  state
-#define METHOD (state->m)
-#define IPTR   iptr
-#define BPTR   (state->bptr)
-#include <typecheck-variablesbased-gen.inc>
-#undef  STATE
-#undef  METHOD
-#undef  IPTR
-#undef  BPTR
-#undef  TYPECHECK_VARIABLESBASED
-
-                       default:
-                               LOG1("ICMD %d\n", opcode);
-                               TYPECHECK_VERIFYERROR_bool("Missing ICMD code during typecheck");
-               }
-
-               /* reach exception handlers for this instruction */
-
-               if (maythrow) {
-                       TYPECHECK_COUNT(stat_ins_maythrow);
-                       TYPECHECK_MARK(state->stat_maythrow);
-                       LOG("reaching exception handlers");
-                       i = 0;
-                       while (state->handlers[i]) {
-                               TYPECHECK_COUNT(stat_handlers_reached);
-                               if (state->handlers[i]->catchtype.any)
-                                       VAR(state->exinvars)->typeinfo.typeclass = state->handlers[i]->catchtype;
-                               else
-                                       VAR(state->exinvars)->typeinfo.typeclass.cls = class_java_lang_Throwable;
-                               if (!typestate_reach(state,
-                                               state->handlers[i]->handler,
-                                               &(state->exinvars), jd->var, 1))
-                                       return false;
-                               i++;
-                       }
-               }
-
-               LOG("\t\tnext instruction");
-               state->iptr++;
-       } /* while instructions */
-
-       LOG("instructions done");
-       LOGSTR("RESULT=> ");
-       DOLOG(typecheck_print_vararray(stdout, jd, state->bptr->outvars,
-                               state->bptr->outdepth));
-       DOLOG(typevector_print(stdout, jd->var, state->numlocals));
-       LOGNL; LOGFLUSH;
-
-       /* propagate stack and variables to the following block */
-       if (!superblockend) {
-               LOG("reaching following block");
-               tbptr = state->bptr->next;
-               while (tbptr->flags == BBDELETED) {
-                       tbptr = tbptr->next;
-#ifdef TYPECHECK_DEBUG
-                       /* this must be checked in parse.c */
-                       if ((tbptr->nr) >= state->basicblockcount)
-                               TYPECHECK_VERIFYERROR_bool("Control flow falls off the last block");
-#endif
-               }
-               if (!typestate_reach(state,tbptr,state->bptr->outvars, jd->var,
-                                       state->bptr->outdepth))
-                       return false;
-       }
-
-       /* We may have to restore the types of the instack slots. They
-        * have been saved if an <init> call inside the block has
-        * modified the instack types. (see INVOKESPECIAL) */
-
-       if (state->savedinvars)
-               typestate_restore_invars(state);
-
-       return true;
-}
-
-
-/****************************************************************************/
-/* typecheck()                                                              */
-/* This is the main function of the bytecode verifier. It is called         */
-/* directly after analyse_stack.                                            */
-/*                                                                          */
-/* IN:                                                                      */
-/*    meth.............the method to verify                                 */
-/*    cdata............codegendata for the method                           */
-/*    rdata............registerdata for the method                          */
-/*                                                                          */
-/* RETURN VALUE:                                                            */
-/*     true.............successful verification                             */
-/*     false............an exception has been thrown                        */
-/*                                                                          */
-/****************************************************************************/
-
-#define MAXPARAMS 255
-
-bool typecheck(jitdata *jd)
-{
-       methodinfo     *meth;
-       codegendata    *cd;
-       varinfo        *savedlocals;
-       verifier_state  state;             /* current state of the verifier */
-
-       /* collect statistics */
-
-#ifdef TYPECHECK_STATISTICS
-       int count_iterations = 0;
-       TYPECHECK_COUNT(stat_typechecked);
-       TYPECHECK_COUNT_FREQ(stat_locals,jd->maxlocals,STAT_LOCALS);
-       TYPECHECK_COUNT_FREQ(stat_blocks,cdata->method->basicblockcount/10,STAT_BLOCKS);
-       TYPECHECK_COUNTIF(cdata->method->exceptiontablelength != 0,stat_methods_with_handlers);
-       state.stat_maythrow = false;
-#endif
-
-       /* get required compiler data */
-
-       meth = jd->m;
-       cd   = jd->cd;
-
-       /* some logging on entry */
-
-
-    LOGSTR("\n==============================================================================\n");
-    DOLOG( show_method(jd, SHOW_STACK) );
-    LOGSTR("\n==============================================================================\n");
-    LOGMETHOD("Entering typecheck: ",cd->method);
-
-       /* initialize the verifier state */
-
-       state.m = meth;
-       state.jd = jd;
-       state.cd = cd;
-       state.basicblockcount = jd->basicblockcount;
-       state.basicblocks = jd->basicblocks;
-       state.savedindices = NULL;
-       state.savedinvars = NULL;
-
-       /* check that the basicblock numbers are valid */
-
-#if !defined(NDEBUG)
-       jit_check_basicblock_numbers(jd);
-#endif
-
-       /* check if this method is an instance initializer method */
-
-    state.initmethod = (state.m->name == utf_init);
-
-       /* initialize the basic block flags for the following CFG traversal */
-
-       typecheck_init_flags(&state, BBFINISHED);
-
-    /* number of local variables */
-    
-    /* In <init> methods we use an extra local variable to indicate whether */
-    /* the 'this' reference has been initialized.                           */
-       /*         TYPE_VOID...means 'this' has not been initialized,           */
-       /*         TYPE_INT....means 'this' has been initialized.               */
-
-    state.numlocals = state.jd->localcount;
-       state.validlocals = state.numlocals;
-    if (state.initmethod) 
-               state.numlocals++; /* VERIFIER_EXTRA_LOCALS */
-
-       DOLOG(
-               s4 i;
-               s4 t;
-               LOG("reverselocalmap:");
-               for (i=0; i<state.validlocals; ++i) {
-                       LOG2("    %i => javaindex %i", i, jd->reverselocalmap[i]);
-               });
-
-    /* allocate the buffer of active exception handlers */
-       
-    state.handlers = DMNEW(exception_entry*, state.jd->exceptiontablelength + 1);
-
-       /* save local variables */
-
-       savedlocals = DMNEW(varinfo, state.numlocals);
-       MCOPY(savedlocals, jd->var, varinfo, state.numlocals);
-
-       /* initialized local variables of first block */
-
-       if (!typecheck_init_locals(&state, true))
-               return false;
-
-    /* initialize invars of exception handlers */
-       
-       state.exinvars = state.numlocals;
-       VAR(state.exinvars)->type = TYPE_ADR;
-       typeinfo_init_classinfo(&(VAR(state.exinvars)->typeinfo),
-                                                       class_java_lang_Throwable); /* changed later */
-
-    LOG("Exception handler stacks set.\n");
-
-    /* loop while there are still blocks to be checked */
-    do {
-               TYPECHECK_COUNT(count_iterations);
-
-        state.repeat = false;
-        
-        state.bptr = state.basicblocks;
-
-        for (; state.bptr; state.bptr = state.bptr->next) {
-            LOGSTR1("---- BLOCK %04d, ",state.bptr->nr);
-            LOGSTR1("blockflags: %d\n",state.bptr->flags);
-            LOGFLUSH;
-            
-                   /* verify reached block */  
-            if (state.bptr->flags == BBTYPECHECK_REACHED) {
-                if (!handle_basic_block(&state))
-                                       return false;
-            }
-        } /* for blocks */
-
-        LOGIF(state.repeat,"state.repeat == true");
-    } while (state.repeat);
-
-       /* statistics */
-       
-#ifdef TYPECHECK_STATISTICS
-       LOG1("Typechecker did %4d iterations",count_iterations);
-       TYPECHECK_COUNT_FREQ(stat_iterations,count_iterations,STAT_ITERATIONS);
-       TYPECHECK_COUNTIF(state.jsrencountered,stat_typechecked_jsr);
-       TYPECHECK_COUNTIF(state.stat_maythrow,stat_methods_maythrow);
-#endif
-
-       /* reset the flags of blocks we haven't reached */
-
-       typecheck_reset_flags(&state);
-
-       /* restore locals */
-
-       MCOPY(jd->var, savedlocals, varinfo, state.numlocals);
-
-       /* everything's ok */
-
-    LOGimp("exiting typecheck");
-       return true;
-}
-#endif /* ENABLE_VERIFIER */
-
-/*
- * 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
- * Emacs will automagically detect them.
- * ---------------------------------------------------------------------
- * Local variables:
- * mode: c
- * indent-tabs-mode: t
- * c-basic-offset: 4
- * tab-width: 4
- * End:
- * vim:noexpandtab:sw=4:ts=4:
- */
diff --git a/src/vm/jit/verify/typecheck.cpp b/src/vm/jit/verify/typecheck.cpp
new file mode 100644 (file)
index 0000000..574e33a
--- /dev/null
@@ -0,0 +1,841 @@
+/* src/vm/jit/verify/typecheck.c - typechecking (part of bytecode verification)
+
+   Copyright (C) 1996-2005, 2006, 2007, 2008
+   CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
+
+   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., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301, USA.
+
+*/
+
+/*
+
+What's the purpose of the `typechecker`?
+----------------------------------------
+
+The typechecker analyses (the intermediate repr. of) the bytecode of
+each method and ensures that for each instruction the values on the
+stack and in local variables are of the correct type whenever the
+instruction is executed.
+
+type checking is a mandatory part of bytecode verification.
+
+
+How does the typechecker work?
+------------------------------
+
+The JVM stack and the local variables are not statically typed, so the
+typechecker has to *infer* the static types of stack slots and local
+variables at each point of the method. The JVM spec imposes a lot of
+restrictions on the bytecode in order to guarantee that this is always
+possible.
+
+Basically the typechecker solves the data flow equations of the method.
+This is done in the usual way for a forward data flow analysis: Starting
+from the entry point of the method the typechecker follows the CFG and
+records the type of each stack slot and local variable at each point[1].
+When two or more control flow paths merge at a point, the union of the
+types for each slot/variable is taken. The algorithm continues to follow
+all possible paths[2] until the recorded types do not change anymore (ie.
+the equations have been solved).
+
+If the solution has been reached and the resulting types are valid for
+all instructions, then type checking terminates with success, otherwise
+an exception is thrown.
+
+
+Why is this code so damn complicated?
+-------------------------------------
+
+Short answer: The devil's in the details.
+
+While the basic operation of the typechecker is no big deal, there are
+many properties of Java bytecode which make type checking hard. Some of
+them are not even addressed in the JVM spec. Some problems and their
+solutions:
+
+*) Finding a good representation of the union of two reference types is
+difficult because of multiple inheritance of interfaces. 
+
+       Solution: The typeinfo system can represent such "merged" types by a
+       list of proper subclasses of a class. Example:
+
+               typeclass=java.lang.Object merged={ InterfaceA, InterfaceB }
+       
+       represents the result of merging two interface types "InterfaceA"
+       and "InterfaceB".
+
+*) When the code of a method is verified, there may still be unresolved
+references to classes/methods/fields in the code, which we may not force
+to be resolved eagerly. (A similar problem arises because of the special
+checks for protected members.)
+
+       Solution: The typeinfo system knows how to deal with unresolved
+       class references. Whenever a check has to be performed for an
+       unresolved type, the type is annotated with constraints representing
+       the check. Later, when the type is resolved, the constraints are
+       checked. (See the constrain_unresolved_... and the resolve_...
+       methods.)[3]
+
+*) Checks for uninitialized object instances are hard because after the
+invocation of <init> on an uninitialized object *all* slots/variables
+referring to this object (and exactly those slots/variables) must be
+marked as initialized.
+
+       Solution: The JVM spec describes a solution, which has been
+       implemented in this typechecker.
+
+Note that some checks mentioned in the JVM spec are unnecessary[4] and
+not performed by either the reference implementation, or this implementation.
+
+
+--- Footnotes
+
+[1] Actually only the types of slots/variables at the start of each
+basic block are remembered. Within a basic block the algorithm only keeps
+the types of the slots/variables for the "current" instruction which is
+being analysed. 
+
+[2] Actually the algorithm iterates through the basic block list until
+there are no more changes. Theoretically it would be wise to sort the
+basic blocks topologically beforehand, but the number of average/max
+iterations observed is so low, that this was not deemed necessary.
+
+[3] This is similar to a method proposed by: Alessandro Coglio et al., A
+Formal Specification of Java Class Loading, Technical Report, Kestrel
+Institute April 2000, revised July 2000 
+http://www.kestrel.edu/home/people/coglio/loading.pdf
+An important difference is that Coglio's subtype constraints are checked
+after loading, while our constraints are checked when the field/method
+is accessed for the first time, so we can guarantee lexically correct
+error reporting.
+
+[4] Alessandro Coglio
+    Improving the official specification of Java bytecode verification
+    Proceedings of the 3rd ECOOP Workshop on Formal Techniques for Java Programs
+    June 2001
+    citeseer.ist.psu.edu/article/coglio03improving.html
+*/
+
+
+#include "config.h"
+
+#include <assert.h>
+#include <string.h>
+
+#include "vm/types.h"
+
+#ifdef ENABLE_VERIFIER
+
+#include "mm/memory.h"
+
+#include "native/native.hpp"
+
+#include "toolbox/logging.h"
+
+#include "vm/access.h"
+#include "vm/array.hpp"
+#include "vm/jit/builtin.hpp"
+#include "vm/exceptions.hpp"
+#include "vm/global.h"
+#include "vm/globals.hpp"
+#include "vm/loader.hpp"
+#include "vm/options.h"
+#include "vm/primitive.hpp"
+#include "vm/resolve.hpp"
+
+#include "vm/jit/jit.hpp"
+#include "vm/jit/parse.hpp"
+#include "vm/jit/show.hpp"
+
+#include "vm/jit/verify/typecheck-common.hpp"
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/****************************************************************************/
+/* MACROS FOR VARIABLE TYPE CHECKING                                        */
+/****************************************************************************/
+
+#define TYPECHECK_CHECK_TYPE(i,tp,msg)                               \
+    do {                                                             \
+        if (VAR(i)->type != (tp)) {                                  \
+            exceptions_throw_verifyerror(state->m, (msg));           \
+            return false;                                            \
+        }                                                            \
+    } while (0)
+
+#define TYPECHECK_INT(i)                                             \
+    TYPECHECK_CHECK_TYPE(i,TYPE_INT,"Expected to find integer value")
+#define TYPECHECK_LNG(i)                                             \
+    TYPECHECK_CHECK_TYPE(i,TYPE_LNG,"Expected to find long value")
+#define TYPECHECK_FLT(i)                                             \
+    TYPECHECK_CHECK_TYPE(i,TYPE_FLT,"Expected to find float value")
+#define TYPECHECK_DBL(i)                                             \
+    TYPECHECK_CHECK_TYPE(i,TYPE_DBL,"Expected to find double value")
+#define TYPECHECK_ADR(i)                                             \
+    TYPECHECK_CHECK_TYPE(i,TYPE_ADR,"Expected to find object value")
+
+#define TYPECHECK_INT_OP(o)  TYPECHECK_INT((o).varindex)
+#define TYPECHECK_LNG_OP(o)  TYPECHECK_LNG((o).varindex)
+#define TYPECHECK_FLT_OP(o)  TYPECHECK_FLT((o).varindex)
+#define TYPECHECK_DBL_OP(o)  TYPECHECK_DBL((o).varindex)
+#define TYPECHECK_ADR_OP(o)  TYPECHECK_ADR((o).varindex)
+
+
+/* typestate_save_invars *******************************************************
+   Save the invars of the current basic block in the space reserved by
+   parse.
+
+   This function must be called before an instruction modifies a variable
+   that is an invar of the current block. In such cases the invars of the
+   block must be saved, and restored at the end of the analysis of this
+   basic block, so that the invars again reflect the *input* to this basic
+   block (and do not randomly contain types that appear within the block).
+
+   IN:
+       state............current state of the verifier
+
+*******************************************************************************/
+
+static void
+typestate_save_invars(verifier_state *state)
+{
+       s4 i, index;
+       s4 *pindex;
+       
+       LOG("saving invars");
+
+       if (!state->savedindices) {
+               LOG("allocating savedindices buffer");
+               pindex = (s4*) DumpMemory::allocate(sizeof(s4) * state->m->maxstack);
+               state->savedindices = pindex;
+               index = state->numlocals + VERIFIER_EXTRA_VARS;
+               for (i=0; i<state->m->maxstack; ++i)
+                       *pindex++ = index++;
+       }
+
+       /* save types */
+
+       typecheck_copy_types(state, state->bptr->invars, state->savedindices, 
+                       state->bptr->indepth);
+
+       /* set the invars of the block to the saved variables */
+       /* and remember the original invars                   */
+
+       state->savedinvars = state->bptr->invars;
+       state->bptr->invars = state->savedindices;
+}
+
+
+/* typestate_restore_invars  ***************************************************
+   Restore the invars of the current basic block that have been previously
+   saved by `typestate_save_invars`.
+
+   IN:
+       state............current state of the verifier
+
+*******************************************************************************/
+
+static void
+typestate_restore_invars(verifier_state *state)
+{
+       TYPECHECK_COUNT(stat_savedstack);
+       LOG("restoring saved invars");
+
+       /* restore the invars pointer */
+
+       state->bptr->invars = state->savedinvars;
+
+       /* copy the types back */
+
+       typecheck_copy_types(state, state->savedindices, state->bptr->invars,
+                       state->bptr->indepth);
+
+       /* mark that there are no saved invars currently */
+
+       state->savedinvars = NULL;
+}
+
+
+/* handle_fieldaccess **********************************************************
+   Verify an ICMD_{GET,PUT}{STATIC,FIELD}(CONST)?
+  
+   IN:
+       state............the current state of the verifier
+
+   RETURN VALUE:
+       true.............successful verification,
+          false............an exception has been thrown.
+
+*******************************************************************************/
+
+static bool
+handle_fieldaccess(verifier_state *state,
+                                  varinfo *instance,
+                                  varinfo *value)
+{
+       jitdata *jd;
+
+       jd = state->jd;
+
+#define TYPECHECK_VARIABLESBASED
+#define EXCEPTION  do { return false; } while (0)
+#define VERIFY_ERROR(msg)  TYPECHECK_VERIFYERROR_bool(msg)
+#include <typecheck-fields.inc>
+#undef  EXCEPTION
+#undef  VERIFY_ERROR
+#undef  TYPECHECK_VARIABLESBASED
+
+       return true;
+}
+
+
+/* handle_invocation ***********************************************************
+   Verify an ICMD_INVOKE* instruction.
+  
+   IN:
+       state............the current state of the verifier
+
+   RETURN VALUE:
+       true.............successful verification,
+          false............an exception has been thrown.
+
+*******************************************************************************/
+
+static bool
+handle_invocation(verifier_state *state)
+{
+       jitdata *jd;
+    varinfo *dv;               /* output variable of current instruction */
+
+       jd = state->jd;
+       dv = VAROP(state->iptr->dst);
+
+#define TYPECHECK_VARIABLESBASED
+#define OP1   VAR(state->iptr->sx.s23.s2.args[0])
+#include <typecheck-invoke.inc>
+#undef  OP1
+#undef  TYPECHECK_VARIABLESBASED
+
+       return true;
+}
+
+
+/* handle_builtin **************************************************************
+   Verify the call of a builtin method.
+  
+   IN:
+       state............the current state of the verifier
+
+   RETURN VALUE:
+       true.............successful verification,
+          false............an exception has been thrown.
+
+*******************************************************************************/
+
+static bool
+handle_builtin(verifier_state *state)
+{
+       jitdata *jd;
+    varinfo *dv;               /* output variable of current instruction */
+
+       jd = state->jd;
+       dv = VAROP(state->iptr->dst);
+
+#define TYPECHECK_VARIABLESBASED
+#define OP1   state->iptr->sx.s23.s2.args[0]
+#include <typecheck-builtins.inc>
+#undef  OP1
+#undef  TYPECHECK_VARIABLESBASED
+
+       return true;
+}
+
+/* handle_multianewarray *******************************************************
+   Verify a MULTIANEWARRAY instruction.
+  
+   IN:
+       state............the current state of the verifier
+
+   RETURN VALUE:
+       true.............successful verification,
+          false............an exception has been thrown.
+
+*******************************************************************************/
+
+static bool
+handle_multianewarray(verifier_state *state)
+{
+       jitdata *jd;
+    varinfo *dv;               /* output variable of current instruction */
+
+       jd = state->jd;
+       dv = VAROP(state->iptr->dst);
+
+#define TYPECHECK_VARIABLESBASED
+#define VERIFY_ERROR(msg)  TYPECHECK_VERIFYERROR_bool(msg)
+#include <typecheck-multianewarray.inc>
+#undef VERIFY_ERROR
+#undef  TYPECHECK_VARIABLESBASED
+
+       return true;
+}
+
+/* typecheck_invalidate_locals *************************************************
+   Invalidate locals that are overwritten by writing to the given local.
+  
+   IN:
+       state............the current state of the verifier
+          index............the index of the local that is written
+          twoword..........true, if a two-word type is written
+
+*******************************************************************************/
+
+static void typecheck_invalidate_locals(verifier_state *state, s4 index, bool twoword)
+{
+       s4 javaindex;
+       s4 t;
+       s4 varindex;
+       jitdata *jd = state->jd;
+       s4 *localmap = jd->local_map;
+       varinfo *vars = jd->var;
+
+       javaindex = jd->reverselocalmap[index];
+
+       /* invalidate locals of two-word type at index javaindex-1 */
+
+       if (javaindex > 0) {
+               localmap += 5 * (javaindex-1);
+               for (t=0; t<5; ++t) {
+                       varindex = *localmap++;
+                       if (varindex >= 0 && IS_2_WORD_TYPE(vars[varindex].type)) {
+                               LOG1("invalidate local %d", varindex);
+                               vars[varindex].type = TYPE_VOID;
+                       }
+               }
+       }
+       else {
+               localmap += 5 * javaindex;
+       }
+
+       /* invalidate locals at index javaindex */
+
+       for (t=0; t<5; ++t) {
+               varindex = *localmap++;
+               if (varindex >= 0) {
+                       LOG1("invalidate local %d", varindex);
+                       vars[varindex].type = TYPE_VOID;
+               }
+       }
+
+       /* if a two-word type is written, invalidate locals at index javaindex+1 */
+
+       if (twoword) {
+               for (t=0; t<5; ++t) {
+                       varindex = *localmap++;
+                       if (varindex >= 0) {
+                               LOG1("invalidate local %d", varindex);
+                               vars[varindex].type = TYPE_VOID;
+                       }
+               }
+       }
+}
+
+
+/* macros used by the generated code ******************************************/
+
+#define EXCEPTION          do { return false; } while (0)
+#define VERIFY_ERROR(msg)  TYPECHECK_VERIFYERROR_bool(msg)
+
+#define CHECK_LOCAL_TYPE(index, t)                                   \
+    do {                                                             \
+        if (!typevector_checktype(jd->var, (index), (t)))            \
+             VERIFY_ERROR("Local variable type mismatch");           \
+    } while (0)
+
+#define STORE_LOCAL(t, index)                                        \
+    do {                                                             \
+         s4 temp_t = (t);                                            \
+         typecheck_invalidate_locals(state, (index), false);         \
+         typevector_store(jd->var, (index), (temp_t), NULL);         \
+    } while (0)
+
+#define STORE_LOCAL_2_WORD(t, index)                                 \
+    do {                                                             \
+         s4 temp_t = (t);                                            \
+         typecheck_invalidate_locals(state, (index), true);          \
+         typevector_store(jd->var, (index), (temp_t), NULL);         \
+    } while (0)
+
+#define REACH_BLOCK(target)                                          \
+    do {                                                             \
+        if (!typestate_reach(state, (target),                        \
+                             state->bptr->outvars, jd->var,          \
+                             state->bptr->outdepth))                 \
+                return false;                                        \
+    } while (0)
+
+#define REACH(target)   REACH_BLOCK((target).block)
+
+
+/* handle_basic_block **********************************************************
+   Perform bytecode verification of a basic block.
+  
+   IN:
+       state............the current state of the verifier
+
+   RETURN VALUE:
+       true.............successful verification,
+          false............an exception has been thrown.
+
+*******************************************************************************/
+
+static bool
+handle_basic_block(verifier_state *state)
+{
+    int opcode;                                      /* current opcode */
+    int len;                        /* for counting instructions, etc. */
+    bool superblockend;        /* true if no fallthrough to next block */
+       instruction *iptr;                      /* the current instruction */
+    basicblock *tbptr;                   /* temporary for target block */
+    bool maythrow;               /* true if this instruction may throw */
+       s4 i;
+       typecheck_result r;
+       branch_target_t *table;
+       lookup_target_t *lookup;
+       jitdata *jd = state->jd;
+       exception_entry *ex;
+       varinfo constvalue;                               /* for PUT*CONST */
+       constant_FMIref *fieldref;
+
+       LOGSTR1("\n---- BLOCK %04d ------------------------------------------------\n",state->bptr->nr);
+       LOGFLUSH;
+
+       superblockend = false;
+       state->bptr->flags = BBFINISHED;
+
+       /* prevent compiler warnings */
+
+
+       /* determine the active exception handlers for this block */
+       /* XXX could use a faster algorithm with sorted lists or  */
+       /* something?                                             */
+       len = 0;
+       for (ex = state->jd->exceptiontable; ex ; ex = ex->down) {
+               if ((ex->start->nr <= state->bptr->nr) && (ex->end->nr > state->bptr->nr)) {
+                       LOG1("active handler L%03d", ex->handler->nr);
+                       state->handlers[len++] = ex;
+               }
+       }
+       state->handlers[len] = NULL;
+
+       /* init variable types at the start of this block */
+       typevector_copy_inplace(state->bptr->inlocals, jd->var, state->numlocals);
+
+       DOLOG(show_basicblock(jd, state->bptr, SHOW_STACK));
+       DOLOG(typecheck_print_vararray(stdout, jd, state->bptr->invars, 
+                               state->bptr->indepth));
+       DOLOG(typevector_print(stdout, jd->var, state->numlocals));
+       LOGNL; LOGFLUSH;
+
+       /* loop over the instructions */
+       len = state->bptr->icount;
+       state->iptr = state->bptr->iinstr;
+       while (--len >= 0)  {
+               TYPECHECK_COUNT(stat_ins);
+
+               iptr = state->iptr;
+
+               DOLOG(typevector_print(stdout, jd->var, state->numlocals));
+               LOGNL; LOGFLUSH;
+               DOLOG(show_icmd(jd, state->iptr, false, SHOW_STACK)); LOGNL; LOGFLUSH;
+
+               opcode = iptr->opc;
+               maythrow = false;
+
+               switch (opcode) {
+
+                       /* include generated code for ICMDs verification */
+
+#define TYPECHECK_VARIABLESBASED
+#define STATE  state
+#define METHOD (state->m)
+#define IPTR   iptr
+#define BPTR   (state->bptr)
+#include <typecheck-variablesbased-gen.inc>
+#undef  STATE
+#undef  METHOD
+#undef  IPTR
+#undef  BPTR
+#undef  TYPECHECK_VARIABLESBASED
+
+                       default:
+                               LOG1("ICMD %d\n", opcode);
+                               TYPECHECK_VERIFYERROR_bool("Missing ICMD code during typecheck");
+               }
+
+               /* reach exception handlers for this instruction */
+
+               if (maythrow) {
+                       TYPECHECK_COUNT(stat_ins_maythrow);
+                       TYPECHECK_MARK(state->stat_maythrow);
+                       LOG("reaching exception handlers");
+                       i = 0;
+                       while (state->handlers[i]) {
+                               TYPECHECK_COUNT(stat_handlers_reached);
+                               if (state->handlers[i]->catchtype.any)
+                                       VAR(state->exinvars)->typeinfo.typeclass = state->handlers[i]->catchtype;
+                               else
+                                       VAR(state->exinvars)->typeinfo.typeclass.cls = class_java_lang_Throwable;
+                               if (!typestate_reach(state,
+                                               state->handlers[i]->handler,
+                                               &(state->exinvars), jd->var, 1))
+                                       return false;
+                               i++;
+                       }
+               }
+
+               LOG("\t\tnext instruction");
+               state->iptr++;
+       } /* while instructions */
+
+       LOG("instructions done");
+       LOGSTR("RESULT=> ");
+       DOLOG(typecheck_print_vararray(stdout, jd, state->bptr->outvars,
+                               state->bptr->outdepth));
+       DOLOG(typevector_print(stdout, jd->var, state->numlocals));
+       LOGNL; LOGFLUSH;
+
+       /* propagate stack and variables to the following block */
+       if (!superblockend) {
+               LOG("reaching following block");
+               tbptr = state->bptr->next;
+               while (tbptr->flags == BBDELETED) {
+                       tbptr = tbptr->next;
+#ifdef TYPECHECK_DEBUG
+                       /* this must be checked in parse.c */
+                       if ((tbptr->nr) >= state->basicblockcount)
+                               TYPECHECK_VERIFYERROR_bool("Control flow falls off the last block");
+#endif
+               }
+               if (!typestate_reach(state,tbptr,state->bptr->outvars, jd->var,
+                                       state->bptr->outdepth))
+                       return false;
+       }
+
+       /* We may have to restore the types of the instack slots. They
+        * have been saved if an <init> call inside the block has
+        * modified the instack types. (see INVOKESPECIAL) */
+
+       if (state->savedinvars)
+               typestate_restore_invars(state);
+
+       return true;
+}
+
+
+/****************************************************************************/
+/* typecheck()                                                              */
+/* This is the main function of the bytecode verifier. It is called         */
+/* directly after analyse_stack.                                            */
+/*                                                                          */
+/* IN:                                                                      */
+/*    meth.............the method to verify                                 */
+/*    cdata............codegendata for the method                           */
+/*    rdata............registerdata for the method                          */
+/*                                                                          */
+/* RETURN VALUE:                                                            */
+/*     true.............successful verification                             */
+/*     false............an exception has been thrown                        */
+/*                                                                          */
+/****************************************************************************/
+
+#define MAXPARAMS 255
+
+bool typecheck(jitdata *jd)
+{
+       methodinfo     *meth;
+       codegendata    *cd;
+       varinfo        *savedlocals;
+       verifier_state  state;             /* current state of the verifier */
+
+       /* collect statistics */
+
+#ifdef TYPECHECK_STATISTICS
+       int count_iterations = 0;
+       TYPECHECK_COUNT(stat_typechecked);
+       TYPECHECK_COUNT_FREQ(stat_locals,jd->maxlocals,STAT_LOCALS);
+       TYPECHECK_COUNT_FREQ(stat_blocks,cdata->method->basicblockcount/10,STAT_BLOCKS);
+       TYPECHECK_COUNTIF(cdata->method->exceptiontablelength != 0,stat_methods_with_handlers);
+       state.stat_maythrow = false;
+#endif
+
+       /* get required compiler data */
+
+       meth = jd->m;
+       cd   = jd->cd;
+
+       /* some logging on entry */
+
+
+    LOGSTR("\n==============================================================================\n");
+    DOLOG( show_method(jd, SHOW_STACK) );
+    LOGSTR("\n==============================================================================\n");
+    LOGMETHOD("Entering typecheck: ",cd->method);
+
+       /* initialize the verifier state */
+
+       state.m = meth;
+       state.jd = jd;
+       state.cd = cd;
+       state.basicblockcount = jd->basicblockcount;
+       state.basicblocks = jd->basicblocks;
+       state.savedindices = NULL;
+       state.savedinvars = NULL;
+
+       /* check that the basicblock numbers are valid */
+
+#if !defined(NDEBUG)
+       jit_check_basicblock_numbers(jd);
+#endif
+
+       /* check if this method is an instance initializer method */
+
+    state.initmethod = (state.m->name == utf_init);
+
+       /* initialize the basic block flags for the following CFG traversal */
+
+       typecheck_init_flags(&state, BBFINISHED);
+
+    /* number of local variables */
+    
+    /* In <init> methods we use an extra local variable to indicate whether */
+    /* the 'this' reference has been initialized.                           */
+       /*         TYPE_VOID...means 'this' has not been initialized,           */
+       /*         TYPE_INT....means 'this' has been initialized.               */
+
+    state.numlocals = state.jd->localcount;
+       state.validlocals = state.numlocals;
+    if (state.initmethod) 
+               state.numlocals++; /* VERIFIER_EXTRA_LOCALS */
+
+       DOLOG(
+               s4 i;
+               s4 t;
+               LOG("reverselocalmap:");
+               for (i=0; i<state.validlocals; ++i) {
+                       LOG2("    %i => javaindex %i", i, jd->reverselocalmap[i]);
+               });
+
+    /* allocate the buffer of active exception handlers */
+       
+    state.handlers = (exception_entry**) DumpMemory::allocate(sizeof(exception_entry*) * (state.jd->exceptiontablelength + 1));
+
+       /* save local variables */
+
+       savedlocals = (varinfo*) DumpMemory::allocate(sizeof(varinfo) * state.numlocals);
+       MCOPY(savedlocals, jd->var, varinfo, state.numlocals);
+
+       /* initialized local variables of first block */
+
+       if (!typecheck_init_locals(&state, true))
+               return false;
+
+    /* initialize invars of exception handlers */
+       
+       state.exinvars = state.numlocals;
+       VAR(state.exinvars)->type = TYPE_ADR;
+       typeinfo_init_classinfo(&(VAR(state.exinvars)->typeinfo),
+                                                       class_java_lang_Throwable); /* changed later */
+
+    LOG("Exception handler stacks set.\n");
+
+    /* loop while there are still blocks to be checked */
+    do {
+               TYPECHECK_COUNT(count_iterations);
+
+        state.repeat = false;
+        
+        state.bptr = state.basicblocks;
+
+        for (; state.bptr; state.bptr = state.bptr->next) {
+            LOGSTR1("---- BLOCK %04d, ",state.bptr->nr);
+            LOGSTR1("blockflags: %d\n",state.bptr->flags);
+            LOGFLUSH;
+            
+                   /* verify reached block */  
+            if (state.bptr->flags == BBTYPECHECK_REACHED) {
+                if (!handle_basic_block(&state))
+                                       return false;
+            }
+        } /* for blocks */
+
+        LOGIF(state.repeat,"state.repeat == true");
+    } while (state.repeat);
+
+       /* statistics */
+       
+#ifdef TYPECHECK_STATISTICS
+       LOG1("Typechecker did %4d iterations",count_iterations);
+       TYPECHECK_COUNT_FREQ(stat_iterations,count_iterations,STAT_ITERATIONS);
+       TYPECHECK_COUNTIF(state.jsrencountered,stat_typechecked_jsr);
+       TYPECHECK_COUNTIF(state.stat_maythrow,stat_methods_maythrow);
+#endif
+
+       /* reset the flags of blocks we haven't reached */
+
+       typecheck_reset_flags(&state);
+
+       /* restore locals */
+
+       MCOPY(jd->var, savedlocals, varinfo, state.numlocals);
+
+       /* everything's ok */
+
+    LOGimp("exiting typecheck");
+       return true;
+}
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* ENABLE_VERIFIER */
+
+/*
+ * 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
+ * Emacs will automagically detect them.
+ * ---------------------------------------------------------------------
+ * Local variables:
+ * mode: c
+ * indent-tabs-mode: t
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ * vim:noexpandtab:sw=4:ts=4:
+ */
diff --git a/src/vm/jit/verify/typecheck.h b/src/vm/jit/verify/typecheck.h
deleted file mode 100644 (file)
index dac58ca..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-/* src/vm/jit/verify/typecheck.h - type checking header
-
-   Copyright (C) 1996-2005, 2006, 2008
-   CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
-
-   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., 51 Franklin Street, Fifth Floor, Boston, MA
-   02110-1301, USA.
-
-*/
-
-
-#ifndef _TYPECHECK_H
-#define _TYPECHECK_H
-
-#include "config.h"
-
-#include "vm/global.h"
-#include "vm/jit/jit.hpp"
-
-
-/* function prototypes ********************************************************/
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#if defined(ENABLE_VERIFIER)
-bool typecheck(jitdata *jd);
-bool typecheck_stackbased(jitdata *jd);
-#endif
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _TYPECHECK_H */
-
-
-/*
- * 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
- * Emacs will automagically detect them.
- * ---------------------------------------------------------------------
- * Local variables:
- * mode: c
- * indent-tabs-mode: t
- * c-basic-offset: 4
- * tab-width: 4
- * End:
- */
diff --git a/src/vm/jit/verify/typecheck.hpp b/src/vm/jit/verify/typecheck.hpp
new file mode 100644 (file)
index 0000000..dac58ca
--- /dev/null
@@ -0,0 +1,64 @@
+/* src/vm/jit/verify/typecheck.h - type checking header
+
+   Copyright (C) 1996-2005, 2006, 2008
+   CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
+
+   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., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301, USA.
+
+*/
+
+
+#ifndef _TYPECHECK_H
+#define _TYPECHECK_H
+
+#include "config.h"
+
+#include "vm/global.h"
+#include "vm/jit/jit.hpp"
+
+
+/* function prototypes ********************************************************/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if defined(ENABLE_VERIFIER)
+bool typecheck(jitdata *jd);
+bool typecheck_stackbased(jitdata *jd);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _TYPECHECK_H */
+
+
+/*
+ * 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
+ * Emacs will automagically detect them.
+ * ---------------------------------------------------------------------
+ * Local variables:
+ * mode: c
+ * indent-tabs-mode: t
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ */
diff --git a/src/vm/jit/verify/typeinfo.c b/src/vm/jit/verify/typeinfo.c
deleted file mode 100644 (file)
index 1da1810..0000000
+++ /dev/null
@@ -1,2565 +0,0 @@
-/* src/vm/jit/verify/typeinfo.c - type system used by the type checker
-
-   Copyright (C) 1996-2005, 2006, 2007, 2008
-   CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
-
-   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., 51 Franklin Street, Fifth Floor, Boston, MA
-   02110-1301, USA.
-
-*/
-
-
-#include "config.h"
-
-#include <assert.h>
-#include <string.h>
-
-#include "mm/memory.h"
-
-#include "toolbox/logging.h"
-
-#include "vm/array.hpp"
-#include "vm/class.hpp"
-#include "vm/descriptor.h"
-#include "vm/exceptions.hpp"
-#include "vm/globals.hpp"
-#include "vm/loader.hpp"
-#include "vm/primitive.hpp"
-#include "vm/resolve.hpp"
-
-#include "vm/jit/jit.hpp"
-#include "vm/jit/verify/typeinfo.h"
-
-
-/* check if a linked class is an array class. Only use for linked classes! */
-#define CLASSINFO_IS_ARRAY(clsinfo)  ((clsinfo)->vftbl->arraydesc != NULL)
-
-/* check if a linked class implements the interface with the given index */
-#define CLASSINFO_IMPLEMENTS_INTERFACE(cls,index)                   \
-    ( ((index) < (cls)->vftbl->interfacetablelength)            \
-      && ( (cls)->vftbl->interfacetable[-(index)] != NULL ) )
-
-/******************************************************************************/
-/* DEBUG HELPERS                                                              */
-/******************************************************************************/
-
-#ifdef TYPEINFO_DEBUG
-#define TYPEINFO_ASSERT(cond)  assert(cond)
-#else
-#define TYPEINFO_ASSERT(cond)
-#endif
-
-/**********************************************************************/
-/* TYPEVECTOR FUNCTIONS                                               */
-/**********************************************************************/
-
-#if defined(ENABLE_VERIFIER)
-
-/* typevector_copy *************************************************************
-   Return a copy of the given typevector.
-  
-   IN:
-          src..............typevector set to copy, must be != NULL
-          size.............number of elements per typevector
-
-   RETURN VALUE:
-       a pointer to the new typevector set
-
-*******************************************************************************/
-
-varinfo *
-typevector_copy(varinfo *src, int size)
-{
-       varinfo *dst;
-       
-       TYPEINFO_ASSERT(src);
-       
-       dst = DNEW_TYPEVECTOR(size);
-       memcpy(dst,src,TYPEVECTOR_SIZE(size));
-
-       return dst;
-}
-
-/* typevector_copy_inplace *****************************************************
-   Copy a typevector to a given destination.
-
-   IN:
-          src..............typevector to copy, must be != NULL
-          dst..............destination to write the copy to
-          size.............number of elements per typevector
-
-*******************************************************************************/
-
-void
-typevector_copy_inplace(varinfo *src,varinfo *dst,int size)
-{
-       memcpy(dst,src,TYPEVECTOR_SIZE(size));
-}
-
-/* typevector_checktype ********************************************************
-   Check if the typevector contains a given type at a given index.
-  
-   IN:
-          vec..............typevector set, must be != NULL
-          index............index of component to check
-          type.............TYPE_* constant to check against
-
-   RETURN VALUE:
-       true if the typevector contains TYPE at INDEX,
-          false otherwise
-
-*******************************************************************************/
-
-bool
-typevector_checktype(varinfo *vec,int index,int type)
-{
-       TYPEINFO_ASSERT(vec);
-
-       return vec[index].type == type;
-}
-
-/* typevector_checkreference ***************************************************
-   Check if the typevector contains a reference at a given index.
-  
-   IN:
-          vec..............typevector, must be != NULL
-          index............index of component to check
-
-   RETURN VALUE:
-       true if the typevector contains a reference at INDEX,
-          false otherwise
-
-*******************************************************************************/
-
-bool
-typevector_checkreference(varinfo *vec, int index)
-{
-       TYPEINFO_ASSERT(vec);
-       return TYPEDESC_IS_REFERENCE(vec[index]);
-}
-
-/* typevectorset_checkretaddr **************************************************
-   Check if the typevectors contains a returnAddress at a given index.
-  
-   IN:
-          vec..............typevector, must be != NULL
-          index............index of component to check
-
-   RETURN VALUE:
-       true if the typevector contains a returnAddress at INDEX,
-          false otherwise
-
-*******************************************************************************/
-
-bool
-typevector_checkretaddr(varinfo *vec,int index)
-{
-       TYPEINFO_ASSERT(vec);
-       return TYPEDESC_IS_RETURNADDRESS(vec[index]);
-}
-
-/* typevector_store ************************************************************
-   Store a type at a given index in the typevector.
-  
-   IN:
-          vec..............typevector set, must be != NULL
-          index............index of component to set
-          type.............TYPE_* constant of type to set
-          info.............typeinfo of type to set, may be NULL, 
-                           if TYPE != TYPE_ADR
-
-*******************************************************************************/
-
-void
-typevector_store(varinfo *vec,int index,int type,typeinfo_t *info)
-{
-       TYPEINFO_ASSERT(vec);
-
-       vec[index].type = type;
-       if (info)
-               TYPEINFO_COPY(*info,vec[index].typeinfo);
-}
-
-/* typevector_store_retaddr ****************************************************
-   Store a returnAddress type at a given index in the typevector.
-  
-   IN:
-          vec..............typevector set, must be != NULL
-          index............index of component to set
-          info.............typeinfo of the returnAddress.
-
-*******************************************************************************/
-
-void
-typevector_store_retaddr(varinfo *vec,int index,typeinfo_t *info)
-{
-       TYPEINFO_ASSERT(vec);
-       TYPEINFO_ASSERT(TYPEINFO_IS_PRIMITIVE(*info));
-       
-       vec[index].type = TYPE_ADR;
-       TYPEINFO_INIT_RETURNADDRESS(vec[index].typeinfo,
-                       TYPEINFO_RETURNADDRESS(*info));
-}
-
-/* typevector_init_object ******************************************************
-   Replace all uninitialized object types in the typevector set which were 
-   created by the given instruction by initialized object types.
-  
-   IN:
-          set..............typevector set
-          ins..............instruction which created the uninitialized object type
-          initclass........class of the initialized object type to set
-          size.............number of elements per typevector
-
-   RETURN VALUE:
-       true.............success
-          false............an exception has been thrown
-
-   XXX maybe we should do the lazy resolving before calling this function
-
-*******************************************************************************/
-
-bool
-typevector_init_object(varinfo *set,void *ins,
-                                          classref_or_classinfo initclass,
-                                          int size)
-{
-       int i;
-
-       for (i=0; i<size; ++i) {
-               if (set[i].type == TYPE_ADR
-                       && TYPEINFO_IS_NEWOBJECT(set[i].typeinfo)
-                       && TYPEINFO_NEWOBJECT_INSTRUCTION(set[i].typeinfo) == ins)
-               {
-                       if (!typeinfo_init_class(&(set[i].typeinfo),initclass))
-                               return false;
-               }
-       }
-       return true;
-}
-
-/* typevector_merge ************************************************************
-   Merge a typevector with another one.
-   The given typevectors must have the same number of components.
-  
-   IN:
-       m................method for exception messages
-          dst..............the first typevector
-          y................the second typevector
-          size.............number of elements per typevector
-
-   OUT:
-       *dst.............the resulting typevector
-
-   RETURN VALUE:
-       typecheck_TRUE...dst has been modified
-          typecheck_FALSE..dst has not been modified
-          typecheck_FAIL...an exception has been thrown
-
-*******************************************************************************/
-
-typecheck_result
-typevector_merge(methodinfo *m,varinfo *dst,varinfo *y,int size)
-{
-       bool changed = false;
-       typecheck_result r;
-       
-       varinfo *a = dst;
-       varinfo *b = y;
-       while (size--) {
-               if (a->type != TYPE_VOID && a->type != b->type) {
-                       a->type = TYPE_VOID;
-                       changed = true;
-               }
-               else if (a->type == TYPE_ADR) {
-                       if (TYPEINFO_IS_PRIMITIVE(a->typeinfo)) {
-                               /* 'a' is a returnAddress */
-                               if (!TYPEINFO_IS_PRIMITIVE(b->typeinfo)
-                                       || (TYPEINFO_RETURNADDRESS(a->typeinfo)
-                                               != TYPEINFO_RETURNADDRESS(b->typeinfo)))
-                               {
-                                       a->type = TYPE_VOID;
-                                       changed = true;
-                               }
-                       }
-                       else {
-                               /* 'a' is a reference */
-                               if (TYPEINFO_IS_PRIMITIVE(b->typeinfo)) {
-                                       a->type = TYPE_VOID;
-                                       changed = true;
-                               }
-                               else {
-                                       /* two reference types are merged. There cannot be */
-                                       /* a merge error. In the worst case we get j.l.O.  */
-                                       r = typeinfo_merge(m,&(a->typeinfo),&(b->typeinfo));
-                                       if (r == typecheck_FAIL)
-                                               return r;
-                                       changed |= r;
-                               }
-                       }
-               }
-               a++;
-               b++;
-       }
-       return changed;
-}
-
-/**********************************************************************/
-/* READ-ONLY FUNCTIONS                                                */
-/* The following functions don't change typeinfo data.                */
-/**********************************************************************/
-
-/* typeinfo_is_array ***********************************************************
-   Check whether a typeinfo describes an array type.
-   
-   IN:
-          info.............the typeinfo, must be != NULL
-
-   RETURN VALUE:
-       true if INFO describes an array type.
-
-*******************************************************************************/
-
-bool
-typeinfo_is_array(typeinfo_t *info)
-{
-       TYPEINFO_ASSERT(info);
-    return TYPEINFO_IS_ARRAY(*info);
-}
-
-/* typeinfo_is_primitive_array *************************************************
-   Check whether a typeinfo describes a primitive array type.
-   
-   IN:
-          info.............the typeinfo, must be != NULL
-
-   RETURN VALUE:
-       true if INFO describes an array of a primitive type.
-
-*******************************************************************************/
-
-bool
-typeinfo_is_primitive_array(typeinfo_t *info,int arraytype)
-{
-       TYPEINFO_ASSERT(info);
-    return TYPEINFO_IS_PRIMITIVE_ARRAY(*info,arraytype);
-}
-
-/* typeinfo_is_array_of_refs ***************************************************
-   Check whether a typeinfo describes an array of references type.
-   
-   IN:
-          info.............the typeinfo, must be != NULL
-
-   RETURN VALUE:
-       true if INFO describes an array of a refrence type.
-
-*******************************************************************************/
-
-bool
-typeinfo_is_array_of_refs(typeinfo_t *info)
-{
-       TYPEINFO_ASSERT(info);
-    return TYPEINFO_IS_ARRAY_OF_REFS(*info);
-}
-
-/* interface_extends_interface *************************************************
-   Check if a resolved interface extends a given resolved interface.
-   
-   IN:
-          cls..............the interface, must be linked
-          interf...........the interface to check against
-
-   RETURN VALUE:
-       true.............CLS extends INTERF
-          false............CLS does not extend INTERF
-
-*******************************************************************************/
-
-static bool
-interface_extends_interface(classinfo *cls,classinfo *interf)
-{
-    int i;
-    
-       TYPEINFO_ASSERT(cls);
-       TYPEINFO_ASSERT(interf);
-       TYPEINFO_ASSERT((interf->flags & ACC_INTERFACE) != 0);
-       TYPEINFO_ASSERT((cls->flags & ACC_INTERFACE) != 0);
-       TYPEINFO_ASSERT(cls->state & CLASS_LINKED);
-
-    /* first check direct superinterfaces */
-    for (i=0; i<cls->interfacescount; ++i) {
-        if (cls->interfaces[i] == interf)
-            return true;
-    }
-    
-    /* check indirect superinterfaces */
-    for (i=0; i<cls->interfacescount; ++i) {
-        if (interface_extends_interface(cls->interfaces[i],interf))
-            return true;
-    }
-    
-    return false;
-}
-
-/* classinfo_implements_interface **********************************************
-   Check if a resolved class implements a given resolved interface.
-   
-   IN:
-          cls..............the class
-          interf...........the interface
-
-   RETURN VALUE:
-       typecheck_TRUE...CLS implements INTERF
-          typecheck_FALSE..CLS does not implement INTERF
-          typecheck_FAIL...an exception has been thrown
-
-*******************************************************************************/
-
-static typecheck_result
-classinfo_implements_interface(classinfo *cls,classinfo *interf)
-{
-       TYPEINFO_ASSERT(cls);
-       TYPEINFO_ASSERT(interf);
-       TYPEINFO_ASSERT((interf->flags & ACC_INTERFACE) != 0);
-
-       if (!(cls->state & CLASS_LINKED))
-               if (!link_class(cls))
-                       return typecheck_FAIL;
-
-    if (cls->flags & ACC_INTERFACE) {
-        /* cls is an interface */
-        if (cls == interf)
-            return typecheck_TRUE;
-
-        /* check superinterfaces */
-        return interface_extends_interface(cls,interf);
-    }
-
-       TYPEINFO_ASSERT(cls->state & CLASS_LINKED);
-    return CLASSINFO_IMPLEMENTS_INTERFACE(cls,interf->index);
-}
-
-/* mergedlist_implements_interface *********************************************
-   Check if all the classes in a given merged list implement a given resolved
-   interface.
-   
-   IN:
-          merged...........the list of merged class types
-          interf...........the interface to check against
-
-   RETURN VALUE:
-       typecheck_TRUE...all classes implement INTERF
-          typecheck_FALSE..there is at least one class that does not implement
-                           INTERF
-          typecheck_MAYBE..check cannot be performed now because of unresolved
-                           classes
-          typecheck_FAIL...an exception has been thrown
-
-*******************************************************************************/
-
-static typecheck_result
-mergedlist_implements_interface(typeinfo_mergedlist_t *merged,
-                                classinfo *interf)
-{
-    int i;
-    classref_or_classinfo *mlist;
-       typecheck_result r;
-    
-       TYPEINFO_ASSERT(interf);
-       TYPEINFO_ASSERT((interf->flags & ACC_INTERFACE) != 0);
-
-    /* Check if there is an non-empty mergedlist. */
-    if (!merged)
-        return typecheck_FALSE;
-
-    /* If all classinfos in the (non-empty) merged array implement the
-     * interface return true, otherwise false.
-     */
-    mlist = merged->list;
-    i = merged->count;
-    while (i--) {
-               if (IS_CLASSREF(*mlist)) {
-                       return typecheck_MAYBE;
-               }
-        r = classinfo_implements_interface((mlist++)->cls,interf);
-        if (r != typecheck_TRUE)
-                       return r;
-    }
-    return typecheck_TRUE;
-}
-
-/* merged_implements_interface *************************************************
-   Check if a possible merged type implements a given resolved interface
-   interface.
-   
-   IN:
-       typeclass........(common) class of the (merged) type
-          merged...........the list of merged class types
-          interf...........the interface to check against
-
-   RETURN VALUE:
-       typecheck_TRUE...the type implement INTERF
-          typecheck_FALSE..the type does not implement INTERF
-          typecheck_MAYBE..check cannot be performed now because of unresolved
-                           classes
-          typecheck_FAIL...an exception has been thrown
-
-*******************************************************************************/
-
-static typecheck_result
-merged_implements_interface(classinfo *typeclass,typeinfo_mergedlist_t *merged,
-                            classinfo *interf)
-{
-       typecheck_result r;
-       
-    /* primitive types don't support interfaces. */
-    if (!typeclass)
-        return typecheck_FALSE;
-
-    /* the null type can be cast to any interface type. */
-    if (typeclass == pseudo_class_Null)
-        return typecheck_TRUE;
-
-    /* check if typeclass implements the interface. */
-    r = classinfo_implements_interface(typeclass,interf);
-       if (r != typecheck_FALSE)
-        return r;
-
-    /* check the mergedlist */
-       if (!merged)
-               return typecheck_FALSE;
-    return mergedlist_implements_interface(merged,interf);
-}
-
-/* merged_is_subclass **********************************************************
-   Check if a possible merged type is a subclass of a given class.
-   A merged type is a subclass of a class C if all types in the merged list
-   are subclasses of C. A sufficient condition for this is that the
-   common type of the merged type is a subclass of C.
-
-   IN:
-       typeclass........(common) class of the (merged) type
-                           MUST be a loaded and linked class
-          merged...........the list of merged class types
-          cls..............the class to theck against
-
-   RETURN VALUE:
-       typecheck_TRUE...the type is a subclass of CLS
-          typecheck_FALSE..the type is not a subclass of CLS
-          typecheck_MAYBE..check cannot be performed now because of unresolved
-                           classes
-          typecheck_FAIL...an exception has been thrown
-
-*******************************************************************************/
-
-static typecheck_result
-merged_is_subclass(classinfo *typeclass,typeinfo_mergedlist_t *merged,
-               classinfo *cls)
-{
-    int i;
-    classref_or_classinfo *mlist;
-
-       TYPEINFO_ASSERT(cls);
-       
-    /* primitive types aren't subclasses of anything. */
-    if (!typeclass)
-        return typecheck_FALSE;
-
-    /* the null type can be cast to any reference type. */
-    if (typeclass == pseudo_class_Null)
-        return typecheck_TRUE;
-
-       TYPEINFO_ASSERT(typeclass->state & CLASS_LOADED);
-       TYPEINFO_ASSERT(typeclass->state & CLASS_LINKED);
-
-    /* check if the common typeclass is a subclass of CLS. */
-       if (class_issubclass(typeclass,cls))
-               return typecheck_TRUE;
-       
-    /* check the mergedlist */
-       if (!merged)
-               return typecheck_FALSE;
-    /* If all classinfos in the (non-empty) merged list are subclasses
-        * of CLS, return true, otherwise false.
-        * If there is at least one unresolved type in the list,
-        * return typecheck_MAYBE.
-     */
-    mlist = merged->list;
-    i = merged->count;
-    while (i--) {
-               if (IS_CLASSREF(*mlist)) {
-                       return typecheck_MAYBE;
-               }
-               if (!(mlist->cls->state & CLASS_LINKED))
-                       if (!link_class(mlist->cls))
-                               return typecheck_FAIL;
-               if (!class_issubclass(mlist->cls,cls))
-                       return typecheck_FALSE;
-               mlist++;
-    }
-    return typecheck_TRUE;
-}
-
-/* typeinfo_is_assignable_to_class *********************************************
-   Check if a type is assignable to a given class type.
-   
-   IN:
-       value............the type of the value
-          dest.............the type of the destination
-
-   RETURN VALUE:
-       typecheck_TRUE...the type is assignable
-          typecheck_FALSE..the type is not assignable
-          typecheck_MAYBE..check cannot be performed now because of unresolved
-                           classes
-          typecheck_FAIL...an exception has been thrown
-
-*******************************************************************************/
-
-typecheck_result
-typeinfo_is_assignable_to_class(typeinfo_t *value,classref_or_classinfo dest)
-{
-       classref_or_classinfo c;
-    classinfo *cls;
-       utf *classname;
-
-       TYPEINFO_ASSERT(value);
-
-    c = value->typeclass;
-
-    /* assignments of primitive values are not checked here. */
-    if (!c.any && !dest.any)
-        return typecheck_TRUE;
-
-    /* primitive and reference types are not assignment compatible. */
-    if (!c.any || !dest.any)
-        return typecheck_FALSE;
-
-    /* the null type can be assigned to any type */
-    if (TYPEINFO_IS_NULLTYPE(*value))
-        return typecheck_TRUE;
-
-    /* uninitialized objects are not assignable */
-    if (TYPEINFO_IS_NEWOBJECT(*value))
-        return typecheck_FALSE;
-
-       if (IS_CLASSREF(c)) {
-               /* The value type is an unresolved class reference. */
-               classname = c.ref->name;
-       }
-       else {
-               classname = c.cls->name;
-       }
-
-       if (IS_CLASSREF(dest)) {
-               /* the destination type is an unresolved class reference */
-               /* In this case we cannot tell a lot about assignability. */
-
-               /* the common case of value and dest type having the same classname */
-               if (dest.ref->name == classname && !value->merged)
-                       return typecheck_TRUE;
-
-               /* we cannot tell if value is assignable to dest, so we */
-               /* leave it up to the resolving code to check this      */
-               return typecheck_MAYBE;
-       }
-
-       /* { we know that dest is a loaded class } */
-
-       if (IS_CLASSREF(c)) {
-               /* the value type is an unresolved class reference */
-               
-               /* the common case of value and dest type having the same classname */
-               if (dest.cls->name == classname)
-                       return typecheck_TRUE;
-
-               /* we cannot tell if value is assignable to dest, so we */
-               /* leave it up to the resolving code to check this      */
-               return typecheck_MAYBE;
-       }
-
-       /* { we know that both c and dest are loaded classes } */
-       /* (c may still have a merged list containing unresolved classrefs!) */
-
-       TYPEINFO_ASSERT(!IS_CLASSREF(c));
-       TYPEINFO_ASSERT(!IS_CLASSREF(dest));
-
-       cls = c.cls;
-       
-       TYPEINFO_ASSERT(cls->state & CLASS_LOADED);
-       TYPEINFO_ASSERT(dest.cls->state & CLASS_LOADED);
-
-       /* maybe we need to link the classes */
-       if (!(cls->state & CLASS_LINKED))
-               if (!link_class(cls))
-                       return typecheck_FAIL;
-       if (!(dest.cls->state & CLASS_LINKED))
-               if (!link_class(dest.cls))
-                       return typecheck_FAIL;
-
-       /* { we know that both c and dest are linked classes } */
-       TYPEINFO_ASSERT(cls->state & CLASS_LINKED);
-       TYPEINFO_ASSERT(dest.cls->state & CLASS_LINKED);
-
-    if (dest.cls->flags & ACC_INTERFACE) {
-        /* We are assigning to an interface type. */
-        return merged_implements_interface(cls,value->merged,dest.cls);
-    }
-
-    if (CLASSINFO_IS_ARRAY(dest.cls)) {
-               arraydescriptor *arraydesc = dest.cls->vftbl->arraydesc;
-               int dimension = arraydesc->dimension;
-               classinfo *elementclass = (arraydesc->elementvftbl)
-                       ? arraydesc->elementvftbl->clazz : NULL;
-                       
-        /* We are assigning to an array type. */
-        if (!TYPEINFO_IS_ARRAY(*value))
-            return typecheck_FALSE;
-
-        /* {Both value and dest.cls are array types.} */
-
-        /* value must have at least the dimension of dest.cls. */
-        if (value->dimension < dimension)
-            return typecheck_FALSE;
-
-        if (value->dimension > dimension) {
-            /* value has higher dimension so we need to check
-             * if its component array can be assigned to the
-             * element type of dest.cls */
-
-                       if (!elementclass) return typecheck_FALSE;
-            
-            if (elementclass->flags & ACC_INTERFACE) {
-                /* We are assigning to an interface type. */
-                return classinfo_implements_interface(pseudo_class_Arraystub,
-                                                      elementclass);
-            }
-
-            /* We are assigning to a class type. */
-            return class_issubclass(pseudo_class_Arraystub,elementclass);
-        }
-
-        /* {value and dest.cls have the same dimension} */
-
-        if (value->elementtype != arraydesc->elementtype)
-            return typecheck_FALSE;
-
-        if (value->elementclass.any) {
-            /* We are assigning an array of objects so we have to
-             * check if the elements are assignable.
-             */
-
-            if (elementclass->flags & ACC_INTERFACE) {
-                /* We are assigning to an interface type. */
-
-                return merged_implements_interface(value->elementclass.cls,
-                                                   value->merged,
-                                                   elementclass);
-            }
-            
-            /* We are assigning to a class type. */
-            return merged_is_subclass(value->elementclass.cls,value->merged,elementclass);
-        }
-
-        return typecheck_TRUE;
-    }
-
-    /* {dest.cls is not an array} */
-    /* {dest.cls is a loaded class} */
-
-       /* If there are any unresolved references in the merged list, we cannot */
-       /* tell if the assignment will be ok.                                   */
-       /* This can only happen when cls is java.lang.Object                    */
-       if (cls == class_java_lang_Object && value->merged) {
-               classref_or_classinfo *mlist = value->merged->list;
-               int i = value->merged->count;
-               while (i--)
-                       if (IS_CLASSREF(*mlist++))
-                               return typecheck_MAYBE;
-       }
-        
-    /* We are assigning to a class type */
-    if (cls->flags & ACC_INTERFACE)
-        cls = class_java_lang_Object;
-    
-    return merged_is_subclass(cls,value->merged,dest.cls);
-}
-
-/* typeinfo_is_assignable ******************************************************
-   Check if a type is assignable to a given type.
-   
-   IN:
-       value............the type of the value
-          dest.............the type of the destination, must not be a merged type
-
-   RETURN VALUE:
-       typecheck_TRUE...the type is assignable
-          typecheck_FALSE..the type is not assignable
-          typecheck_MAYBE..check cannot be performed now because of unresolved
-                           classes
-          typecheck_FAIL...an exception has been thrown
-
-*******************************************************************************/
-
-typecheck_result
-typeinfo_is_assignable(typeinfo_t *value,typeinfo_t *dest)
-{
-       TYPEINFO_ASSERT(value);
-       TYPEINFO_ASSERT(dest);
-       TYPEINFO_ASSERT(dest->merged == NULL);
-
-       return typeinfo_is_assignable_to_class(value,dest->typeclass);
-}
-
-/**********************************************************************/
-/* INITIALIZATION FUNCTIONS                                           */
-/* The following functions fill in uninitialized typeinfo structures. */
-/**********************************************************************/
-
-/* typeinfo_init_classinfo *****************************************************
-   Initialize a typeinfo to a resolved class.
-   
-   IN:
-          c................the class
-
-   OUT:
-       *info............is initialized
-
-   RETURN VALUE:
-       true.............success
-          false............an exception has been thrown
-
-*******************************************************************************/
-
-void
-typeinfo_init_classinfo(typeinfo_t *info, classinfo *c)
-{
-       if ((info->typeclass.cls = c)->vftbl->arraydesc) {
-               if (c->vftbl->arraydesc->elementvftbl)
-                       info->elementclass.cls = c->vftbl->arraydesc->elementvftbl->clazz;
-               else
-                       info->elementclass.any = NULL;
-               info->dimension = c->vftbl->arraydesc->dimension;
-               info->elementtype = c->vftbl->arraydesc->elementtype;
-       }
-       else {
-               info->elementclass.any = NULL;
-               info->dimension = 0;
-               info->elementtype = 0;
-       }
-       info->merged = NULL;
-}
-
-/* typeinfo_init_class *********************************************************
-   Initialize a typeinfo to a possibly unresolved class type.
-   
-   IN:
-          c................the class type
-
-   OUT:
-       *info............is initialized
-
-   RETURN VALUE:
-       true.............success
-          false............an exception has been thrown
-
-*******************************************************************************/
-
-bool
-typeinfo_init_class(typeinfo_t *info,classref_or_classinfo c)
-{
-       char *utf_ptr;
-       int len;
-       classinfo *cls;
-               
-       TYPEINFO_ASSERT(c.any);
-       TYPEINFO_ASSERT(info);
-
-       /* if necessary, try to resolve lazily */
-       if (!resolve_classref_or_classinfo(NULL /* XXX should know method */,
-                               c,resolveLazy,false,true,&cls))
-       {
-               return false;
-       }
-       
-       if (cls) {
-               typeinfo_init_classinfo(info,cls);
-               return true;
-       }
-
-       /* {the type could no be resolved lazily} */
-
-       info->typeclass.ref = c.ref;
-       info->elementclass.any = NULL;
-       info->dimension = 0;
-       info->merged = NULL;
-
-       /* handle array type references */
-       utf_ptr = c.ref->name->text;
-       len = c.ref->name->blength;
-       if (*utf_ptr == '[') {
-               /* count dimensions */
-               while (*utf_ptr == '[') {
-                       utf_ptr++;
-                       info->dimension++;
-                       len--;
-               }
-               if (*utf_ptr == 'L') {
-                       utf_ptr++;
-                       len -= 2;
-                       info->elementtype = ARRAYTYPE_OBJECT;
-                       info->elementclass.ref = class_get_classref(c.ref->referer,utf_new(utf_ptr,len));
-               }
-               else {
-                       /* an array with primitive element type */
-                       /* should have been resolved above */
-                       TYPEINFO_ASSERT(false);
-               }
-       }
-       return true;
-}
-
-/* typeinfo_init_from_typedesc *************************************************
-   Initialize a typeinfo from a typedesc.
-   
-   IN:
-          desc.............the typedesc
-
-   OUT:
-       *type............set to the TYPE_* constant of DESC (if type != NULL)
-       *info............receives the typeinfo (if info != NULL)
-
-   RETURN VALUE:
-       true.............success
-          false............an exception has been thrown
-
-*******************************************************************************/
-
-bool
-typeinfo_init_from_typedesc(typedesc *desc,u1 *type,typeinfo_t *info)
-{
-       TYPEINFO_ASSERT(desc);
-
-#ifdef TYPEINFO_VERBOSE
-       fprintf(stderr,"typeinfo_init_from_typedesc(");
-       descriptor_debug_print_typedesc(stderr,desc);
-       fprintf(stderr,")\n");
-#endif
-
-       if (type)
-               *type = desc->type;
-
-       if (info) {
-               if (desc->type == TYPE_ADR) {
-                       TYPEINFO_ASSERT(desc->classref);
-                       if (!typeinfo_init_class(info,CLASSREF_OR_CLASSINFO(desc->classref)))
-                               return false;
-               }
-               else {
-                       TYPEINFO_INIT_PRIMITIVE(*info);
-               }
-       }
-       return true;
-}
-
-/* typeinfos_init_from_methoddesc **********************************************
-   Initialize an array of typeinfos and u1 TYPE_* values from a methoddesc.
-   
-   IN:
-       desc.............the methoddesc
-       buflen...........number of parameters the buffer can hold
-       twoword..........if true, use two parameter slots for two-word types
-
-   OUT:
-       *typebuf.........receives a TYPE_* constant for each parameter
-                        typebuf must be != NULL
-       *infobuf.........receives a typeinfo for each parameter
-                        infobuf must be != NULL
-       *returntype......receives a TYPE_* constant for the return type
-                        returntype may be NULL
-       *returntypeinfo..receives a typeinfo for the return type
-                        returntypeinfo may be NULL
-
-   RETURN VALUE:
-       true.............success
-       false............an exception has been thrown
-
-   NOTE:
-       If (according to BUFLEN) the buffers are to small to hold the
-          parameter types, an internal error is thrown. This must be
-          avoided by checking the number of parameters and allocating enough
-          space before calling this function.
-
-*******************************************************************************/
-
-bool
-typeinfos_init_from_methoddesc(methoddesc *desc,u1 *typebuf,typeinfo_t *infobuf,
-                              int buflen,bool twoword,
-                              u1 *returntype,typeinfo_t *returntypeinfo)
-{
-       int i;
-    int args = 0;
-
-       TYPEINFO_ASSERT(desc);
-       TYPEINFO_ASSERT(typebuf);
-       TYPEINFO_ASSERT(infobuf);
-
-#ifdef TYPEINFO_VERBOSE
-       fprintf(stderr,"typeinfos_init_from_methoddesc(");
-       descriptor_debug_print_methoddesc(stderr,desc);
-       fprintf(stderr,")\n");
-#endif
-
-    /* check arguments */
-    for (i=0; i<desc->paramcount; ++i) {
-               if (++args > buflen) {
-                       exceptions_throw_internalerror("Buffer too small for method arguments.");
-                       return false;
-               }
-
-               if (!typeinfo_init_from_typedesc(desc->paramtypes + i,typebuf++,infobuf++))
-                       return false;
-               
-               if (twoword && (typebuf[-1] == TYPE_LNG || typebuf[-1] == TYPE_DBL)) {
-                       if (++args > buflen) {
-                               exceptions_throw_internalerror("Buffer too small for method arguments.");
-                               return false;
-                       }
-
-                       *typebuf++ = TYPE_VOID;
-                       TYPEINFO_INIT_PRIMITIVE(*infobuf);
-                       infobuf++;
-               }
-    }
-
-    /* check returntype */
-    if (returntype) {
-               if (!typeinfo_init_from_typedesc(&(desc->returntype),returntype,returntypeinfo))
-                       return false;
-       }
-
-       return true;
-}
-
-/* typedescriptor_init_from_typedesc *******************************************
-   Initialize a typedescriptor from a typedesc.
-   
-   IN:
-          desc.............the typedesc
-
-   OUT:
-       *td..............receives the typedescriptor
-                           td must be != NULL
-
-   RETURN VALUE:
-       true.............success
-          false............an exception has been thrown
-
-*******************************************************************************/
-
-bool
-typedescriptor_init_from_typedesc(typedescriptor_t *td,
-                                                                 typedesc *desc)
-{
-       TYPEINFO_ASSERT(td);
-       TYPEINFO_ASSERT(desc);
-
-       td->type = desc->type;
-       if (td->type == TYPE_ADR) {
-               if (!typeinfo_init_class(&(td->typeinfo),CLASSREF_OR_CLASSINFO(desc->classref)))
-                       return false;
-       }
-       else {
-               TYPEINFO_INIT_PRIMITIVE(td->typeinfo);
-       }
-       return true;
-}
-
-/* typeinfo_init_varinfo_from_typedesc *****************************************
-   Initialize a varinfo from a typedesc.
-   
-   IN:
-          desc.............the typedesc
-
-   OUT:
-       *var.............receives the type
-                           var must be != NULL
-
-   RETURN VALUE:
-       true.............success
-          false............an exception has been thrown
-
-*******************************************************************************/
-
-bool
-typeinfo_init_varinfo_from_typedesc(varinfo *var,
-                                                                 typedesc *desc)
-{
-       TYPEINFO_ASSERT(var);
-       TYPEINFO_ASSERT(desc);
-
-       var->type = desc->type;
-       if (var->type == TYPE_ADR) {
-               if (!typeinfo_init_class(&(var->typeinfo),CLASSREF_OR_CLASSINFO(desc->classref)))
-                       return false;
-       }
-       else {
-               TYPEINFO_INIT_PRIMITIVE(var->typeinfo);
-       }
-       return true;
-}
-
-/* typeinfo_init_varinfos_from_methoddesc **************************************
-   Initialize an array of varinfos from a methoddesc.
-   
-   IN:
-       desc.............the methoddesc
-       buflen...........number of parameters the buffer can hold
-          startindex.......the zero-based index of the first parameter to
-                           write to the array. In other words the number of
-                                               parameters to skip at the beginning of the methoddesc.
-          map..............map from parameter indices to varinfo indices
-                           (indexed like jitdata.local_map)
-
-   OUT:
-       *vars............array receiving the varinfos
-                           td[0] receives the type of the
-                                               (startindex+1)th parameter of the method
-       *returntype......receives the typedescriptor of the return type.
-                           returntype may be NULL
-
-   RETURN VALUE:
-       true.............everything ok
-          false............an exception has been thrown
-
-   NOTE:
-       If (according to BUFLEN) the buffer is to small to hold the
-          parameter types, an internal error is thrown. This must be
-          avoided by checking the number of parameters and allocating enough
-          space before calling this function.
-
-*******************************************************************************/
-
-bool
-typeinfo_init_varinfos_from_methoddesc(varinfo *vars,
-                                                                        methoddesc *desc,
-                                                                        int buflen, int startindex,
-                                                                        s4 *map,
-                                                                        typedescriptor_t *returntype)
-{
-       s4 i;
-    s4 varindex;
-       s4 type;
-       s4 slot = 0;
-
-       /* skip arguments */
-       for (i=0; i<startindex; ++i) {
-               slot++;
-               if (IS_2_WORD_TYPE(desc->paramtypes[i].type))
-                       slot++;
-       }
-
-    /* check arguments */
-    for (i=startindex; i<desc->paramcount; ++i) {
-               type = desc->paramtypes[i].type;
-               varindex = map[5*slot + type];
-
-               slot++;
-               if (IS_2_WORD_TYPE(type))
-                       slot++;
-
-               if (varindex == UNUSED)
-                       continue;
-
-               if (varindex >= buflen) {
-                       exceptions_throw_internalerror("Buffer too small for method arguments.");
-                       return false;
-               }
-
-               if (!typeinfo_init_varinfo_from_typedesc(vars + varindex, desc->paramtypes + i))
-                       return false;
-    }
-
-    /* check returntype */
-    if (returntype) {
-               if (!typedescriptor_init_from_typedesc(returntype,&(desc->returntype)))
-                       return false;
-       }
-
-       return true;
-}
-
-/* typedescriptors_init_from_methoddesc ****************************************
-   Initialize an array of typedescriptors from a methoddesc.
-   
-   IN:
-       desc.............the methoddesc
-       buflen...........number of parameters the buffer can hold
-       twoword..........if true, use two parameter slots for two-word types
-          startindex.......the zero-based index of the first parameter to
-                           write to the array. In other words the number of
-                                               parameters to skip at the beginning of the methoddesc.
-
-   OUT:
-       *td..............array receiving the typedescriptors.
-                           td[0] receives the typedescriptor of the
-                                               (startindex+1)th parameter of the method
-       *returntype......receives the typedescriptor of the return type.
-                           returntype may be NULL
-
-   RETURN VALUE:
-       >= 0.............number of typedescriptors filled in TD
-          -1...............an exception has been thrown
-
-   NOTE:
-       If (according to BUFLEN) the buffer is to small to hold the
-          parameter types, an internal error is thrown. This must be
-          avoided by checking the number of parameters and allocating enough
-          space before calling this function.
-
-*******************************************************************************/
-
-int
-typedescriptors_init_from_methoddesc(typedescriptor_t *td,
-                                                                        methoddesc *desc,
-                                                                        int buflen,bool twoword,int startindex,
-                                                                        typedescriptor_t *returntype)
-{
-       int i;
-    int args = 0;
-
-    /* check arguments */
-    for (i=startindex; i<desc->paramcount; ++i) {
-               if (++args > buflen) {
-                       exceptions_throw_internalerror("Buffer too small for method arguments.");
-                       return -1;
-               }
-
-               if (!typedescriptor_init_from_typedesc(td,desc->paramtypes + i))
-                       return -1;
-               td++;
-
-               if (twoword && (td[-1].type == TYPE_LNG || td[-1].type == TYPE_DBL)) {
-                       if (++args > buflen) {
-                               exceptions_throw_internalerror("Buffer too small for method arguments.");
-                               return -1;
-                       }
-
-                       td->type = TYPE_VOID;
-                       TYPEINFO_INIT_PRIMITIVE(td->typeinfo);
-                       td++;
-               }
-    }
-
-    /* check returntype */
-    if (returntype) {
-               if (!typedescriptor_init_from_typedesc(returntype,&(desc->returntype)))
-                       return -1;
-       }
-
-       return args;
-}
-
-/* typeinfo_init_component *****************************************************
-   Initialize a typeinfo with the component type of a given array type.
-   
-   IN:
-          srcarray.........the typeinfo of the array type
-
-   OUT:
-       *dst.............receives the typeinfo of the component type
-
-   RETURN VALUE:
-       true.............success
-          false............an exception has been thrown
-
-*******************************************************************************/
-
-bool
-typeinfo_init_component(typeinfo_t *srcarray,typeinfo_t *dst)
-{
-       typeinfo_mergedlist_t *merged;
-
-       TYPEINFO_ASSERT(srcarray);
-       TYPEINFO_ASSERT(dst);
-
-    if (TYPEINFO_IS_NULLTYPE(*srcarray)) {
-        TYPEINFO_INIT_NULLTYPE(*dst);
-        return true;
-    }
-    
-    if (!TYPEINFO_IS_ARRAY(*srcarray)) {
-               /* XXX should we make that a verify error? */
-               exceptions_throw_internalerror("Trying to access component of non-array");
-               return false;
-       }
-
-       /* save the mergedlist (maybe dst == srcarray) */
-
-       merged = srcarray->merged;
-
-       if (IS_CLASSREF(srcarray->typeclass)) {
-               constant_classref *comp;
-               comp = class_get_classref_component_of(srcarray->typeclass.ref);
-
-               if (comp) {
-                       if (!typeinfo_init_class(dst,CLASSREF_OR_CLASSINFO(comp)))
-                               return false;
-               }
-               else {
-                       TYPEINFO_INIT_PRIMITIVE(*dst);
-               }
-       }
-       else {
-               vftbl_t *comp;
-               
-               if (!(srcarray->typeclass.cls->state & CLASS_LINKED)) {
-                       if (!link_class(srcarray->typeclass.cls)) {
-                               return false;
-                       }
-               }
-
-               TYPEINFO_ASSERT(srcarray->typeclass.cls->vftbl);
-               TYPEINFO_ASSERT(srcarray->typeclass.cls->vftbl->arraydesc);
-
-               comp = srcarray->typeclass.cls->vftbl->arraydesc->componentvftbl;
-               if (comp)
-                       typeinfo_init_classinfo(dst,comp->clazz);
-               else
-                       TYPEINFO_INIT_PRIMITIVE(*dst);
-       }
-    
-    dst->merged = merged; /* XXX should we do a deep copy? */
-       return true;
-}
-
-/* typeinfo_clone **************************************************************
-   Create a deep copy of a typeinfo struct.
-   
-   IN:
-          src..............the typeinfo to copy
-
-   OUT:
-       *dest............receives the copy
-
-   NOTE:
-       If src == dest this function is a nop.
-
-*******************************************************************************/
-
-void
-typeinfo_clone(typeinfo_t *src,typeinfo_t *dest)
-{
-    int count;
-    classref_or_classinfo *srclist,*destlist;
-
-    if (src == dest)
-        return;
-    
-    *dest = *src;
-
-    if (src->merged) {
-        count = src->merged->count;
-        TYPEINFO_ALLOCMERGED(dest->merged,count);
-        dest->merged->count = count;
-
-        srclist = src->merged->list;
-        destlist = dest->merged->list;
-        while (count--)
-            *destlist++ = *srclist++;
-    }
-}
-
-/**********************************************************************/
-/* MISCELLANEOUS FUNCTIONS                                            */
-/**********************************************************************/
-
-/* typeinfo_free ***************************************************************
-   Free memory referenced by the given typeinfo. The typeinfo itself is not
-   freed.
-   
-   IN:
-       info.............the typeinfo
-
-*******************************************************************************/
-
-void
-typeinfo_free(typeinfo_t *info)
-{
-    TYPEINFO_FREEMERGED_IF_ANY(info->merged);
-    info->merged = NULL;
-}
-
-/**********************************************************************/
-/* MERGING FUNCTIONS                                                  */
-/* The following functions are used to merge the types represented by */
-/* two typeinfo structures into one typeinfo structure.               */
-/**********************************************************************/
-
-static
-void
-typeinfo_merge_error(methodinfo *m,char *str,typeinfo_t *x,typeinfo_t *y) {
-#ifdef TYPEINFO_VERBOSE
-    fprintf(stderr,"Error in typeinfo_merge: %s\n",str);
-    fprintf(stderr,"Typeinfo x:\n");
-    typeinfo_print(stderr,x,1);
-    fprintf(stderr,"Typeinfo y:\n");
-    typeinfo_print(stderr,y,1);
-    log_text(str);
-#endif
-
-       exceptions_throw_verifyerror(m, str);
-}
-
-/* Condition: clsx != clsy. */
-/* Returns: true if dest was changed (currently always true). */
-static
-bool
-typeinfo_merge_two(typeinfo_t *dest,classref_or_classinfo clsx,classref_or_classinfo clsy)
-{
-       TYPEINFO_ASSERT(dest);
-    TYPEINFO_FREEMERGED_IF_ANY(dest->merged);
-    TYPEINFO_ALLOCMERGED(dest->merged,2);
-    dest->merged->count = 2;
-
-       TYPEINFO_ASSERT(clsx.any != clsy.any);
-
-    if (clsx.any < clsy.any) {
-        dest->merged->list[0] = clsx;
-        dest->merged->list[1] = clsy;
-    }
-    else {
-        dest->merged->list[0] = clsy;
-        dest->merged->list[1] = clsx;
-    }
-
-    return true;
-}
-
-/* Returns: true if dest was changed. */
-static
-bool
-typeinfo_merge_add(typeinfo_t *dest,typeinfo_mergedlist_t *m,classref_or_classinfo cls)
-{
-    int count;
-    typeinfo_mergedlist_t *newmerged;
-    classref_or_classinfo *mlist,*newlist;
-
-    count = m->count;
-    mlist = m->list;
-
-    /* Check if cls is already in the mergedlist m. */
-    while (count--) {
-        if ((mlist++)->any == cls.any) { /* XXX check equal classrefs? */
-            /* cls is in the list, so m is the resulting mergedlist */
-            if (dest->merged == m)
-                return false;
-
-            /* We have to copy the mergedlist */
-            TYPEINFO_FREEMERGED_IF_ANY(dest->merged);
-            count = m->count;
-            TYPEINFO_ALLOCMERGED(dest->merged,count);
-            dest->merged->count = count;
-            newlist = dest->merged->list;
-            mlist = m->list;
-            while (count--) {
-                *newlist++ = *mlist++;
-            }
-            return true;
-        }
-    }
-
-    /* Add cls to the mergedlist. */
-    count = m->count;
-    TYPEINFO_ALLOCMERGED(newmerged,count+1);
-    newmerged->count = count+1;
-    newlist = newmerged->list;    
-    mlist = m->list;
-    while (count) {
-        if (mlist->any > cls.any)
-            break;
-        *newlist++ = *mlist++;
-        count--;
-    }
-    *newlist++ = cls;
-    while (count--) {
-        *newlist++ = *mlist++;
-    }
-
-    /* Put the new mergedlist into dest. */
-    TYPEINFO_FREEMERGED_IF_ANY(dest->merged);
-    dest->merged = newmerged;
-    
-    return true;
-}
-
-/* Returns: true if dest was changed. */
-static
-bool
-typeinfo_merge_mergedlists(typeinfo_t *dest,typeinfo_mergedlist_t *x,
-                           typeinfo_mergedlist_t *y)
-{
-    int count = 0;
-    int countx,county;
-    typeinfo_mergedlist_t *temp,*result;
-    classref_or_classinfo *clsx,*clsy,*newlist;
-
-    /* count the elements that will be in the resulting list */
-    /* (Both lists are sorted, equal elements are counted only once.) */
-    clsx = x->list;
-    clsy = y->list;
-    countx = x->count;
-    county = y->count;
-    while (countx && county) {
-        if (clsx->any == clsy->any) {
-            clsx++;
-            clsy++;
-            countx--;
-            county--;
-        }
-        else if (clsx->any < clsy->any) {
-            clsx++;
-            countx--;
-        }
-        else {
-            clsy++;
-            county--;
-        }
-        count++;
-    }
-    count += countx + county;
-
-    /* {The new mergedlist will have count entries.} */
-
-    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.} */
-    if (x->count == count) {
-        /* x->merged is equal to the result */
-        if (x == dest->merged)
-            return false;
-
-        if (!dest->merged || dest->merged->count != count) {
-            TYPEINFO_FREEMERGED_IF_ANY(dest->merged);
-            TYPEINFO_ALLOCMERGED(dest->merged,count);
-            dest->merged->count = count;
-        }
-
-        newlist = dest->merged->list;
-        clsx = x->list;
-        while (count--) {
-            *newlist++ = *clsx++;
-        }
-        return true;
-    }
-
-    /* {We have to merge two lists.} */
-
-    /* allocate the result list */
-    TYPEINFO_ALLOCMERGED(result,count);
-    result->count = count;
-    newlist = result->list;
-
-    /* merge the sorted lists */
-    clsx = x->list;
-    clsy = y->list;
-    countx = x->count;
-    county = y->count;
-    while (countx && county) {
-        if (clsx->any == clsy->any) {
-            *newlist++ = *clsx++;
-            clsy++;
-            countx--;
-            county--;
-        }
-        else if (clsx->any < clsy->any) {
-            *newlist++ = *clsx++;
-            countx--;
-        }
-        else {
-            *newlist++ = *clsy++;
-            county--;
-        }
-    }
-    while (countx--)
-            *newlist++ = *clsx++;
-    while (county--)
-            *newlist++ = *clsy++;
-
-    /* replace the list in dest with the result list */
-    TYPEINFO_FREEMERGED_IF_ANY(dest->merged);
-    dest->merged = result;
-
-    return true;
-}
-
-/* typeinfo_merge_nonarrays ****************************************************
-   Merge two non-array types.
-   
-   IN:
-       x................the first type
-          y................the second type
-          mergedx..........merged list of the first type, may be NULL
-          mergedy..........merged list of the descond type, may be NULL
-
-   OUT:
-       *dest............receives the resulting merged list
-          *result..........receives the resulting type
-
-   RETURN VALUE:
-       typecheck_TRUE...*dest has been modified
-          typecheck_FALSE..*dest has not been modified
-          typecheck_FAIL...an exception has been thrown
-
-   NOTE:
-       RESULT is an extra parameter so it can point to dest->typeclass or to
-          dest->elementclass.
-
-*******************************************************************************/
-
-static typecheck_result
-typeinfo_merge_nonarrays(typeinfo_t *dest,
-                         classref_or_classinfo *result,
-                         classref_or_classinfo x,classref_or_classinfo y,
-                         typeinfo_mergedlist_t *mergedx,
-                         typeinfo_mergedlist_t *mergedy)
-{
-       classref_or_classinfo t;
-    classinfo *tcls,*common;
-    typeinfo_mergedlist_t *tmerged;
-    bool changed;
-       typecheck_result r;
-       utf *xname;
-       utf *yname;
-
-       TYPEINFO_ASSERT(dest && result && x.any && y.any);
-       TYPEINFO_ASSERT(x.cls != pseudo_class_Null);
-       TYPEINFO_ASSERT(y.cls != pseudo_class_Null);
-       TYPEINFO_ASSERT(x.cls != pseudo_class_New);
-       TYPEINFO_ASSERT(y.cls != pseudo_class_New);
-
-       /*--------------------------------------------------*/
-       /* common cases                                     */
-       /*--------------------------------------------------*/
-
-    /* Common case 1: x and y are the same class or class reference */
-    /* (This case is very simple unless *both* x and y really represent
-     *  merges of subclasses of clsx==clsy.)
-     */
-    if ( (x.any == y.any) && (!mergedx || !mergedy) ) {
-  return_simple_x:
-        /* DEBUG */ /* log_text("return simple x"); */
-        changed = (dest->merged != NULL);
-        TYPEINFO_FREEMERGED_IF_ANY(dest->merged);
-        dest->merged = NULL;
-        *result = x;
-        /* DEBUG */ /* log_text("returning"); */
-        return changed;
-    }
-
-       xname = (IS_CLASSREF(x)) ? x.ref->name : x.cls->name;
-       yname = (IS_CLASSREF(y)) ? y.ref->name : y.cls->name;
-
-       /* Common case 2: xname == yname, at least one unresolved */
-    if ((IS_CLASSREF(x) || IS_CLASSREF(y)) && (xname == yname))
-       {
-               /* use the loaded one if any */
-               if (!IS_CLASSREF(y))
-                       x = y;
-               goto return_simple_x;
-    }
-
-       /*--------------------------------------------------*/
-       /* non-trivial cases                                */
-       /*--------------------------------------------------*/
-
-#ifdef TYPEINFO_VERBOSE
-       {
-               typeinfo_t dbgx,dbgy;
-               fprintf(stderr,"merge_nonarrays:\n");
-               fprintf(stderr,"    ");if(IS_CLASSREF(x))fprintf(stderr,"<ref>");utf_fprint_printable_ascii(stderr,xname);fprintf(stderr,"\n");
-               fprintf(stderr,"    ");if(IS_CLASSREF(y))fprintf(stderr,"<ref>");utf_fprint_printable_ascii(stderr,yname);fprintf(stderr,"\n");
-               fflush(stderr);
-               typeinfo_init_class(&dbgx,x);
-               dbgx.merged = mergedx;
-               typeinfo_init_class(&dbgy,y);
-               dbgy.merged = mergedy;
-               typeinfo_print(stderr,&dbgx,4);
-               fprintf(stderr,"  with:\n");
-               typeinfo_print(stderr,&dbgy,4);
-       }
-#endif
-
-       TYPEINFO_ASSERT(IS_CLASSREF(x) || (x.cls->state & CLASS_LOADED));
-       TYPEINFO_ASSERT(IS_CLASSREF(y) || (y.cls->state & CLASS_LOADED));
-
-    /* If y is unresolved or an interface, swap x and y. */
-    if (IS_CLASSREF(y) || (!IS_CLASSREF(x) && y.cls->flags & ACC_INTERFACE))
-       {
-        t = x; x = y; y = t;
-        tmerged = mergedx; mergedx = mergedy; mergedy = tmerged;
-    }
-       
-    /* {We know: If only one of x,y is unresolved it is x,} */
-    /* {         If both x,y are resolved and only one of x,y is an interface it is x.} */
-
-       if (IS_CLASSREF(x)) {
-               /* {We know: x and y have different class names} */
-               
-        /* Check if we are merging an unresolved type with java.lang.Object */
-        if (y.cls == class_java_lang_Object && !mergedy) {
-            x = y;
-            goto return_simple_x;
-        }
-            
-               common = class_java_lang_Object;
-               goto merge_with_simple_x;
-       }
-
-       /* {We know: both x and y are resolved} */
-    /* {We know: If only one of x,y is an interface it is x.} */
-
-       TYPEINFO_ASSERT(!IS_CLASSREF(x) && !IS_CLASSREF(y));
-       TYPEINFO_ASSERT(x.cls->state & CLASS_LOADED);
-       TYPEINFO_ASSERT(y.cls->state & CLASS_LOADED);
-
-    /* Handle merging of interfaces: */
-    if (x.cls->flags & ACC_INTERFACE) {
-        /* {x.cls is an interface and mergedx == NULL.} */
-        
-        if (y.cls->flags & ACC_INTERFACE) {
-            /* We are merging two interfaces. */
-            /* {mergedy == NULL} */
-
-            /* {We know that x.cls!=y.cls (see common case at beginning.)} */
-            result->cls = class_java_lang_Object;
-            return typeinfo_merge_two(dest,x,y);
-        }
-
-        /* {We know: x is an interface, y is a class.} */
-
-        /* Check if we are merging an interface with java.lang.Object */
-        if (y.cls == class_java_lang_Object && !mergedy) {
-            x = y;
-            goto return_simple_x;
-        }
-
-        /* If the type y implements x then the result of the merge
-         * is x regardless of mergedy.
-         */
-
-               /* we may have to link the classes */
-               if (!(x.cls->state & CLASS_LINKED))
-                       if (!link_class(x.cls))
-                               return typecheck_FAIL;
-               if (!(y.cls->state & CLASS_LINKED))
-                       if (!link_class(y.cls))
-                               return typecheck_FAIL;
-        
-               TYPEINFO_ASSERT(x.cls->state & CLASS_LINKED);
-               TYPEINFO_ASSERT(y.cls->state & CLASS_LINKED);
-
-        if (CLASSINFO_IMPLEMENTS_INTERFACE(y.cls,x.cls->index))
-               {
-            /* y implements x, so the result of the merge is x. */
-            goto return_simple_x;
-               }
-               
-        r = mergedlist_implements_interface(mergedy,x.cls);
-               if (r == typecheck_FAIL)
-                       return r;
-               if (r == typecheck_TRUE)
-        {
-            /* y implements x, so the result of the merge is x. */
-            goto return_simple_x;
-        }
-        
-        /* {We know: x is an interface, the type y a class or a merge
-         * of subclasses and is not guaranteed to implement x.} */
-
-        common = class_java_lang_Object;
-        goto merge_with_simple_x;
-    }
-
-    /* {We know: x and y are classes (not interfaces).} */
-    
-       /* we may have to link the classes */
-       if (!(x.cls->state & CLASS_LINKED))
-               if (!link_class(x.cls))
-                       return typecheck_FAIL;
-       if (!(y.cls->state & CLASS_LINKED))
-               if (!link_class(y.cls))
-                       return typecheck_FAIL;
-        
-       TYPEINFO_ASSERT(x.cls->state & CLASS_LINKED);
-       TYPEINFO_ASSERT(y.cls->state & CLASS_LINKED);
-
-    /* If *x is deeper in the inheritance hierarchy swap x and y. */
-    if (x.cls->index > y.cls->index) {
-        t = x; x = y; y = t;
-        tmerged = mergedx; mergedx = mergedy; mergedy = tmerged;
-    }
-
-    /* {We know: y is at least as deep in the hierarchy as x.} */
-
-    /* Find nearest common anchestor for the classes. */
-
-    common = x.cls;
-    tcls   = y.cls;
-
-    while (tcls->index > common->index)
-        tcls = tcls->super;
-
-    while (common != tcls) {
-        common = common->super;
-        tcls = tcls->super;
-    }
-
-    /* {common == nearest common anchestor of x and y.} */
-
-    /* If x.cls==common and x is a whole class (not a merge of subclasses)
-     * then the result of the merge is x.
-     */
-    if (x.cls == common && !mergedx) {
-        goto return_simple_x;
-    }
-   
-    if (mergedx) {
-        result->cls = common;
-        if (mergedy)
-            return typeinfo_merge_mergedlists(dest,mergedx,mergedy);
-        else
-            return typeinfo_merge_add(dest,mergedx,y);
-    }
-
-merge_with_simple_x:
-    result->cls = common;
-    if (mergedy)
-        return typeinfo_merge_add(dest,mergedy,x);
-    else
-        return typeinfo_merge_two(dest,x,y);
-}
-
-/* typeinfo_merge **************************************************************
-   Merge two types.
-   
-   IN:
-       m................method for exception messages
-       dest.............the first type
-       y................the second type
-
-   OUT:
-       *dest............receives the result of the merge
-
-   RETURN VALUE:
-       typecheck_TRUE...*dest has been modified
-       typecheck_FALSE..*dest has not been modified
-       typecheck_FAIL...an exception has been thrown
-
-   PRE-CONDITIONS:
-       1) *dest must be a valid initialized typeinfo
-       2) dest != y
-
-*******************************************************************************/
-
-typecheck_result
-typeinfo_merge(methodinfo *m,typeinfo_t *dest,typeinfo_t* y)
-{
-    typeinfo_t *x;
-    typeinfo_t *tmp;
-    classref_or_classinfo common;
-    classref_or_classinfo elementclass;
-    int dimension;
-    int elementtype;
-    bool changed;
-       typecheck_result r;
-
-       /*--------------------------------------------------*/
-       /* fast checks                                      */
-       /*--------------------------------------------------*/
-
-    /* Merging something with itself is a nop */
-    if (dest == y)
-        return typecheck_FALSE;
-
-    /* Merging two returnAddress types is ok. */
-       /* Merging two different returnAddresses never happens, as the verifier */
-       /* keeps them separate in order to check all the possible return paths  */
-       /* from JSR subroutines.                                                */
-    if (!dest->typeclass.any && !y->typeclass.any) {
-               TYPEINFO_ASSERT(TYPEINFO_RETURNADDRESS(*dest) ==  TYPEINFO_RETURNADDRESS(*y));
-        return typecheck_FALSE;
-       }
-    
-    /* Primitive types cannot be merged with reference types */
-       /* This must be checked before calls to typeinfo_merge.  */
-    TYPEINFO_ASSERT(dest->typeclass.any && y->typeclass.any);
-
-    /* handle uninitialized object types */
-    if (TYPEINFO_IS_NEWOBJECT(*dest) || TYPEINFO_IS_NEWOBJECT(*y)) {
-        if (!TYPEINFO_IS_NEWOBJECT(*dest) || !TYPEINFO_IS_NEWOBJECT(*y)) {
-            typeinfo_merge_error(m,"Trying to merge uninitialized object type.",dest,y);
-                       return typecheck_FAIL;
-               }
-        if (TYPEINFO_NEWOBJECT_INSTRUCTION(*dest) != TYPEINFO_NEWOBJECT_INSTRUCTION(*y)) {
-            typeinfo_merge_error(m,"Trying to merge different uninitialized objects.",dest,y);
-                       return typecheck_FAIL;
-               }
-               /* the same uninitialized object -- no change */
-               return typecheck_FALSE;
-    }
-    
-       /*--------------------------------------------------*/
-       /* common cases                                     */
-       /*--------------------------------------------------*/
-
-    /* Common case: dest and y are the same class or class reference */
-    /* (This case is very simple unless *both* dest and y really represent
-     *  merges of subclasses of class dest==class y.)
-     */
-    if ((dest->typeclass.any == y->typeclass.any) && (!dest->merged || !y->merged)) {
-return_simple:
-        changed = (dest->merged != NULL);
-        TYPEINFO_FREEMERGED_IF_ANY(dest->merged);
-        dest->merged = NULL;
-        return changed;
-    }
-    
-    /* Handle null types: */
-    if (TYPEINFO_IS_NULLTYPE(*y)) {
-        return typecheck_FALSE;
-    }
-    if (TYPEINFO_IS_NULLTYPE(*dest)) {
-        TYPEINFO_FREEMERGED_IF_ANY(dest->merged);
-        TYPEINFO_CLONE(*y,*dest);
-        return typecheck_TRUE;
-    }
-
-       /* Common case: two types with the same name, at least one unresolved */
-       if (IS_CLASSREF(dest->typeclass)) {
-               if (IS_CLASSREF(y->typeclass)) {
-                       if (dest->typeclass.ref->name == y->typeclass.ref->name)
-                               goto return_simple;
-               }
-               else {
-                       /* XXX should we take y instead of dest here? */
-                       if (dest->typeclass.ref->name == y->typeclass.cls->name)
-                               goto return_simple;
-               }
-       }
-       else {
-               if (IS_CLASSREF(y->typeclass) 
-                   && (dest->typeclass.cls->name == y->typeclass.ref->name))
-               {
-                       goto return_simple;
-               }
-       }
-
-       /*--------------------------------------------------*/
-       /* non-trivial cases                                */
-       /*--------------------------------------------------*/
-
-#ifdef TYPEINFO_VERBOSE
-       fprintf(stderr,"merge:\n");
-    typeinfo_print(stderr,dest,4);
-    typeinfo_print(stderr,y,4);
-#endif
-
-    /* This function uses x internally, so x and y can be swapped
-     * without changing dest. */
-    x = dest;
-    changed = false;
-    
-    /* Handle merging of arrays: */
-    if (TYPEINFO_IS_ARRAY(*x) && TYPEINFO_IS_ARRAY(*y)) {
-        
-        /* Make x the one with lesser dimension */
-        if (x->dimension > y->dimension) {
-            tmp = x; x = y; y = tmp;
-        }
-
-        /* If one array (y) has higher dimension than the other,
-         * interpret it as an array (same dim. as x) of Arraystubs. */
-        if (x->dimension < y->dimension) {
-            dimension = x->dimension;
-            elementtype = ARRAYTYPE_OBJECT;
-            elementclass.cls = pseudo_class_Arraystub;
-        }
-        else {
-            dimension = y->dimension;
-            elementtype = y->elementtype;
-            elementclass = y->elementclass;
-        }
-        
-        /* {The arrays are of the same dimension.} */
-        
-        if (x->elementtype != elementtype) {
-            /* Different element types are merged, so the resulting array
-             * type has one accessible dimension less. */
-            if (--dimension == 0) {
-                common.cls = pseudo_class_Arraystub;
-                elementtype = 0;
-                elementclass.any = NULL;
-            }
-            else {
-                common.cls = class_multiarray_of(dimension,pseudo_class_Arraystub,true);
-                               if (!common.cls) {
-                                       exceptions_throw_internalerror("XXX Coult not create array class");
-                                       return typecheck_FAIL;
-                               }
-
-                elementtype = ARRAYTYPE_OBJECT;
-                elementclass.cls = pseudo_class_Arraystub;
-            }
-        }
-        else {
-            /* {The arrays have the same dimension and elementtype.} */
-
-            if (elementtype == ARRAYTYPE_OBJECT) {
-                /* The elements are references, so their respective
-                 * types must be merged.
-                 */
-                               r = typeinfo_merge_nonarrays(dest,
-                                               &elementclass,
-                                               x->elementclass,
-                                               elementclass,
-                                               x->merged,y->merged);
-                               TYPEINFO_ASSERT(r != typecheck_MAYBE);
-                               if (r == typecheck_FAIL)
-                                       return r;
-                               changed |= r;
-
-                /* DEBUG */ /* log_text("finding resulting array class: "); */
-                               if (IS_CLASSREF(elementclass))
-                                       common.ref = class_get_classref_multiarray_of(dimension,elementclass.ref);
-                               else {
-                                       common.cls = class_multiarray_of(dimension,elementclass.cls,true);
-                                       if (!common.cls) {
-                                               exceptions_throw_internalerror("XXX Coult not create array class");
-                                               return typecheck_FAIL;
-                                       }
-                               }
-                /* DEBUG */ /* utf_display_printable_ascii(common->name); printf("\n"); */
-            }
-                       else {
-                               common.any = y->typeclass.any;
-                       }
-        }
-    }
-    else {
-        /* {We know that at least one of x or y is no array, so the
-         *  result cannot be an array.} */
-        
-               r = typeinfo_merge_nonarrays(dest,
-                               &common,
-                               x->typeclass,y->typeclass,
-                               x->merged,y->merged);
-               TYPEINFO_ASSERT(r != typecheck_MAYBE);
-               if (r == typecheck_FAIL)
-                       return r;
-               changed |= r;
-
-        dimension = 0;
-        elementtype = 0;
-        elementclass.any = NULL;
-    }
-
-    /* Put the new values into dest if neccessary. */
-
-    if (dest->typeclass.any != common.any) {
-        dest->typeclass.any = common.any;
-        changed = true;
-    }
-    if (dest->dimension != dimension) {
-        dest->dimension = dimension;
-        changed = true;
-    }
-    if (dest->elementtype != elementtype) {
-        dest->elementtype = elementtype;
-        changed = true;
-    }
-    if (dest->elementclass.any != elementclass.any) {
-        dest->elementclass.any = elementclass.any;
-        changed = true;
-    }
-
-    return changed;
-}
-#endif /* ENABLE_VERIFER */
-
-
-/**********************************************************************/
-/* DEBUGGING HELPERS                                                  */
-/**********************************************************************/
-
-#ifdef TYPEINFO_DEBUG
-
-#if 0
-static int
-typeinfo_test_compare(classref_or_classinfo *a,classref_or_classinfo *b)
-{
-    if (a->any == b->any) return 0;
-    if (a->any < b->any) return -1;
-    return +1;
-}
-
-static void
-typeinfo_test_parse(typeinfo_t *info,char *str)
-{
-    int num;
-    int i;
-    typeinfo_t *infobuf;
-    u1 *typebuf;
-    int returntype;
-    utf *desc = utf_new_char(str);
-    
-    num = typeinfo_count_method_args(desc,false);
-    if (num) {
-        typebuf = DMNEW(u1,num);
-        infobuf = DMNEW(typeinfo_t,num);
-        
-        typeinfo_init_from_method_args(desc,typebuf,infobuf,num,false,
-                                       &returntype,info);
-
-        TYPEINFO_ALLOCMERGED(info->merged,num);
-        info->merged->count = num;
-
-        for (i=0; i<num; ++i) {
-            if (typebuf[i] != TYPE_ADR) {
-                log_text("non-reference type in mergedlist");
-                               assert(0);
-                       }
-
-            info->merged->list[i].any = infobuf[i].typeclass.any;
-        }
-        qsort(info->merged->list,num,sizeof(classref_or_classinfo),
-              (int(*)(const void *,const void *))&typeinfo_test_compare);
-    }
-    else {
-        typeinfo_init_from_method_args(desc,NULL,NULL,0,false,
-                                       &returntype,info);
-    }
-}
-#endif
-
-#define TYPEINFO_TEST_BUFLEN  4000
-
-static bool
-typeinfo_equal(typeinfo_t *x,typeinfo_t *y)
-{
-    int i;
-    
-    if (x->typeclass.any != y->typeclass.any) return false;
-    if (x->dimension != y->dimension) return false;
-    if (x->dimension) {
-        if (x->elementclass.any != y->elementclass.any) return false;
-        if (x->elementtype != y->elementtype) return false;
-    }
-
-    if (TYPEINFO_IS_NEWOBJECT(*x))
-        if (TYPEINFO_NEWOBJECT_INSTRUCTION(*x)
-            != TYPEINFO_NEWOBJECT_INSTRUCTION(*y))
-            return false;
-
-    if (x->merged || y->merged) {
-        if (!(x->merged && y->merged)) return false;
-        if (x->merged->count != y->merged->count) return false;
-        for (i=0; i<x->merged->count; ++i)
-            if (x->merged->list[i].any != y->merged->list[i].any)
-                return false;
-    }
-    return true;
-}
-
-static void
-typeinfo_testmerge(typeinfo_t *a,typeinfo_t *b,typeinfo_t *result,int *failed)
-{
-    typeinfo_t dest;
-    bool changed,changed_should_be;
-       typecheck_result r;
-
-    TYPEINFO_CLONE(*a,dest);
-    
-    printf("\n          ");
-    typeinfo_print_short(stdout,&dest);
-    printf("\n          ");
-    typeinfo_print_short(stdout,b);
-    printf("\n");
-
-       r = typeinfo_merge(NULL,&dest,b);
-       if (r == typecheck_FAIL) {
-               printf("EXCEPTION\n");
-               return;
-       }
-    changed = (r) ? 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    ");
-        typeinfo_print_short(stdout,&dest);
-        printf("\n");
-        printf("SHOULD BE ");
-        typeinfo_print_short(stdout,result);
-        printf("\n");
-        (*failed)++;
-    }
-}
-
-#if 0
-static void
-typeinfo_inc_dimension(typeinfo_t *info)
-{
-    if (info->dimension++ == 0) {
-        info->elementtype = ARRAYTYPE_OBJECT;
-        info->elementclass = info->typeclass;
-    }
-    info->typeclass = class_array_of(info->typeclass,true);
-}
-#endif
-
-#define TYPEINFO_TEST_MAXDIM  10
-
-static void
-typeinfo_testrun(char *filename)
-{
-    char buf[TYPEINFO_TEST_BUFLEN];
-    char bufa[TYPEINFO_TEST_BUFLEN];
-    char bufb[TYPEINFO_TEST_BUFLEN];
-    char bufc[TYPEINFO_TEST_BUFLEN];
-    typeinfo_t a,b,c;
-    int maxdim;
-    int failed = 0;
-    FILE *file = fopen(filename,"rt");
-       int res;
-    
-    if (!file) {
-        log_text("could not open typeinfo test file");
-               assert(0);
-       }
-
-    while (fgets(buf,TYPEINFO_TEST_BUFLEN,file)) {
-        if (buf[0] == '#' || !strlen(buf))
-            continue;
-        
-        res = sscanf(buf,"%s\t%s\t%s\n",bufa,bufb,bufc);
-        if (res != 3 || !strlen(bufa) || !strlen(bufb) || !strlen(bufc)) {
-            log_text("Invalid line in typeinfo test file (none of empty, comment or test)");
-                       assert(0);
-               }
-
-#if 0
-        typeinfo_test_parse(&a,bufa);
-        typeinfo_test_parse(&b,bufb);
-        typeinfo_test_parse(&c,bufc);
-#endif
-#if 0
-        do {
-#endif
-            typeinfo_testmerge(&a,&b,&c,&failed); /* check result */
-            typeinfo_testmerge(&b,&a,&c,&failed); /* check commutativity */
-
-            if (TYPEINFO_IS_NULLTYPE(a)) break;
-            if (TYPEINFO_IS_NULLTYPE(b)) break;
-            if (TYPEINFO_IS_NULLTYPE(c)) break;
-            
-            maxdim = a.dimension;
-            if (b.dimension > maxdim) maxdim = b.dimension;
-            if (c.dimension > maxdim) maxdim = c.dimension;
-
-#if 0
-            if (maxdim < TYPEINFO_TEST_MAXDIM) {
-                typeinfo_inc_dimension(&a);
-                typeinfo_inc_dimension(&b);
-                typeinfo_inc_dimension(&c);
-            }
-        } while (maxdim < TYPEINFO_TEST_MAXDIM);
-#endif
-    }
-
-    fclose(file);
-
-    if (failed) {
-        fprintf(stderr,"Failed typeinfo_merge tests: %d\n",failed);
-        log_text("Failed test");
-               assert(0);
-    }
-}
-
-void
-typeinfo_test()
-{
-    log_text("Running typeinfo test file...");
-    typeinfo_testrun("typeinfo.tst");
-    log_text("Finished typeinfo test file.");
-}
-
-#if 0
-void
-typeinfo_init_from_fielddescriptor(typeinfo_t *info,char *desc)
-{
-    typeinfo_init_from_descriptor(info,desc,desc+strlen(desc));
-}
-#endif
-
-#define TYPEINFO_MAXINDENT  80
-
-void
-typeinfo_print_class(FILE *file,classref_or_classinfo c)
-{
-       /*fprintf(file,"<class %p>",c.any);*/
-
-       if (!c.any) {
-               fprintf(file,"<null>");
-       }
-       else {
-               if (IS_CLASSREF(c)) {
-                       fprintf(file,"<ref>");
-                       utf_fprint_printable_ascii(file,c.ref->name);
-               }
-               else {
-                       utf_fprint_printable_ascii(file,c.cls->name);
-               }
-       }
-}
-
-void
-typeinfo_print(FILE *file,typeinfo_t *info,int indent)
-{
-    int i;
-    char ind[TYPEINFO_MAXINDENT + 1];
-    instruction *ins;
-       basicblock *bptr;
-
-    if (indent > TYPEINFO_MAXINDENT) indent = TYPEINFO_MAXINDENT;
-    
-    for (i=0; i<indent; ++i)
-        ind[i] = ' ';
-    ind[i] = (char) 0;
-    
-    if (TYPEINFO_IS_PRIMITIVE(*info)) {
-               bptr = (basicblock*) TYPEINFO_RETURNADDRESS(*info);
-               if (bptr)
-                       fprintf(file,"%sreturnAddress (L%03d)\n",ind,bptr->nr);
-               else
-                       fprintf(file,"%sprimitive\n",ind);
-        return;
-    }
-    
-    if (TYPEINFO_IS_NULLTYPE(*info)) {
-        fprintf(file,"%snull\n",ind);
-        return;
-    }
-
-    if (TYPEINFO_IS_NEWOBJECT(*info)) {
-        ins = (instruction *) TYPEINFO_NEWOBJECT_INSTRUCTION(*info);
-        if (ins) {
-            fprintf(file,"%sNEW(%p):",ind,(void*)ins);
-                       typeinfo_print_class(file,ins[-1].sx.val.c);
-            fprintf(file,"\n");
-        }
-        else {
-            fprintf(file,"%sNEW(this)",ind);
-        }
-        return;
-    }
-
-    fprintf(file,"%sClass:      ",ind);
-       typeinfo_print_class(file,info->typeclass);
-    fprintf(file,"\n");
-
-    if (TYPEINFO_IS_ARRAY(*info)) {
-        fprintf(file,"%sDimension:    %d",ind,(int)info->dimension);
-        fprintf(file,"\n%sElements:     ",ind);
-        switch (info->elementtype) {
-          case ARRAYTYPE_INT     : fprintf(file,"int\n"); break;
-          case ARRAYTYPE_LONG    : fprintf(file,"long\n"); break;
-          case ARRAYTYPE_FLOAT   : fprintf(file,"float\n"); break;
-          case ARRAYTYPE_DOUBLE  : fprintf(file,"double\n"); break;
-          case ARRAYTYPE_BYTE    : fprintf(file,"byte\n"); break;
-          case ARRAYTYPE_CHAR    : fprintf(file,"char\n"); break;
-          case ARRAYTYPE_SHORT   : fprintf(file,"short\n"); break;
-          case ARRAYTYPE_BOOLEAN : fprintf(file,"boolean\n"); break;
-              
-          case ARRAYTYPE_OBJECT:
-                         typeinfo_print_class(file,info->elementclass);
-              fprintf(file,"\n");
-              break;
-              
-          default:
-              fprintf(file,"INVALID ARRAYTYPE!\n");
-        }
-    }
-
-    if (info->merged) {
-        fprintf(file,"%sMerged:     ",ind);
-        for (i=0; i<info->merged->count; ++i) {
-            if (i) fprintf(file,", ");
-                       typeinfo_print_class(file,info->merged->list[i]);
-        }
-        fprintf(file,"\n");
-    }
-}
-
-void
-typeinfo_print_short(FILE *file,typeinfo_t *info)
-{
-    int i;
-    instruction *ins;
-       basicblock *bptr;
-
-       /*fprintf(file,"<typeinfo %p>",info);*/
-
-       if (!info) {
-               fprintf(file,"(typeinfo*)NULL");
-               return;
-       }
-
-    if (TYPEINFO_IS_PRIMITIVE(*info)) {
-               bptr = (basicblock*) TYPEINFO_RETURNADDRESS(*info);
-               if (bptr)
-                       fprintf(file,"ret(L%03d)",bptr->nr);
-               else
-                       fprintf(file,"primitive");
-        return;
-    }
-    
-    if (TYPEINFO_IS_NULLTYPE(*info)) {
-        fprintf(file,"null");
-        return;
-    }
-    
-    if (TYPEINFO_IS_NEWOBJECT(*info)) {
-        ins = (instruction *) TYPEINFO_NEWOBJECT_INSTRUCTION(*info);
-        if (ins) {
-                       /*fprintf(file,"<ins %p>",ins);*/
-            fprintf(file,"NEW(%p):",(void*)ins);
-                       typeinfo_print_class(file,ins[-1].sx.val.c);
-        }
-        else
-            fprintf(file,"NEW(this)");
-        return;
-    }
-
-    typeinfo_print_class(file,info->typeclass);
-
-    if (info->merged) {
-        fprintf(file,"{");
-        for (i=0; i<info->merged->count; ++i) {
-            if (i) fprintf(file,",");
-                       typeinfo_print_class(file,info->merged->list[i]);
-        }
-        fprintf(file,"}");
-    }
-}
-
-void
-typeinfo_print_type(FILE *file,int type,typeinfo_t *info)
-{
-    switch (type) {
-      case TYPE_VOID: fprintf(file,"V"); break;
-      case TYPE_INT:  fprintf(file,"I"); break;
-      case TYPE_FLT:  fprintf(file,"F"); break;
-      case TYPE_DBL:  fprintf(file,"D"); break;
-      case TYPE_LNG:  fprintf(file,"J"); break;
-         case TYPE_RET:  fprintf(file,"R:"); /* FALLTHROUGH! */
-      case TYPE_ADR:
-                 typeinfo_print_short(file,info);
-          break;
-          
-      default:
-          fprintf(file,"!");
-    }
-}
-
-void
-typedescriptor_print(FILE *file,typedescriptor_t *td)
-{
-       typeinfo_print_type(file,td->type,&(td->typeinfo));
-}
-
-void
-typevector_print(FILE *file,varinfo *vec,int size)
-{
-    int i;
-
-    for (i=0; i<size; ++i) {
-               fprintf(file," %d=",i);
-        typeinfo_print_type(file, vec[i].type, &(vec[i].typeinfo));
-    }
-}
-
-#endif /* TYPEINFO_DEBUG */
-
-
-/*
- * 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
- * Emacs will automagically detect them.
- * ---------------------------------------------------------------------
- * Local variables:
- * mode: c
- * indent-tabs-mode: t
- * c-basic-offset: 4
- * tab-width: 4
- * End:
- * vim:noexpandtab:sw=4:ts=4:
- */
diff --git a/src/vm/jit/verify/typeinfo.cpp b/src/vm/jit/verify/typeinfo.cpp
new file mode 100644 (file)
index 0000000..1a02ca0
--- /dev/null
@@ -0,0 +1,2572 @@
+/* src/vm/jit/verify/typeinfo.c - type system used by the type checker
+
+   Copyright (C) 1996-2005, 2006, 2007, 2008
+   CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
+
+   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., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301, USA.
+
+*/
+
+
+#include "config.h"
+
+#include <assert.h>
+#include <string.h>
+
+#include "mm/memory.h"
+
+#include "toolbox/logging.h"
+
+#include "vm/array.hpp"
+#include "vm/class.hpp"
+#include "vm/descriptor.h"
+#include "vm/exceptions.hpp"
+#include "vm/globals.hpp"
+#include "vm/loader.hpp"
+#include "vm/primitive.hpp"
+#include "vm/resolve.hpp"
+
+#include "vm/jit/jit.hpp"
+#include "vm/jit/verify/typeinfo.hpp"
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+/* check if a linked class is an array class. Only use for linked classes! */
+#define CLASSINFO_IS_ARRAY(clsinfo)  ((clsinfo)->vftbl->arraydesc != NULL)
+
+/* check if a linked class implements the interface with the given index */
+#define CLASSINFO_IMPLEMENTS_INTERFACE(cls,index)                   \
+    ( ((index) < (cls)->vftbl->interfacetablelength)            \
+      && ( (cls)->vftbl->interfacetable[-(index)] != NULL ) )
+
+/******************************************************************************/
+/* DEBUG HELPERS                                                              */
+/******************************************************************************/
+
+#ifdef TYPEINFO_DEBUG
+#define TYPEINFO_ASSERT(cond)  assert(cond)
+#else
+#define TYPEINFO_ASSERT(cond)
+#endif
+
+/**********************************************************************/
+/* TYPEVECTOR FUNCTIONS                                               */
+/**********************************************************************/
+
+#if defined(ENABLE_VERIFIER)
+
+/* typevector_copy *************************************************************
+   Return a copy of the given typevector.
+  
+   IN:
+          src..............typevector set to copy, must be != NULL
+          size.............number of elements per typevector
+
+   RETURN VALUE:
+       a pointer to the new typevector set
+
+*******************************************************************************/
+
+varinfo *
+typevector_copy(varinfo *src, int size)
+{
+       varinfo *dst;
+       
+       TYPEINFO_ASSERT(src);
+       
+       dst = DNEW_TYPEVECTOR(size);
+       memcpy(dst,src,TYPEVECTOR_SIZE(size));
+
+       return dst;
+}
+
+/* typevector_copy_inplace *****************************************************
+   Copy a typevector to a given destination.
+
+   IN:
+          src..............typevector to copy, must be != NULL
+          dst..............destination to write the copy to
+          size.............number of elements per typevector
+
+*******************************************************************************/
+
+void
+typevector_copy_inplace(varinfo *src,varinfo *dst,int size)
+{
+       memcpy(dst,src,TYPEVECTOR_SIZE(size));
+}
+
+/* typevector_checktype ********************************************************
+   Check if the typevector contains a given type at a given index.
+  
+   IN:
+          vec..............typevector set, must be != NULL
+          index............index of component to check
+          type.............TYPE_* constant to check against
+
+   RETURN VALUE:
+       true if the typevector contains TYPE at INDEX,
+          false otherwise
+
+*******************************************************************************/
+
+bool
+typevector_checktype(varinfo *vec,int index,int type)
+{
+       TYPEINFO_ASSERT(vec);
+
+       return vec[index].type == type;
+}
+
+/* typevector_checkreference ***************************************************
+   Check if the typevector contains a reference at a given index.
+  
+   IN:
+          vec..............typevector, must be != NULL
+          index............index of component to check
+
+   RETURN VALUE:
+       true if the typevector contains a reference at INDEX,
+          false otherwise
+
+*******************************************************************************/
+
+bool
+typevector_checkreference(varinfo *vec, int index)
+{
+       TYPEINFO_ASSERT(vec);
+       return TYPEDESC_IS_REFERENCE(vec[index]);
+}
+
+/* typevectorset_checkretaddr **************************************************
+   Check if the typevectors contains a returnAddress at a given index.
+  
+   IN:
+          vec..............typevector, must be != NULL
+          index............index of component to check
+
+   RETURN VALUE:
+       true if the typevector contains a returnAddress at INDEX,
+          false otherwise
+
+*******************************************************************************/
+
+bool
+typevector_checkretaddr(varinfo *vec,int index)
+{
+       TYPEINFO_ASSERT(vec);
+       return TYPEDESC_IS_RETURNADDRESS(vec[index]);
+}
+
+/* typevector_store ************************************************************
+   Store a type at a given index in the typevector.
+  
+   IN:
+          vec..............typevector set, must be != NULL
+          index............index of component to set
+          type.............TYPE_* constant of type to set
+          info.............typeinfo of type to set, may be NULL, 
+                           if TYPE != TYPE_ADR
+
+*******************************************************************************/
+
+void
+typevector_store(varinfo *vec,int index,int type,typeinfo_t *info)
+{
+       TYPEINFO_ASSERT(vec);
+
+       vec[index].type = type;
+       if (info)
+               TYPEINFO_COPY(*info,vec[index].typeinfo);
+}
+
+/* typevector_store_retaddr ****************************************************
+   Store a returnAddress type at a given index in the typevector.
+  
+   IN:
+          vec..............typevector set, must be != NULL
+          index............index of component to set
+          info.............typeinfo of the returnAddress.
+
+*******************************************************************************/
+
+void
+typevector_store_retaddr(varinfo *vec,int index,typeinfo_t *info)
+{
+       TYPEINFO_ASSERT(vec);
+       TYPEINFO_ASSERT(TYPEINFO_IS_PRIMITIVE(*info));
+       
+       vec[index].type = TYPE_ADR;
+       TYPEINFO_INIT_RETURNADDRESS(vec[index].typeinfo,
+                       TYPEINFO_RETURNADDRESS(*info));
+}
+
+/* typevector_init_object ******************************************************
+   Replace all uninitialized object types in the typevector set which were 
+   created by the given instruction by initialized object types.
+  
+   IN:
+          set..............typevector set
+          ins..............instruction which created the uninitialized object type
+          initclass........class of the initialized object type to set
+          size.............number of elements per typevector
+
+   RETURN VALUE:
+       true.............success
+          false............an exception has been thrown
+
+   XXX maybe we should do the lazy resolving before calling this function
+
+*******************************************************************************/
+
+bool
+typevector_init_object(varinfo *set,void *ins,
+                                          classref_or_classinfo initclass,
+                                          int size)
+{
+       int i;
+
+       for (i=0; i<size; ++i) {
+               if (set[i].type == TYPE_ADR
+                       && TYPEINFO_IS_NEWOBJECT(set[i].typeinfo)
+                       && TYPEINFO_NEWOBJECT_INSTRUCTION(set[i].typeinfo) == ins)
+               {
+                       if (!typeinfo_init_class(&(set[i].typeinfo),initclass))
+                               return false;
+               }
+       }
+       return true;
+}
+
+/* typevector_merge ************************************************************
+   Merge a typevector with another one.
+   The given typevectors must have the same number of components.
+  
+   IN:
+       m................method for exception messages
+          dst..............the first typevector
+          y................the second typevector
+          size.............number of elements per typevector
+
+   OUT:
+       *dst.............the resulting typevector
+
+   RETURN VALUE:
+       typecheck_TRUE...dst has been modified
+          typecheck_FALSE..dst has not been modified
+          typecheck_FAIL...an exception has been thrown
+
+*******************************************************************************/
+
+typecheck_result
+typevector_merge(methodinfo *m,varinfo *dst,varinfo *y,int size)
+{
+       bool changed = false;
+       typecheck_result r;
+       
+       varinfo *a = dst;
+       varinfo *b = y;
+       while (size--) {
+               if (a->type != TYPE_VOID && a->type != b->type) {
+                       a->type = TYPE_VOID;
+                       changed = true;
+               }
+               else if (a->type == TYPE_ADR) {
+                       if (TYPEINFO_IS_PRIMITIVE(a->typeinfo)) {
+                               /* 'a' is a returnAddress */
+                               if (!TYPEINFO_IS_PRIMITIVE(b->typeinfo)
+                                       || (TYPEINFO_RETURNADDRESS(a->typeinfo)
+                                               != TYPEINFO_RETURNADDRESS(b->typeinfo)))
+                               {
+                                       a->type = TYPE_VOID;
+                                       changed = true;
+                               }
+                       }
+                       else {
+                               /* 'a' is a reference */
+                               if (TYPEINFO_IS_PRIMITIVE(b->typeinfo)) {
+                                       a->type = TYPE_VOID;
+                                       changed = true;
+                               }
+                               else {
+                                       /* two reference types are merged. There cannot be */
+                                       /* a merge error. In the worst case we get j.l.O.  */
+                                       r = typeinfo_merge(m,&(a->typeinfo),&(b->typeinfo));
+                                       if (r == typecheck_FAIL)
+                                               return r;
+                                       changed |= r;
+                               }
+                       }
+               }
+               a++;
+               b++;
+       }
+       return (typecheck_result) changed;
+}
+
+/**********************************************************************/
+/* READ-ONLY FUNCTIONS                                                */
+/* The following functions don't change typeinfo data.                */
+/**********************************************************************/
+
+/* typeinfo_is_array ***********************************************************
+   Check whether a typeinfo describes an array type.
+   
+   IN:
+          info.............the typeinfo, must be != NULL
+
+   RETURN VALUE:
+       true if INFO describes an array type.
+
+*******************************************************************************/
+
+bool
+typeinfo_is_array(typeinfo_t *info)
+{
+       TYPEINFO_ASSERT(info);
+    return TYPEINFO_IS_ARRAY(*info);
+}
+
+/* typeinfo_is_primitive_array *************************************************
+   Check whether a typeinfo describes a primitive array type.
+   
+   IN:
+          info.............the typeinfo, must be != NULL
+
+   RETURN VALUE:
+       true if INFO describes an array of a primitive type.
+
+*******************************************************************************/
+
+bool
+typeinfo_is_primitive_array(typeinfo_t *info,int arraytype)
+{
+       TYPEINFO_ASSERT(info);
+    return TYPEINFO_IS_PRIMITIVE_ARRAY(*info,arraytype);
+}
+
+/* typeinfo_is_array_of_refs ***************************************************
+   Check whether a typeinfo describes an array of references type.
+   
+   IN:
+          info.............the typeinfo, must be != NULL
+
+   RETURN VALUE:
+       true if INFO describes an array of a refrence type.
+
+*******************************************************************************/
+
+bool
+typeinfo_is_array_of_refs(typeinfo_t *info)
+{
+       TYPEINFO_ASSERT(info);
+    return TYPEINFO_IS_ARRAY_OF_REFS(*info);
+}
+
+/* interface_extends_interface *************************************************
+   Check if a resolved interface extends a given resolved interface.
+   
+   IN:
+          cls..............the interface, must be linked
+          interf...........the interface to check against
+
+   RETURN VALUE:
+       true.............CLS extends INTERF
+          false............CLS does not extend INTERF
+
+*******************************************************************************/
+
+static bool
+interface_extends_interface(classinfo *cls,classinfo *interf)
+{
+    int i;
+    
+       TYPEINFO_ASSERT(cls);
+       TYPEINFO_ASSERT(interf);
+       TYPEINFO_ASSERT((interf->flags & ACC_INTERFACE) != 0);
+       TYPEINFO_ASSERT((cls->flags & ACC_INTERFACE) != 0);
+       TYPEINFO_ASSERT(cls->state & CLASS_LINKED);
+
+    /* first check direct superinterfaces */
+    for (i=0; i<cls->interfacescount; ++i) {
+        if (cls->interfaces[i] == interf)
+            return true;
+    }
+    
+    /* check indirect superinterfaces */
+    for (i=0; i<cls->interfacescount; ++i) {
+        if (interface_extends_interface(cls->interfaces[i],interf))
+            return true;
+    }
+    
+    return false;
+}
+
+/* classinfo_implements_interface **********************************************
+   Check if a resolved class implements a given resolved interface.
+   
+   IN:
+          cls..............the class
+          interf...........the interface
+
+   RETURN VALUE:
+       typecheck_TRUE...CLS implements INTERF
+          typecheck_FALSE..CLS does not implement INTERF
+          typecheck_FAIL...an exception has been thrown
+
+*******************************************************************************/
+
+static typecheck_result
+classinfo_implements_interface(classinfo *cls,classinfo *interf)
+{
+       TYPEINFO_ASSERT(cls);
+       TYPEINFO_ASSERT(interf);
+       TYPEINFO_ASSERT((interf->flags & ACC_INTERFACE) != 0);
+
+       if (!(cls->state & CLASS_LINKED))
+               if (!link_class(cls))
+                       return typecheck_FAIL;
+
+    if (cls->flags & ACC_INTERFACE) {
+        /* cls is an interface */
+        if (cls == interf)
+            return typecheck_TRUE;
+
+        /* check superinterfaces */
+        return (typecheck_result) interface_extends_interface(cls,interf);
+    }
+
+       TYPEINFO_ASSERT(cls->state & CLASS_LINKED);
+    return (typecheck_result) CLASSINFO_IMPLEMENTS_INTERFACE(cls,interf->index);
+}
+
+/* mergedlist_implements_interface *********************************************
+   Check if all the classes in a given merged list implement a given resolved
+   interface.
+   
+   IN:
+          merged...........the list of merged class types
+          interf...........the interface to check against
+
+   RETURN VALUE:
+       typecheck_TRUE...all classes implement INTERF
+          typecheck_FALSE..there is at least one class that does not implement
+                           INTERF
+          typecheck_MAYBE..check cannot be performed now because of unresolved
+                           classes
+          typecheck_FAIL...an exception has been thrown
+
+*******************************************************************************/
+
+static typecheck_result
+mergedlist_implements_interface(typeinfo_mergedlist_t *merged,
+                                classinfo *interf)
+{
+    int i;
+    classref_or_classinfo *mlist;
+       typecheck_result r;
+    
+       TYPEINFO_ASSERT(interf);
+       TYPEINFO_ASSERT((interf->flags & ACC_INTERFACE) != 0);
+
+    /* Check if there is an non-empty mergedlist. */
+    if (!merged)
+        return typecheck_FALSE;
+
+    /* If all classinfos in the (non-empty) merged array implement the
+     * interface return true, otherwise false.
+     */
+    mlist = merged->list;
+    i = merged->count;
+    while (i--) {
+               if (IS_CLASSREF(*mlist)) {
+                       return typecheck_MAYBE;
+               }
+        r = classinfo_implements_interface((mlist++)->cls,interf);
+        if (r != typecheck_TRUE)
+                       return r;
+    }
+    return typecheck_TRUE;
+}
+
+/* merged_implements_interface *************************************************
+   Check if a possible merged type implements a given resolved interface
+   interface.
+   
+   IN:
+       typeclass........(common) class of the (merged) type
+          merged...........the list of merged class types
+          interf...........the interface to check against
+
+   RETURN VALUE:
+       typecheck_TRUE...the type implement INTERF
+          typecheck_FALSE..the type does not implement INTERF
+          typecheck_MAYBE..check cannot be performed now because of unresolved
+                           classes
+          typecheck_FAIL...an exception has been thrown
+
+*******************************************************************************/
+
+static typecheck_result
+merged_implements_interface(classinfo *typeclass,typeinfo_mergedlist_t *merged,
+                            classinfo *interf)
+{
+       typecheck_result r;
+       
+    /* primitive types don't support interfaces. */
+    if (!typeclass)
+        return typecheck_FALSE;
+
+    /* the null type can be cast to any interface type. */
+    if (typeclass == pseudo_class_Null)
+        return typecheck_TRUE;
+
+    /* check if typeclass implements the interface. */
+    r = classinfo_implements_interface(typeclass,interf);
+       if (r != typecheck_FALSE)
+        return r;
+
+    /* check the mergedlist */
+       if (!merged)
+               return typecheck_FALSE;
+    return mergedlist_implements_interface(merged,interf);
+}
+
+/* merged_is_subclass **********************************************************
+   Check if a possible merged type is a subclass of a given class.
+   A merged type is a subclass of a class C if all types in the merged list
+   are subclasses of C. A sufficient condition for this is that the
+   common type of the merged type is a subclass of C.
+
+   IN:
+       typeclass........(common) class of the (merged) type
+                           MUST be a loaded and linked class
+          merged...........the list of merged class types
+          cls..............the class to theck against
+
+   RETURN VALUE:
+       typecheck_TRUE...the type is a subclass of CLS
+          typecheck_FALSE..the type is not a subclass of CLS
+          typecheck_MAYBE..check cannot be performed now because of unresolved
+                           classes
+          typecheck_FAIL...an exception has been thrown
+
+*******************************************************************************/
+
+static typecheck_result
+merged_is_subclass(classinfo *typeclass,typeinfo_mergedlist_t *merged,
+               classinfo *cls)
+{
+    int i;
+    classref_or_classinfo *mlist;
+
+       TYPEINFO_ASSERT(cls);
+       
+    /* primitive types aren't subclasses of anything. */
+    if (!typeclass)
+        return typecheck_FALSE;
+
+    /* the null type can be cast to any reference type. */
+    if (typeclass == pseudo_class_Null)
+        return typecheck_TRUE;
+
+       TYPEINFO_ASSERT(typeclass->state & CLASS_LOADED);
+       TYPEINFO_ASSERT(typeclass->state & CLASS_LINKED);
+
+    /* check if the common typeclass is a subclass of CLS. */
+       if (class_issubclass(typeclass,cls))
+               return typecheck_TRUE;
+       
+    /* check the mergedlist */
+       if (!merged)
+               return typecheck_FALSE;
+    /* If all classinfos in the (non-empty) merged list are subclasses
+        * of CLS, return true, otherwise false.
+        * If there is at least one unresolved type in the list,
+        * return typecheck_MAYBE.
+     */
+    mlist = merged->list;
+    i = merged->count;
+    while (i--) {
+               if (IS_CLASSREF(*mlist)) {
+                       return typecheck_MAYBE;
+               }
+               if (!(mlist->cls->state & CLASS_LINKED))
+                       if (!link_class(mlist->cls))
+                               return typecheck_FAIL;
+               if (!class_issubclass(mlist->cls,cls))
+                       return typecheck_FALSE;
+               mlist++;
+    }
+    return typecheck_TRUE;
+}
+
+/* typeinfo_is_assignable_to_class *********************************************
+   Check if a type is assignable to a given class type.
+   
+   IN:
+       value............the type of the value
+          dest.............the type of the destination
+
+   RETURN VALUE:
+       typecheck_TRUE...the type is assignable
+          typecheck_FALSE..the type is not assignable
+          typecheck_MAYBE..check cannot be performed now because of unresolved
+                           classes
+          typecheck_FAIL...an exception has been thrown
+
+*******************************************************************************/
+
+typecheck_result
+typeinfo_is_assignable_to_class(typeinfo_t *value,classref_or_classinfo dest)
+{
+       classref_or_classinfo c;
+    classinfo *cls;
+       utf *classname;
+
+       TYPEINFO_ASSERT(value);
+
+    c = value->typeclass;
+
+    /* assignments of primitive values are not checked here. */
+    if (!c.any && !dest.any)
+        return typecheck_TRUE;
+
+    /* primitive and reference types are not assignment compatible. */
+    if (!c.any || !dest.any)
+        return typecheck_FALSE;
+
+    /* the null type can be assigned to any type */
+    if (TYPEINFO_IS_NULLTYPE(*value))
+        return typecheck_TRUE;
+
+    /* uninitialized objects are not assignable */
+    if (TYPEINFO_IS_NEWOBJECT(*value))
+        return typecheck_FALSE;
+
+       if (IS_CLASSREF(c)) {
+               /* The value type is an unresolved class reference. */
+               classname = c.ref->name;
+       }
+       else {
+               classname = c.cls->name;
+       }
+
+       if (IS_CLASSREF(dest)) {
+               /* the destination type is an unresolved class reference */
+               /* In this case we cannot tell a lot about assignability. */
+
+               /* the common case of value and dest type having the same classname */
+               if (dest.ref->name == classname && !value->merged)
+                       return typecheck_TRUE;
+
+               /* we cannot tell if value is assignable to dest, so we */
+               /* leave it up to the resolving code to check this      */
+               return typecheck_MAYBE;
+       }
+
+       /* { we know that dest is a loaded class } */
+
+       if (IS_CLASSREF(c)) {
+               /* the value type is an unresolved class reference */
+               
+               /* the common case of value and dest type having the same classname */
+               if (dest.cls->name == classname)
+                       return typecheck_TRUE;
+
+               /* we cannot tell if value is assignable to dest, so we */
+               /* leave it up to the resolving code to check this      */
+               return typecheck_MAYBE;
+       }
+
+       /* { we know that both c and dest are loaded classes } */
+       /* (c may still have a merged list containing unresolved classrefs!) */
+
+       TYPEINFO_ASSERT(!IS_CLASSREF(c));
+       TYPEINFO_ASSERT(!IS_CLASSREF(dest));
+
+       cls = c.cls;
+       
+       TYPEINFO_ASSERT(cls->state & CLASS_LOADED);
+       TYPEINFO_ASSERT(dest.cls->state & CLASS_LOADED);
+
+       /* maybe we need to link the classes */
+       if (!(cls->state & CLASS_LINKED))
+               if (!link_class(cls))
+                       return typecheck_FAIL;
+       if (!(dest.cls->state & CLASS_LINKED))
+               if (!link_class(dest.cls))
+                       return typecheck_FAIL;
+
+       /* { we know that both c and dest are linked classes } */
+       TYPEINFO_ASSERT(cls->state & CLASS_LINKED);
+       TYPEINFO_ASSERT(dest.cls->state & CLASS_LINKED);
+
+    if (dest.cls->flags & ACC_INTERFACE) {
+        /* We are assigning to an interface type. */
+        return merged_implements_interface(cls,value->merged,dest.cls);
+    }
+
+    if (CLASSINFO_IS_ARRAY(dest.cls)) {
+               arraydescriptor *arraydesc = dest.cls->vftbl->arraydesc;
+               int dimension = arraydesc->dimension;
+               classinfo *elementclass = (arraydesc->elementvftbl)
+                       ? arraydesc->elementvftbl->clazz : NULL;
+                       
+        /* We are assigning to an array type. */
+        if (!TYPEINFO_IS_ARRAY(*value))
+            return typecheck_FALSE;
+
+        /* {Both value and dest.cls are array types.} */
+
+        /* value must have at least the dimension of dest.cls. */
+        if (value->dimension < dimension)
+            return typecheck_FALSE;
+
+        if (value->dimension > dimension) {
+            /* value has higher dimension so we need to check
+             * if its component array can be assigned to the
+             * element type of dest.cls */
+
+                       if (!elementclass) return typecheck_FALSE;
+            
+            if (elementclass->flags & ACC_INTERFACE) {
+                /* We are assigning to an interface type. */
+                return classinfo_implements_interface(pseudo_class_Arraystub,
+                                                      elementclass);
+            }
+
+            /* We are assigning to a class type. */
+            return (typecheck_result) class_issubclass(pseudo_class_Arraystub,elementclass);
+        }
+
+        /* {value and dest.cls have the same dimension} */
+
+        if (value->elementtype != arraydesc->elementtype)
+            return typecheck_FALSE;
+
+        if (value->elementclass.any) {
+            /* We are assigning an array of objects so we have to
+             * check if the elements are assignable.
+             */
+
+            if (elementclass->flags & ACC_INTERFACE) {
+                /* We are assigning to an interface type. */
+
+                return merged_implements_interface(value->elementclass.cls,
+                                                   value->merged,
+                                                   elementclass);
+            }
+            
+            /* We are assigning to a class type. */
+            return merged_is_subclass(value->elementclass.cls,value->merged,elementclass);
+        }
+
+        return typecheck_TRUE;
+    }
+
+    /* {dest.cls is not an array} */
+    /* {dest.cls is a loaded class} */
+
+       /* If there are any unresolved references in the merged list, we cannot */
+       /* tell if the assignment will be ok.                                   */
+       /* This can only happen when cls is java.lang.Object                    */
+       if (cls == class_java_lang_Object && value->merged) {
+               classref_or_classinfo *mlist = value->merged->list;
+               int i = value->merged->count;
+               while (i--)
+                       if (IS_CLASSREF(*mlist++))
+                               return typecheck_MAYBE;
+       }
+        
+    /* We are assigning to a class type */
+    if (cls->flags & ACC_INTERFACE)
+        cls = class_java_lang_Object;
+    
+    return merged_is_subclass(cls,value->merged,dest.cls);
+}
+
+/* typeinfo_is_assignable ******************************************************
+   Check if a type is assignable to a given type.
+   
+   IN:
+       value............the type of the value
+          dest.............the type of the destination, must not be a merged type
+
+   RETURN VALUE:
+       typecheck_TRUE...the type is assignable
+          typecheck_FALSE..the type is not assignable
+          typecheck_MAYBE..check cannot be performed now because of unresolved
+                           classes
+          typecheck_FAIL...an exception has been thrown
+
+*******************************************************************************/
+
+typecheck_result
+typeinfo_is_assignable(typeinfo_t *value,typeinfo_t *dest)
+{
+       TYPEINFO_ASSERT(value);
+       TYPEINFO_ASSERT(dest);
+       TYPEINFO_ASSERT(dest->merged == NULL);
+
+       return typeinfo_is_assignable_to_class(value,dest->typeclass);
+}
+
+/**********************************************************************/
+/* INITIALIZATION FUNCTIONS                                           */
+/* The following functions fill in uninitialized typeinfo structures. */
+/**********************************************************************/
+
+/* typeinfo_init_classinfo *****************************************************
+   Initialize a typeinfo to a resolved class.
+   
+   IN:
+          c................the class
+
+   OUT:
+       *info............is initialized
+
+   RETURN VALUE:
+       true.............success
+          false............an exception has been thrown
+
+*******************************************************************************/
+
+void
+typeinfo_init_classinfo(typeinfo_t *info, classinfo *c)
+{
+       if ((info->typeclass.cls = c)->vftbl->arraydesc) {
+               if (c->vftbl->arraydesc->elementvftbl)
+                       info->elementclass.cls = c->vftbl->arraydesc->elementvftbl->clazz;
+               else
+                       info->elementclass.any = NULL;
+               info->dimension = c->vftbl->arraydesc->dimension;
+               info->elementtype = c->vftbl->arraydesc->elementtype;
+       }
+       else {
+               info->elementclass.any = NULL;
+               info->dimension = 0;
+               info->elementtype = 0;
+       }
+       info->merged = NULL;
+}
+
+/* typeinfo_init_class *********************************************************
+   Initialize a typeinfo to a possibly unresolved class type.
+   
+   IN:
+          c................the class type
+
+   OUT:
+       *info............is initialized
+
+   RETURN VALUE:
+       true.............success
+          false............an exception has been thrown
+
+*******************************************************************************/
+
+bool
+typeinfo_init_class(typeinfo_t *info,classref_or_classinfo c)
+{
+       char *utf_ptr;
+       int len;
+       classinfo *cls;
+               
+       TYPEINFO_ASSERT(c.any);
+       TYPEINFO_ASSERT(info);
+
+       /* if necessary, try to resolve lazily */
+       if (!resolve_classref_or_classinfo(NULL /* XXX should know method */,
+                               c,resolveLazy,false,true,&cls))
+       {
+               return false;
+       }
+       
+       if (cls) {
+               typeinfo_init_classinfo(info,cls);
+               return true;
+       }
+
+       /* {the type could no be resolved lazily} */
+
+       info->typeclass.ref = c.ref;
+       info->elementclass.any = NULL;
+       info->dimension = 0;
+       info->merged = NULL;
+
+       /* handle array type references */
+       utf_ptr = c.ref->name->text;
+       len = c.ref->name->blength;
+       if (*utf_ptr == '[') {
+               /* count dimensions */
+               while (*utf_ptr == '[') {
+                       utf_ptr++;
+                       info->dimension++;
+                       len--;
+               }
+               if (*utf_ptr == 'L') {
+                       utf_ptr++;
+                       len -= 2;
+                       info->elementtype = ARRAYTYPE_OBJECT;
+                       info->elementclass.ref = class_get_classref(c.ref->referer,utf_new(utf_ptr,len));
+               }
+               else {
+                       /* an array with primitive element type */
+                       /* should have been resolved above */
+                       TYPEINFO_ASSERT(false);
+               }
+       }
+       return true;
+}
+
+/* typeinfo_init_from_typedesc *************************************************
+   Initialize a typeinfo from a typedesc.
+   
+   IN:
+          desc.............the typedesc
+
+   OUT:
+       *type............set to the TYPE_* constant of DESC (if type != NULL)
+       *info............receives the typeinfo (if info != NULL)
+
+   RETURN VALUE:
+       true.............success
+          false............an exception has been thrown
+
+*******************************************************************************/
+
+bool
+typeinfo_init_from_typedesc(typedesc *desc,u1 *type,typeinfo_t *info)
+{
+       TYPEINFO_ASSERT(desc);
+
+#ifdef TYPEINFO_VERBOSE
+       fprintf(stderr,"typeinfo_init_from_typedesc(");
+       descriptor_debug_print_typedesc(stderr,desc);
+       fprintf(stderr,")\n");
+#endif
+
+       if (type)
+               *type = desc->type;
+
+       if (info) {
+               if (desc->type == TYPE_ADR) {
+                       TYPEINFO_ASSERT(desc->classref);
+                       if (!typeinfo_init_class(info,CLASSREF_OR_CLASSINFO(desc->classref)))
+                               return false;
+               }
+               else {
+                       TYPEINFO_INIT_PRIMITIVE(*info);
+               }
+       }
+       return true;
+}
+
+/* typeinfos_init_from_methoddesc **********************************************
+   Initialize an array of typeinfos and u1 TYPE_* values from a methoddesc.
+   
+   IN:
+       desc.............the methoddesc
+       buflen...........number of parameters the buffer can hold
+       twoword..........if true, use two parameter slots for two-word types
+
+   OUT:
+       *typebuf.........receives a TYPE_* constant for each parameter
+                        typebuf must be != NULL
+       *infobuf.........receives a typeinfo for each parameter
+                        infobuf must be != NULL
+       *returntype......receives a TYPE_* constant for the return type
+                        returntype may be NULL
+       *returntypeinfo..receives a typeinfo for the return type
+                        returntypeinfo may be NULL
+
+   RETURN VALUE:
+       true.............success
+       false............an exception has been thrown
+
+   NOTE:
+       If (according to BUFLEN) the buffers are to small to hold the
+          parameter types, an internal error is thrown. This must be
+          avoided by checking the number of parameters and allocating enough
+          space before calling this function.
+
+*******************************************************************************/
+
+bool
+typeinfos_init_from_methoddesc(methoddesc *desc,u1 *typebuf,typeinfo_t *infobuf,
+                              int buflen,bool twoword,
+                              u1 *returntype,typeinfo_t *returntypeinfo)
+{
+       int i;
+    int args = 0;
+
+       TYPEINFO_ASSERT(desc);
+       TYPEINFO_ASSERT(typebuf);
+       TYPEINFO_ASSERT(infobuf);
+
+#ifdef TYPEINFO_VERBOSE
+       fprintf(stderr,"typeinfos_init_from_methoddesc(");
+       descriptor_debug_print_methoddesc(stderr,desc);
+       fprintf(stderr,")\n");
+#endif
+
+    /* check arguments */
+    for (i=0; i<desc->paramcount; ++i) {
+               if (++args > buflen) {
+                       exceptions_throw_internalerror("Buffer too small for method arguments.");
+                       return false;
+               }
+
+               if (!typeinfo_init_from_typedesc(desc->paramtypes + i,typebuf++,infobuf++))
+                       return false;
+               
+               if (twoword && (typebuf[-1] == TYPE_LNG || typebuf[-1] == TYPE_DBL)) {
+                       if (++args > buflen) {
+                               exceptions_throw_internalerror("Buffer too small for method arguments.");
+                               return false;
+                       }
+
+                       *typebuf++ = TYPE_VOID;
+                       TYPEINFO_INIT_PRIMITIVE(*infobuf);
+                       infobuf++;
+               }
+    }
+
+    /* check returntype */
+    if (returntype) {
+               if (!typeinfo_init_from_typedesc(&(desc->returntype),returntype,returntypeinfo))
+                       return false;
+       }
+
+       return true;
+}
+
+/* typedescriptor_init_from_typedesc *******************************************
+   Initialize a typedescriptor from a typedesc.
+   
+   IN:
+          desc.............the typedesc
+
+   OUT:
+       *td..............receives the typedescriptor
+                           td must be != NULL
+
+   RETURN VALUE:
+       true.............success
+          false............an exception has been thrown
+
+*******************************************************************************/
+
+bool
+typedescriptor_init_from_typedesc(typedescriptor_t *td,
+                                                                 typedesc *desc)
+{
+       TYPEINFO_ASSERT(td);
+       TYPEINFO_ASSERT(desc);
+
+       td->type = desc->type;
+       if (td->type == TYPE_ADR) {
+               if (!typeinfo_init_class(&(td->typeinfo),CLASSREF_OR_CLASSINFO(desc->classref)))
+                       return false;
+       }
+       else {
+               TYPEINFO_INIT_PRIMITIVE(td->typeinfo);
+       }
+       return true;
+}
+
+/* typeinfo_init_varinfo_from_typedesc *****************************************
+   Initialize a varinfo from a typedesc.
+   
+   IN:
+          desc.............the typedesc
+
+   OUT:
+       *var.............receives the type
+                           var must be != NULL
+
+   RETURN VALUE:
+       true.............success
+          false............an exception has been thrown
+
+*******************************************************************************/
+
+bool
+typeinfo_init_varinfo_from_typedesc(varinfo *var,
+                                                                 typedesc *desc)
+{
+       TYPEINFO_ASSERT(var);
+       TYPEINFO_ASSERT(desc);
+
+       var->type = desc->type;
+       if (var->type == TYPE_ADR) {
+               if (!typeinfo_init_class(&(var->typeinfo),CLASSREF_OR_CLASSINFO(desc->classref)))
+                       return false;
+       }
+       else {
+               TYPEINFO_INIT_PRIMITIVE(var->typeinfo);
+       }
+       return true;
+}
+
+/* typeinfo_init_varinfos_from_methoddesc **************************************
+   Initialize an array of varinfos from a methoddesc.
+   
+   IN:
+       desc.............the methoddesc
+       buflen...........number of parameters the buffer can hold
+          startindex.......the zero-based index of the first parameter to
+                           write to the array. In other words the number of
+                                               parameters to skip at the beginning of the methoddesc.
+          map..............map from parameter indices to varinfo indices
+                           (indexed like jitdata.local_map)
+
+   OUT:
+       *vars............array receiving the varinfos
+                           td[0] receives the type of the
+                                               (startindex+1)th parameter of the method
+       *returntype......receives the typedescriptor of the return type.
+                           returntype may be NULL
+
+   RETURN VALUE:
+       true.............everything ok
+          false............an exception has been thrown
+
+   NOTE:
+       If (according to BUFLEN) the buffer is to small to hold the
+          parameter types, an internal error is thrown. This must be
+          avoided by checking the number of parameters and allocating enough
+          space before calling this function.
+
+*******************************************************************************/
+
+bool
+typeinfo_init_varinfos_from_methoddesc(varinfo *vars,
+                                                                        methoddesc *desc,
+                                                                        int buflen, int startindex,
+                                                                        s4 *map,
+                                                                        typedescriptor_t *returntype)
+{
+       s4 i;
+    s4 varindex;
+       s4 type;
+       s4 slot = 0;
+
+       /* skip arguments */
+       for (i=0; i<startindex; ++i) {
+               slot++;
+               if (IS_2_WORD_TYPE(desc->paramtypes[i].type))
+                       slot++;
+       }
+
+    /* check arguments */
+    for (i=startindex; i<desc->paramcount; ++i) {
+               type = desc->paramtypes[i].type;
+               varindex = map[5*slot + type];
+
+               slot++;
+               if (IS_2_WORD_TYPE(type))
+                       slot++;
+
+               if (varindex == UNUSED)
+                       continue;
+
+               if (varindex >= buflen) {
+                       exceptions_throw_internalerror("Buffer too small for method arguments.");
+                       return false;
+               }
+
+               if (!typeinfo_init_varinfo_from_typedesc(vars + varindex, desc->paramtypes + i))
+                       return false;
+    }
+
+    /* check returntype */
+    if (returntype) {
+               if (!typedescriptor_init_from_typedesc(returntype,&(desc->returntype)))
+                       return false;
+       }
+
+       return true;
+}
+
+/* typedescriptors_init_from_methoddesc ****************************************
+   Initialize an array of typedescriptors from a methoddesc.
+   
+   IN:
+       desc.............the methoddesc
+       buflen...........number of parameters the buffer can hold
+       twoword..........if true, use two parameter slots for two-word types
+          startindex.......the zero-based index of the first parameter to
+                           write to the array. In other words the number of
+                                               parameters to skip at the beginning of the methoddesc.
+
+   OUT:
+       *td..............array receiving the typedescriptors.
+                           td[0] receives the typedescriptor of the
+                                               (startindex+1)th parameter of the method
+       *returntype......receives the typedescriptor of the return type.
+                           returntype may be NULL
+
+   RETURN VALUE:
+       >= 0.............number of typedescriptors filled in TD
+          -1...............an exception has been thrown
+
+   NOTE:
+       If (according to BUFLEN) the buffer is to small to hold the
+          parameter types, an internal error is thrown. This must be
+          avoided by checking the number of parameters and allocating enough
+          space before calling this function.
+
+*******************************************************************************/
+
+int
+typedescriptors_init_from_methoddesc(typedescriptor_t *td,
+                                                                        methoddesc *desc,
+                                                                        int buflen,bool twoword,int startindex,
+                                                                        typedescriptor_t *returntype)
+{
+       int i;
+    int args = 0;
+
+    /* check arguments */
+    for (i=startindex; i<desc->paramcount; ++i) {
+               if (++args > buflen) {
+                       exceptions_throw_internalerror("Buffer too small for method arguments.");
+                       return -1;
+               }
+
+               if (!typedescriptor_init_from_typedesc(td,desc->paramtypes + i))
+                       return -1;
+               td++;
+
+               if (twoword && (td[-1].type == TYPE_LNG || td[-1].type == TYPE_DBL)) {
+                       if (++args > buflen) {
+                               exceptions_throw_internalerror("Buffer too small for method arguments.");
+                               return -1;
+                       }
+
+                       td->type = TYPE_VOID;
+                       TYPEINFO_INIT_PRIMITIVE(td->typeinfo);
+                       td++;
+               }
+    }
+
+    /* check returntype */
+    if (returntype) {
+               if (!typedescriptor_init_from_typedesc(returntype,&(desc->returntype)))
+                       return -1;
+       }
+
+       return args;
+}
+
+/* typeinfo_init_component *****************************************************
+   Initialize a typeinfo with the component type of a given array type.
+   
+   IN:
+          srcarray.........the typeinfo of the array type
+
+   OUT:
+       *dst.............receives the typeinfo of the component type
+
+   RETURN VALUE:
+       true.............success
+          false............an exception has been thrown
+
+*******************************************************************************/
+
+bool
+typeinfo_init_component(typeinfo_t *srcarray,typeinfo_t *dst)
+{
+       typeinfo_mergedlist_t *merged;
+
+       TYPEINFO_ASSERT(srcarray);
+       TYPEINFO_ASSERT(dst);
+
+    if (TYPEINFO_IS_NULLTYPE(*srcarray)) {
+        TYPEINFO_INIT_NULLTYPE(*dst);
+        return true;
+    }
+    
+    if (!TYPEINFO_IS_ARRAY(*srcarray)) {
+               /* XXX should we make that a verify error? */
+               exceptions_throw_internalerror("Trying to access component of non-array");
+               return false;
+       }
+
+       /* save the mergedlist (maybe dst == srcarray) */
+
+       merged = srcarray->merged;
+
+       if (IS_CLASSREF(srcarray->typeclass)) {
+               constant_classref *comp;
+               comp = class_get_classref_component_of(srcarray->typeclass.ref);
+
+               if (comp) {
+                       if (!typeinfo_init_class(dst,CLASSREF_OR_CLASSINFO(comp)))
+                               return false;
+               }
+               else {
+                       TYPEINFO_INIT_PRIMITIVE(*dst);
+               }
+       }
+       else {
+               vftbl_t *comp;
+               
+               if (!(srcarray->typeclass.cls->state & CLASS_LINKED)) {
+                       if (!link_class(srcarray->typeclass.cls)) {
+                               return false;
+                       }
+               }
+
+               TYPEINFO_ASSERT(srcarray->typeclass.cls->vftbl);
+               TYPEINFO_ASSERT(srcarray->typeclass.cls->vftbl->arraydesc);
+
+               comp = srcarray->typeclass.cls->vftbl->arraydesc->componentvftbl;
+               if (comp)
+                       typeinfo_init_classinfo(dst,comp->clazz);
+               else
+                       TYPEINFO_INIT_PRIMITIVE(*dst);
+       }
+    
+    dst->merged = merged; /* XXX should we do a deep copy? */
+       return true;
+}
+
+/* typeinfo_clone **************************************************************
+   Create a deep copy of a typeinfo struct.
+   
+   IN:
+          src..............the typeinfo to copy
+
+   OUT:
+       *dest............receives the copy
+
+   NOTE:
+       If src == dest this function is a nop.
+
+*******************************************************************************/
+
+void
+typeinfo_clone(typeinfo_t *src,typeinfo_t *dest)
+{
+    int count;
+    classref_or_classinfo *srclist,*destlist;
+
+    if (src == dest)
+        return;
+    
+    *dest = *src;
+
+    if (src->merged) {
+        count = src->merged->count;
+        TYPEINFO_ALLOCMERGED(dest->merged,count);
+        dest->merged->count = count;
+
+        srclist = src->merged->list;
+        destlist = dest->merged->list;
+        while (count--)
+            *destlist++ = *srclist++;
+    }
+}
+
+/**********************************************************************/
+/* MISCELLANEOUS FUNCTIONS                                            */
+/**********************************************************************/
+
+/* typeinfo_free ***************************************************************
+   Free memory referenced by the given typeinfo. The typeinfo itself is not
+   freed.
+   
+   IN:
+       info.............the typeinfo
+
+*******************************************************************************/
+
+void
+typeinfo_free(typeinfo_t *info)
+{
+    TYPEINFO_FREEMERGED_IF_ANY(info->merged);
+    info->merged = NULL;
+}
+
+/**********************************************************************/
+/* MERGING FUNCTIONS                                                  */
+/* The following functions are used to merge the types represented by */
+/* two typeinfo structures into one typeinfo structure.               */
+/**********************************************************************/
+
+static
+void
+typeinfo_merge_error(methodinfo *m,char *str,typeinfo_t *x,typeinfo_t *y) {
+#ifdef TYPEINFO_VERBOSE
+    fprintf(stderr,"Error in typeinfo_merge: %s\n",str);
+    fprintf(stderr,"Typeinfo x:\n");
+    typeinfo_print(stderr,x,1);
+    fprintf(stderr,"Typeinfo y:\n");
+    typeinfo_print(stderr,y,1);
+    log_text(str);
+#endif
+
+       exceptions_throw_verifyerror(m, str);
+}
+
+/* Condition: clsx != clsy. */
+/* Returns: true if dest was changed (currently always true). */
+static
+bool
+typeinfo_merge_two(typeinfo_t *dest,classref_or_classinfo clsx,classref_or_classinfo clsy)
+{
+       TYPEINFO_ASSERT(dest);
+    TYPEINFO_FREEMERGED_IF_ANY(dest->merged);
+    TYPEINFO_ALLOCMERGED(dest->merged,2);
+    dest->merged->count = 2;
+
+       TYPEINFO_ASSERT(clsx.any != clsy.any);
+
+    if (clsx.any < clsy.any) {
+        dest->merged->list[0] = clsx;
+        dest->merged->list[1] = clsy;
+    }
+    else {
+        dest->merged->list[0] = clsy;
+        dest->merged->list[1] = clsx;
+    }
+
+    return true;
+}
+
+/* Returns: true if dest was changed. */
+static
+bool
+typeinfo_merge_add(typeinfo_t *dest,typeinfo_mergedlist_t *m,classref_or_classinfo cls)
+{
+    int count;
+    typeinfo_mergedlist_t *newmerged;
+    classref_or_classinfo *mlist,*newlist;
+
+    count = m->count;
+    mlist = m->list;
+
+    /* Check if cls is already in the mergedlist m. */
+    while (count--) {
+        if ((mlist++)->any == cls.any) { /* XXX check equal classrefs? */
+            /* cls is in the list, so m is the resulting mergedlist */
+            if (dest->merged == m)
+                return false;
+
+            /* We have to copy the mergedlist */
+            TYPEINFO_FREEMERGED_IF_ANY(dest->merged);
+            count = m->count;
+            TYPEINFO_ALLOCMERGED(dest->merged,count);
+            dest->merged->count = count;
+            newlist = dest->merged->list;
+            mlist = m->list;
+            while (count--) {
+                *newlist++ = *mlist++;
+            }
+            return true;
+        }
+    }
+
+    /* Add cls to the mergedlist. */
+    count = m->count;
+    TYPEINFO_ALLOCMERGED(newmerged,count+1);
+    newmerged->count = count+1;
+    newlist = newmerged->list;    
+    mlist = m->list;
+    while (count) {
+        if (mlist->any > cls.any)
+            break;
+        *newlist++ = *mlist++;
+        count--;
+    }
+    *newlist++ = cls;
+    while (count--) {
+        *newlist++ = *mlist++;
+    }
+
+    /* Put the new mergedlist into dest. */
+    TYPEINFO_FREEMERGED_IF_ANY(dest->merged);
+    dest->merged = newmerged;
+    
+    return true;
+}
+
+/* Returns: true if dest was changed. */
+static
+bool
+typeinfo_merge_mergedlists(typeinfo_t *dest,typeinfo_mergedlist_t *x,
+                           typeinfo_mergedlist_t *y)
+{
+    int count = 0;
+    int countx,county;
+    typeinfo_mergedlist_t *temp,*result;
+    classref_or_classinfo *clsx,*clsy,*newlist;
+
+    /* count the elements that will be in the resulting list */
+    /* (Both lists are sorted, equal elements are counted only once.) */
+    clsx = x->list;
+    clsy = y->list;
+    countx = x->count;
+    county = y->count;
+    while (countx && county) {
+        if (clsx->any == clsy->any) {
+            clsx++;
+            clsy++;
+            countx--;
+            county--;
+        }
+        else if (clsx->any < clsy->any) {
+            clsx++;
+            countx--;
+        }
+        else {
+            clsy++;
+            county--;
+        }
+        count++;
+    }
+    count += countx + county;
+
+    /* {The new mergedlist will have count entries.} */
+
+    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.} */
+    if (x->count == count) {
+        /* x->merged is equal to the result */
+        if (x == dest->merged)
+            return false;
+
+        if (!dest->merged || dest->merged->count != count) {
+            TYPEINFO_FREEMERGED_IF_ANY(dest->merged);
+            TYPEINFO_ALLOCMERGED(dest->merged,count);
+            dest->merged->count = count;
+        }
+
+        newlist = dest->merged->list;
+        clsx = x->list;
+        while (count--) {
+            *newlist++ = *clsx++;
+        }
+        return true;
+    }
+
+    /* {We have to merge two lists.} */
+
+    /* allocate the result list */
+    TYPEINFO_ALLOCMERGED(result,count);
+    result->count = count;
+    newlist = result->list;
+
+    /* merge the sorted lists */
+    clsx = x->list;
+    clsy = y->list;
+    countx = x->count;
+    county = y->count;
+    while (countx && county) {
+        if (clsx->any == clsy->any) {
+            *newlist++ = *clsx++;
+            clsy++;
+            countx--;
+            county--;
+        }
+        else if (clsx->any < clsy->any) {
+            *newlist++ = *clsx++;
+            countx--;
+        }
+        else {
+            *newlist++ = *clsy++;
+            county--;
+        }
+    }
+    while (countx--)
+            *newlist++ = *clsx++;
+    while (county--)
+            *newlist++ = *clsy++;
+
+    /* replace the list in dest with the result list */
+    TYPEINFO_FREEMERGED_IF_ANY(dest->merged);
+    dest->merged = result;
+
+    return true;
+}
+
+/* typeinfo_merge_nonarrays ****************************************************
+   Merge two non-array types.
+   
+   IN:
+       x................the first type
+          y................the second type
+          mergedx..........merged list of the first type, may be NULL
+          mergedy..........merged list of the descond type, may be NULL
+
+   OUT:
+       *dest............receives the resulting merged list
+          *result..........receives the resulting type
+
+   RETURN VALUE:
+       typecheck_TRUE...*dest has been modified
+          typecheck_FALSE..*dest has not been modified
+          typecheck_FAIL...an exception has been thrown
+
+   NOTE:
+       RESULT is an extra parameter so it can point to dest->typeclass or to
+          dest->elementclass.
+
+*******************************************************************************/
+
+static typecheck_result
+typeinfo_merge_nonarrays(typeinfo_t *dest,
+                         classref_or_classinfo *result,
+                         classref_or_classinfo x,classref_or_classinfo y,
+                         typeinfo_mergedlist_t *mergedx,
+                         typeinfo_mergedlist_t *mergedy)
+{
+       classref_or_classinfo t;
+    classinfo *tcls,*common;
+    typeinfo_mergedlist_t *tmerged;
+    bool changed;
+       typecheck_result r;
+       utf *xname;
+       utf *yname;
+
+       TYPEINFO_ASSERT(dest && result && x.any && y.any);
+       TYPEINFO_ASSERT(x.cls != pseudo_class_Null);
+       TYPEINFO_ASSERT(y.cls != pseudo_class_Null);
+       TYPEINFO_ASSERT(x.cls != pseudo_class_New);
+       TYPEINFO_ASSERT(y.cls != pseudo_class_New);
+
+       /*--------------------------------------------------*/
+       /* common cases                                     */
+       /*--------------------------------------------------*/
+
+    /* Common case 1: x and y are the same class or class reference */
+    /* (This case is very simple unless *both* x and y really represent
+     *  merges of subclasses of clsx==clsy.)
+     */
+    if ( (x.any == y.any) && (!mergedx || !mergedy) ) {
+  return_simple_x:
+        /* DEBUG */ /* log_text("return simple x"); */
+        changed = (dest->merged != NULL);
+        TYPEINFO_FREEMERGED_IF_ANY(dest->merged);
+        dest->merged = NULL;
+        *result = x;
+        /* DEBUG */ /* log_text("returning"); */
+        return (typecheck_result) changed;
+    }
+
+       xname = (IS_CLASSREF(x)) ? x.ref->name : x.cls->name;
+       yname = (IS_CLASSREF(y)) ? y.ref->name : y.cls->name;
+
+       /* Common case 2: xname == yname, at least one unresolved */
+    if ((IS_CLASSREF(x) || IS_CLASSREF(y)) && (xname == yname))
+       {
+               /* use the loaded one if any */
+               if (!IS_CLASSREF(y))
+                       x = y;
+               goto return_simple_x;
+    }
+
+       /*--------------------------------------------------*/
+       /* non-trivial cases                                */
+       /*--------------------------------------------------*/
+
+#ifdef TYPEINFO_VERBOSE
+       {
+               typeinfo_t dbgx,dbgy;
+               fprintf(stderr,"merge_nonarrays:\n");
+               fprintf(stderr,"    ");if(IS_CLASSREF(x))fprintf(stderr,"<ref>");utf_fprint_printable_ascii(stderr,xname);fprintf(stderr,"\n");
+               fprintf(stderr,"    ");if(IS_CLASSREF(y))fprintf(stderr,"<ref>");utf_fprint_printable_ascii(stderr,yname);fprintf(stderr,"\n");
+               fflush(stderr);
+               typeinfo_init_class(&dbgx,x);
+               dbgx.merged = mergedx;
+               typeinfo_init_class(&dbgy,y);
+               dbgy.merged = mergedy;
+               typeinfo_print(stderr,&dbgx,4);
+               fprintf(stderr,"  with:\n");
+               typeinfo_print(stderr,&dbgy,4);
+       }
+#endif
+
+       TYPEINFO_ASSERT(IS_CLASSREF(x) || (x.cls->state & CLASS_LOADED));
+       TYPEINFO_ASSERT(IS_CLASSREF(y) || (y.cls->state & CLASS_LOADED));
+
+    /* If y is unresolved or an interface, swap x and y. */
+    if (IS_CLASSREF(y) || (!IS_CLASSREF(x) && y.cls->flags & ACC_INTERFACE))
+       {
+        t = x; x = y; y = t;
+        tmerged = mergedx; mergedx = mergedy; mergedy = tmerged;
+    }
+       
+    /* {We know: If only one of x,y is unresolved it is x,} */
+    /* {         If both x,y are resolved and only one of x,y is an interface it is x.} */
+
+       if (IS_CLASSREF(x)) {
+               /* {We know: x and y have different class names} */
+               
+        /* Check if we are merging an unresolved type with java.lang.Object */
+        if (y.cls == class_java_lang_Object && !mergedy) {
+            x = y;
+            goto return_simple_x;
+        }
+            
+               common = class_java_lang_Object;
+               goto merge_with_simple_x;
+       }
+
+       /* {We know: both x and y are resolved} */
+    /* {We know: If only one of x,y is an interface it is x.} */
+
+       TYPEINFO_ASSERT(!IS_CLASSREF(x) && !IS_CLASSREF(y));
+       TYPEINFO_ASSERT(x.cls->state & CLASS_LOADED);
+       TYPEINFO_ASSERT(y.cls->state & CLASS_LOADED);
+
+    /* Handle merging of interfaces: */
+    if (x.cls->flags & ACC_INTERFACE) {
+        /* {x.cls is an interface and mergedx == NULL.} */
+        
+        if (y.cls->flags & ACC_INTERFACE) {
+            /* We are merging two interfaces. */
+            /* {mergedy == NULL} */
+
+            /* {We know that x.cls!=y.cls (see common case at beginning.)} */
+            result->cls = class_java_lang_Object;
+            return (typecheck_result) typeinfo_merge_two(dest,x,y);
+        }
+
+        /* {We know: x is an interface, y is a class.} */
+
+        /* Check if we are merging an interface with java.lang.Object */
+        if (y.cls == class_java_lang_Object && !mergedy) {
+            x = y;
+            goto return_simple_x;
+        }
+
+        /* If the type y implements x then the result of the merge
+         * is x regardless of mergedy.
+         */
+
+               /* we may have to link the classes */
+               if (!(x.cls->state & CLASS_LINKED))
+                       if (!link_class(x.cls))
+                               return typecheck_FAIL;
+               if (!(y.cls->state & CLASS_LINKED))
+                       if (!link_class(y.cls))
+                               return typecheck_FAIL;
+        
+               TYPEINFO_ASSERT(x.cls->state & CLASS_LINKED);
+               TYPEINFO_ASSERT(y.cls->state & CLASS_LINKED);
+
+        if (CLASSINFO_IMPLEMENTS_INTERFACE(y.cls,x.cls->index))
+               {
+            /* y implements x, so the result of the merge is x. */
+            goto return_simple_x;
+               }
+               
+        r = mergedlist_implements_interface(mergedy,x.cls);
+               if (r == typecheck_FAIL)
+                       return r;
+               if (r == typecheck_TRUE)
+        {
+            /* y implements x, so the result of the merge is x. */
+            goto return_simple_x;
+        }
+        
+        /* {We know: x is an interface, the type y a class or a merge
+         * of subclasses and is not guaranteed to implement x.} */
+
+        common = class_java_lang_Object;
+        goto merge_with_simple_x;
+    }
+
+    /* {We know: x and y are classes (not interfaces).} */
+    
+       /* we may have to link the classes */
+       if (!(x.cls->state & CLASS_LINKED))
+               if (!link_class(x.cls))
+                       return typecheck_FAIL;
+       if (!(y.cls->state & CLASS_LINKED))
+               if (!link_class(y.cls))
+                       return typecheck_FAIL;
+        
+       TYPEINFO_ASSERT(x.cls->state & CLASS_LINKED);
+       TYPEINFO_ASSERT(y.cls->state & CLASS_LINKED);
+
+    /* If *x is deeper in the inheritance hierarchy swap x and y. */
+    if (x.cls->index > y.cls->index) {
+        t = x; x = y; y = t;
+        tmerged = mergedx; mergedx = mergedy; mergedy = tmerged;
+    }
+
+    /* {We know: y is at least as deep in the hierarchy as x.} */
+
+    /* Find nearest common anchestor for the classes. */
+
+    common = x.cls;
+    tcls   = y.cls;
+
+    while (tcls->index > common->index)
+        tcls = tcls->super;
+
+    while (common != tcls) {
+        common = common->super;
+        tcls = tcls->super;
+    }
+
+    /* {common == nearest common anchestor of x and y.} */
+
+    /* If x.cls==common and x is a whole class (not a merge of subclasses)
+     * then the result of the merge is x.
+     */
+    if (x.cls == common && !mergedx) {
+        goto return_simple_x;
+    }
+   
+    if (mergedx) {
+        result->cls = common;
+        if (mergedy)
+            return (typecheck_result) typeinfo_merge_mergedlists(dest,mergedx,mergedy);
+        else
+            return (typecheck_result) typeinfo_merge_add(dest,mergedx,y);
+    }
+
+merge_with_simple_x:
+    result->cls = common;
+    if (mergedy)
+        return (typecheck_result) typeinfo_merge_add(dest,mergedy,x);
+    else
+        return (typecheck_result) typeinfo_merge_two(dest,x,y);
+}
+
+/* typeinfo_merge **************************************************************
+   Merge two types.
+   
+   IN:
+       m................method for exception messages
+       dest.............the first type
+       y................the second type
+
+   OUT:
+       *dest............receives the result of the merge
+
+   RETURN VALUE:
+       typecheck_TRUE...*dest has been modified
+       typecheck_FALSE..*dest has not been modified
+       typecheck_FAIL...an exception has been thrown
+
+   PRE-CONDITIONS:
+       1) *dest must be a valid initialized typeinfo
+       2) dest != y
+
+*******************************************************************************/
+
+typecheck_result
+typeinfo_merge(methodinfo *m,typeinfo_t *dest,typeinfo_t* y)
+{
+    typeinfo_t *x;
+    typeinfo_t *tmp;
+    classref_or_classinfo common;
+    classref_or_classinfo elementclass;
+    int dimension;
+    int elementtype;
+    bool changed;
+       typecheck_result r;
+
+       /*--------------------------------------------------*/
+       /* fast checks                                      */
+       /*--------------------------------------------------*/
+
+    /* Merging something with itself is a nop */
+    if (dest == y)
+        return typecheck_FALSE;
+
+    /* Merging two returnAddress types is ok. */
+       /* Merging two different returnAddresses never happens, as the verifier */
+       /* keeps them separate in order to check all the possible return paths  */
+       /* from JSR subroutines.                                                */
+    if (!dest->typeclass.any && !y->typeclass.any) {
+               TYPEINFO_ASSERT(TYPEINFO_RETURNADDRESS(*dest) ==  TYPEINFO_RETURNADDRESS(*y));
+        return typecheck_FALSE;
+       }
+    
+    /* Primitive types cannot be merged with reference types */
+       /* This must be checked before calls to typeinfo_merge.  */
+    TYPEINFO_ASSERT(dest->typeclass.any && y->typeclass.any);
+
+    /* handle uninitialized object types */
+    if (TYPEINFO_IS_NEWOBJECT(*dest) || TYPEINFO_IS_NEWOBJECT(*y)) {
+        if (!TYPEINFO_IS_NEWOBJECT(*dest) || !TYPEINFO_IS_NEWOBJECT(*y)) {
+            typeinfo_merge_error(m,(char*) "Trying to merge uninitialized object type.",dest,y);
+                       return typecheck_FAIL;
+               }
+        if (TYPEINFO_NEWOBJECT_INSTRUCTION(*dest) != TYPEINFO_NEWOBJECT_INSTRUCTION(*y)) {
+            typeinfo_merge_error(m,(char*) "Trying to merge different uninitialized objects.",dest,y);
+                       return typecheck_FAIL;
+               }
+               /* the same uninitialized object -- no change */
+               return typecheck_FALSE;
+    }
+    
+       /*--------------------------------------------------*/
+       /* common cases                                     */
+       /*--------------------------------------------------*/
+
+    /* Common case: dest and y are the same class or class reference */
+    /* (This case is very simple unless *both* dest and y really represent
+     *  merges of subclasses of class dest==class y.)
+     */
+    if ((dest->typeclass.any == y->typeclass.any) && (!dest->merged || !y->merged)) {
+return_simple:
+        changed = (dest->merged != NULL);
+        TYPEINFO_FREEMERGED_IF_ANY(dest->merged);
+        dest->merged = NULL;
+        return (typecheck_result) changed;
+    }
+    
+    /* Handle null types: */
+    if (TYPEINFO_IS_NULLTYPE(*y)) {
+        return typecheck_FALSE;
+    }
+    if (TYPEINFO_IS_NULLTYPE(*dest)) {
+        TYPEINFO_FREEMERGED_IF_ANY(dest->merged);
+        TYPEINFO_CLONE(*y,*dest);
+        return typecheck_TRUE;
+    }
+
+       /* Common case: two types with the same name, at least one unresolved */
+       if (IS_CLASSREF(dest->typeclass)) {
+               if (IS_CLASSREF(y->typeclass)) {
+                       if (dest->typeclass.ref->name == y->typeclass.ref->name)
+                               goto return_simple;
+               }
+               else {
+                       /* XXX should we take y instead of dest here? */
+                       if (dest->typeclass.ref->name == y->typeclass.cls->name)
+                               goto return_simple;
+               }
+       }
+       else {
+               if (IS_CLASSREF(y->typeclass) 
+                   && (dest->typeclass.cls->name == y->typeclass.ref->name))
+               {
+                       goto return_simple;
+               }
+       }
+
+       /*--------------------------------------------------*/
+       /* non-trivial cases                                */
+       /*--------------------------------------------------*/
+
+#ifdef TYPEINFO_VERBOSE
+       fprintf(stderr,"merge:\n");
+    typeinfo_print(stderr,dest,4);
+    typeinfo_print(stderr,y,4);
+#endif
+
+    /* This function uses x internally, so x and y can be swapped
+     * without changing dest. */
+    x = dest;
+    changed = false;
+    
+    /* Handle merging of arrays: */
+    if (TYPEINFO_IS_ARRAY(*x) && TYPEINFO_IS_ARRAY(*y)) {
+        
+        /* Make x the one with lesser dimension */
+        if (x->dimension > y->dimension) {
+            tmp = x; x = y; y = tmp;
+        }
+
+        /* If one array (y) has higher dimension than the other,
+         * interpret it as an array (same dim. as x) of Arraystubs. */
+        if (x->dimension < y->dimension) {
+            dimension = x->dimension;
+            elementtype = ARRAYTYPE_OBJECT;
+            elementclass.cls = pseudo_class_Arraystub;
+        }
+        else {
+            dimension = y->dimension;
+            elementtype = y->elementtype;
+            elementclass = y->elementclass;
+        }
+        
+        /* {The arrays are of the same dimension.} */
+        
+        if (x->elementtype != elementtype) {
+            /* Different element types are merged, so the resulting array
+             * type has one accessible dimension less. */
+            if (--dimension == 0) {
+                common.cls = pseudo_class_Arraystub;
+                elementtype = 0;
+                elementclass.any = NULL;
+            }
+            else {
+                common.cls = class_multiarray_of(dimension,pseudo_class_Arraystub,true);
+                               if (!common.cls) {
+                                       exceptions_throw_internalerror("XXX Coult not create array class");
+                                       return typecheck_FAIL;
+                               }
+
+                elementtype = ARRAYTYPE_OBJECT;
+                elementclass.cls = pseudo_class_Arraystub;
+            }
+        }
+        else {
+            /* {The arrays have the same dimension and elementtype.} */
+
+            if (elementtype == ARRAYTYPE_OBJECT) {
+                /* The elements are references, so their respective
+                 * types must be merged.
+                 */
+                               r = typeinfo_merge_nonarrays(dest,
+                                               &elementclass,
+                                               x->elementclass,
+                                               elementclass,
+                                               x->merged,y->merged);
+                               TYPEINFO_ASSERT(r != typecheck_MAYBE);
+                               if (r == typecheck_FAIL)
+                                       return r;
+                               changed |= r;
+
+                /* DEBUG */ /* log_text("finding resulting array class: "); */
+                               if (IS_CLASSREF(elementclass))
+                                       common.ref = class_get_classref_multiarray_of(dimension,elementclass.ref);
+                               else {
+                                       common.cls = class_multiarray_of(dimension,elementclass.cls,true);
+                                       if (!common.cls) {
+                                               exceptions_throw_internalerror("XXX Coult not create array class");
+                                               return typecheck_FAIL;
+                                       }
+                               }
+                /* DEBUG */ /* utf_display_printable_ascii(common->name); printf("\n"); */
+            }
+                       else {
+                               common.any = y->typeclass.any;
+                       }
+        }
+    }
+    else {
+        /* {We know that at least one of x or y is no array, so the
+         *  result cannot be an array.} */
+        
+               r = typeinfo_merge_nonarrays(dest,
+                               &common,
+                               x->typeclass,y->typeclass,
+                               x->merged,y->merged);
+               TYPEINFO_ASSERT(r != typecheck_MAYBE);
+               if (r == typecheck_FAIL)
+                       return r;
+               changed |= r;
+
+        dimension = 0;
+        elementtype = 0;
+        elementclass.any = NULL;
+    }
+
+    /* Put the new values into dest if neccessary. */
+
+    if (dest->typeclass.any != common.any) {
+        dest->typeclass.any = common.any;
+        changed = true;
+    }
+    if (dest->dimension != dimension) {
+        dest->dimension = dimension;
+        changed = true;
+    }
+    if (dest->elementtype != elementtype) {
+        dest->elementtype = elementtype;
+        changed = true;
+    }
+    if (dest->elementclass.any != elementclass.any) {
+        dest->elementclass.any = elementclass.any;
+        changed = true;
+    }
+
+    return (typecheck_result) changed;
+}
+#endif /* ENABLE_VERIFER */
+
+
+/**********************************************************************/
+/* DEBUGGING HELPERS                                                  */
+/**********************************************************************/
+
+#ifdef TYPEINFO_DEBUG
+
+#if 0
+static int
+typeinfo_test_compare(classref_or_classinfo *a,classref_or_classinfo *b)
+{
+    if (a->any == b->any) return 0;
+    if (a->any < b->any) return -1;
+    return +1;
+}
+
+static void
+typeinfo_test_parse(typeinfo_t *info,char *str)
+{
+    int num;
+    int i;
+    typeinfo_t *infobuf;
+    u1 *typebuf;
+    int returntype;
+    utf *desc = utf_new_char(str);
+    
+    num = typeinfo_count_method_args(desc,false);
+    if (num) {
+        typebuf = (u1*) DumpMemory::allocate(sizeof(u1) * num);
+        infobuf = (typeinfo_t*) DumpMemory::allocate(sizeof(typeinfo_t) * num);
+        
+        typeinfo_init_from_method_args(desc,typebuf,infobuf,num,false,
+                                       &returntype,info);
+
+        TYPEINFO_ALLOCMERGED(info->merged,num);
+        info->merged->count = num;
+
+        for (i=0; i<num; ++i) {
+            if (typebuf[i] != TYPE_ADR) {
+                log_text("non-reference type in mergedlist");
+                               assert(0);
+                       }
+
+            info->merged->list[i].any = infobuf[i].typeclass.any;
+        }
+        qsort(info->merged->list,num,sizeof(classref_or_classinfo),
+              (int(*)(const void *,const void *))&typeinfo_test_compare);
+    }
+    else {
+        typeinfo_init_from_method_args(desc,NULL,NULL,0,false,
+                                       &returntype,info);
+    }
+}
+#endif
+
+#define TYPEINFO_TEST_BUFLEN  4000
+
+static bool
+typeinfo_equal(typeinfo_t *x,typeinfo_t *y)
+{
+    int i;
+    
+    if (x->typeclass.any != y->typeclass.any) return false;
+    if (x->dimension != y->dimension) return false;
+    if (x->dimension) {
+        if (x->elementclass.any != y->elementclass.any) return false;
+        if (x->elementtype != y->elementtype) return false;
+    }
+
+    if (TYPEINFO_IS_NEWOBJECT(*x))
+        if (TYPEINFO_NEWOBJECT_INSTRUCTION(*x)
+            != TYPEINFO_NEWOBJECT_INSTRUCTION(*y))
+            return false;
+
+    if (x->merged || y->merged) {
+        if (!(x->merged && y->merged)) return false;
+        if (x->merged->count != y->merged->count) return false;
+        for (i=0; i<x->merged->count; ++i)
+            if (x->merged->list[i].any != y->merged->list[i].any)
+                return false;
+    }
+    return true;
+}
+
+static void
+typeinfo_testmerge(typeinfo_t *a,typeinfo_t *b,typeinfo_t *result,int *failed)
+{
+    typeinfo_t dest;
+    bool changed,changed_should_be;
+       typecheck_result r;
+
+    TYPEINFO_CLONE(*a,dest);
+    
+    printf("\n          ");
+    typeinfo_print_short(stdout,&dest);
+    printf("\n          ");
+    typeinfo_print_short(stdout,b);
+    printf("\n");
+
+       r = typeinfo_merge(NULL,&dest,b);
+       if (r == typecheck_FAIL) {
+               printf("EXCEPTION\n");
+               return;
+       }
+    changed = (r) ? 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    ");
+        typeinfo_print_short(stdout,&dest);
+        printf("\n");
+        printf("SHOULD BE ");
+        typeinfo_print_short(stdout,result);
+        printf("\n");
+        (*failed)++;
+    }
+}
+
+#if 0
+static void
+typeinfo_inc_dimension(typeinfo_t *info)
+{
+    if (info->dimension++ == 0) {
+        info->elementtype = ARRAYTYPE_OBJECT;
+        info->elementclass = info->typeclass;
+    }
+    info->typeclass = class_array_of(info->typeclass,true);
+}
+#endif
+
+#define TYPEINFO_TEST_MAXDIM  10
+
+static void
+typeinfo_testrun(char *filename)
+{
+    char buf[TYPEINFO_TEST_BUFLEN];
+    char bufa[TYPEINFO_TEST_BUFLEN];
+    char bufb[TYPEINFO_TEST_BUFLEN];
+    char bufc[TYPEINFO_TEST_BUFLEN];
+    typeinfo_t a,b,c;
+    int maxdim;
+    int failed = 0;
+    FILE *file = fopen(filename,"rt");
+       int res;
+    
+    if (!file) {
+        log_text("could not open typeinfo test file");
+               assert(0);
+       }
+
+    while (fgets(buf,TYPEINFO_TEST_BUFLEN,file)) {
+        if (buf[0] == '#' || !strlen(buf))
+            continue;
+        
+        res = sscanf(buf,"%s\t%s\t%s\n",bufa,bufb,bufc);
+        if (res != 3 || !strlen(bufa) || !strlen(bufb) || !strlen(bufc)) {
+            log_text("Invalid line in typeinfo test file (none of empty, comment or test)");
+                       assert(0);
+               }
+
+#if 0
+        typeinfo_test_parse(&a,bufa);
+        typeinfo_test_parse(&b,bufb);
+        typeinfo_test_parse(&c,bufc);
+#endif
+#if 0
+        do {
+#endif
+            typeinfo_testmerge(&a,&b,&c,&failed); /* check result */
+            typeinfo_testmerge(&b,&a,&c,&failed); /* check commutativity */
+
+            if (TYPEINFO_IS_NULLTYPE(a)) break;
+            if (TYPEINFO_IS_NULLTYPE(b)) break;
+            if (TYPEINFO_IS_NULLTYPE(c)) break;
+            
+            maxdim = a.dimension;
+            if (b.dimension > maxdim) maxdim = b.dimension;
+            if (c.dimension > maxdim) maxdim = c.dimension;
+
+#if 0
+            if (maxdim < TYPEINFO_TEST_MAXDIM) {
+                typeinfo_inc_dimension(&a);
+                typeinfo_inc_dimension(&b);
+                typeinfo_inc_dimension(&c);
+            }
+        } while (maxdim < TYPEINFO_TEST_MAXDIM);
+#endif
+    }
+
+    fclose(file);
+
+    if (failed) {
+        fprintf(stderr,"Failed typeinfo_merge tests: %d\n",failed);
+        log_text("Failed test");
+               assert(0);
+    }
+}
+
+void
+typeinfo_test()
+{
+    log_text("Running typeinfo test file...");
+    typeinfo_testrun("typeinfo.tst");
+    log_text("Finished typeinfo test file.");
+}
+
+#if 0
+void
+typeinfo_init_from_fielddescriptor(typeinfo_t *info,char *desc)
+{
+    typeinfo_init_from_descriptor(info,desc,desc+strlen(desc));
+}
+#endif
+
+#define TYPEINFO_MAXINDENT  80
+
+void
+typeinfo_print_class(FILE *file,classref_or_classinfo c)
+{
+       /*fprintf(file,"<class %p>",c.any);*/
+
+       if (!c.any) {
+               fprintf(file,"<null>");
+       }
+       else {
+               if (IS_CLASSREF(c)) {
+                       fprintf(file,"<ref>");
+                       utf_fprint_printable_ascii(file,c.ref->name);
+               }
+               else {
+                       utf_fprint_printable_ascii(file,c.cls->name);
+               }
+       }
+}
+
+void
+typeinfo_print(FILE *file,typeinfo_t *info,int indent)
+{
+    int i;
+    char ind[TYPEINFO_MAXINDENT + 1];
+    instruction *ins;
+       basicblock *bptr;
+
+    if (indent > TYPEINFO_MAXINDENT) indent = TYPEINFO_MAXINDENT;
+    
+    for (i=0; i<indent; ++i)
+        ind[i] = ' ';
+    ind[i] = (char) 0;
+    
+    if (TYPEINFO_IS_PRIMITIVE(*info)) {
+               bptr = (basicblock*) TYPEINFO_RETURNADDRESS(*info);
+               if (bptr)
+                       fprintf(file,"%sreturnAddress (L%03d)\n",ind,bptr->nr);
+               else
+                       fprintf(file,"%sprimitive\n",ind);
+        return;
+    }
+    
+    if (TYPEINFO_IS_NULLTYPE(*info)) {
+        fprintf(file,"%snull\n",ind);
+        return;
+    }
+
+    if (TYPEINFO_IS_NEWOBJECT(*info)) {
+        ins = (instruction *) TYPEINFO_NEWOBJECT_INSTRUCTION(*info);
+        if (ins) {
+            fprintf(file,"%sNEW(%p):",ind,(void*)ins);
+                       typeinfo_print_class(file,ins[-1].sx.val.c);
+            fprintf(file,"\n");
+        }
+        else {
+            fprintf(file,"%sNEW(this)",ind);
+        }
+        return;
+    }
+
+    fprintf(file,"%sClass:      ",ind);
+       typeinfo_print_class(file,info->typeclass);
+    fprintf(file,"\n");
+
+    if (TYPEINFO_IS_ARRAY(*info)) {
+        fprintf(file,"%sDimension:    %d",ind,(int)info->dimension);
+        fprintf(file,"\n%sElements:     ",ind);
+        switch (info->elementtype) {
+          case ARRAYTYPE_INT     : fprintf(file,"int\n"); break;
+          case ARRAYTYPE_LONG    : fprintf(file,"long\n"); break;
+          case ARRAYTYPE_FLOAT   : fprintf(file,"float\n"); break;
+          case ARRAYTYPE_DOUBLE  : fprintf(file,"double\n"); break;
+          case ARRAYTYPE_BYTE    : fprintf(file,"byte\n"); break;
+          case ARRAYTYPE_CHAR    : fprintf(file,"char\n"); break;
+          case ARRAYTYPE_SHORT   : fprintf(file,"short\n"); break;
+          case ARRAYTYPE_BOOLEAN : fprintf(file,"boolean\n"); break;
+              
+          case ARRAYTYPE_OBJECT:
+                         typeinfo_print_class(file,info->elementclass);
+              fprintf(file,"\n");
+              break;
+              
+          default:
+              fprintf(file,"INVALID ARRAYTYPE!\n");
+        }
+    }
+
+    if (info->merged) {
+        fprintf(file,"%sMerged:     ",ind);
+        for (i=0; i<info->merged->count; ++i) {
+            if (i) fprintf(file,", ");
+                       typeinfo_print_class(file,info->merged->list[i]);
+        }
+        fprintf(file,"\n");
+    }
+}
+
+void
+typeinfo_print_short(FILE *file,typeinfo_t *info)
+{
+    int i;
+    instruction *ins;
+       basicblock *bptr;
+
+       /*fprintf(file,"<typeinfo %p>",info);*/
+
+       if (!info) {
+               fprintf(file,"(typeinfo*)NULL");
+               return;
+       }
+
+    if (TYPEINFO_IS_PRIMITIVE(*info)) {
+               bptr = (basicblock*) TYPEINFO_RETURNADDRESS(*info);
+               if (bptr)
+                       fprintf(file,"ret(L%03d)",bptr->nr);
+               else
+                       fprintf(file,"primitive");
+        return;
+    }
+    
+    if (TYPEINFO_IS_NULLTYPE(*info)) {
+        fprintf(file,"null");
+        return;
+    }
+    
+    if (TYPEINFO_IS_NEWOBJECT(*info)) {
+        ins = (instruction *) TYPEINFO_NEWOBJECT_INSTRUCTION(*info);
+        if (ins) {
+                       /*fprintf(file,"<ins %p>",ins);*/
+            fprintf(file,"NEW(%p):",(void*)ins);
+                       typeinfo_print_class(file,ins[-1].sx.val.c);
+        }
+        else
+            fprintf(file,"NEW(this)");
+        return;
+    }
+
+    typeinfo_print_class(file,info->typeclass);
+
+    if (info->merged) {
+        fprintf(file,"{");
+        for (i=0; i<info->merged->count; ++i) {
+            if (i) fprintf(file,",");
+                       typeinfo_print_class(file,info->merged->list[i]);
+        }
+        fprintf(file,"}");
+    }
+}
+
+void
+typeinfo_print_type(FILE *file,int type,typeinfo_t *info)
+{
+    switch (type) {
+      case TYPE_VOID: fprintf(file,"V"); break;
+      case TYPE_INT:  fprintf(file,"I"); break;
+      case TYPE_FLT:  fprintf(file,"F"); break;
+      case TYPE_DBL:  fprintf(file,"D"); break;
+      case TYPE_LNG:  fprintf(file,"J"); break;
+         case TYPE_RET:  fprintf(file,"R:"); /* FALLTHROUGH! */
+      case TYPE_ADR:
+                 typeinfo_print_short(file,info);
+          break;
+          
+      default:
+          fprintf(file,"!");
+    }
+}
+
+void
+typedescriptor_print(FILE *file,typedescriptor_t *td)
+{
+       typeinfo_print_type(file,td->type,&(td->typeinfo));
+}
+
+void
+typevector_print(FILE *file,varinfo *vec,int size)
+{
+    int i;
+
+    for (i=0; i<size; ++i) {
+               fprintf(file," %d=",i);
+        typeinfo_print_type(file, vec[i].type, &(vec[i].typeinfo));
+    }
+}
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif /* TYPEINFO_DEBUG */
+
+
+/*
+ * 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
+ * Emacs will automagically detect them.
+ * ---------------------------------------------------------------------
+ * Local variables:
+ * mode: c
+ * indent-tabs-mode: t
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ * vim:noexpandtab:sw=4:ts=4:
+ */
diff --git a/src/vm/jit/verify/typeinfo.h b/src/vm/jit/verify/typeinfo.h
deleted file mode 100644 (file)
index 806bca9..0000000
+++ /dev/null
@@ -1,539 +0,0 @@
-/* src/vm/jit/verify/typeinfo.h - type system used by the type checker
-
-   Copyright (C) 1996-2005, 2006, 2007, 2008
-   CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
-
-   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., 51 Franklin Street, Fifth Floor, Boston, MA
-   02110-1301, USA.
-
-*/
-
-#ifndef _TYPEINFO_H
-#define _TYPEINFO_H
-
-/* resolve typedef cycles *****************************************************/
-
-typedef struct typeinfo            typeinfo_t;
-typedef struct typeinfo_mergedlist typeinfo_mergedlist_t;
-typedef struct typedescriptor      typedescriptor_t;
-
-#include "config.h"
-#include "vm/types.h"
-
-#include "vm/global.h"
-#include "vm/references.h"
-
-
-/* configuration **************************************************************/
-
-/*
- * TYPECHECK_STATISTICS activates gathering statistical information.
- * 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
- * TYPEINFO_VERBOSE activates debug prints in typeinfo.c
- */
-#ifdef ENABLE_VERIFIER
-#ifndef NDEBUG
-/*#define TYPECHECK_STATISTICS*/
-#define TYPEINFO_DEBUG
-/*#define TYPEINFO_VERBOSE*/
-#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
-#endif
-#endif
-
-#ifdef TYPECHECK_VERBOSE_OPT
-extern bool opt_typecheckverbose;
-#endif
-
-/* types **********************************************************************/
-
-/* typecheck_result - return type for boolean and tristate  functions     */
-/*                    which may also throw exceptions (typecheck_FAIL).   */
-
-/* NOTE: Use the enum values, not the uppercase #define macros!          */
-#define TYPECHECK_MAYBE  0x02
-#define TYPECHECK_FAIL   0x04
-
-typedef enum {
-       typecheck_FALSE = false,
-       typecheck_TRUE  = true,
-       typecheck_MAYBE = TYPECHECK_MAYBE,
-       typecheck_FAIL  = TYPECHECK_FAIL
-} typecheck_result;
-
-/* check that typecheck_MAYBE is not ambiguous */
-#if TYPECHECK_MAYBE == true
-#error "`typecheck_MAYBE` must not be the same as `true`"
-#endif
-#if TYPECHECK_MAYBE == false
-#error "`typecheck_MAYBE` must not be the same as `false`"
-#endif
-
-/* check that typecheck_FAIL is not ambiguous */
-#if (true & TYPECHECK_FAIL) != 0
-#error "`true` must not have bit 0x02 set (conflicts with typecheck_FAIL)"
-#endif
-
-/* data structures for the type system ****************************************/
-
-/* The typeinfo structure stores detailed information on address types.
- * (stack elements, variables, etc. with type == TYPE_ADR.)
- *
- * There are two kinds of address types which can be distinguished by
- * the value of the typeclass field:
- *
- * 1) typeclass == NULL: returnAddress type
- *                       use TYPEINFO_IS_PRIMITIVE to test for this
- *
- * 2) typeclass != NULL: reference type
- *                       use TYPEINFO_IS_REFERENCE to test for this
- *
- * Note: For non-address types either there is no typeinfo allocated
- * or the fields of the typeinfo struct contain undefined values!
- * DO NOT access the typeinfo for non-address types!
- *
- * CAUTION: The typeinfo structure should be considered opaque outside of
- *          typeinfo.[ch]. Please use the macros and functions defined here to
- *          access typeinfo structures!
- */
-
-/* At all times *exactly one* of the following conditions is true for
- * a particular typeinfo struct:
- *
- * A) typeclass == NULL
- *
- *        This is a returnAddress type.
- *
- *        Use TYPEINFO_IS_PRIMITIVE to check for this.
- *        Use TYPEINFO_RETURNADDRESS to access the pointer in elementclass.
- *        Don't access other fields of the struct.
- *
- * B) typeclass == pseudo_class_Null
- *
- *        This is the null-reference type. 
- *        Use TYPEINFO_IS_NULLTYPE to check for this.
- *        Don't access other fields of the struct.
- *
- * C) typeclass == pseudo_class_New
- *
- *        This is an 'uninitialized object' type. elementclass can be
- *        cast to instruction* and points to the NEW instruction
- *        responsible for creating this type.
- *
- *        Use TYPEINFO_NEWOBJECT_INSTRUCTION to access the pointer in
- *        elementclass.
- *        Don't access other fields of the struct.
- *
- * D) typeclass == pseudo_class_Arraystub
- *
- *        This type is used to represent the result of merging array types
- *        with incompatible component types. An arraystub allows no access
- *        to its components (since their type is undefined), but it allows
- *        operations which act directly on an arbitrary array type (such as
- *        requesting the array size).
- *
- *        NOTE: An array stub does *not* count as an array. It has dimension
- *              zero.
- *
- *        Otherwise like a normal class reference type.
- *        Don't access other fields of the struct.
- *
- * E) typeclass is an array class
- *
- *        An array reference.
- *            elementclass...typeclass of the element type
- *            dimension......dimension of the array (>=1)
- *            elementtype....element type (ARRAYTYPE_...)
- *            merged.........mergedlist of the element type
- *
- *        Use TYPEINFO_IS_ARRAY to check for this case.
- *
- *        The elementclass may be one of the following:
- *        1) pseudo_class_Arraystub
- *        2) an unresolved type
- *        3) a loaded interface
- *        4) a loaded (non-pseudo-,non-array-)class != (BOOTSTRAP)java.lang.Object
- *                Note: `merged` may be used
- *        5) (BOOTSTRAP)java.lang.Object
- *                Note: `merged` may be used
- *
- *        For the semantics of the merged field in cases 4) and 5) consult the 
- *        corresponding descriptions with `elementclass` replaced by `typeclass`.
- *
- * F) typeclass is an unresolved type (a symbolic class/interface reference)
- *
- *        The type has not been resolved yet. (Meaning it corresponds to an
- *        unloaded class or interface).
- *        Don't access other fields of the struct.
- *
- * G) typeclass is a loaded interface
- *
- *        An interface reference type.
- *        Don't access other fields of the struct.
- *
- * H) typeclass is a loaded (non-pseudo-,non-array-)class != (BOOTSTRAP)java.lang.Object
- *
- *        A loaded class type.
- *        All classref_or_classinfos in u.merged.list (if any) are
- *        loaded subclasses of typeclass (no interfaces, array classes, or
- *        unresolved types).
- *        Don't access other fields of the struct.
- *
- * I) typeclass is (BOOTSTRAP)java.lang.Object
- *
- *        The most general kind of reference type.
- *        In this case u.merged.count and u.merged.list
- *        are valid and may be non-zero.
- *        The classref_or_classinfos in u.merged.list (if any) may be
- *        classes, interfaces, pseudo classes or unresolved types.
- *        Don't access other fields of the struct.
- */
-
-/* The following algorithm is used to determine if the type described
- * by this typeinfo struct supports the interface X:  * XXX add MAYBE *
- *
- *     1) If typeclass is X or a subinterface of X the answer is "yes".
- *     2) If typeclass is a (pseudo) class implementing X the answer is "yes".
- *     3) If typeclass is not an array and u.merged.count>0
- *        and all classes/interfaces in u.merged.list implement X
- *        the answer is "yes".
- *     4) If none of the above is true the answer is "no".
- */
-
-/*
- * CAUTION: The typeinfo structure should be considered opaque outside of
- *          typeinfo.[ch]. Please use the macros and functions defined here to
- *          access typeinfo structures!
- */
-struct typeinfo {
-       classref_or_classinfo  typeclass;
-       classref_or_classinfo  elementclass; /* valid if dimension>0 */ /* various uses! */
-       typeinfo_mergedlist_t *merged;
-       u1                     dimension;
-       u1                     elementtype;  /* valid if dimension>0           */
-};
-
-struct typeinfo_mergedlist {
-       s4                    count;
-       classref_or_classinfo list[1];       /* variable length!                        */
-};
-
-/* a type descriptor stores a basic type and the typeinfo                */
-/* this is used for storing the type of a local variable, and for        */
-/* storing types in the signature of a method                            */
-
-struct typedescriptor {
-       typeinfo_t      typeinfo; /* valid if type == TYPE_ADR               */
-       u1              type;     /* basic type (TYPE_INT, ...)              */
-};
-
-/****************************************************************************/
-/* MACROS                                                                   */
-/****************************************************************************/
-
-/* NOTE: The TYPEINFO macros take typeinfo *structs*, not pointers as
- *       arguments.  You have to dereference any pointers.
- */
-
-/* typevectors **************************************************************/
-
-#define TYPEVECTOR_SIZE(size)                                          \
-    ((size) * sizeof(varinfo)) 
-
-#define DNEW_TYPEVECTOR(size)                                          \
-    ((varinfo *) DMNEW(uint8_t, TYPEVECTOR_SIZE(size)))
-
-#define DMNEW_TYPEVECTOR(num,size)                                             \
-    ((void *) DMNEW(uint8_t, (num) * TYPEVECTOR_SIZE(size)))
-
-#define MGET_TYPEVECTOR(array,index,size) \
-    ((varinfo*) (((u1*)(array)) + TYPEVECTOR_SIZE(size) * (index)))
-
-/* internally used macros ***************************************************/
-
-/* internal, don't use this explicitly! */
-#define TYPEINFO_ALLOCMERGED(mergedlist,count)                                 \
-    do {(mergedlist) = (typeinfo_mergedlist_t *) DMNEW(uint8_t,        \
-            sizeof(typeinfo_mergedlist_t)                       \
-            + ((count)-1)*sizeof(classinfo*));} while(0)
-
-/* internal, don't use this explicitly! */
-#define TYPEINFO_FREEMERGED(mergedlist)
-
-/* internal, don't use this explicitly! */
-#define TYPEINFO_FREEMERGED_IF_ANY(mergedlist)
-
-/* macros for type queries **************************************************/
-
-#define TYPEINFO_IS_PRIMITIVE(info)                             \
-            ((info).typeclass.any == NULL)
-
-#define TYPEINFO_IS_REFERENCE(info)                             \
-            ((info).typeclass.any != NULL)
-
-#define TYPEINFO_IS_NULLTYPE(info)                              \
-            ((info).typeclass.cls == pseudo_class_Null)
-
-#define TYPEINFO_IS_NEWOBJECT(info)                             \
-            ((info).typeclass.cls == pseudo_class_New)
-
-#define TYPEINFO_IS_JAVA_LANG_CLASS(info)                       \
-            ((info).typeclass.cls == class_java_lang_Class)
-
-/* only use this if TYPEINFO_IS_PRIMITIVE returned true! */
-#define TYPEINFO_RETURNADDRESS(info)                            \
-            ((info).elementclass.any)
-
-/* only use this if TYPEINFO_IS_NEWOBJECT returned true! */
-#define TYPEINFO_NEWOBJECT_INSTRUCTION(info)                    \
-               ((info).elementclass.any)
-
-/* only use this if TYPEINFO_IS_JAVA_LANG_CLASS returned true! */
-#define TYPEINFO_JAVA_LANG_CLASS_CLASSREF(info)                 \
-               ((info).elementclass.ref)
-
-/* macros for array type queries ********************************************/
-
-#define TYPEINFO_IS_ARRAY(info)                                 \
-            ( TYPEINFO_IS_REFERENCE(info)                       \
-              && ((info).dimension != 0) )
-
-#define TYPEINFO_IS_SIMPLE_ARRAY(info)                          \
-            ( ((info).dimension == 1) )
-
-#define TYPEINFO_IS_ARRAY_ARRAY(info)                           \
-            ( ((info).dimension >= 2) )
-
-#define TYPEINFO_IS_PRIMITIVE_ARRAY(info,arraytype)             \
-            ( TYPEINFO_IS_SIMPLE_ARRAY(info)                    \
-              && ((info).elementtype == (arraytype)) )
-
-#define TYPEINFO_IS_OBJECT_ARRAY(info)                          \
-            ( TYPEINFO_IS_SIMPLE_ARRAY(info)                    \
-              && ((info).elementclass.any != NULL) )
-
-/* assumes that info describes an array type */
-#define TYPEINFO_IS_ARRAY_OF_REFS_NOCHECK(info)                 \
-            ( ((info).elementclass.any != NULL)                 \
-              || ((info).dimension >= 2) )
-
-#define TYPEINFO_IS_ARRAY_OF_REFS(info)                         \
-            ( TYPEINFO_IS_ARRAY(info)                           \
-              && TYPEINFO_IS_ARRAY_OF_REFS_NOCHECK(info) )
-
-#define TYPE_IS_RETURNADDRESS(type,info)                        \
-            ( ((type)==TYPE_RET)                                \
-              && TYPEINFO_IS_PRIMITIVE(info) )
-
-#define TYPE_IS_REFERENCE(type,info)                            \
-            ( ((type)==TYPE_ADR)                                \
-              && !TYPEINFO_IS_PRIMITIVE(info) )
-
-#define TYPEDESC_IS_RETURNADDRESS(td)                           \
-            TYPE_IS_RETURNADDRESS((td).type,(td).typeinfo)
-
-#define TYPEDESC_IS_REFERENCE(td)                               \
-            TYPE_IS_REFERENCE((td).type,(td).typeinfo)
-
-/* queries allowing the null type ********************************************/
-
-#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)                           \
-         do {(info).typeclass.any = NULL;                       \
-             (info).elementclass.any = NULL;                    \
-             (info).merged = NULL;                              \
-             (info).dimension = 0;                              \
-             (info).elementtype = 0;} while(0)
-
-#define TYPEINFO_INIT_RETURNADDRESS(info,adr)                   \
-         do {(info).typeclass.any = NULL;                       \
-             (info).elementclass.any = (adr);                   \
-             (info).merged = NULL;                              \
-             (info).dimension = 0;                              \
-             (info).elementtype = 0;} while(0)
-
-#define TYPEINFO_INIT_NON_ARRAY_CLASSINFO(info,cinfo)   \
-         do {(info).typeclass.cls = (cinfo);            \
-             (info).elementclass.any = NULL;            \
-             (info).merged = NULL;                      \
-             (info).dimension = 0;                      \
-             (info).elementtype = 0;} while(0)
-
-#define TYPEINFO_INIT_JAVA_LANG_CLASS(info,c)                   \
-         do {(info).typeclass.any = class_java_lang_Class;      \
-             (info).elementclass = (c);                         \
-             (info).merged = NULL;                              \
-             (info).dimension = 0;                              \
-             (info).elementtype = 0;} while(0)
-
-#define TYPEINFO_INIT_NULLTYPE(info)                            \
-            TYPEINFO_INIT_NON_ARRAY_CLASSINFO(info,pseudo_class_Null)
-
-#define TYPEINFO_INIT_NEWOBJECT(info,instr)             \
-         do {(info).typeclass.cls = pseudo_class_New;   \
-             (info).elementclass.any = (instr);         \
-             (info).merged = NULL;                      \
-             (info).dimension = 0;                      \
-             (info).elementtype = 0;} while(0)
-
-#define TYPEINFO_INIT_PRIMITIVE_ARRAY(info,arraytype)                   \
-    typeinfo_init_classinfo(&(info),primitivetype_table[arraytype].arrayclass);
-
-/* macros for copying types (destinition is not checked or freed) ***********/
-
-/* TYPEINFO_COPY makes a shallow copy, the merged pointer is simply copied. */
-#define TYPEINFO_COPY(src,dst)                                  \
-    do {(dst) = (src);} while(0)
-
-/* TYPEINFO_CLONE makes a deep copy, the merged list (if any) is duplicated
- * into a newly allocated array.
- */
-#define TYPEINFO_CLONE(src,dst)                                 \
-    do {(dst) = (src);                                          \
-        if ((dst).merged) typeinfo_clone(&(src),&(dst));} while(0)
-
-/****************************************************************************/
-/* FUNCTIONS                                                                */
-/****************************************************************************/
-
-#ifdef __cplusplus
-extern "C" { 
-#endif
-
-/* typevector functions *****************************************************/
-
-/* element read-only access */
-bool typevector_checktype(varinfo *set,int index,int type);
-bool typevector_checkreference(varinfo *set,int index);
-bool typevector_checkretaddr(varinfo *set,int index);
-
-/* element write access */
-void typevector_store(varinfo *set,int index,int type,typeinfo_t *info);
-void typevector_store_retaddr(varinfo *set,int index,typeinfo_t *info);
-bool typevector_init_object(varinfo *set,void *ins,classref_or_classinfo initclass,int size);
-
-/* vector functions */
-varinfo *typevector_copy(varinfo *src,int size);
-void typevector_copy_inplace(varinfo *src,varinfo *dst,int size);
-typecheck_result typevector_merge(methodinfo *m,varinfo *dst,varinfo *y,int size);
-
-/* inquiry functions (read-only) ********************************************/
-
-bool typeinfo_is_array(typeinfo_t *info);
-bool typeinfo_is_primitive_array(typeinfo_t *info,int arraytype);
-bool typeinfo_is_array_of_refs(typeinfo_t *info);
-
-typecheck_result typeinfo_is_assignable(typeinfo_t *value,typeinfo_t *dest);
-typecheck_result typeinfo_is_assignable_to_class(typeinfo_t *value,classref_or_classinfo dest);
-
-/* initialization functions *************************************************/
-
-/* RETURN VALUE (bool):
- *     true.............ok,
- *     false............an exception has been thrown.
- *
- * RETURN VALUE (int):
- *     >= 0.............ok,
- *     -1...............an exception has been thrown.
- */
-void typeinfo_init_classinfo(typeinfo_t *info,classinfo *c);
-bool typeinfo_init_class(typeinfo_t *info,classref_or_classinfo c);
-bool typeinfo_init_component(typeinfo_t *srcarray,typeinfo_t *dst);
-
-bool typeinfo_init_from_typedesc(typedesc *desc,u1 *type,typeinfo_t *info);
-bool typeinfos_init_from_methoddesc(methoddesc *desc,u1 *typebuf,
-                                   typeinfo_t *infobuf,
-                                   int buflen,bool twoword,
-                                   u1 *returntype,typeinfo_t *returntypeinfo);
-bool  typedescriptor_init_from_typedesc(typedescriptor_t *td,
-                                                                           typedesc *desc);
-bool  typeinfo_init_varinfo_from_typedesc(varinfo *var,
-                                                                           typedesc *desc);
-int  typedescriptors_init_from_methoddesc(typedescriptor_t *td,
-                                                                                 methoddesc *desc,
-                                                                                 int buflen,bool twoword,int startindex,
-                                                                                 typedescriptor_t *returntype);
-bool typeinfo_init_varinfos_from_methoddesc(varinfo *vars,
-                                                                                 methoddesc *desc,
-                                                                                 int buflen, int startindex,
-                                                                                 s4 *map,
-                                                                                 typedescriptor_t *returntype);
-
-void typeinfo_clone(typeinfo_t *src,typeinfo_t *dest);
-
-/* freeing memory ***********************************************************/
-
-void typeinfo_free(typeinfo_t *info);
-
-/* functions for merging types **********************************************/
-
-typecheck_result typeinfo_merge(methodinfo *m,typeinfo_t *dest,typeinfo_t* y);
-
-/* debugging helpers ********************************************************/
-
-#ifdef TYPEINFO_DEBUG
-
-#include <stdio.h>
-
-void typeinfo_test();
-void typeinfo_print_class(FILE *file,classref_or_classinfo c);
-void typeinfo_print(FILE *file,typeinfo_t *info,int indent);
-void typeinfo_print_short(FILE *file,typeinfo_t *info);
-void typeinfo_print_type(FILE *file,int type,typeinfo_t *info);
-void typedescriptor_print(FILE *file,typedescriptor_t *td);
-void typevector_print(FILE *file,varinfo *vec,int size);
-
-#endif /* TYPEINFO_DEBUG */
-
-#ifdef __cplusplus
-} 
-#endif
-
-#endif /* _TYPEINFO_H */
-
-
-/*
- * 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
- * Emacs will automagically detect them.
- * ---------------------------------------------------------------------
- * Local variables:
- * mode: c
- * indent-tabs-mode: t
- * c-basic-offset: 4
- * tab-width: 4
- * End:
- */
diff --git a/src/vm/jit/verify/typeinfo.hpp b/src/vm/jit/verify/typeinfo.hpp
new file mode 100644 (file)
index 0000000..00d78e0
--- /dev/null
@@ -0,0 +1,538 @@
+/* src/vm/jit/verify/typeinfo.h - type system used by the type checker
+
+   Copyright (C) 1996-2005, 2006, 2007, 2008
+   CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
+
+   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., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301, USA.
+
+*/
+
+#ifndef _TYPEINFO_H
+#define _TYPEINFO_H
+
+/* resolve typedef cycles *****************************************************/
+
+typedef struct typeinfo            typeinfo_t;
+typedef struct typeinfo_mergedlist typeinfo_mergedlist_t;
+typedef struct typedescriptor      typedescriptor_t;
+
+#include "config.h"
+#include "vm/types.h"
+
+#include "vm/global.h"
+#include "vm/references.h"
+
+
+/* configuration **************************************************************/
+
+/*
+ * TYPECHECK_STATISTICS activates gathering statistical information.
+ * 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
+ * TYPEINFO_VERBOSE activates debug prints in typeinfo.c
+ */
+#ifdef ENABLE_VERIFIER
+#ifndef NDEBUG
+/*#define TYPECHECK_STATISTICS*/
+#define TYPEINFO_DEBUG
+/*#define TYPEINFO_VERBOSE*/
+#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
+#endif
+#endif
+
+#ifdef TYPECHECK_VERBOSE_OPT
+extern bool opt_typecheckverbose;
+#endif
+
+/* types **********************************************************************/
+
+/* typecheck_result - return type for boolean and tristate  functions     */
+/*                    which may also throw exceptions (typecheck_FAIL).   */
+
+/* NOTE: Use the enum values, not the uppercase #define macros!          */
+#define TYPECHECK_MAYBE  0x02
+#define TYPECHECK_FAIL   0x04
+
+typedef enum {
+       typecheck_FALSE = false,
+       typecheck_TRUE  = true,
+       typecheck_MAYBE = TYPECHECK_MAYBE,
+       typecheck_FAIL  = TYPECHECK_FAIL
+} typecheck_result;
+
+/* check that typecheck_MAYBE is not ambiguous */
+#if TYPECHECK_MAYBE == true
+#error "`typecheck_MAYBE` must not be the same as `true`"
+#endif
+#if TYPECHECK_MAYBE == false
+#error "`typecheck_MAYBE` must not be the same as `false`"
+#endif
+
+/* check that typecheck_FAIL is not ambiguous */
+#if (true & TYPECHECK_FAIL) != 0
+#error "`true` must not have bit 0x02 set (conflicts with typecheck_FAIL)"
+#endif
+
+/* data structures for the type system ****************************************/
+
+/* The typeinfo structure stores detailed information on address types.
+ * (stack elements, variables, etc. with type == TYPE_ADR.)
+ *
+ * There are two kinds of address types which can be distinguished by
+ * the value of the typeclass field:
+ *
+ * 1) typeclass == NULL: returnAddress type
+ *                       use TYPEINFO_IS_PRIMITIVE to test for this
+ *
+ * 2) typeclass != NULL: reference type
+ *                       use TYPEINFO_IS_REFERENCE to test for this
+ *
+ * Note: For non-address types either there is no typeinfo allocated
+ * or the fields of the typeinfo struct contain undefined values!
+ * DO NOT access the typeinfo for non-address types!
+ *
+ * CAUTION: The typeinfo structure should be considered opaque outside of
+ *          typeinfo.[ch]. Please use the macros and functions defined here to
+ *          access typeinfo structures!
+ */
+
+/* At all times *exactly one* of the following conditions is true for
+ * a particular typeinfo struct:
+ *
+ * A) typeclass == NULL
+ *
+ *        This is a returnAddress type.
+ *
+ *        Use TYPEINFO_IS_PRIMITIVE to check for this.
+ *        Use TYPEINFO_RETURNADDRESS to access the pointer in elementclass.
+ *        Don't access other fields of the struct.
+ *
+ * B) typeclass == pseudo_class_Null
+ *
+ *        This is the null-reference type. 
+ *        Use TYPEINFO_IS_NULLTYPE to check for this.
+ *        Don't access other fields of the struct.
+ *
+ * C) typeclass == pseudo_class_New
+ *
+ *        This is an 'uninitialized object' type. elementclass can be
+ *        cast to instruction* and points to the NEW instruction
+ *        responsible for creating this type.
+ *
+ *        Use TYPEINFO_NEWOBJECT_INSTRUCTION to access the pointer in
+ *        elementclass.
+ *        Don't access other fields of the struct.
+ *
+ * D) typeclass == pseudo_class_Arraystub
+ *
+ *        This type is used to represent the result of merging array types
+ *        with incompatible component types. An arraystub allows no access
+ *        to its components (since their type is undefined), but it allows
+ *        operations which act directly on an arbitrary array type (such as
+ *        requesting the array size).
+ *
+ *        NOTE: An array stub does *not* count as an array. It has dimension
+ *              zero.
+ *
+ *        Otherwise like a normal class reference type.
+ *        Don't access other fields of the struct.
+ *
+ * E) typeclass is an array class
+ *
+ *        An array reference.
+ *            elementclass...typeclass of the element type
+ *            dimension......dimension of the array (>=1)
+ *            elementtype....element type (ARRAYTYPE_...)
+ *            merged.........mergedlist of the element type
+ *
+ *        Use TYPEINFO_IS_ARRAY to check for this case.
+ *
+ *        The elementclass may be one of the following:
+ *        1) pseudo_class_Arraystub
+ *        2) an unresolved type
+ *        3) a loaded interface
+ *        4) a loaded (non-pseudo-,non-array-)class != (BOOTSTRAP)java.lang.Object
+ *                Note: `merged` may be used
+ *        5) (BOOTSTRAP)java.lang.Object
+ *                Note: `merged` may be used
+ *
+ *        For the semantics of the merged field in cases 4) and 5) consult the 
+ *        corresponding descriptions with `elementclass` replaced by `typeclass`.
+ *
+ * F) typeclass is an unresolved type (a symbolic class/interface reference)
+ *
+ *        The type has not been resolved yet. (Meaning it corresponds to an
+ *        unloaded class or interface).
+ *        Don't access other fields of the struct.
+ *
+ * G) typeclass is a loaded interface
+ *
+ *        An interface reference type.
+ *        Don't access other fields of the struct.
+ *
+ * H) typeclass is a loaded (non-pseudo-,non-array-)class != (BOOTSTRAP)java.lang.Object
+ *
+ *        A loaded class type.
+ *        All classref_or_classinfos in u.merged.list (if any) are
+ *        loaded subclasses of typeclass (no interfaces, array classes, or
+ *        unresolved types).
+ *        Don't access other fields of the struct.
+ *
+ * I) typeclass is (BOOTSTRAP)java.lang.Object
+ *
+ *        The most general kind of reference type.
+ *        In this case u.merged.count and u.merged.list
+ *        are valid and may be non-zero.
+ *        The classref_or_classinfos in u.merged.list (if any) may be
+ *        classes, interfaces, pseudo classes or unresolved types.
+ *        Don't access other fields of the struct.
+ */
+
+/* The following algorithm is used to determine if the type described
+ * by this typeinfo struct supports the interface X:  * XXX add MAYBE *
+ *
+ *     1) If typeclass is X or a subinterface of X the answer is "yes".
+ *     2) If typeclass is a (pseudo) class implementing X the answer is "yes".
+ *     3) If typeclass is not an array and u.merged.count>0
+ *        and all classes/interfaces in u.merged.list implement X
+ *        the answer is "yes".
+ *     4) If none of the above is true the answer is "no".
+ */
+
+/*
+ * CAUTION: The typeinfo structure should be considered opaque outside of
+ *          typeinfo.[ch]. Please use the macros and functions defined here to
+ *          access typeinfo structures!
+ */
+struct typeinfo {
+       classref_or_classinfo  typeclass;
+       classref_or_classinfo  elementclass; /* valid if dimension>0 */ /* various uses! */
+       typeinfo_mergedlist_t *merged;
+       u1                     dimension;
+       u1                     elementtype;  /* valid if dimension>0           */
+};
+
+struct typeinfo_mergedlist {
+       s4                    count;
+       classref_or_classinfo list[1];       /* variable length!                        */
+};
+
+/* a type descriptor stores a basic type and the typeinfo                */
+/* this is used for storing the type of a local variable, and for        */
+/* storing types in the signature of a method                            */
+
+struct typedescriptor {
+       typeinfo_t      typeinfo; /* valid if type == TYPE_ADR               */
+       u1              type;     /* basic type (TYPE_INT, ...)              */
+};
+
+/****************************************************************************/
+/* MACROS                                                                   */
+/****************************************************************************/
+
+/* NOTE: The TYPEINFO macros take typeinfo *structs*, not pointers as
+ *       arguments.  You have to dereference any pointers.
+ */
+
+/* typevectors **************************************************************/
+
+#define TYPEVECTOR_SIZE(size)                                          \
+    ((size) * sizeof(varinfo)) 
+
+#define DNEW_TYPEVECTOR(size)                                          \
+    ((varinfo *) DumpMemory::allocate(TYPEVECTOR_SIZE(size)))
+
+#define DMNEW_TYPEVECTOR(num,size)                                     \
+    ((varinfo *) DumpMemory::allocate((num) * TYPEVECTOR_SIZE(size)))
+
+#define MGET_TYPEVECTOR(array,index,size) \
+    ((varinfo*) (((u1*)(array)) + TYPEVECTOR_SIZE(size) * (index)))
+
+/* internally used macros ***************************************************/
+
+/* internal, don't use this explicitly! */
+#define TYPEINFO_ALLOCMERGED(mergedlist,count)                                 \
+    do {(mergedlist) = (typeinfo_mergedlist_t *) DumpMemory::allocate(sizeof(typeinfo_mergedlist_t) \
+            + ((count)-1)*sizeof(classinfo*));} while(0)
+
+/* internal, don't use this explicitly! */
+#define TYPEINFO_FREEMERGED(mergedlist)
+
+/* internal, don't use this explicitly! */
+#define TYPEINFO_FREEMERGED_IF_ANY(mergedlist)
+
+/* macros for type queries **************************************************/
+
+#define TYPEINFO_IS_PRIMITIVE(info)                             \
+            ((info).typeclass.any == NULL)
+
+#define TYPEINFO_IS_REFERENCE(info)                             \
+            ((info).typeclass.any != NULL)
+
+#define TYPEINFO_IS_NULLTYPE(info)                              \
+            ((info).typeclass.cls == pseudo_class_Null)
+
+#define TYPEINFO_IS_NEWOBJECT(info)                             \
+            ((info).typeclass.cls == pseudo_class_New)
+
+#define TYPEINFO_IS_JAVA_LANG_CLASS(info)                       \
+            ((info).typeclass.cls == class_java_lang_Class)
+
+/* only use this if TYPEINFO_IS_PRIMITIVE returned true! */
+#define TYPEINFO_RETURNADDRESS(info)                            \
+            ((info).elementclass.any)
+
+/* only use this if TYPEINFO_IS_NEWOBJECT returned true! */
+#define TYPEINFO_NEWOBJECT_INSTRUCTION(info)                    \
+               ((info).elementclass.any)
+
+/* only use this if TYPEINFO_IS_JAVA_LANG_CLASS returned true! */
+#define TYPEINFO_JAVA_LANG_CLASS_CLASSREF(info)                 \
+               ((info).elementclass.ref)
+
+/* macros for array type queries ********************************************/
+
+#define TYPEINFO_IS_ARRAY(info)                                 \
+            ( TYPEINFO_IS_REFERENCE(info)                       \
+              && ((info).dimension != 0) )
+
+#define TYPEINFO_IS_SIMPLE_ARRAY(info)                          \
+            ( ((info).dimension == 1) )
+
+#define TYPEINFO_IS_ARRAY_ARRAY(info)                           \
+            ( ((info).dimension >= 2) )
+
+#define TYPEINFO_IS_PRIMITIVE_ARRAY(info,arraytype)             \
+            ( TYPEINFO_IS_SIMPLE_ARRAY(info)                    \
+              && ((info).elementtype == (arraytype)) )
+
+#define TYPEINFO_IS_OBJECT_ARRAY(info)                          \
+            ( TYPEINFO_IS_SIMPLE_ARRAY(info)                    \
+              && ((info).elementclass.any != NULL) )
+
+/* assumes that info describes an array type */
+#define TYPEINFO_IS_ARRAY_OF_REFS_NOCHECK(info)                 \
+            ( ((info).elementclass.any != NULL)                 \
+              || ((info).dimension >= 2) )
+
+#define TYPEINFO_IS_ARRAY_OF_REFS(info)                         \
+            ( TYPEINFO_IS_ARRAY(info)                           \
+              && TYPEINFO_IS_ARRAY_OF_REFS_NOCHECK(info) )
+
+#define TYPE_IS_RETURNADDRESS(type,info)                        \
+            ( ((type)==TYPE_RET)                                \
+              && TYPEINFO_IS_PRIMITIVE(info) )
+
+#define TYPE_IS_REFERENCE(type,info)                            \
+            ( ((type)==TYPE_ADR)                                \
+              && !TYPEINFO_IS_PRIMITIVE(info) )
+
+#define TYPEDESC_IS_RETURNADDRESS(td)                           \
+            TYPE_IS_RETURNADDRESS((td).type,(td).typeinfo)
+
+#define TYPEDESC_IS_REFERENCE(td)                               \
+            TYPE_IS_REFERENCE((td).type,(td).typeinfo)
+
+/* queries allowing the null type ********************************************/
+
+#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)                           \
+         do {(info).typeclass.any = NULL;                       \
+             (info).elementclass.any = NULL;                    \
+             (info).merged = NULL;                              \
+             (info).dimension = 0;                              \
+             (info).elementtype = 0;} while(0)
+
+#define TYPEINFO_INIT_RETURNADDRESS(info,adr)                   \
+         do {(info).typeclass.any = NULL;                       \
+             (info).elementclass.any = (adr);                   \
+             (info).merged = NULL;                              \
+             (info).dimension = 0;                              \
+             (info).elementtype = 0;} while(0)
+
+#define TYPEINFO_INIT_NON_ARRAY_CLASSINFO(info,cinfo)   \
+         do {(info).typeclass.cls = (cinfo);            \
+             (info).elementclass.any = NULL;            \
+             (info).merged = NULL;                      \
+             (info).dimension = 0;                      \
+             (info).elementtype = 0;} while(0)
+
+#define TYPEINFO_INIT_JAVA_LANG_CLASS(info,c)                   \
+         do {(info).typeclass.any = class_java_lang_Class;      \
+             (info).elementclass = (c);                         \
+             (info).merged = NULL;                              \
+             (info).dimension = 0;                              \
+             (info).elementtype = 0;} while(0)
+
+#define TYPEINFO_INIT_NULLTYPE(info)                            \
+            TYPEINFO_INIT_NON_ARRAY_CLASSINFO(info,pseudo_class_Null)
+
+#define TYPEINFO_INIT_NEWOBJECT(info,instr)             \
+         do {(info).typeclass.cls = pseudo_class_New;   \
+             (info).elementclass.any = (instr);         \
+             (info).merged = NULL;                      \
+             (info).dimension = 0;                      \
+             (info).elementtype = 0;} while(0)
+
+#define TYPEINFO_INIT_PRIMITIVE_ARRAY(info,arraytype)                   \
+    typeinfo_init_classinfo(&(info),primitivetype_table[arraytype].arrayclass);
+
+/* macros for copying types (destinition is not checked or freed) ***********/
+
+/* TYPEINFO_COPY makes a shallow copy, the merged pointer is simply copied. */
+#define TYPEINFO_COPY(src,dst)                                  \
+    do {(dst) = (src);} while(0)
+
+/* TYPEINFO_CLONE makes a deep copy, the merged list (if any) is duplicated
+ * into a newly allocated array.
+ */
+#define TYPEINFO_CLONE(src,dst)                                 \
+    do {(dst) = (src);                                          \
+        if ((dst).merged) typeinfo_clone(&(src),&(dst));} while(0)
+
+/****************************************************************************/
+/* FUNCTIONS                                                                */
+/****************************************************************************/
+
+#ifdef __cplusplus
+extern "C" { 
+#endif
+
+/* typevector functions *****************************************************/
+
+/* element read-only access */
+bool typevector_checktype(varinfo *set,int index,int type);
+bool typevector_checkreference(varinfo *set,int index);
+bool typevector_checkretaddr(varinfo *set,int index);
+
+/* element write access */
+void typevector_store(varinfo *set,int index,int type,typeinfo_t *info);
+void typevector_store_retaddr(varinfo *set,int index,typeinfo_t *info);
+bool typevector_init_object(varinfo *set,void *ins,classref_or_classinfo initclass,int size);
+
+/* vector functions */
+varinfo *typevector_copy(varinfo *src,int size);
+void typevector_copy_inplace(varinfo *src,varinfo *dst,int size);
+typecheck_result typevector_merge(methodinfo *m,varinfo *dst,varinfo *y,int size);
+
+/* inquiry functions (read-only) ********************************************/
+
+bool typeinfo_is_array(typeinfo_t *info);
+bool typeinfo_is_primitive_array(typeinfo_t *info,int arraytype);
+bool typeinfo_is_array_of_refs(typeinfo_t *info);
+
+typecheck_result typeinfo_is_assignable(typeinfo_t *value,typeinfo_t *dest);
+typecheck_result typeinfo_is_assignable_to_class(typeinfo_t *value,classref_or_classinfo dest);
+
+/* initialization functions *************************************************/
+
+/* RETURN VALUE (bool):
+ *     true.............ok,
+ *     false............an exception has been thrown.
+ *
+ * RETURN VALUE (int):
+ *     >= 0.............ok,
+ *     -1...............an exception has been thrown.
+ */
+void typeinfo_init_classinfo(typeinfo_t *info,classinfo *c);
+bool typeinfo_init_class(typeinfo_t *info,classref_or_classinfo c);
+bool typeinfo_init_component(typeinfo_t *srcarray,typeinfo_t *dst);
+
+bool typeinfo_init_from_typedesc(typedesc *desc,u1 *type,typeinfo_t *info);
+bool typeinfos_init_from_methoddesc(methoddesc *desc,u1 *typebuf,
+                                   typeinfo_t *infobuf,
+                                   int buflen,bool twoword,
+                                   u1 *returntype,typeinfo_t *returntypeinfo);
+bool  typedescriptor_init_from_typedesc(typedescriptor_t *td,
+                                                                           typedesc *desc);
+bool  typeinfo_init_varinfo_from_typedesc(varinfo *var,
+                                                                           typedesc *desc);
+int  typedescriptors_init_from_methoddesc(typedescriptor_t *td,
+                                                                                 methoddesc *desc,
+                                                                                 int buflen,bool twoword,int startindex,
+                                                                                 typedescriptor_t *returntype);
+bool typeinfo_init_varinfos_from_methoddesc(varinfo *vars,
+                                                                                 methoddesc *desc,
+                                                                                 int buflen, int startindex,
+                                                                                 s4 *map,
+                                                                                 typedescriptor_t *returntype);
+
+void typeinfo_clone(typeinfo_t *src,typeinfo_t *dest);
+
+/* freeing memory ***********************************************************/
+
+void typeinfo_free(typeinfo_t *info);
+
+/* functions for merging types **********************************************/
+
+typecheck_result typeinfo_merge(methodinfo *m,typeinfo_t *dest,typeinfo_t* y);
+
+/* debugging helpers ********************************************************/
+
+#ifdef TYPEINFO_DEBUG
+
+#include <stdio.h>
+
+void typeinfo_test();
+void typeinfo_print_class(FILE *file,classref_or_classinfo c);
+void typeinfo_print(FILE *file,typeinfo_t *info,int indent);
+void typeinfo_print_short(FILE *file,typeinfo_t *info);
+void typeinfo_print_type(FILE *file,int type,typeinfo_t *info);
+void typedescriptor_print(FILE *file,typedescriptor_t *td);
+void typevector_print(FILE *file,varinfo *vec,int size);
+
+#endif /* TYPEINFO_DEBUG */
+
+#ifdef __cplusplus
+} 
+#endif
+
+#endif /* _TYPEINFO_H */
+
+
+/*
+ * 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
+ * Emacs will automagically detect them.
+ * ---------------------------------------------------------------------
+ * Local variables:
+ * mode: c
+ * indent-tabs-mode: t
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ */
index cdd42a733ef852c8ec3cb955bc0695fdcbcf00a5..0dc57ef3e31d6b288b1b487ef0c15cef93f58bf0 100644 (file)
@@ -44,7 +44,7 @@
 #include "vm/resolve.hpp"
 
 #include "vm/jit/jit.hpp"
-#include "vm/jit/verify/typeinfo.h"
+#include "vm/jit/verify/typeinfo.hpp"
 
 
 /******************************************************************************/
index 148604ebc4c9677b0f43da64ee15451ea45096e5..dc6ccfc1c36bee122d66b5d41428c383c051dd48 100644 (file)
@@ -47,7 +47,7 @@ typedef struct unresolved_subtype_set unresolved_subtype_set;
 #include "vm/jit/reg.h"
 
 #include "vm/jit/ir/instruction.hpp"
-#include "vm/jit/verify/typeinfo.h"
+#include "vm/jit/verify/typeinfo.hpp"
 
 
 /* constants ******************************************************************/