#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 *************************************************/
# include "vm/jit/python.h"
#endif
-#include "vm/jit/verify/typecheck.h"
+#include "vm/jit/verify/typecheck.hpp"
/* debug macros ***************************************************************/
# include "vm/jit/allocator/lsra.h"
#endif
-#include "vm/jit/verify/typeinfo.h"
+#include "vm/jit/verify/typeinfo.hpp"
/* common jit/codegen macros **************************************************/
#include "arch.h"
#include "vm/jit/jit.hpp"
-#include "vm/jit/verify/typeinfo.h"
+#include "vm/jit/verify/typeinfo.hpp"
/************************* pseudo variable structure **************************/
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:
+++ /dev/null
-/* 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:
- */
--- /dev/null
+/* 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:
+ */
+++ /dev/null
-/* 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:
- */
--- /dev/null
+/* 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:
+ */
+++ /dev/null
-/* 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:
- */
--- /dev/null
+/* 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:
+ */
+++ /dev/null
-/* 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:
- */
-
--- /dev/null
+/* 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:
+ */
+
+++ /dev/null
-/* 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:
- */
--- /dev/null
+/* 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:
+ */
+++ /dev/null
-/* 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:
- */
--- /dev/null
+/* 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:
+ */
+++ /dev/null
-/* 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:
- */
--- /dev/null
+/* 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:
+ */
+++ /dev/null
-/* 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:
- */
--- /dev/null
+/* 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:
+ */
+++ /dev/null
-/* 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:
- */
--- /dev/null
+/* 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:
+ */
+++ /dev/null
-/* 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:
- */
--- /dev/null
+/* 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:
+ */
#include "vm/resolve.hpp"
#include "vm/jit/jit.hpp"
-#include "vm/jit/verify/typeinfo.h"
+#include "vm/jit/verify/typeinfo.hpp"
/******************************************************************************/
#include "vm/jit/reg.h"
#include "vm/jit/ir/instruction.hpp"
-#include "vm/jit/verify/typeinfo.h"
+#include "vm/jit/verify/typeinfo.hpp"
/* constants ******************************************************************/