* Removed all Id tags.
[cacao.git] / src / vm / jit / verify / typecheck-common.c
index 51892a131d47b19d27d64159499c5dc4de252125..a06c12da764078e5f02e08f5b7ccce2dca583496 100644 (file)
@@ -1,9 +1,43 @@
+/* src/vm/jit/verify/typecheck-common.c - shared verifier code
+
+   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
+
+   Changes: 
+
+*/
+
+
 #include "config.h"
 #include "vm/types.h"
 #include "vm/global.h"
 
 #include <assert.h>
 
+#include <vm/exceptions.h>
 #include <vm/jit/show.h>
 #include <typecheck-common.h>
 
@@ -139,12 +173,10 @@ void typecheck_print_statistics(FILE *file) {
 
 void typecheck_init_flags(verifier_state *state, s4 minflags)
 {
-       s4 i;
        basicblock *block;
 
     /* set all BBFINISHED blocks to BBTYPECHECK_UNDEF. */
        
-    i = state->basicblockcount;
     for (block = state->basicblocks; block; block = block->next) {
                
 #ifdef TYPECHECK_DEBUG
@@ -208,6 +240,307 @@ void typecheck_reset_flags(verifier_state *state)
 }
 
 
+/****************************************************************************/
+/* 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->class);
+               }
+
+               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