* src/toolbox/Makefile.am (libtoolbox_la_SOURCES): Added set.[ch]
authorPeter Molnar <pm@complang.tuwien.ac.at>
Thu, 14 Feb 2008 13:49:34 +0000 (14:49 +0100)
committerPeter Molnar <pm@complang.tuwien.ac.at>
Thu, 14 Feb 2008 13:49:34 +0000 (14:49 +0100)
* src/toolbox/bitvector.h: Added missing include

* src/toolbox/set.c,
src/toolbox/set.h: New file. Set (of pointers) implementation.

* src/vm/jit/allocator/simplereg.c [ENABLE_SSA]: Fix for SSA.

* src/vm/jit/cfg.c,
src/vm/jit/cfg.h (cfg_insert_successors, cfg_add_root): New functions.
(cfg_build): Using controlflow constants rather than opcodes, fixed multiple
predecessors/successors problem.

* src/vm/jit/jit.c,
src/vm/jit/jit.h: Added various inline accessors for varinfo and instruction.
(basicblock [ENABLE_SSA]): Added new fields.

* src/vm/jit/optimizing/Makefile.am (SSA_SOURCES): Added ssa2.c.
* src/vm/jit/optimizing/dominators.c,
src/vm/jit/optimizing/dominators.h: Added cleaned up dominator tree and dominance
frontier implementation.

* src/vm/jit/optimizing/ssa.c: Hooked in cleaned up ssa and dominators.

* src/vm/jit/optimizing/ssa2.c,
src/vm/jit/optimizing/ssa2.h: New (temporary) files.
Added cleanead up ssa implementation. Currently renames only locals and passes
all dacapo benchmarks.

* src/vm/jit/python.c.
src/vm/jit/python.h: Changed a lot.

* src/vm/jit/show.c (show_basicblock): Support NULL bptr->javalocals.

18 files changed:
src/toolbox/Makefile.am
src/toolbox/bitvector.h
src/toolbox/set.c [new file with mode: 0644]
src/toolbox/set.h [new file with mode: 0644]
src/vm/jit/allocator/simplereg.c
src/vm/jit/cfg.c
src/vm/jit/cfg.h
src/vm/jit/jit.c
src/vm/jit/jit.h
src/vm/jit/optimizing/Makefile.am
src/vm/jit/optimizing/dominators.c
src/vm/jit/optimizing/dominators.h
src/vm/jit/optimizing/ssa.c
src/vm/jit/optimizing/ssa2.c [new file with mode: 0644]
src/vm/jit/optimizing/ssa2.h [new file with mode: 0644]
src/vm/jit/python.c
src/vm/jit/python.h
src/vm/jit/show.c

index 0a5d3377c4c05591cf38c283fa0f527fc6901ec8..e6d1085cd40a0158c499e11e25802783ae87ce1b 100644 (file)
@@ -47,6 +47,8 @@ libtoolbox_la_SOURCES = \
        list.h \
        logging.c \
        logging.h \
+       set.h \
+       set.c \
        tree.c \
        tree.h \
        util.c \
index a9428c226a725861155b2fd436c282b2039a8934..9ca46ea472989042233808e483d67ce0d830a3c4 100644 (file)
@@ -33,6 +33,8 @@
 #ifndef _BITVECTOR_H
 #define _BITVECTOR_H
 
+#include "vm/global.h"
+
 #if !defined(NDEBUG)
 #include <assert.h>
 
diff --git a/src/toolbox/set.c b/src/toolbox/set.c
new file mode 100644 (file)
index 0000000..b4fd7e7
--- /dev/null
@@ -0,0 +1,191 @@
+/* src/toolbox/set.c - Set implementation.
+
+   Copyright (C) 2008
+   CACAOVM - Verein zu Foerderung der freien virtuellen Machine 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.
+
+   This file implements a set of pointers.
+
+   The current implementation is naive and should be improved in the future,
+   so that the O(size) operations take O(log(size)) instead.
+
+   The representation of the set is an contingous unordered array of the
+   elements (pointers).
+*/
+
+#include "toolbox/set.h"
+
+#include <assert.h>
+
+#include "mm/memory.h"
+
+/* struct set ******************************************************************
+
+   Represents the set.
+
+*******************************************************************************/
+
+struct set {
+       void **elements;   /* An array of elements */
+       unsigned capacity; /* Size of elements */
+       unsigned size;     /* Current number of elements */
+};
+
+/* set_new ********************************************************************
+
+   Creates an instance of a set on the dump area.
+
+   IN:
+       capacity: Maximal number of elements of elements the set can hold.
+
+*******************************************************************************/
+
+set *set_new(unsigned capacity) {
+       set *s = DNEW(set);
+
+       s->elements = DMNEW(void *, capacity);
+       MZERO(s->elements, void *, capacity);
+       s->capacity = capacity;
+       s->size = 0;
+
+       return s;
+}
+
+/* set_insert ******************************************************************
+
+   Inserts element e into set s
+
+   The current implementation takes O(size).
+
+*******************************************************************************/
+
+void set_insert(set *s, void *element) {
+       unsigned i;
+
+       for (i = 0; i < s->size; ++i) {
+               if (s->elements[i] == element) {
+                       return;
+               }
+       }
+
+       assert(i < s->capacity);
+
+       s->size += 1;
+       s->elements[i] = element;
+}
+
+/* set_remove ******************************************************************
+
+   Removes element e into set s
+
+   The current implementation takes O(size).
+
+*******************************************************************************/
+
+void set_remove(set *s, void *element) {
+       unsigned i;
+       for (i = 0; i < s->size; ++i) {
+               if (s->elements[i] == element) {
+                       /* Do not creaet a "hole".
+                        * Overwrite this element with the last element.
+                        */
+                       if (i == (s->size - 1)) { /* The last one */
+                               s->elements[i] = NULL;
+                       } else {
+                               s->elements[i] = s->elements[s->size - 1];
+                               s->elements[s->size - 1] = NULL;
+                       }
+                       s->size -= 1;
+               }
+       }
+}
+
+/* set_size ********************************************************************
+
+   Returns the number of elements in the set s.
+   The complexity of the operation is O(1).
+
+*******************************************************************************/
+
+unsigned set_size(const set *s) {
+       return s->size;
+}
+
+/* set_empty *******************************************************************
+
+   Returns true, iif the set s is empty.
+   The complexity of the operation is O(1).
+
+*******************************************************************************/
+
+bool set_empty(const set *s) {
+       return s->size == 0;
+}
+
+/* set_contains ****************************************************************
+
+   Returns true, iif the set s contains element element.
+
+   The current implementation takes O(size).
+
+*******************************************************************************/
+
+bool set_contains(const set *s, void *element) {
+       unsigned i;
+       for (i = 0; i < s->size; ++i) {
+               if (s->elements[i] == element) {
+                       return true;
+               }
+       }
+       return false;
+}
+
+/* set_pop *********************************************************************
+
+   Pics and removes some element from the set s and returns it.
+   Returns NULL if the set s is empty.
+   The complexity of the operation is O(1).
+
+*******************************************************************************/
+
+void *set_pop(set *s) {
+       void *ret = NULL;
+
+       if (s->size > 0) {
+               ret = s->elements[s->size - 1];
+               s->elements[s->size - 1] = NULL;
+               s->size -= 1;
+       }
+
+       return ret;
+}
+
+/*
+ * These are local overrides for various environment variables in Emacs.
+ * Please do not remove this and leave it at the end of the file, where
+ * Emacs will automagically detect them.
+ * ---------------------------------------------------------------------
+ * Local variables:
+ * mode: c
+ * indent-tabs-mode: t
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ * vim:noexpandtab:sw=4:ts=4:
+ */
diff --git a/src/toolbox/set.h b/src/toolbox/set.h
new file mode 100644 (file)
index 0000000..491ce4f
--- /dev/null
@@ -0,0 +1,54 @@
+/* src/toolbox/set.h - Set implementation.
+
+   Copyright (C) 2008
+   CACAOVM - Verein zu Foerderung der freien virtuellen Machine 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 _TOOLBOX_SET_H
+#define _TOOLBOX_SET_H
+
+#include "vm/global.h"
+
+typedef struct set set;
+
+set *set_new(unsigned capacity);
+void set_insert(set *s, void *element);
+void set_remove(set *s, void *element);
+bool set_contains(const set *s, void *element);
+unsigned set_size(const set *s);
+bool set_empty(const set *s);
+void *set_pop(set *s);
+
+#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:
+ */
index d400406f0e4e5171dc0d032efd0d9c6501333f80..f5cd6fce9f2b665cb917c91e55fbcbd22d6fa442 100644 (file)
@@ -1350,7 +1350,7 @@ static void simplereg_allocate_temporaries(jitdata *jd)
 
                        /* assert that all copy counts are zero */
 
-#if !defined(NDEBUG)
+#if !defined(NDEBUG) && !defined(ENABLE_SSA)
                        for (i=0; i < TOTAL_REG_CNT; ++i)
                                assert(rd->regcopycount[i] == 0);
 #endif
index 607261eaea683702503ee9889c541f93971556c2..2df6dd7baa6be195a94fdb75c038ce4e49744156 100644 (file)
@@ -98,6 +98,25 @@ static void cfg_insert_predecessors(basicblock *bptr, basicblock *pbptr)
        bptr->predecessorcount++;
 }
 
+static void cfg_insert_successors(basicblock *bptr, basicblock *pbptr)
+{
+       basicblock **tbptr;
+       int          i;
+
+       tbptr = bptr->successors;
+
+       /* check if the successor is already stored in the array */
+
+       for (i = 0; i < bptr->successorcount; i++, tbptr++)
+               if (*tbptr == pbptr)
+                       return;
+
+       /* not found, insert it */
+
+       bptr->successors[bptr->successorcount] = pbptr;
+       bptr->successorcount++;
+}
+
 
 /* cfg_build *******************************************************************
 
@@ -134,35 +153,13 @@ bool cfg_build(jitdata *jd)
                        iptr--;
                }
 
-               switch (iptr->opc) {
-               case ICMD_RETURN:
-               case ICMD_IRETURN:
-               case ICMD_LRETURN:
-               case ICMD_FRETURN:
-               case ICMD_DRETURN:
-               case ICMD_ARETURN:
-               case ICMD_ATHROW:
+               switch (icmd_table[iptr->opc].controlflow) {
+
+               case CF_END:
                        break;
 
-               case ICMD_IFEQ:
-               case ICMD_IFNE:
-               case ICMD_IFLT:
-               case ICMD_IFGE:
-               case ICMD_IFGT:
-               case ICMD_IFLE:
-
-               case ICMD_IFNULL:
-               case ICMD_IFNONNULL:
-
-               case ICMD_IF_ICMPEQ:
-               case ICMD_IF_ICMPNE:
-               case ICMD_IF_ICMPLT:
-               case ICMD_IF_ICMPGE:
-               case ICMD_IF_ICMPGT:
-               case ICMD_IF_ICMPLE:
-
-               case ICMD_IF_ACMPEQ:
-               case ICMD_IF_ACMPNE:
+               case CF_IF:
+
                        bptr->successorcount += 2;
 
                        tbptr  = iptr->dst.block;
@@ -172,22 +169,22 @@ bool cfg_build(jitdata *jd)
                        ntbptr->predecessorcount++;
                        break;
 
-               case ICMD_JSR:
+               case CF_JSR:
                        bptr->successorcount++;
 
                        tbptr = iptr->sx.s23.s3.jsrtarget.block;
                        tbptr->predecessorcount++;
                        break;
 
-               case ICMD_GOTO:
-               case ICMD_RET:
+               case CF_GOTO:
+               case CF_RET:
                        bptr->successorcount++;
 
                        tbptr = iptr->dst.block;
                        tbptr->predecessorcount++;
                        break;
 
-               case ICMD_TABLESWITCH:
+               case CF_TABLE:
                        table = iptr->dst.table;
 
                        bptr->successorcount++;
@@ -207,7 +204,7 @@ bool cfg_build(jitdata *jd)
                        }
                        break;
                                        
-               case ICMD_LOOKUPSWITCH:
+               case CF_LOOKUP:
                        lookup = iptr->dst.lookup;
 
                        bptr->successorcount++;
@@ -258,74 +255,47 @@ bool cfg_build(jitdata *jd)
                        iptr--;
                }
 
-               switch (iptr->opc) {
-               case ICMD_RETURN:
-               case ICMD_IRETURN:
-               case ICMD_LRETURN:
-               case ICMD_FRETURN:
-               case ICMD_DRETURN:
-               case ICMD_ARETURN:
-               case ICMD_ATHROW:
+               switch (icmd_table[iptr->opc].controlflow) {
+
+               case CF_END:
                        break;
 
-               case ICMD_IFEQ:
-               case ICMD_IFNE:
-               case ICMD_IFLT:
-               case ICMD_IFGE:
-               case ICMD_IFGT:
-               case ICMD_IFLE:
-
-               case ICMD_IFNULL:
-               case ICMD_IFNONNULL:
-
-               case ICMD_IF_ICMPEQ:
-               case ICMD_IF_ICMPNE:
-               case ICMD_IF_ICMPLT:
-               case ICMD_IF_ICMPGE:
-               case ICMD_IF_ICMPGT:
-               case ICMD_IF_ICMPLE:
-
-               case ICMD_IF_ACMPEQ:
-               case ICMD_IF_ACMPNE:
+               case CF_IF:
+
                        tbptr  = iptr->dst.block;
                        ntbptr = bptr->next;
 
                        cfg_allocate_successors(bptr);
 
-                       bptr->successors[0] = tbptr;
-                       bptr->successors[1] = ntbptr;
-                       bptr->successorcount += 2;
+                       cfg_insert_successors(bptr, tbptr);
+                       cfg_insert_successors(bptr, ntbptr);
 
                        cfg_allocate_predecessors(tbptr);
                        cfg_allocate_predecessors(ntbptr);
 
-                       tbptr->predecessors[tbptr->predecessorcount] = bptr;
-                       tbptr->predecessorcount++;
-
-                       ntbptr->predecessors[ntbptr->predecessorcount] = bptr;
-                       ntbptr->predecessorcount++;
+                       cfg_insert_predecessors(tbptr, bptr);
+                       cfg_insert_predecessors(ntbptr, bptr);
                        break;
 
-               case ICMD_JSR:
+               case CF_JSR:
                        tbptr = iptr->sx.s23.s3.jsrtarget.block;
                        goto goto_tail;
 
-               case ICMD_GOTO:
-               case ICMD_RET:
+               case CF_GOTO:
+               case CF_RET:
+
                        tbptr = iptr->dst.block;
 goto_tail:
                        cfg_allocate_successors(bptr);
 
-                       bptr->successors[0] = tbptr;
-                       bptr->successorcount++;
+                       cfg_insert_successors(bptr, tbptr);
 
                        cfg_allocate_predecessors(tbptr);
 
-                       tbptr->predecessors[tbptr->predecessorcount] = bptr;
-                       tbptr->predecessorcount++;
+                       cfg_insert_predecessors(tbptr, bptr);
                        break;
 
-               case ICMD_TABLESWITCH:
+               case CF_TABLE:
                        table = iptr->dst.table;
 
                        tbptr = table->block;
@@ -333,13 +303,11 @@ goto_tail:
 
                        cfg_allocate_successors(bptr);
 
-                       bptr->successors[0] = tbptr;
-                       bptr->successorcount++;
+                       cfg_insert_successors(bptr, tbptr);
 
                        cfg_allocate_predecessors(tbptr);
 
-                       tbptr->predecessors[tbptr->predecessorcount] = bptr;
-                       tbptr->predecessorcount++;
+                       cfg_insert_predecessors(tbptr, bptr);
 
                        i = iptr->sx.s23.s3.tablehigh - iptr->sx.s23.s2.tablelow + 1;
 
@@ -347,28 +315,25 @@ goto_tail:
                                tbptr = table->block;
                                table++;
 
-                               bptr->successors[bptr->successorcount] = tbptr;
-                               bptr->successorcount++;
+                               cfg_insert_successors(bptr, tbptr);
 
                                cfg_allocate_predecessors(tbptr);
                                cfg_insert_predecessors(tbptr, bptr);
                        }
                        break;
                                        
-               case ICMD_LOOKUPSWITCH:
+               case CF_LOOKUP:
                        lookup = iptr->dst.lookup;
 
                        tbptr = iptr->sx.s23.s3.lookupdefault.block;
 
                        cfg_allocate_successors(bptr);
 
-                       bptr->successors[0] = tbptr;
-                       bptr->successorcount++;
+                       cfg_insert_successors(bptr, tbptr);
 
                        cfg_allocate_predecessors(tbptr);
 
-                       tbptr->predecessors[tbptr->predecessorcount] = bptr;
-                       tbptr->predecessorcount++;
+                       cfg_insert_predecessors(tbptr, bptr);
 
                        i = iptr->sx.s23.s2.lookupcount;
 
@@ -376,8 +341,7 @@ goto_tail:
                                tbptr = lookup->target.block;
                                lookup++;
 
-                               bptr->successors[bptr->successorcount] = tbptr;
-                               bptr->successorcount++;
+                               cfg_insert_successors(bptr, tbptr);
 
                                cfg_allocate_predecessors(tbptr);
                                cfg_insert_predecessors(tbptr, bptr);
@@ -409,6 +373,45 @@ goto_tail:
        return true;
 }
 
+/* cfg_add_root ****************************************************************
+
+   Adds an empty root basicblock.
+   The numbers of all other basicblocks are set off by one.
+   Needed for some analyses that require the root basicblock to have no 
+   predecessors and to perform special initializations.
+
+*******************************************************************************/
+
+void cfg_add_root(jitdata *jd) {
+       basicblock *root, *zero, *it;
+
+       zero = jd->basicblocks;
+
+       root = DNEW(basicblock);
+       MZERO(root, basicblock, 1);
+
+       root->successorcount = 1;
+       root->successors = DMNEW(basicblock *, 1);
+       root->successors[0] = zero;
+       root->next = zero;
+       root->nr = 0;
+       root->type = BBTYPE_STD;
+
+       if (zero->predecessorcount == 0) {
+               zero->predecessors = DNEW(basicblock *);
+       } else {
+               zero->predecessors = DMREALLOC(zero->predecessors, basicblock *, zero->predecessorcount, zero->predecessorcount + 1);
+       }
+       zero->predecessors[zero->predecessorcount] = root;
+       zero->predecessorcount += 1;
+
+       jd->basicblocks = root;
+       jd->basicblockcount += 1;
+
+       for (it = zero; it; it = it->next) {
+               it->nr += 1;
+       }
+}
 
 /*
  * These are local overrides for various environment variables in Emacs.
index 18adc1d8609627aff8f5df39eb37baf68222d7e6..a82b75ad7036f4b3a9ed619c013743f642712df8 100644 (file)
@@ -44,6 +44,8 @@
 
 bool cfg_build(jitdata *jd);
 
+void cfg_add_root(jitdata *jd);
+
 #endif /* _CFG_H */
 
 
index 09fc0c08919144dd114f29db14fd0780f6f2fcce..a08de3de60fa334786b111e6382e9b0c14230107 100644 (file)
@@ -560,6 +560,9 @@ u1 *jit_recompile(methodinfo *m)
        return r;
 }
 
+#if defined(ENABLE_PM_HACKS)
+#include "vm/jit/jit_pm_1.inc"
+#endif
 
 /* jit_compile_intern **********************************************************
 
@@ -730,12 +733,6 @@ static u1 *jit_compile_intern(jitdata *jd)
                }
 #endif
 
-#if defined(ENABLE_PYTHON)
-               if (!pythonpass_run(jd, "langauer_tarjan", "main")) {
-                       /*return NULL;*/
-               }
-#endif
-
 #if defined(ENABLE_PROFILING)
                /* Basic block reordering.  I think this should be done after
                   if-conversion, as we could lose the ability to do the
@@ -748,6 +745,9 @@ static u1 *jit_compile_intern(jitdata *jd)
                }
 #endif
 
+#if defined(ENABLE_PM_HACKS)
+#include "vm/jit/jit_pm_2.inc"
+#endif
                DEBUG_JIT_COMPILEVERBOSE("Allocating registers: ");
 
 #if defined(ENABLE_LSRA) && !defined(ENABLE_SSA)
@@ -764,8 +764,9 @@ static u1 *jit_compile_intern(jitdata *jd)
                /* allocate registers */
                if ((opt_lsra) && (jd->exceptiontablelength == 0)) {
                        jd->ls = DNEW(lsradata);
+                       jd->ls = NULL;
                        ssa(jd);
-                       lsra(jd);
+                       /*lsra(jd);*/ regalloc(jd);
 
                        STATISTICS(count_methods_allocated_by_lsra++);
 
@@ -1177,6 +1178,15 @@ void jit_check_basicblock_numbers(jitdata *jd)
 }
 #endif /* !defined(NDEBUG) */
 
+methoddesc *instruction_call_site(const instruction *iptr) {
+       if (iptr->opc == ICMD_BUILTIN) {
+               return iptr->sx.s23.s3.bte->md;
+       } else if (INSTRUCTION_IS_UNRESOLVED(iptr)) {
+               return iptr->sx.s23.s3.um->methodref->parseddesc.md;
+       } else {
+               return iptr->sx.s23.s3.fmiref->p.method->parseddesc;
+       }
+}
 
 /*
  * These are local overrides for various environment variables in Emacs.
index d98a72661d41491e9ff2fe6cbcd912f8b064da23..c097c32eda03e7391cb12fca95c56eabb1504d32 100644 (file)
@@ -70,6 +70,7 @@ typedef struct exception_entry exception_entry;
 
 #include "vm/jit/verify/typeinfo.h"
 
+#include "vmcore/descriptor.h"
 #include "vmcore/method.h"
 #include "vmcore/references.h"
 
@@ -212,17 +213,6 @@ struct jitdata {
     ((jd)->flags & JITDATA_FLAG_VERBOSECALL)
 
 
-/* macros for accessing variables *********************************************
-   Use VAROP for s1, s2, s3 and dst operands (eg. VAROP(iptr->s1)),
-   use VAR if you have the variable index (eg. VAR(iptr->sx.s23.s2.args[0])).
-
-******************************************************************************/
-
-#define VAROP(v) (jd->var + (v).varindex)
-#define VAR(i)   (jd->var + (i))
-
-
 /* exception_entry ************************************************************/
 
 struct exception_entry {
@@ -271,6 +261,38 @@ struct stackelement {
        s4       varnum;            /* number of variable                         */
 };
 
+/* macros for accessing variables *********************************************
+   Use VAROP for s1, s2, s3 and dst operands (eg. VAROP(iptr->s1)),
+   use VAR if you have the variable index (eg. VAR(iptr->sx.s23.s2.args[0])).
+
+******************************************************************************/
+
+#define VAROP(v) (jd->var + (v).varindex)
+#define VAR(i)   (jd->var + (i))
+
+static inline bool var_is_local(const jitdata *jd, s4 i) {
+       return (i < jd->localcount);
+}
+
+static inline bool var_is_prealloc(const jitdata *jd, s4 i) {
+       return ((i >= jd->localcount) && (jd->var[i].flags & PREALLOC));
+}
+
+static inline bool var_is_inout(const jitdata *jd, s4 i) {
+       const varinfo *v = jd->var + i;
+       return ((i >= jd->localcount) && !(v->flags & PREALLOC) && (v->flags & INOUT));
+}
+
+static inline bool var_is_temp(const jitdata *jd, s4 i) {
+       const varinfo *v = jd->var + i;
+       return ((i >= jd->localcount) && !(v->flags & PREALLOC) && !(v->flags & INOUT));
+}
+
+static inline bool var_is_saved(const jitdata *jd, s4 i) {
+       return (jd->var[i].flags & SAVEDVAR);
+}
+
 
 /**************************** instruction structure ***************************/
 
@@ -427,7 +449,6 @@ struct instruction {
                        md = iptr->sx.s23.s3.fmiref->parseddesc.md; \
        } while (0)
 
-
 /* additional info structs for special instructions ***************************/
 
 /* for ICMD_INLINE_START and ICMD_INLINE_END */
@@ -518,6 +539,19 @@ struct basicblock {
        insinfo_inline *inlineinfo; /* inlineinfo for the start of this block     */
 
        s4            mpc;          /* machine code pc at start of block          */
+
+       /* TODO: those fields are probably usefull for other passes as well. */
+
+#if defined(ENABLE_SSA)         
+       basicblock   *idom;         /* Immediate dominator, parent in dominator tree */
+       basicblock  **domsuccessors;/* Children in dominator tree                 */
+       s4            domsuccessorcount;
+
+       basicblock  **domfrontier;  /* Dominance frontier                         */
+       s4            domfrontiercount;
+
+       void         *vp;           /* Freely used by different passes            */
+#endif
 };
 
 /* [+]...the javalocals array: This array is indexed by the javaindex (the    */
@@ -921,6 +955,20 @@ enum {
        ICMD_BUILTIN          = 255         /* internal opcode                    */
 };
 
+/* Additional instruction accessors */
+
+methoddesc *instruction_call_site(const instruction *iptr);
+
+static inline bool instruction_has_dst(const instruction *iptr) {
+       if (
+               (icmd_table[iptr->opc].dataflow == DF_INVOKE) ||
+               (icmd_table[iptr->opc].dataflow == DF_BUILTIN)
+       ) {
+               return instruction_call_site(iptr)->returntype.type != TYPE_VOID;
+       } else {
+               return icmd_table[iptr->opc].dataflow >= DF_DST_BASE;
+       }
+}
 
 /***************************** register types *********************************/
 
index 4e9d34a7292ac27a5a21f0625438458586f64b8f..02b29221bc79311cac825b26959e431529a37789 100644 (file)
@@ -64,7 +64,8 @@ SSA_SOURCES = \
        dominators.c \
        dominators.h \
        lifetimes.c \
-       lifetimes.h
+       lifetimes.h \
+       ssa2.c
 endif
 
 noinst_LTLIBRARIES = \
index 82768c3417d2e1b6479cf0fe9246aa0a5ffad579..71352b76251bccd65f854ff5cb51bb3960932bbe 100644 (file)
@@ -260,6 +260,391 @@ void dom_Link(dominatordata *dd, int p, int n) {
        dd->best[n] = n;
 }
 
+/*********************************************************/
+
+typedef struct basicblock_info basicblock_info;
+
+struct basicblock_info {
+       basicblock *bb;
+       int dfnum;
+       basicblock_info *parent;
+       basicblock_info *semi;
+       basicblock_info *ancestor;
+       basicblock_info *best;
+       basicblock_info *idom;
+       basicblock_info *samedom;
+       basicblock_info **bucket;
+       unsigned bucketcount;
+};
+
+typedef struct dominator_tree_info dominator_tree_info;
+
+struct dominator_tree_info {
+       jitdata *jd;
+       basicblock_info *basicblocks;
+       basicblock_info **df_map;
+       unsigned df_counter;
+};
+
+static dominator_tree_info *dominator_tree_init(jitdata *jd) {
+       dominator_tree_info *di;
+       basicblock *itb;
+       basicblock_info *iti;
+
+       di = DNEW(dominator_tree_info);
+
+       di->jd = jd;
+
+       di->basicblocks = DMNEW(basicblock_info, jd->basicblockcount);
+       MZERO(di->basicblocks, basicblock_info, jd->basicblockcount);
+       
+       for (iti = di->basicblocks; iti != di->basicblocks + jd->basicblockcount; ++iti) {
+               iti->dfnum = -1;
+               iti->bucket = DMNEW(basicblock_info *, jd->basicblockcount);
+               iti->bucketcount = 0;
+       }
+
+       for (itb = jd->basicblocks; itb; itb = itb->next) {
+               di->basicblocks[itb->nr].bb = itb;
+       }
+
+       di->df_map = DMNEW(basicblock_info *, jd->basicblockcount);
+       MZERO(di->df_map, basicblock_info *, jd->basicblockcount);
+
+       di->df_counter = 0;
+
+       return di;
+}
+
+inline basicblock_info *dominator_tree_get_basicblock(dominator_tree_info *di, basicblock *bb) {
+       return di->basicblocks + bb->nr;
+}
+
+static void dominator_tree_depth_first_search(
+       dominator_tree_info *di, basicblock_info *parent, basicblock_info *node
+) {
+       basicblock **it;
+
+       if (node->dfnum == -1) {
+
+               node->dfnum = di->df_counter;
+               node->parent = parent;
+               di->df_map[di->df_counter] = node;
+               di->df_counter += 1;
+
+               for (it = node->bb->successors; it != node->bb->successors + node->bb->successorcount; ++it) {
+                       dominator_tree_depth_first_search(
+                               di, node, 
+                               dominator_tree_get_basicblock(di, *it)
+                       );
+               }
+       }
+}
+
+void dominator_tree_link(dominator_tree_info *di, basicblock_info *parent, basicblock_info *node) {
+       node->ancestor = parent;
+       node->best = node;
+}
+
+basicblock_info *dominator_tree_ancestor_with_lowest_semi(
+       dominator_tree_info *di, basicblock_info *node
+) {
+       basicblock_info *a, *b;
+
+       a = node->ancestor;
+
+       if (a->ancestor != NULL) {
+               b = dominator_tree_ancestor_with_lowest_semi(di, a);
+               node->ancestor = a->ancestor;
+               if (b->semi->dfnum < node->best->semi->dfnum) {
+                       node->best = b;
+               }
+       }
+
+       return node->best;
+}
+
+void dominator_tree_build_intern(jitdata *jd) {
+       
+       dominator_tree_info *di;
+       basicblock_info *node;
+       basicblock_info *semicand;
+       basicblock_info *pred;
+       basicblock **itb;
+       basicblock_info **itii;
+       basicblock_info *v, *y;
+       int i;
+
+       di = dominator_tree_init(jd);
+
+       dominator_tree_depth_first_search(di, NULL, dominator_tree_get_basicblock(di, jd->basicblocks));
+
+       for (i = di->df_counter - 1; i >= 1; --i) {
+               node = di->df_map[i];
+
+               node->semi = node->parent;
+
+               for (
+                       itb = node->bb->predecessors; 
+                       itb != node->bb->predecessors + node->bb->predecessorcount; 
+                       ++itb
+               ) {
+
+                       pred = dominator_tree_get_basicblock(di, *itb);
+
+                       if (pred->dfnum <= node->dfnum) {
+                               semicand = pred;
+                       } else {
+                               semicand = dominator_tree_ancestor_with_lowest_semi(di, pred)->semi;
+                       }
+
+                       if (semicand->dfnum < node->semi->dfnum) {
+                               node->semi = semicand;
+                       }
+               }
+
+               node->semi->bucket[node->semi->bucketcount] = node;
+               node->semi->bucketcount += 1;
+
+               dominator_tree_link(di, node->parent, node);
+
+               for (itii = node->parent->bucket; itii != node->parent->bucket + node->parent->bucketcount; ++itii) {
+                       v = *itii;
+                       y = dominator_tree_ancestor_with_lowest_semi(di, v);
+                       if (y->semi == v->semi) {
+                               v->idom = node->parent;
+                       } else {
+                               v->samedom = y;
+                       }
+               }
+
+               node->parent->bucketcount = 0;
+       }
+
+       for (i = 1; i < di->df_counter; ++i) {
+               node = di->df_map[i];
+               if (node->samedom) {
+                       node->idom = node->samedom->idom;
+               }
+
+               node->bb->idom = node->idom->bb;
+               node->idom->bb->domsuccessorcount += 1;
+       }
+}
+
+void dominator_tree_link_children(jitdata *jd) {
+       basicblock *bb;
+       int32_t ds;
+       /* basicblock number => current number of successors */
+       unsigned *numsuccessors;
+
+       /* Allocate memory for successors */
+
+       for (bb = jd->basicblocks; bb; bb = bb->next) {
+               if (bb->domsuccessorcount > 0) {
+                       bb->domsuccessors = DMNEW(basicblock *, bb->domsuccessorcount);
+               }
+       }
+
+       /* Allocate memory for per basic block counter of successors */
+
+       ds = dump_size();
+       numsuccessors = DMNEW(unsigned, jd->basicblockcount);
+       MZERO(numsuccessors, unsigned, jd->basicblockcount);
+
+       /* Link immediate dominators with successors */
+
+       for (bb = jd->basicblocks; bb; bb = bb->next) {
+               if (bb->idom) {
+                       bb->idom->domsuccessors[numsuccessors[bb->idom->nr]] = bb;
+                       numsuccessors[bb->idom->nr] += 1;
+               }
+       }
+
+       /* Free memory */
+
+       dump_release(ds);
+}
+
+bool dominator_tree_build(jitdata *jd) {
+       int32_t ds;
+       
+       ds = dump_size();
+       dominator_tree_build_intern(jd);
+       dump_release(ds);
+
+       dominator_tree_link_children(jd);
+
+       return true;
+}
+
+typedef struct dominance_frontier_item dominance_frontier_item;
+
+struct dominance_frontier_item {
+       basicblock *bb;
+       dominance_frontier_item *next;
+};
+
+typedef struct dominance_frontier_list dominance_frontier_list;
+
+struct dominance_frontier_list {
+       dominance_frontier_item *first;
+       unsigned count;
+};
+
+void dominance_frontier_list_add(dominance_frontier_list *list, basicblock *bb) {
+       dominance_frontier_item *item;
+       
+       for (item = list->first; item; item = item->next) {
+               if (item->bb == bb) return;
+       }
+
+       item = DNEW(dominance_frontier_item);
+       item->bb = bb;
+       item->next = list->first;
+       list->first = item;
+       list->count += 1;
+}
+
+typedef struct dominance_frontier_info dominance_frontier_info;
+
+struct dominance_frontier_info {
+       jitdata *jd;
+       dominance_frontier_list *map;
+};
+
+dominance_frontier_info *dominance_frontier_init(jitdata *jd) {
+       dominance_frontier_info *dfi = DNEW(dominance_frontier_info);
+
+       dfi->jd = jd;
+
+       dfi->map = DMNEW(dominance_frontier_list, jd->basicblockcount);
+       MZERO(dfi->map, dominance_frontier_list, jd->basicblockcount);
+
+       return dfi;
+}
+
+bool dominance_frontier_dominates(basicblock *d, basicblock *x) {
+       x = x->idom;
+
+       while (x != NULL) {
+               if (x == d) {
+                       return true;
+               }
+               x = x->idom;
+       }
+
+       return false;
+}
+
+void dominance_frontier_for_block(dominance_frontier_info *dfi, basicblock *b) {
+       basicblock **it;
+       dominance_frontier_item *itdf;
+       dominance_frontier_list s = { NULL, 0 };
+
+       for (it = b->successors; it != b->successors + b->successorcount; ++it) {
+               if ((*it)->idom != b) {
+                       dominance_frontier_list_add(&s, *it);
+               }
+       }
+
+       for (it = b->domsuccessors; it != b->domsuccessors + b->domsuccessorcount; ++it) {
+               dominance_frontier_for_block(dfi, *it);
+               for (itdf = dfi->map[(*it)->nr].first; itdf; itdf = itdf->next) {
+                       if (! dominance_frontier_dominates(b, itdf->bb)) {
+                               dominance_frontier_list_add(&s, itdf->bb);
+                       }
+               }
+       }
+
+       dfi->map[b->nr] = s;
+}
+
+void dominance_frontier_store(dominance_frontier_info *dfi) {
+       basicblock *bb;
+       dominance_frontier_item *itdf;
+       basicblock **itout;
+
+       for (bb = dfi->jd->basicblocks; bb; bb = bb->next) {
+               if (bb->nr < dfi->jd->basicblockcount) {
+                       if (dfi->map[bb->nr].count > 0) {
+                               bb->domfrontiercount = dfi->map[bb->nr].count;
+                               itout = bb->domfrontier = DMNEW(basicblock *, bb->domfrontiercount);
+                               for (itdf = dfi->map[bb->nr].first; itdf; itdf = itdf->next) {
+                                       *itout = itdf->bb;
+                                       itout += 1;
+                               }
+                       }
+               }
+       }
+}
+
+bool dominance_frontier_build(jitdata *jd) {
+       int32_t ds = dump_size();
+
+       dominance_frontier_info *dfi = dominance_frontier_init(jd);
+       dominance_frontier_for_block(dfi, jd->basicblocks);
+       dominance_frontier_store(dfi);
+}
+
+#include "vm/jit/show.h"
+#include "vm/jit/python.h"
+
+extern void graph_add_edge( graphdata *gd, int from, int to );
+
+void dominator_tree_validate(jitdata *jd, dominatordata *_dd) {
+       int32_t ds = dump_size();
+       graphdata *gd;
+       int i, j;
+       basicblock *bptr, **it;
+       dominatordata *dd;
+       int *itnr;
+       bool found;
+
+       fprintf(stderr, "%s/%s: \n", jd->m->class->name->text, jd->m->name->text);
+       gd = graph_init(jd->basicblockcount);
+
+       for (bptr = jd->basicblocks; bptr; bptr = bptr->next) {
+               for (it = bptr->successors; it != bptr->successors + bptr->successorcount; ++it) {
+                       graph_add_edge(gd, bptr->nr, (*it)->nr);
+               }
+       }
+
+       dd = compute_Dominators(gd, jd->basicblockcount);
+
+       for (bptr = jd->basicblocks; bptr; bptr = bptr->next) {
+               if (bptr->flags >= BBREACHED) {
+                       if (bptr->idom == NULL) {
+                               if (!(dd->idom[bptr->nr] == -1)) {
+                                       printf("-- %d %d\n", dd->idom[bptr->nr], bptr->nr);
+                                       assert(0);
+                               }
+                       } else {
+                               assert(dd->idom[bptr->nr] == bptr->idom->nr);
+                       }
+               }
+       }
+
+       computeDF(gd, dd, jd->basicblockcount, 0);
+
+       for (bptr = jd->basicblocks; bptr; bptr = bptr->next) {
+               if (bptr->flags >= BBREACHED) {
+                       assert(bptr->domfrontiercount == dd->num_DF[bptr->nr]);
+                       for (itnr = dd->DF[bptr->nr]; itnr != dd->DF[bptr->nr] + dd->num_DF[bptr->nr]; ++itnr) {
+                               found = false;
+                               for (it = bptr->domfrontier; it != bptr->domfrontier + bptr->domfrontiercount; ++it) {
+                                       if ((*it)->nr == *itnr) {
+                                               found =true; break;
+                                       }
+                               }
+                               assert(found);
+                       }
+               }
+       }
+
+       dump_release(ds);
+}
+
 /*
  * 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
index 13ac48c0cff3fd377e7ee341de9f11bcddabd6b4..376b78e4a601911acf9349da6d5d8c70ad829e9a 100644 (file)
@@ -70,6 +70,14 @@ typedef struct dominatordata dominatordata;
 dominatordata *compute_Dominators(graphdata *gd, int basicblockcount);
 void computeDF(graphdata *gd, dominatordata *dd, int basicblockcount, int n);
 
+/* ............................... */
+
+bool dominator_tree_build(jitdata *jd);
+
+bool dominance_frontier_build(jitdata *jd);
+
+void dominator_tree_validate(jitdata *jd, dominatordata *dd);
+
 #endif /* _DOMINATORS_H */
 
 /*
index e7dcbe02ed1a92a94df13ccb17d842e2cf6dec88..1e443e387e48bce70f4a2e74dfbdbe5f66f7b743 100644 (file)
@@ -48,6 +48,8 @@
 #include "vm/jit/optimizing/ssa_rename.h"
 #include "vm/jit/optimizing/ssa_phi.h"
 
+#include "vm/jit/python.h"
+
 #if defined(SSA_DEBUG_VERBOSE)
 #include "vmcore/options.h"   /* compileverbose */
 #endif
@@ -99,6 +101,7 @@ page 441 Algorithm 19.6. Inserting phi-functions:
            W <- W join {Y}
 
 ******************************************************************************/
+void xssa(jitdata *jd);
 void ssa(jitdata *jd) {
        struct dominatordata *dd;
        lsradata *ls;
@@ -113,6 +116,17 @@ void ssa(jitdata *jd) {
        }
 #endif
 
+       cfg_add_root(jd);
+       dominator_tree_build(jd);
+       /*pythonpass_run(jd, "foo", "cfg_print");*/
+       dominance_frontier_build(jd);
+       /*dominator_tree_validate(jd, dd);*/
+       /*pythonpass_run(jd, "ssa2", "main");*/
+       pythonpass_run(jd, "foo", "before");
+       xssa(jd);
+       pythonpass_run(jd, "foo", "after");
+       return;
+
        ls = jd->ls;
 
     ssa_init(jd);
diff --git a/src/vm/jit/optimizing/ssa2.c b/src/vm/jit/optimizing/ssa2.c
new file mode 100644 (file)
index 0000000..9bcc518
--- /dev/null
@@ -0,0 +1,618 @@
+#include "config.h"
+
+#include "mm/memory.h"
+
+#include "toolbox/bitvector.h"
+#include "toolbox/set.h"
+#include "toolbox/worklist.h"
+
+#include "vm/global.h"
+#include "vm/jit/jit.h"
+
+#if 1
+#define printf(...) do { if (getenv("VERB")) printf(__VA_ARGS__); } while (0)
+#define show_method(...) do { if (getenv("VERB")) show_method(__VA_ARGS__); } while (0)
+#endif
+
+typedef struct phi_function {
+       s4 dst;
+       s4 *args;
+} phi_function;
+
+typedef struct basicblock_info {
+       bitvector defines;
+       bitvector phi;
+       unsigned phi_count;
+       phi_function *phi_functions;
+} basicblock_info;
+
+typedef struct var_info {
+       set *work;
+       unsigned num_defs;
+
+       unsigned offset;
+
+       unsigned count;
+       unsigned *stack;
+       unsigned *stack_top;
+
+} var_info;
+
+typedef struct ssa_info {
+       jitdata *jd;
+       var_info *vars;
+       unsigned vars_count;
+       unsigned total_local_count;
+} ssa_info;
+
+static inline basicblock_info *bb_info(basicblock *bb) {
+       return (basicblock_info *)(bb->vp);
+}
+
+static ssa_info *ssa_init(jitdata *jd) {
+       unsigned i;
+       ssa_info *ssa;
+
+       ssa = DNEW(ssa_info);
+       ssa->jd = jd;
+       ssa->vars_count = jd->localcount;
+
+       ssa->vars = DMNEW(var_info, ssa->vars_count);
+       MZERO(ssa->vars, var_info, ssa->vars_count);
+       for (i = 0; i < ssa->vars_count; ++i) {
+               ssa->vars[i].work = set_new(jd->basicblockcount);
+       }
+
+       return ssa;
+}
+
+static void ssa_place_phi_functions(ssa_info *ssa) {
+
+       basicblock *bptr, *Y, *n, **itdf;
+       basicblock_info *bbi;
+       instruction *iptr;
+       s4 a;
+       set *work;
+
+       for (bptr = ssa->jd->basicblocks; bptr; bptr = bptr->next) {
+       
+               bbi = DNEW(basicblock_info);
+               bbi->defines = bv_new(ssa->vars_count);
+               bbi->phi = bv_new(ssa->vars_count);
+               bbi->phi_count = 0;
+
+               bptr->vp = bbi;
+
+               for (iptr = bptr->iinstr; iptr != bptr->iinstr + bptr->icount; ++iptr) {
+                       if (instruction_has_dst(iptr)) {
+                               if (
+                                       var_is_local(ssa->jd, iptr->dst.varindex) 
+                               ) {
+                                       /* A_orig */
+                                       bv_set_bit(bbi->defines, iptr->dst.varindex);
+                                       /* defsites */
+                                       set_insert(ssa->vars[iptr->dst.varindex].work, bptr);
+                                       /* Accout definition */
+                                       ssa->vars[iptr->dst.varindex].num_defs += 1;
+                               }
+                       }
+               }
+       }
+
+       bptr = ssa->jd->basicblocks;
+       bbi = bb_info(bptr);
+       for (a = 0;  a < ssa->vars_count; ++a) {
+               bv_set_bit(bbi->defines, a);
+               set_insert(ssa->vars[a].work, bptr);
+               ssa->vars[a].num_defs += 1;
+       }
+
+       for (a = 0; a < ssa->vars_count; ++a) {
+               work = ssa->vars[a].work;
+               while (! set_empty(work)) {
+                       n = (basicblock *)set_pop(work);
+                       for (
+                               itdf = n->domfrontier; 
+                               itdf != n->domfrontier + n->domfrontiercount; 
+                               ++itdf
+                       ) {
+                               Y = *itdf;
+                               if (! bv_get_bit(bb_info(Y)->phi, a)) {
+                                       bv_set_bit(bb_info(Y)->phi, a);
+                                       printf(" *** BB %d: phi for var %d\n", Y->nr, a);
+                                       bb_info(Y)->phi_count += 1;
+                                       ssa->vars[a].num_defs += 1;
+                                       if (! bv_get_bit(bb_info(Y)->defines, a)) {
+                                               set_insert(work, Y);
+                                       }
+                               }
+                       }
+               }
+       }
+}
+
+static void ssa_create_phi_functions(ssa_info *ssa) {
+       unsigned i, j;
+       basicblock_info *bbi;
+       basicblock *bptr;
+       phi_function *itph;
+
+       for (bptr = ssa->jd->basicblocks; bptr; bptr = bptr->next) {
+
+               bbi = bb_info(bptr);
+               bbi->phi_functions = DMNEW(phi_function, bbi->phi_count);
+               itph = bbi->phi_functions;
+
+               for (i = 0; i < ssa->vars_count; ++i) {
+                       if (bv_get_bit(bbi->phi, i)) {
+                               itph->dst = i;
+                               itph->args = DMNEW(s4, bptr->predecessorcount);
+                               for (j = 0; j < bptr->predecessorcount; ++j) {
+                                       itph->args[j] = i;
+                               }
+                               itph += 1;
+                       }
+               }
+       }
+}
+
+static void ssa_calculate_offsets(ssa_info *ssa) {
+       int i;
+       unsigned cur_offset = ssa->jd->localcount;
+
+       ssa->total_local_count = 0;
+
+       for (i = 0; i < ssa->vars_count; ++i) {
+
+               ssa->vars[i].offset = cur_offset;
+
+               ssa->total_local_count += ssa->vars[i].num_defs;
+
+               if (ssa->vars[i].num_defs > 1) {
+                       cur_offset += (ssa->vars[i].num_defs - 1);
+               }
+       }
+}
+
+
+static s4 ssa_rename_var(ssa_info *ssa, s4 var, unsigned index) {
+       s4 ret;
+#define return ret=
+       if (var_is_local(ssa->jd, var)) {
+               assert(0 < index && index <= ssa->vars[var].num_defs);
+               if (index == 1) {
+                       return var;
+               } else {
+                       return ssa->vars[var].offset + (index - 2);
+               }
+               assert(ret < ssa->total_local_count);
+       } else {
+               return ssa->total_local_count + (var - ssa->vars_count);
+       }
+#undef return
+       printf(" *** rename %c %d vers %d => %d\n", var_is_local(ssa->jd, var) ? 'L' : 'O',  var, index, ret);
+       return ret;
+}
+
+static void ssa_rename_uses(ssa_info *ssa, s4 *uses, unsigned uses_count) {
+       while (uses_count > 0) {
+               if (var_is_local(ssa->jd, *uses)) {
+                       *uses = ssa_rename_var(ssa, *uses, *(ssa->vars[*uses].stack_top));
+               } else {
+                       *uses = ssa_rename_var(ssa, *uses, 0);
+               }
+               uses_count -= 1;
+               uses += 1;
+       }
+}
+
+static void ssa_rename_definition(ssa_info *ssa, s4 *pdef) {
+       s4 def = *pdef;
+       unsigned i = 0;
+
+       if (var_is_local(ssa->jd, def)) {
+               ssa->vars[def].count += 1;
+               i = ssa->vars[def].count;
+               ssa->vars[def].stack_top += 1;
+               *(ssa->vars[def].stack_top) = i;
+       }
+
+       *pdef = ssa_rename_var(ssa, def, i);
+}
+
+static void ssa_rename_block(ssa_info *ssa, basicblock *bptr) {
+
+       basicblock_info *bbi = bb_info(bptr);
+       s4 s[3];
+       s4 *uses;
+       unsigned uses_count;
+       instruction *iptr;
+       basicblock **itsucc, **itpred, **itdsucc, *Y;
+       phi_function *itph;
+       unsigned j;
+       s4 i, tmp;
+       s4 a;
+       s4 **orig_stack_top;
+
+       /* XXX */
+       orig_stack_top = DMNEW(s4 *, ssa->vars_count);
+       for (a = 0; a < ssa->vars_count; ++a) orig_stack_top[a] = ssa->vars[a].stack_top;
+
+               int jj;
+
+printf(" *** === %d ===========\n", bptr->nr);
+
+       ssa_rename_uses(ssa, bptr->invars, bptr->indepth);
+
+       /* Phi functions are the first instructions in the block */
+printf(" *** --- phis ---------\n");
+       for (
+               itph = bbi->phi_functions; 
+               itph != bbi->phi_functions + bbi->phi_count;
+               ++itph
+       ) {
+               ssa_rename_definition(ssa, &(itph->dst));
+       }
+
+printf(" *** --- vars ---------\n");
+       
+       if (bptr == ssa->jd->basicblocks) {
+               for (i = 0; i < ssa->jd->localcount; ++i) {
+                       tmp = i;
+                       ssa_rename_definition(ssa, &tmp);
+               }
+       }
+
+       for (iptr = bptr->iinstr; iptr != bptr->iinstr + bptr->icount; ++iptr) {
+
+               /* Determine uses */
+
+               uses_count = 0;
+
+               switch (icmd_table[iptr->opc].dataflow) {
+                       case DF_3_TO_0:
+                       case DF_3_TO_1:
+                               s[2] = iptr->sx.s23.s3.varindex;
+                               uses_count += 1;
+
+                       case DF_2_TO_0:
+                       case DF_2_TO_1:
+                               s[1] = iptr->sx.s23.s2.varindex;
+                               uses_count += 1;
+
+                       case DF_1_TO_0:
+                       case DF_1_TO_1:
+                       case DF_COPY:
+                       case DF_MOVE:
+                               s[0] = iptr->s1.varindex;
+                               uses_count += 1;
+
+                               uses = s;
+                               break;
+               
+                       case DF_N_TO_1:
+                       case DF_INVOKE:
+                       case DF_BUILTIN:
+
+                               uses = iptr->sx.s23.s2.args;
+                               uses_count = iptr->s1.argcount;
+                               break;
+
+               }
+
+               printf(" *** %s uses ", icmd_table[iptr->opc].name);
+               for (jj = 0; jj < uses_count; ++jj) printf("%d ",uses[jj]);
+               printf("\n");
+
+               if (uses_count > 0) {
+                       /* Update uses, if there are any */
+
+                       ssa_rename_uses(ssa, uses, uses_count);
+
+                       /* If uses were s, then we need to update the instruction */
+
+                       if (uses == s) {
+                               switch (uses_count) {
+                                       case 3:
+                                               iptr->sx.s23.s3.varindex = s[2];
+                                       case 2:
+                                               iptr->sx.s23.s2.varindex = s[1];
+                                       case 1:
+                                               iptr->s1.varindex = s[0];
+                               }
+                       }
+               }
+
+               /* Rename definitions */
+
+               if (instruction_has_dst(iptr)) {
+                       printf(" *** %s defines %d\n", icmd_table[iptr->opc].name, iptr->dst.varindex);
+                       ssa_rename_definition(ssa, &(iptr->dst.varindex));
+               }
+
+       }
+
+       for (i = 0; i < bptr->outdepth; ++i) {
+               ssa_rename_definition(ssa, bptr->outvars + i);
+       }
+
+       /* Successors */
+
+       printf(" *** succs %d\n", bptr->successorcount);
+
+       for (
+               itsucc = bptr->successors; 
+               itsucc != bptr->successors + bptr->successorcount; 
+               ++itsucc
+       ) {
+               Y = *itsucc;
+
+               for (
+                       itpred = Y->predecessors, j = 0;
+                       itpred != Y->predecessors + Y->predecessorcount;
+                       ++itpred, ++j
+               ) {
+                       if (*itpred == bptr) break;
+               }
+
+               assert(j != Y->predecessorcount);
+
+               for (
+                       itph = bb_info(Y)->phi_functions;
+                       itph != bb_info(Y)->phi_functions + bb_info(Y)->phi_count;
+                       ++itph
+               ) {
+                       ssa_rename_uses(ssa, itph->args + j, 1);
+               }
+       }
+
+       /* Recurse */
+
+       for (
+               itdsucc = bptr->domsuccessors;
+               itdsucc != bptr->domsuccessors + bptr->domsuccessorcount;
+               ++itdsucc
+       ) {
+               ssa_rename_block(ssa, *itdsucc);
+       }
+
+       /* For each definition of some variable a in the original S, pop stack */
+
+       /* XXX */
+       for (a = 0; a < ssa->vars_count; ++a)  ssa->vars[a].stack_top = orig_stack_top[a];
+}
+
+static void ssa_rename(ssa_info *ssa) {
+       unsigned i;
+
+       for (i = 0; i < ssa->vars_count; ++i) {
+               ssa->vars[i].stack = DMNEW(unsigned, ssa->vars[i].num_defs + 1);
+               ssa->vars[i].stack[0] = 0;
+               ssa->vars[i].stack_top = ssa->vars[i].stack;
+       }
+
+       ssa_rename_block(ssa, ssa->jd->basicblocks);
+}
+
+static void ssa_export(ssa_info *ssa) {
+       unsigned i, j;
+       jitdata *jd = ssa->jd;
+       methoddesc *md = jd->m->parseddesc;
+       varinfo *vars, *it;
+       s4 vartop, varindex;
+
+       vartop = ssa->total_local_count + jd->vartop - jd->localcount;
+       vars = DMNEW(varinfo, vartop);
+
+       printf(" *** vartop(%d) = ssa->total_local_count(%d) + jd->vartop(%d) - jd->localcount(%d)\n",
+               vartop , ssa->total_local_count , jd->vartop , jd->localcount);
+
+       it = vars;
+
+       /* Version 1 of each local */
+
+       for (i = 0; i < jd->localcount; ++i) {
+               *(it++) = jd->var[i];
+       }
+
+       /* Other versions of each local */
+
+       for (i = 0; i < jd->localcount; ++i) {
+               for (j = 1; j < ssa->vars[i].num_defs; ++j) {
+                       *(it++) = jd->var[i];           
+               }
+       }
+
+       /* Other vars */
+
+       for (i = jd->localcount; i < jd->vartop; ++i) {
+               *(it++) = jd->var[i];
+       }
+
+       jd->var = vars;
+       jd->vartop = jd->varcount = vartop;
+
+       jd->local_map = DMREALLOC(jd->local_map, s4, 5 * jd->maxlocals, 5 * (jd->maxlocals + ssa->total_local_count - jd->localcount));
+
+       for (i = 0; i < ssa->total_local_count - jd->localcount; ++i) {
+               for (j = 0; j < 5; ++j) {
+                       varindex = jd->localcount + i;
+                       if (jd->var[varindex].type != j) {
+                               varindex = UNUSED;
+                       }
+                       jd->local_map[((jd->maxlocals + i) * 5) + j] = varindex;
+               }
+       }
+
+       jd->maxlocals += (ssa->total_local_count - jd->localcount);
+       jd->localcount = ssa->total_local_count;
+
+       printf(" *** jd->localcount %d, jd->maxlocals %d\n", jd->localcount , jd->maxlocals);
+}
+
+unsigned get_predecessor_index(basicblock *from, basicblock *to) {
+       basicblock **itpred;
+       unsigned j = 0;
+
+       for (itpred = to->predecessors; itpred != to->predecessors + to->predecessorcount; ++itpred) {
+               if (*itpred == from) break;
+               j++;
+       }
+       
+       if (j == to->predecessorcount) {
+               printf(" *** %d => %d\n", from->nr, to->nr);
+               assert(j != to->predecessorcount);
+       }
+
+       return j;
+}
+
+basicblock *create_block(ssa_info *ssa, basicblock *from, basicblock *to) {
+       basicblock *mid;
+       basicblock_info *toi;
+       instruction *iptr;
+       phi_function *itph;
+       unsigned j = get_predecessor_index(from, to);
+       
+       mid = DNEW(basicblock);
+       MZERO(mid, basicblock, 1);
+
+       toi = bb_info(to);
+       assert(toi);
+
+       mid->nr = ssa->jd->basicblockcount;
+       ssa->jd->basicblockcount += 1;
+       mid->mpc = -1;
+       mid->type = 666;
+       mid->icount = toi->phi_count + 1;
+       iptr = mid->iinstr = DMNEW(instruction, mid->icount);
+       MZERO(mid->iinstr, instruction, mid->icount);
+
+       for (itph = toi->phi_functions; itph != toi->phi_functions + toi->phi_count; ++itph) {
+               iptr->opc = ICMD_COPY;
+               iptr->dst.varindex = itph->dst;
+               iptr->s1.varindex =  itph->args[j];
+               assert(itph->dst < ssa->total_local_count);
+               assert(itph->args[j] < ssa->total_local_count);
+               iptr++;
+       }
+
+       iptr->opc = ICMD_GOTO;
+       iptr->dst.block = to;
+
+       while (from->next) {
+               from = from->next;
+       }
+
+       from->next = mid;
+
+       return mid;
+}
+
+void crate_fallthrough(ssa_info *ssa, basicblock *bptr) {
+       unsigned j;
+       basicblock_info *toi;
+       instruction *iptr;
+       phi_function *itph;
+
+       if (bptr->next == NULL) return;
+
+       j = get_predecessor_index(bptr, bptr->next);
+
+       toi = bb_info(bptr->next);
+       assert(toi);
+
+       bptr->iinstr = DMREALLOC(bptr->iinstr, instruction, bptr->icount, bptr->icount + toi->phi_count);
+       iptr = bptr->iinstr + bptr->icount;
+       bptr->icount += toi->phi_count;
+
+       for (itph = toi->phi_functions; itph != toi->phi_functions + toi->phi_count; ++itph) {
+               iptr->opc = ICMD_COPY;
+               iptr->dst.varindex = itph->dst;
+               iptr->s1.varindex =  itph->args[j];
+               assert(itph->dst < ssa->total_local_count);
+               assert(itph->args[j] < ssa->total_local_count);
+               iptr++;
+       }
+
+}
+
+void ssa_create_phi_moves(ssa_info *ssa) {
+       basicblock *bptr;
+       instruction *iptr;
+
+       s4 i, l;
+       branch_target_t *table;
+       lookup_target_t *lookup;
+       bool gt;
+
+       for (bptr = ssa->jd->basicblocks; bptr; bptr = bptr->next) {
+               if (bptr->type == 666) {
+                       bptr->type = BBTYPE_STD;
+                       continue;
+               }
+               if (! bptr->vp) continue;
+               if (! (bptr->flags >= BBREACHED)) continue;
+               gt = false;
+               for (iptr = bptr->iinstr; iptr != bptr->iinstr + bptr->icount; ++iptr) {
+                       switch (icmd_table[iptr->opc].controlflow) {
+                               case CF_IF:
+                               case CF_RET:
+                               case CF_GOTO:
+                                       iptr->dst.block = create_block(ssa, bptr, iptr->dst.block);     
+                                       break;
+                               case CF_TABLE:
+                                       table = iptr->dst.table;
+                                       l = iptr->sx.s23.s2.tablelow;
+                                       i = iptr->sx.s23.s3.tablehigh;
+                                       i = i - l + 1;
+                                       i += 1; /* default */
+                                       while (--i >= 0) {
+                                               table->block = create_block(ssa, bptr, table->block);
+                                               ++table;
+                                       }
+                                       break;
+                               case CF_LOOKUP:
+                                       lookup = iptr->dst.lookup;
+                                       i = iptr->sx.s23.s2.lookupcount;
+                                       while (--i >= 0) {
+                                               lookup->target.block = create_block(ssa, bptr, lookup->target.block);
+                                               lookup++;
+                                       }
+                                       iptr->sx.s23.s3.lookupdefault.block = create_block(ssa, bptr, iptr->sx.s23.s3.lookupdefault.block);
+                                       break;
+                               case CF_JSR:
+                                       iptr->sx.s23.s3.jsrtarget.block = create_block(ssa, bptr, iptr->sx.s23.s3.jsrtarget.block);
+                                       break;
+                       }
+                       if ((iptr->opc == ICMD_GOTO) || icmd_table[iptr->opc].controlflow == CF_END)
+                               gt = true;
+                       else if (iptr->opc != ICMD_NOP)
+                               gt = false;
+               }
+               if (! bptr->next) continue;
+               if (! (bptr->next->flags >= BBREACHED)) continue;
+               if (bptr->next->type == 666) continue;
+               if (!gt) crate_fallthrough(ssa, bptr);
+       }
+}
+
+void xssa(jitdata *jd) {
+       ssa_info *ssa = ssa_init(jd);
+
+       printf("=============== [ before %s ] =========================\n", jd->m->name->text);
+       show_method(jd, 3);
+       printf("=============== [ /before ] =========================\n");
+
+       ssa_place_phi_functions(ssa);
+       ssa_create_phi_functions(ssa);
+       ssa_calculate_offsets(ssa);
+       ssa_rename(ssa);
+       ssa_export(ssa);
+       ssa_create_phi_moves(ssa);
+
+       printf("=============== [ after ] =========================\n");
+       show_method(jd, 3);
+       printf("=============== [ /after ] =========================\n");
+}
+
diff --git a/src/vm/jit/optimizing/ssa2.h b/src/vm/jit/optimizing/ssa2.h
new file mode 100644 (file)
index 0000000..f4bd3b0
--- /dev/null
@@ -0,0 +1,4 @@
+#ifndef _VM_JIT_OPTIMIZING_SSA2
+#define _VM_JIT_OPTIMIZING_SSA2
+
+#endif
index e78f7b8ed075f843287673c6b4ae46161750bad6..4f5926bf71151102cc4b5d6d4504d855924ee6fc 100644 (file)
@@ -1,9 +1,7 @@
 /* src/vm/jit/python.c - Python pass
 
-   Copyright (C) 1996-2005, 2006, 2007 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
+   Copyright (C) 2007, 2008
+   CACAOVM - Verein zu Foerderung der freien virtuellen Machine CACAO
 
    This file is part of CACAO.
 
@@ -50,7 +48,7 @@
    an integer constant. This is achieved using the field_map array.
 
    We could have used a wrapper generator like swig, but we don't want to 
-   wrap the rather low level C api to python 1:1. When wrappig stuff, try
+   wrap the rather low level C api to python 1:1. When wrapping stuff, try
    to do it rather high level and in a pythonic way. Examples:
 
     * Bad: instruction.flags and cacao.FLAG_UNRESOLVED == 0
        * Bad: for i in range(0, bb.icount): instr = bb.instructions[i]
        * Good: for instr in bb.instructions
 
-   TODO:
+  Adding instructions or variables is currently problematic, because it 
+  requires to resize fixed sized arrays. Reallocating an array means that
+  all elements are possibly moved, their addresses are changed and the 
+  associated python object become invalid. Further, usually there is the 
+  need to add several instructions, which possibly results in several 
+  reallocations of the array. A good solution would be:
+
+   * Copy-on-write the array (ex. bptr->instructions) into a python list,
+     and put that list into the dictionnary of the parent object.
+   * When the python parent object is destroyed, recreate the array from the
+     list.
+   * From python, bptr.instructions will return either the wrapped array, or
+     the list from the dictionnary.
 
-    * Everywhere we return a variable number, we should return a varinfo
-         (varinfo wrapper has an index member anyways)
 */
 
 #include <Python.h>
+#include <structmember.h>
 
 #include "vm/global.h"
 #include "vm/jit/python.h"
@@ -81,15 +90,23 @@ static java_object_t *python_global_lock;
  * Defs
  */
 
-struct class_state {
+typedef struct root_state root_state;
+
+struct root_state {
        jitdata *jd;
-       void *vp;
+       PyObject *object_cache;
 };
 
 typedef struct class_state class_state;
 
+struct class_state {
+       root_state *root;
+       void *vp;
+};
+
 union class_arg {
        struct {
+               int is_method;
                int field;
                PyObject **result;
        } get;
@@ -101,9 +118,15 @@ union class_arg {
                PyObject *args;
                PyObject **result;
        } call;
+       struct {
+               int method;
+               PyObject *args;
+               PyObject **result;
+       } method_call;
        struct {
                PyObject **result;
        } str;
+       void *key;
 };
 
 typedef union class_arg class_arg;
@@ -112,16 +135,18 @@ enum class_op {
        CLASS_SET_FIELD,
        CLASS_GET_FIELD,
        CLASS_CALL,
-       CLASS_STR
+       CLASS_STR,
+       CLASS_METHOD_CALL
 };
 
 typedef enum class_op class_op;
 
 typedef int(*class_func)(class_op, class_state *, class_arg *);
 #define CLASS_FUNC(name) int name(class_op op, class_state *state, class_arg *arg)
+#define CLASS_FUNC_CALL(name) name(op, state, arg)
 
 struct iterator_state {
-       jitdata *jd;
+       root_state *root;
        void *data;
        void *pos;
 };
@@ -135,6 +160,10 @@ union iterator_arg {
                PyObject **result;
        } subscript;
        int length;
+       struct {
+               unsigned int index;
+               PyObject *value;
+       } setitem;
 };
 
 typedef union iterator_arg iterator_arg;
@@ -147,7 +176,8 @@ enum iterator_op {
        ITERATOR_FORWARD,
        ITERATOR_END,
        ITERATOR_SUBSCRIPT,
-       ITERATOR_LENGTH
+       ITERATOR_LENGTH,
+       ITERATOR_SETITEM
 };
 
 typedef enum iterator_op iterator_op;
@@ -155,6 +185,14 @@ typedef enum iterator_op iterator_op;
 typedef int(*iterator_func)(iterator_op op, iterator_state *state, iterator_arg *arg);
 #define ITERATOR_FUNC(name) int name (iterator_op op, iterator_state *state, iterator_arg *arg)
 #define ITERATOR_SUBSCRIPT_CHECK(end) if (arg->subscript.index >= (end)) return -1
+#define ITERATOR_SETITEM_CHECK(end) if (arg->setitem.index >= (end)) return -1
+
+typedef struct method_state method_state;
+
+struct method_state {
+       int method;
+       class_state *cstate;
+};
 
 struct field_map_entry {
        const char *name;
@@ -164,21 +202,32 @@ struct field_map_entry {
 typedef struct field_map_entry field_map_entry;
 
 enum field {
+       F_ADD_INSTRUCTIONS,
        F_BASIC_BLOCKS,
-       F_CLASS_CALL_RETURN_TYPE,
-       F_CLASS_CALL_ARGS,
+       F_CALL_RETURN_TYPE,
+       F_CALL_ARGS,
        F_CLASSREF,
        F_CONTROL_FLOW,
        F_CONTROL_FLOW_EX,
        F_DATA_FLOW,
        F_DATA_FLOW_EX,
        F_DESCRIPTOR,
+       F_DOM_SUCCESSORS,
+       F_DOMINANCE_FRONTIER,
        F_DST,
+       F_END,
        F_EXCEPTION_HANDLER,
-       F_FIELD_TYPE,
+       F_EXCEPTION_TABLE,
        F_FIELD,
+       F_FIELD_TYPE,
+       F_HANDLER,
+       F_HAS_CALL_ARGS,
+       F_HAS_DST,
+       F_IDOM,
        F_INDEX,
        F_INSTRUCTIONS,
+       F_INTERFACE_MAP,
+       F_IN_VARS,
        F_IS_CLASS_CONSTANT,
        F_IS_INOUT,
        F_IS_LOCAL,
@@ -197,39 +246,52 @@ enum field {
        F_OFFSET,
        F_OPCODE,
        F_OPCODE_EX,
+       F_OUT_VARS,
+       F_PARAMS,
        F_PARAM_TYPES,
        F_PEI,
        F_PEI_EX,
        F_PREDECESSORS,
        F_REACHED,
        F_RETURN_TYPE,
-       F_S1,
-       F_S2,
-       F_S3,
+       F_S,
        F_SHOW,
        F_SUCCESSORS,
+       F_START,
        F_TYPE,
        F_UNRESOLVED_FIELD,
+       F_UNUSED,
        F_VARS
 };
 
 /* Keep it soreted alphabetically, so we can support binary search in future. */
 struct field_map_entry field_map[] = {
+       { "add_instructions", F_ADD_INSTRUCTIONS },
        { "basic_blocks", F_BASIC_BLOCKS },
-       { "call_return_type", F_CLASS_CALL_RETURN_TYPE },
-       { "call_args", F_CLASS_CALL_ARGS },
+       { "call_return_type", F_CALL_RETURN_TYPE },
+       { "call_args", F_CALL_ARGS },
        { "classref", F_CLASSREF },
        { "control_flow", F_CONTROL_FLOW },
        { "control_flow_ex", F_CONTROL_FLOW_EX },
        { "data_flow", F_DATA_FLOW },
        { "data_flow_ex", F_DATA_FLOW_EX },
        { "descriptor", F_DESCRIPTOR },
+       { "dom_successors", F_DOM_SUCCESSORS },
+       { "dominance_frontier", F_DOMINANCE_FRONTIER },
        { "dst", F_DST },
+       { "end", F_END },
        { "exception_handler", F_EXCEPTION_HANDLER },
+       { "exception_table", F_EXCEPTION_TABLE },
        { "field", F_FIELD },
        { "field_type", F_FIELD_TYPE },
+       { "handler", F_HANDLER },
+       { "has_call_args", F_HAS_CALL_ARGS },
+       { "has_dst", F_HAS_DST },
+       { "idom", F_IDOM, },
        { "index", F_INDEX },
        { "instructions", F_INSTRUCTIONS },
+       { "interface_map", F_INTERFACE_MAP },
+       { "in_vars", F_IN_VARS },
        { "is_class_constant", F_IS_CLASS_CONSTANT },
        { "is_inout", F_IS_INOUT },
        { "is_local", F_IS_LOCAL },
@@ -248,19 +310,21 @@ struct field_map_entry field_map[] = {
        { "offset", F_OFFSET },
        { "opcode", F_OPCODE },
        { "opcode_ex", F_OPCODE_EX },
+       { "out_vars", F_OUT_VARS },
+       { "params", F_PARAMS },
        { "param_types", F_PARAM_TYPES },
        { "pei", F_PEI },
        { "pei_ex", F_PEI_EX },
        { "predecessors", F_PREDECESSORS },
        { "reached", F_REACHED },
        { "return_type", F_RETURN_TYPE },
-       { "s1", F_S1 },
-       { "s2", F_S2 },
-       { "s3", F_S3 },
+       { "s", F_S },
        { "show", F_SHOW },
+       { "start", F_START },
        { "successors", F_SUCCESSORS },
        { "type", F_TYPE },
        { "unresolved_field", F_UNRESOLVED_FIELD },
+       { "unused", F_UNUSED },
        { "vars", F_VARS },
        { NULL, 0 }
 };
@@ -281,10 +345,81 @@ int field_find(const char *key) {
  * Python
  */
 
+typedef struct method method;
+
+struct method {
+       PyObject_HEAD;
+       class_func func;
+       method_state state;
+};
+
+PyObject *method_call(method *m, PyObject *args, PyObject *kw) {
+       class_arg arg;
+       PyObject *result = NULL;
+
+       arg.method_call.method = m->state.method;
+       arg.method_call.args = args;
+       arg.method_call.result = &result;
+
+       if (m->func(CLASS_METHOD_CALL, m->state.cstate, &arg) == -1) {
+               return NULL;
+       }
+
+       if (result == NULL) {
+               Py_INCREF(Py_None);
+               result = Py_None;
+       }
+
+       return result;
+}
+
+PyTypeObject method_type = {
+       PyObject_HEAD_INIT(NULL)
+       0, /* ob_size */
+       "method", /* tp_name */
+       sizeof(method), /* tp_basicsize */
+       0, /* tp_itemsize */
+       0, /* tp_dealloc */
+       0, /* tp_print */
+       0, /* tp_getattr */
+       0, /* tp_setattr */
+       0, /* tp_compare */
+       0, /* tp_repr */
+       0, /* tp_as_number */
+       0, /* tp_as_sequence */
+       0, /* tp_as_mapping */
+       0, /* tp_hash */
+       method_call, /* tp_call */
+       0, /* tp_str */
+       0, /* tp_getattro */
+       0, /* tp_setattro */
+       0, /* tp_as_buffer */
+       Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+       0, /* tp_doc */
+       0, /* tp_traverse */
+       0, /* tp_clear */
+       0, /* tp_richcompare */
+       0, /* tp_weaklistoffset */
+       0, /* tp_iter */
+       0, /* tp_iternext */
+       0, /* tp_methods */
+       0, /* tp_members */
+       0, /* tp_getset */
+       0, /* tp_base */
+       0, /* tp_dict */
+       0, /* tp_descr_get */
+       0, /* tp_descr_set */
+       0, /* tp_dictoffset */
+       0, /* tp_init */
+       0, /* tp_alloc */
+       PyType_GenericNew, /* tp_new */
+};
+
 struct wrapper {
        PyObject_HEAD
        class_state state;
        class_func func;
+       PyObject *dict;
 };
 
 typedef struct wrapper wrapper;
@@ -293,18 +428,43 @@ PyObject *wrapper_getattr(wrapper *w, PyObject *fld) {
        class_arg arg;
        PyObject *result;
 
+       /* First, try generic getattr */
+
+       result = PyObject_GenericGetAttr(w, fld);
+
+       if (result != NULL) {
+               return result;
+       }
+
+       /* Exception is set here */
+
        arg.get.field = field_find(PyString_AsString(fld));
        if (arg.get.field == -1) {
-               return NULL;
+               goto failout;
        }
 
+       arg.get.is_method = 0;
        arg.get.result = &result;
 
        if (w->func(CLASS_GET_FIELD, &w->state, &arg) == -1) {
-               return NULL;
+               goto failout;
        }
 
+       if (arg.get.is_method) {
+               result = PyObject_CallObject((PyObject *)&method_type, NULL);
+               method *m = (method *)result;
+               m->func = w->func;
+               m->state.method = arg.get.field;
+               m->state.cstate = &w->state;
+       }
+
+       PyErr_Clear();
+
        return result;
+
+failout:
+
+       return NULL;
 }
 
 int wrapper_setattr(wrapper *w, PyObject *fld, PyObject *value) {
@@ -312,24 +472,35 @@ int wrapper_setattr(wrapper *w, PyObject *fld, PyObject *value) {
 
        arg.set.field = field_find(PyString_AsString(fld));
        if (arg.set.field == -1) {
-               return -1;
+               goto failout;
        }
        arg.set.value = value;
 
        if (w->func(CLASS_SET_FIELD, &w->state, &arg) == -1) {
-               return -1;
+               goto failout;
        }
 
        return 0;
+
+failout:
+
+       return PyObject_GenericSetAttr(w, fld, value);
 }
 
 extern PyTypeObject wrapper_type;
 
+inline void *wrapper_key(wrapper *w) {
+       return w->state.vp;
+}
+
 int wrapper_compare(wrapper *a, wrapper *b) {
+       void *keya, *keyb;
        if (PyObject_TypeCheck(b, &wrapper_type)) {
-               if (a->state.vp < b->state.vp) {
+               keya = wrapper_key(a);
+               keyb = wrapper_key(b);
+               if (keya < keyb) {
                        return -1;
-               } else if (a->state.vp > b->state.vp) {
+               } else if (keya > keyb) {
                        return 1;
                } else {
                        return 0;
@@ -341,7 +512,7 @@ int wrapper_compare(wrapper *a, wrapper *b) {
 }
 
 long wrapper_hash(wrapper *a) {
-       return (long)a->state.vp;
+       return (long)wrapper_key(a);
 }
 
 PyObject *wrapper_call(wrapper *w, PyObject *args, PyObject *kw) {
@@ -405,7 +576,7 @@ PyTypeObject wrapper_type = {
        0, /* tp_dict */
        0, /* tp_descr_get */
        0, /* tp_descr_set */
-       0, /* tp_dictoffset */
+       offsetof(wrapper, dict), /* tp_dictoffset */
        0, /* tp_init */
        0, /* tp_alloc */
        PyType_GenericNew, /* tp_new */
@@ -457,6 +628,21 @@ PyObject *iterator_getitem(struct iterator *it, PyObject* item) {
        }
 }
 
+int iterator_setitem(struct iterator *it, PyObject *item, PyObject *value) {
+       iterator_arg arg;
+       if (PyInt_Check(item)) {
+               arg.setitem.index = PyInt_AS_LONG(item);
+               arg.setitem.value = value;
+               if (it->func(ITERATOR_SETITEM, &it->state, &arg) != -1) {
+                       return 0;
+               } else {
+                       return -1;
+               }
+       } else {
+               return -1;
+       }
+}
+
 int iterator_length(struct iterator *it) {
        iterator_arg arg;
        if (it->func(ITERATOR_LENGTH, &it->state, &arg) == -1) {
@@ -469,7 +655,7 @@ int iterator_length(struct iterator *it) {
 PyMappingMethods iterator_mapping = {
        iterator_length,
        iterator_getitem,
-       0
+       iterator_setitem
 };
 
 PyTypeObject iterator_type = {
@@ -518,7 +704,7 @@ PyTypeObject iterator_type = {
  * Utils
  */
 
-int set_int(int *p, PyObject *o) {
+int set_s4(s4 *p, PyObject *o) {
        if (PyInt_Check(o)) {
                *p = PyInt_AsLong(o);   
                return 0;
@@ -528,7 +714,7 @@ int set_int(int *p, PyObject *o) {
 }
 
 int get_int(PyObject **o, int p) {
-       *o = Py_BuildValue("i", p);
+       *o = PyInt_FromLong(p);
        return 0;
 }
 
@@ -537,15 +723,22 @@ int get_string(PyObject **o, const char *str) {
        return 0;
 }
 
-int get_obj(PyObject **res, class_func f, jitdata *jd, void *p) {
+int get_obj(PyObject **res, class_func f, root_state *root, void *p) {
        if (p == NULL) {
                return get_none(res);
        } else {
-               PyObject *o = PyObject_CallObject((PyObject *)&wrapper_type, NULL);
-               struct wrapper * w = (struct wrapper *)o;
-               w->func = f;
-               w->state.jd = jd;
-               w->state.vp = p;
+               PyObject *key = PyInt_FromLong((long)p);
+               PyObject *o = PyDict_GetItem(root->object_cache, key);
+               if (o == NULL) {
+                       o = PyObject_CallObject((PyObject *)&wrapper_type, NULL);
+                       struct wrapper * w = (struct wrapper *)o;
+                       w->func = f;
+                       w->state.root = root;
+                       w->state.vp = p;
+                       PyDict_SetItem(root->object_cache, key, o);
+               } else {
+                       Py_INCREF(o);
+               }
                *res = o;
                return 0;
        }
@@ -573,11 +766,11 @@ int get_bool(PyObject **res, int cond) {
        return cond ? get_true(res) : get_false(res);
 }
        
-int get_iter(PyObject **res, iterator_func f, jitdata *jd, void *p) {
+int get_iter(PyObject **res, iterator_func f, root_state *root, void *p) {
        PyObject *o = PyObject_CallObject((PyObject *)&iterator_type, NULL);
        struct iterator * it = (struct iterator *)o;
        it->func = f;
-       it->state.jd = jd;
+       it->state.root = root;
        it->state.data = p;
        f(ITERATOR_INIT, &it->state, NULL);
        *res = o;
@@ -591,6 +784,15 @@ int add_const(PyObject *module, const char *name, int value) {
        }
 }
 
+void *get_vp(PyObject *o, class_func func) {
+       if (o->ob_type == &wrapper_type) {
+               if (((wrapper *)o)->func == func) {
+                       return ((wrapper *)o)->state.vp;
+               }
+       }
+       return NULL;
+}
+
 /*
  * Implemnetation
  */
@@ -599,15 +801,10 @@ CLASS_FUNC(basicblock_func);
 CLASS_FUNC(classinfo_func);
 CLASS_FUNC(constant_classref_func);
 CLASS_FUNC(methodinfo_func);
+CLASS_FUNC(varinfo_func);
 
-static inline methoddesc *instruction_call_site(instruction *iptr) {
-       if (iptr->opc == ICMD_BUILTIN) {
-               return iptr->sx.s23.s3.bte->md;
-       } else if (INSTRUCTION_IS_UNRESOLVED(iptr)) {
-               return iptr->sx.s23.s3.um->methodref->parseddesc.md;
-       } else {
-               return iptr->sx.s23.s3.fmiref->p.method->parseddesc;
-       }
+int get_varinfo(PyObject **res, root_state *root, s4 index) {
+       return get_obj(res, varinfo_func, root, root->jd->var + index);
 }
 
 static inline int instruction_opcode_ex(instruction *iptr) {
@@ -625,18 +822,22 @@ ITERATOR_FUNC(call_args_iter_func) {
                        state->pos = iptr->sx.s23.s2.args;
                        return 0;
                case ITERATOR_LENGTH:
-                       arg->length = instruction_call_site(iptr)->paramcount;
+                       arg->length = iptr->s1.argcount;
                        return 0;
                case ITERATOR_GET:
-                       return get_int(arg->get.result, *(int *)state->pos);
+                       /* return get_int(arg->get.result, *(int *)state->pos);*/
+                       return get_varinfo(arg->get.result, state->root, *(int *)state->pos);
                case ITERATOR_END:
-                       return state->pos == (iptr->sx.s23.s2.args + instruction_call_site(iptr)->paramcount);
+                       return state->pos == iptr->sx.s23.s2.args + iptr->s1.argcount;
                case ITERATOR_FORWARD:
                        state->pos = ((int *)state->pos) + 1;
                        return 0;
                case ITERATOR_SUBSCRIPT:
-                       ITERATOR_SUBSCRIPT_CHECK(instruction_call_site(iptr)->paramcount);
+                       ITERATOR_SUBSCRIPT_CHECK(iptr->s1.argcount);
                        return get_int(arg->subscript.result, iptr->sx.s23.s2.args[arg->subscript.index]);
+               case ITERATOR_SETITEM:
+                       ITERATOR_SETITEM_CHECK(iptr->s1.argcount);
+                       return set_s4(iptr->sx.s23.s2.args + arg->setitem.index, arg->setitem.value);
        }
        return -1;
 }
@@ -654,7 +855,7 @@ CLASS_FUNC(fieldinfo_func) {
                                case F_NAME:
                                        return get_string(arg->get.result, fi->name->text);
                                case F_KLASS:
-                                       return get_obj(arg->get.result, classinfo_func, state->jd, fi->class);
+                                       return get_obj(arg->get.result, classinfo_func, state->root, fi->class);
                        }
        }
 
@@ -672,13 +873,13 @@ CLASS_FUNC(unresolved_field_func) {
                                        if (IS_FMIREF_RESOLVED(uf->fieldref)) {
                                                return get_none(arg->get.result);
                                        } else {
-                                               return get_obj(arg->get.result, constant_classref_func, state->jd, uf->fieldref->p.classref);
+                                               return get_obj(arg->get.result, constant_classref_func, state->root, uf->fieldref->p.classref);
                                        }
                                case F_DESCRIPTOR:
                                        return get_string(arg->get.result, uf->fieldref->descriptor->text);
                                case F_FIELD:
                                        if (IS_FMIREF_RESOLVED(uf->fieldref)) {
-                                               return get_obj(arg->get.result, fieldinfo_func, state->jd, uf->fieldref->p.field);
+                                               return get_obj(arg->get.result, fieldinfo_func, state->root, uf->fieldref->p.field);
                                        } else {
                                                return get_none(arg->get.result);
                                        }
@@ -689,11 +890,62 @@ CLASS_FUNC(unresolved_field_func) {
        return -1;
 }
 
-CLASS_FUNC(instruction_show_func) {
+static inline int instruction_num_s(instruction *iptr) {
+       switch (icmd_table[iptr->opc].dataflow) {
+               case DF_1_TO_0:
+               case DF_1_TO_1:
+               case DF_COPY:
+               case DF_MOVE:
+                       return 1;
+               case DF_2_TO_0:
+               case DF_2_TO_1:
+                       return 2;
+               case DF_3_TO_0:
+               case DF_3_TO_1:
+                       return 3;
+               default:
+                       return 0;
+       }
+}
+
+static inline s4 *instruction_get_s(instruction *iptr, int s) {
+       switch (s) {
+               case 0:
+                       return &(iptr->s1.varindex);
+               case 1:
+                       return &(iptr->sx.s23.s2.varindex);
+               case 2:
+                       return &(iptr->sx.s23.s3.varindex);
+       }
+}
+
+ITERATOR_FUNC(s_iter_func) {
+       instruction *iptr = (instruction *)state->data;
+       uintptr_t pos = (uintptr_t)state->pos;
+
        switch (op) {
-               case CLASS_CALL:
-                       show_icmd(state->jd, (instruction *)state->vp, 1, SHOW_REGS);   
-                       return get_none(arg->get.result);
+               case ITERATOR_INIT:
+                       state->pos = (void *)0;
+                       return 0;
+               case ITERATOR_LENGTH:
+                       arg->length = instruction_num_s(iptr);
+                       return 0;
+               case ITERATOR_GET:
+                       return get_varinfo(arg->get.result, state->root, 
+                               *instruction_get_s(iptr, pos));
+               case ITERATOR_END:
+                       return pos == instruction_num_s(iptr);
+               case ITERATOR_FORWARD:
+                       state->pos = (void *)(pos + 1);
+                       return 0;
+               case ITERATOR_SUBSCRIPT:
+                       ITERATOR_SUBSCRIPT_CHECK(3);
+                       return get_varinfo(arg->subscript.result, state->root, 
+                               *instruction_get_s(iptr, arg->subscript.index));
+               case ITERATOR_SETITEM:
+                       ITERATOR_SETITEM_CHECK(3);
+                       return set_s4(instruction_get_s(iptr, arg->setitem.index), 
+                               arg->setitem.value);
        }
        return -1;
 }
@@ -713,32 +965,46 @@ CLASS_FUNC(instruction_func) {
                                        return get_string(arg->get.result, icmd_table[iptr->opc].name);
                                case F_NAME_EX:
                                        return get_string(arg->get.result, icmd_table[instruction_opcode_ex(iptr)].name);
-                               case F_S1:
-                                       return get_int(arg->get.result, iptr->s1.varindex);
-                               case F_S2:
-                                       return get_int(arg->get.result, iptr->sx.s23.s2.varindex);
-                               case F_S3:
-                                       return get_int(arg->get.result, iptr->sx.s23.s3.varindex);
+                               case F_S:
+                                       return get_iter(arg->get.result, s_iter_func, state->root, iptr);       
                                case F_DST:
-                                       return get_int(arg->get.result, iptr->dst.varindex);
-                               case F_CLASS_CALL_RETURN_TYPE:
+                                       return get_varinfo(arg->get.result, state->root, 
+                                               iptr->dst.varindex);
+                               case F_HAS_DST:
+                                       if (
+                                               (icmd_table[iptr->opc].dataflow == DF_INVOKE) ||
+                                               (icmd_table[iptr->opc].dataflow == DF_BUILTIN)
+                                       ) {
+                                               return get_bool(
+                                                       arg->get.result,
+                                                       instruction_call_site(iptr)->returntype.type != TYPE_VOID
+                                               );
+                                       }
+                                       return get_bool(arg->get.result, icmd_table[iptr->opc].dataflow >= DF_DST_BASE);
+                               case F_CALL_RETURN_TYPE:
                                        return get_int(arg->get.result, instruction_call_site(iptr)->returntype.type);
-                               case F_CLASS_CALL_ARGS:
-                                       return get_iter(arg->get.result, call_args_iter_func, state->jd, iptr); 
+                               case F_CALL_ARGS:
+                                       return get_iter(arg->get.result, call_args_iter_func, state->root, iptr);       
+                               case F_HAS_CALL_ARGS:
+                                       return get_bool(arg->get.result,
+                                               icmd_table[iptr->opc].dataflow == DF_INVOKE ||
+                                               icmd_table[iptr->opc].dataflow == DF_BUILTIN ||
+                                               icmd_table[iptr->opc].dataflow == DF_N_TO_1
+                                       );
                                case F_IS_UNRESOLVED:
                                        return get_bool(arg->get.result, iptr->flags.bits & INS_FLAG_UNRESOLVED);
                                case F_IS_CLASS_CONSTANT:
                                        return get_bool(arg->get.result, iptr->flags.bits & INS_FLAG_CLASS);
                                case F_KLASS:
-                                       return get_obj(arg->get.result, classinfo_func, state->jd, iptr->sx.val.c.cls);
+                                       return get_obj(arg->get.result, classinfo_func, state->root, iptr->sx.val.c.cls);
                                case F_CLASSREF:
-                                       return get_obj(arg->get.result, constant_classref_func, state->jd, iptr->sx.val.c.ref);
+                                       return get_obj(arg->get.result, constant_classref_func, state->root, iptr->sx.val.c.ref);
                                case F_LOCAL_METHODINFO:
                                        if (INSTRUCTION_IS_UNRESOLVED(iptr)) {
                                                return get_none(arg->get.result);
                                        } else {        
                                                return get_obj(arg->get.result, methodinfo_func, 
-                                                       state->jd, iptr->sx.s23.s3.fmiref->p.method);
+                                                       state->root, iptr->sx.s23.s3.fmiref->p.method);
                                        }
                                case F_FIELD_TYPE:
                                        if (INSTRUCTION_IS_UNRESOLVED(iptr)) {
@@ -752,20 +1018,18 @@ CLASS_FUNC(instruction_func) {
                                        if (INSTRUCTION_IS_UNRESOLVED(iptr)) {
                                                return get_none(arg->get.result);
                                        } else {
-                                               return get_obj(arg->get.result, fieldinfo_func, state->jd, iptr->sx.s23.s3.fmiref->p.field);
+                                               return get_obj(arg->get.result, fieldinfo_func, state->root, iptr->sx.s23.s3.fmiref->p.field);
                                        }
                                        break;
                                case F_UNRESOLVED_FIELD:
                                        if (INSTRUCTION_IS_UNRESOLVED(iptr)) {
-                                               return get_obj(arg->get.result, unresolved_field_func, state->jd, iptr->sx.s23.s3.uf);
+                                               return get_obj(arg->get.result, unresolved_field_func, state->root, iptr->sx.s23.s3.uf);
                                        } else {
                                                return get_none(arg->get.result);
                                        }
                                        break;
                                case F_LINE:
                                        return get_int(arg->get.result, iptr->line);
-                               case F_SHOW:
-                                       return get_obj(arg->get.result, instruction_show_func, state->jd, iptr);
                                case F_PEI:
                                        return get_bool(arg->get.result, icmd_table[iptr->opc].flags & ICMDTABLE_PEI);
                                case F_PEI_EX:
@@ -778,6 +1042,22 @@ CLASS_FUNC(instruction_func) {
                                        return get_int(arg->get.result, icmd_table[iptr->opc].controlflow);
                                case F_CONTROL_FLOW_EX:
                                        return get_int(arg->get.result, icmd_table[instruction_opcode_ex(iptr)].controlflow);
+                               case F_SHOW:
+                                       arg->get.is_method = 1;
+                                       return 0;
+                       }
+               case CLASS_SET_FIELD:
+                       switch (arg->set.field) {
+                               case F_DST:
+                                       return set_s4(&(iptr->dst.varindex), arg->set.value);
+                               case F_OPCODE:
+                                       return set_s4(&(iptr->opc), arg->set.value);
+                       }
+               case CLASS_METHOD_CALL:
+                       switch (arg->method_call.method) {
+                               case F_SHOW:
+                                       show_icmd(state->root->jd, iptr, 1, SHOW_CFG);
+                                       return 0;
                        }
        }
 
@@ -792,7 +1072,11 @@ ITERATOR_FUNC(predecessors_iter_func) {
                        state->pos = bptr->predecessors;
                        return 0;
                case ITERATOR_GET:
-                       return get_obj(arg->get.result, basicblock_func, state->jd, *(basicblock **)state->pos);
+                       return get_obj(arg->get.result, basicblock_func, state->root, *(basicblock **)state->pos);
+               case ITERATOR_SUBSCRIPT:
+                       ITERATOR_SUBSCRIPT_CHECK(bptr->predecessorcount);
+                       return get_obj(arg->subscript.result, basicblock_func, state->root, 
+                               bptr->predecessors[arg->subscript.index]);
                case ITERATOR_END:
                        return 
                                (state->pos == (bptr->predecessors + bptr->predecessorcount)) ||
@@ -800,6 +1084,9 @@ ITERATOR_FUNC(predecessors_iter_func) {
                case ITERATOR_FORWARD:
                        state->pos = ((basicblock **)state->pos) + 1;
                        return 0;
+               case ITERATOR_LENGTH:
+                       arg->length = bptr->predecessorcount;
+                       return 0;
        }
 
        return -1;
@@ -813,7 +1100,11 @@ ITERATOR_FUNC(successors_iter_func) {
                        state->pos = bptr->successors;
                        return 0;
                case ITERATOR_GET:
-                       return get_obj(arg->get.result, basicblock_func, state->jd, *(basicblock **)state->pos);
+                       return get_obj(arg->get.result, basicblock_func, state->root, *(basicblock **)state->pos);
+               case ITERATOR_SUBSCRIPT:
+                       ITERATOR_SUBSCRIPT_CHECK(bptr->successorcount);
+                       return get_obj(arg->subscript.result, basicblock_func, state->root, 
+                               bptr->successors[arg->subscript.index]);
                case ITERATOR_END:
                        return 
                                (state->pos == (bptr->successors + bptr->successorcount)) || 
@@ -821,6 +1112,50 @@ ITERATOR_FUNC(successors_iter_func) {
                case ITERATOR_FORWARD:
                        state->pos = ((basicblock **)state->pos) + 1;
                        return 0;
+               case ITERATOR_LENGTH:
+                       arg->length = bptr->successorcount;
+                       return 0;
+       }
+
+       return  -1;
+}
+
+ITERATOR_FUNC(dom_successors_iter_func) {
+       basicblock *bptr = (basicblock *)state->data;
+
+       switch (op) {
+               case ITERATOR_INIT:
+                       state->pos = bptr->domsuccessors;
+                       return 0;
+               case ITERATOR_GET:
+                       return get_obj(arg->get.result, basicblock_func, state->root, *(basicblock **)state->pos);
+               case ITERATOR_END:
+                       return (state->pos == (bptr->domsuccessors + bptr->domsuccessorcount));
+               case ITERATOR_FORWARD:
+                       state->pos = ((basicblock **)state->pos) + 1;
+                       return 0;
+               case ITERATOR_LENGTH:
+                       arg->length = bptr->domsuccessorcount;
+                       return 0;
+       }
+
+       return  -1;
+}
+
+ITERATOR_FUNC(dominance_frontier_iter_func) {
+       basicblock *bptr = (basicblock *)state->data;
+
+       switch (op) {
+               case ITERATOR_INIT:
+                       state->pos = bptr->domfrontier;
+                       return 0;
+               case ITERATOR_GET:
+                       return get_obj(arg->get.result, basicblock_func, state->root, *(basicblock **)state->pos);
+               case ITERATOR_END:
+                       return (state->pos == (bptr->domfrontier + bptr->domfrontiercount));
+               case ITERATOR_FORWARD:
+                       state->pos = ((basicblock **)state->pos) + 1;
+                       return 0;
        }
 
        return  -1;
@@ -834,7 +1169,7 @@ ITERATOR_FUNC(instruction_iter_func) {
                        state->pos = bptr->iinstr;
                        return 0;
                case ITERATOR_GET:
-                       return get_obj(arg->get.result, instruction_func, state->jd, state->pos);
+                       return get_obj(arg->get.result, instruction_func, state->root, state->pos);
                case ITERATOR_FORWARD:
                        state->pos = ((instruction *)state->pos) + 1;
                        return 0;
@@ -842,7 +1177,7 @@ ITERATOR_FUNC(instruction_iter_func) {
                        return state->pos == (bptr->iinstr + bptr->icount);
                case ITERATOR_SUBSCRIPT:
                        ITERATOR_SUBSCRIPT_CHECK(bptr->icount);
-                       return get_obj(arg->subscript.result, instruction_func, state->jd, bptr->iinstr + arg->subscript.index);
+                       return get_obj(arg->subscript.result, instruction_func, state->root, bptr->iinstr + arg->subscript.index);
                case ITERATOR_LENGTH:
                        arg->length = bptr->icount;
                        return 0;
@@ -850,14 +1185,82 @@ ITERATOR_FUNC(instruction_iter_func) {
        return -1;
 }
 
-CLASS_FUNC(basicblock_show_func) {
-       basicblock *bptr = (basicblock *)state->vp;
+int basicblock_add_instructions(basicblock *bptr, PyObject *args) {
+       int pos = 0, count = 1, dst, src, num;
+
+       if (! PyArg_ParseTuple(args, "|ii", &pos, &count)) {
+               return -1;
+       }
+
+       if ((pos < 0) || (pos > bptr->icount)) {
+               return -1;
+       }
+
+       if (count < 1) {
+               return -1;
+       }
+
+       bptr->iinstr = DMREALLOC(bptr->iinstr, instruction, bptr->icount, bptr->icount + count);
+
+       src = pos;
+       dst = pos + count;
+       num = bptr->icount - pos;
+
+       dst += num;
+       src += num;
+
+       while (num-- > 0) {
+               bptr->iinstr[--dst] = bptr->iinstr[--src];
+       }
+
+       MZERO(bptr->iinstr + pos, instruction, count);
+       bptr->icount += count;
+       
+       return 0;
+}
+
+ITERATOR_FUNC(in_vars_iter_func) {
+       basicblock *bptr = (basicblock *)state->data;
        switch (op) {
-               case CLASS_CALL:
-                       show_basicblock(state->jd, bptr, SHOW_REGS);
-                       return get_none(arg->call.result);
+               case ITERATOR_INIT:
+                       state->pos = bptr->invars;
+                       return 0;
+               case ITERATOR_GET:
+                       return get_varinfo(arg->get.result, state->root, *(s4 *)(state->pos));
+               case ITERATOR_FORWARD:
+                       state->pos = ((s4 *)state->pos) + 1;
+                       return 0;
+               case ITERATOR_END:
+                       return state->pos == (bptr->invars + bptr->indepth);
+               case ITERATOR_SUBSCRIPT:
+                       ITERATOR_SUBSCRIPT_CHECK(bptr->icount);
+                       return get_varinfo(arg->subscript.result, state->root, bptr->invars[arg->subscript.index]);
+               case ITERATOR_LENGTH:
+                       arg->length = bptr->indepth;
+                       return 0;
+       }
+}
+
+ITERATOR_FUNC(out_vars_iter_func) {
+       basicblock *bptr = (basicblock *)state->data;
+       switch (op) {
+               case ITERATOR_INIT:
+                       state->pos = bptr->outvars;
+                       return 0;
+               case ITERATOR_GET:
+                       return get_varinfo(arg->get.result, state->root, *(s4 *)(state->pos));
+               case ITERATOR_FORWARD:
+                       state->pos = ((s4 *)state->pos) + 1;
+                       return 0;
+               case ITERATOR_END:
+                       return state->pos == (bptr->outvars + bptr->outdepth);
+               case ITERATOR_SUBSCRIPT:
+                       ITERATOR_SUBSCRIPT_CHECK(bptr->icount);
+                       return get_varinfo(arg->subscript.result, state->root, bptr->outvars[arg->subscript.index]);
+               case ITERATOR_LENGTH:
+                       arg->length = bptr->outdepth;
+                       return 0;
        }
-       return -1;
 }
 
 CLASS_FUNC(basicblock_func) {
@@ -867,23 +1270,44 @@ CLASS_FUNC(basicblock_func) {
                case CLASS_GET_FIELD:
                        switch (arg->get.field) {
                                case F_INSTRUCTIONS:
-                                       return get_iter(arg->get.result, instruction_iter_func, state->jd, bptr);
+                                       return get_iter(arg->get.result, instruction_iter_func, state->root, bptr);
                                case F_NR:
                                        return get_int(arg->get.result, bptr->nr);
                                case F_PREDECESSORS:
-                                       return get_iter(arg->get.result, predecessors_iter_func, state->jd, bptr);
+                                       return get_iter(arg->get.result, predecessors_iter_func, state->root, bptr);
                                case F_SUCCESSORS:
-                                       return get_iter(arg->get.result, successors_iter_func, state->jd, bptr);
+                                       return get_iter(arg->get.result, successors_iter_func, state->root, bptr);
                                case F_REACHED:
                                        return get_bool(arg->get.result, bptr->flags >= BBREACHED);
                                case F_EXCEPTION_HANDLER:
                                        return get_bool(arg->get.result, bptr->type == BBTYPE_EXH);
+                               case F_IDOM:
+                                       return get_obj(arg->get.result, basicblock_func, state->root, bptr->idom);
+                               case F_DOM_SUCCESSORS:
+                                       return get_iter(arg->get.result, dom_successors_iter_func, state->root, bptr);
+                               case F_DOMINANCE_FRONTIER:
+                                       return get_iter(arg->get.result, dominance_frontier_iter_func, state->root, bptr);
+                               case F_IN_VARS:
+                                       return get_iter(arg->get.result, in_vars_iter_func, state->root, bptr);
+                               case F_OUT_VARS:
+                                       return get_iter(arg->get.result, in_vars_iter_func, state->root, bptr);
                                case F_SHOW:
-                                       return get_obj(arg->get.result, basicblock_show_func, state->jd, bptr);
+                               case F_ADD_INSTRUCTIONS:
+                                       arg->get.is_method = 1;
+                                       return 0;
                        }
                case CLASS_STR:
                        *arg->str.result = PyString_FromFormat("BB_%d", bptr->nr);
                        return 0;
+               case CLASS_METHOD_CALL:
+                       switch (arg->method_call.method) {      
+                               case F_SHOW:
+                                       show_basicblock(state->root->jd, bptr, SHOW_CFG);
+                                       return 0;
+                               /* XXX remove */
+                               case F_ADD_INSTRUCTIONS:
+                                       return basicblock_add_instructions(bptr, arg->method_call.args);
+                       }
        }
 
        return -1;
@@ -898,7 +1322,7 @@ ITERATOR_FUNC(basicblocks_iter_func) {
                        state->pos = jd->basicblocks;
                        return 0;       
                case ITERATOR_GET:
-                       return get_obj(arg->get.result, basicblock_func, state->jd, state->pos);
+                       return get_obj(arg->get.result, basicblock_func, state->root, state->pos);
                case ITERATOR_FORWARD:
                        state->pos = ((basicblock *)(state->pos))->next;
                        return 0;
@@ -907,7 +1331,7 @@ ITERATOR_FUNC(basicblocks_iter_func) {
                case ITERATOR_SUBSCRIPT:
                        for (bb = jd->basicblocks; bb != NULL; bb = bb->next) {
                                if (bb->nr == arg->subscript.index) {
-                                       return get_obj(arg->subscript.result, basicblock_func, state->jd, bb);
+                                       return get_obj(arg->subscript.result, basicblock_func, state->root, bb);
                                }
                        }
                        return -1;
@@ -965,6 +1389,35 @@ ITERATOR_FUNC(param_types_iter_func) {
        return -1;
 }
 
+ITERATOR_FUNC(params_iter_func) {
+
+       methodinfo *m = (methodinfo *)state->data;
+       /* param counter */
+       uint16_t p = (uintptr_t)(state->pos) & 0xFFFF;
+       /* local counter */
+       uint16_t l = ((uintptr_t)(state->pos) >> 16) & 0xFFFF;
+
+       int varnum;
+
+       switch (op) {
+               case ITERATOR_INIT:
+                       state->pos = (void *)0;
+                       return 0;
+               case ITERATOR_END:
+                       return p == m->parseddesc->paramcount;
+               case ITERATOR_FORWARD:
+                       l += (IS_2_WORD_TYPE(m->parseddesc->paramtypes[p].type) ? 2 : 1);
+                       p += 1;
+                       state->pos = (void *)(uintptr_t)((l << 16) | p);
+                       return 0;
+               case ITERATOR_GET:
+                       varnum = state->root->jd->local_map[(5 * l) + m->parseddesc->paramtypes[p].type];
+                       return get_varinfo(arg->get.result, state->root, varnum);
+       }
+               
+       return -1;
+}
+
 CLASS_FUNC(methodinfo_func) {
        methodinfo *m = (methodinfo *)state->vp;
        switch (op) {
@@ -973,21 +1426,78 @@ CLASS_FUNC(methodinfo_func) {
                                case F_NAME:
                                        return get_string(arg->get.result, m->name->text);
                                case F_KLASS:
-                                       return get_obj(arg->get.result, classinfo_func, state->jd, m->class);
+                                       return get_obj(arg->get.result, classinfo_func, state->root, m->class);
                                case F_PARAM_TYPES:
-                                       return get_iter(arg->get.result, param_types_iter_func, state->jd, m);
+                                       return get_iter(arg->get.result, param_types_iter_func, state->root, m);
+                               case F_PARAMS:
+                                       if (m == state->root->jd->m) {
+                                               return get_iter(arg->get.result, params_iter_func, state->root, m);
+                                       } else {
+                                               return get_none(arg->get.result);
+                                       }
                                case F_RETURN_TYPE:
                                        return get_int(arg->get.result, m->parseddesc->returntype.type);
+                               case F_SHOW:
+                                       if (m == state->root->jd->m) {
+                                               arg->get.is_method = 1;
+                                               return 0;
+                                       }
+                       }
+               case CLASS_METHOD_CALL:
+                       switch (arg->method_call.method) {
+                               case F_SHOW:
+                                       show_method(state->root->jd, SHOW_CFG);
+                                       return 0;
                        }
        }
        return -1;
 }
 
+static inline PyObject *varinfo_str(jitdata *jd, int index, varinfo *v) {
+       char type = '?';
+       char kind = '?';
+
+       switch (v->type) {
+               case TYPE_INT: type = 'i'; break;
+               case TYPE_LNG: type = 'l'; break;
+               case TYPE_FLT: type = 'f'; break;
+               case TYPE_DBL: type = 'd'; break;
+               case TYPE_ADR: type = 'a'; break;
+               case TYPE_RET: type = 'r'; break;
+               default:       type = '?';
+       }
+
+       if (index < jd->localcount) {
+               kind = 'L';
+       }
+       else {
+               if (v->flags & PREALLOC) {
+                       kind = 'A';
+                       if (v->flags & INOUT) {
+                               /* PREALLOC is used to avoid allocation of TYPE_RET */
+                               if (v->type == TYPE_RET)
+                                       kind = 'i';
+                       }
+               }
+               else if (v->flags & INOUT)
+                       kind = 'I';
+               else
+                       kind = 'T';
+       }
+
+       if (index == -1) {
+               return PyString_FromString("UNUSED");
+       } else {
+               return PyString_FromFormat("%c%c%d", kind, type, index);
+       }
+}
+
 
 CLASS_FUNC(varinfo_func) {
-       jitdata *jd = state->jd;
+       jitdata *jd = state->root->jd;
        varinfo *var = (varinfo *)state->vp;
        int index = var - jd->var;
+
        switch (op) {
                case CLASS_GET_FIELD:
                        switch (arg->get.field) {
@@ -1003,25 +1513,97 @@ CLASS_FUNC(varinfo_func) {
                                case F_IS_INOUT:
                                        return get_bool(
                                                arg->get.result, 
-                                               (index >= jd->localcount) && !(var->flags && PREALLOC) && (var->flags & INOUT)
+                                               (index >= jd->localcount) && !(var->flags & PREALLOC) && (var->flags & INOUT)
                                        );
                                case F_IS_TEMPORARY:
                                        return get_bool(
                                                arg->get.result, 
-                                               (index >= jd->localcount) && !(var->flags && PREALLOC) && !(var->flags & INOUT)
+                                               (index >= jd->localcount) && !(var->flags & PREALLOC) && !(var->flags & INOUT)
                                        );
                                case F_IS_SAVED:
                                        return get_bool(arg->get.result, var->flags & SAVEDVAR);
                                case F_INDEX:
                                        return get_int(arg->get.result, index);
+                               case F_UNUSED:
+                                       return get_bool(arg->get.result, index == UNUSED);
                        }
+               case CLASS_SET_FIELD:
+                       switch (arg->set.field) {
+                               case F_TYPE:
+                                       return set_s4(&(var->type), arg->set.value);
+                               case F_IS_LOCAL:
+                                       if (PyBool_Check(arg->set.value)) {
+                                               if (arg->set.value == Py_True) {
+                                                       if (jd->localcount < (index + 1)) {
+                                                               jd->localcount = (index + 1);
+                                                       }
+                                               } else {
+                                                       if (jd->localcount > (index)) {
+                                                               jd->localcount = index;
+                                                       }
+                                               }
+                                               return 0;
+                                       }
+                                       break;
+                               case F_IS_SAVED:
+                                       if (PyBool_Check(arg->set.value)) {
+                                               if (arg->set.value == Py_True) {
+                                                       var->flags |= SAVEDVAR;
+                                               } else {
+                                                       var->flags &= ~SAVEDVAR;
+                                               }
+                                               return 0;
+                                       }
+                                       break;
+                               case F_IS_PREALLOCATED:
+                                       if (arg->set.value == Py_True) {
+                                               var->flags |= PREALLOC;
+                                               return 0;
+                                       }
+                                       break;
+                               case F_IS_INOUT:
+                                       if (arg->set.value == Py_True) {
+                                               var->flags &= ~PREALLOC;
+                                               var->flags |= INOUT;
+                                               return 0;
+                                       }
+                                       break;
+                               case F_IS_TEMPORARY:
+                                       if (arg->set.value == Py_True) {
+                                               var->flags &= ~PREALLOC;
+                                               var->flags &= ~INOUT;
+                                               return 0;
+                                       }
+                                       break;
+                       }
+               case CLASS_STR:
+                       *arg->str.result = varinfo_str(jd, index, var);
+                       return 0;
 
        }
        return -1;
 }
 
-ITERATOR_FUNC(vars_func) {
+int vars_grow(jitdata *jd, unsigned size) {
+       int newcount;
+       if (size > 16 * 1024) {
+               return 0;
+       }
+       if (size >= jd->varcount) {
+               newcount = 2 * jd->varcount;
+               if (size > newcount) {
+                       newcount = size;
+               }
+               jd->var = DMREALLOC(jd->var, varinfo, jd->varcount, newcount);
+               MZERO(jd->var + jd->varcount, varinfo, (newcount - jd->varcount));
+               jd->varcount = newcount;
+       }
+       return 1;
+}
+
+ITERATOR_FUNC(vars_iter_func) {
        jitdata *jd = (jitdata *)state->data;
+       void *vp;
        switch (op) {
                case ITERATOR_INIT:
                        state->pos = jd->var;
@@ -1030,20 +1612,38 @@ ITERATOR_FUNC(vars_func) {
                        state->pos = ((varinfo *)state->pos) + 1;
                        return 0;
                case ITERATOR_END:
-                       return state->pos == (jd->var + jd->varcount);
+                       return state->pos == (jd->var + jd->vartop);
                case ITERATOR_GET:
-                       return get_obj(arg->get.result, varinfo_func, state->jd, state->pos);
+                       return get_obj(arg->get.result, varinfo_func, state->root, state->pos);
                case ITERATOR_LENGTH:
-                       arg->length = jd->varcount;
+                       arg->length = jd->vartop;
                        return 0;
+               /* XXX remove grow */
                case ITERATOR_SUBSCRIPT:
-                       ITERATOR_SUBSCRIPT_CHECK(jd->varcount);
-                       return get_obj(arg->subscript.result, varinfo_func, state->jd, jd->var + arg->subscript.index);
+                       if (vars_grow(jd, arg->subscript.index + 1)) {
+                               if (jd->vartop < (arg->subscript.index + 1)) {
+                                       jd->vartop = (arg->subscript.index + 1);
+                               }
+                               return get_obj(arg->subscript.result, varinfo_func, 
+                                       state->root, jd->var + arg->subscript.index);
+                       }
+               case ITERATOR_SETITEM:
+                       if (vars_grow(jd, arg->setitem.index + 1)) {
+                               if (jd->vartop < (arg->subscript.index + 1)) {
+                                       jd->vartop = (arg->subscript.index + 1);
+                               }
+                               vp = get_vp(arg->setitem.value, varinfo_func);
+                               if (vp) {
+                                       jd->var[arg->setitem.index] = *(varinfo *)vp;
+                                       return 0;
+                               }
+                       }
+
        }
        return -1;
 }
 
-ITERATOR_FUNC(local_map_2_iter_func) {
+ITERATOR_FUNC(map_2_iter_func) {
        int *arr = (int *)state->data;
        switch (op) {
                case ITERATOR_SUBSCRIPT:
@@ -1052,21 +1652,104 @@ ITERATOR_FUNC(local_map_2_iter_func) {
                case ITERATOR_LENGTH:
                        arg->length = 5;
                        return 0;
+               case ITERATOR_SETITEM:
+                       ITERATOR_SETITEM_CHECK(5);
+                       return set_s4(arr + arg->subscript.index, arg->setitem.value);
        }
        return -1;
 }
 
+static inline void map_grow(s4 **pmap, s4 *pold_size, s4 new_size) {
+
+       int i;
+       s4 *map = *pmap;
+       s4 old_size = *pold_size;
+
+       if (new_size > old_size) {
+               *pmap = DMREALLOC(map, s4, old_size * 5, new_size * 5);
+               for (i = old_size * 5; i < (new_size * 5); ++i) {
+                       map[i] = UNUSED;
+               }
+               *pold_size = new_size;
+       }
+}
+
 ITERATOR_FUNC(local_map_iter_func) {
        jitdata *jd = (jitdata *)state->data;
        switch (op) {
                case ITERATOR_SUBSCRIPT:
-                       /* todo ITERATOR_SUBSCRIPT_CHECK(); */
-                       return get_iter(arg->subscript.result, local_map_2_iter_func, state->jd,
+                       map_grow(&jd->local_map, &jd->maxlocals, arg->subscript.index + 1);
+                       return get_iter(arg->subscript.result, map_2_iter_func, state->root,
                                jd->local_map + (5 * arg->subscript.index));
        }
        return -1;
 }
 
+ITERATOR_FUNC(interface_map_iter_func) {
+       jitdata *jd = (jitdata *)state->data;
+       switch (op) {
+               case ITERATOR_SUBSCRIPT:
+                       /* XXX remove grow */
+                       map_grow(&jd->interface_map, &jd->maxinterfaces, arg->subscript.index + 1);
+                       return get_iter(arg->subscript.result, map_2_iter_func, state->root,
+                               jd->interface_map + (5 * arg->subscript.index));
+       }
+       return -1;
+}
+
+ITERATOR_FUNC(exception_entry_basic_blocks_iter_func) {
+       exception_entry *ee = (exception_entry *)state->data;
+       switch (op) {
+               case ITERATOR_INIT:
+                       state->pos = ee->start;
+                       return 0;
+               case ITERATOR_FORWARD:
+                       state->pos = ((basicblock *)state->pos)->next;
+                       return 0;
+               case ITERATOR_END:
+                       return state->pos == ee->end;
+               case ITERATOR_GET:
+                       return get_obj(arg->get.result, basicblock_func, state->root, state->pos);
+       }
+       return -1;
+}
+
+CLASS_FUNC(exception_entry_func) {
+       exception_entry *ee = (exception_entry *)state->vp;
+       switch (op) {
+               case CLASS_GET_FIELD:
+                       switch (arg->get.field) {
+                               case F_START:
+                                       return get_obj(arg->get.result, basicblock_func, state->root, ee->start);
+                               case F_END:
+                                       return get_obj(arg->get.result, basicblock_func, state->root, ee->end);
+                               case F_HANDLER:
+                                       return get_obj(arg->get.result, basicblock_func, state->root, ee->handler);
+                               case F_BASIC_BLOCKS:
+                                       return get_iter(arg->get.result, exception_entry_basic_blocks_iter_func, state->root, ee);
+                       }
+                       break;
+       }
+       return -1;
+}
+
+ITERATOR_FUNC(exception_table_iter_func) {
+       jitdata *jd = (jitdata *)state->data;
+       switch (op) {
+               case ITERATOR_INIT:
+                       state->pos = jd->exceptiontable;
+                       return 0;
+               case ITERATOR_FORWARD:
+                       state->pos = ((exception_entry *)state->pos)->down;
+                       return 0;
+               case ITERATOR_END:
+                       return state->pos == NULL;
+               case ITERATOR_GET:
+                       return get_obj(arg->get.result, exception_entry_func, state->root, state->pos);
+       }
+       return -1;
+}
+
 CLASS_FUNC(jd_func) {
        jitdata *jd = (jitdata *)state->vp;
 
@@ -1074,13 +1757,17 @@ CLASS_FUNC(jd_func) {
                case CLASS_GET_FIELD:
                        switch (arg->get.field) {
                                case F_BASIC_BLOCKS:
-                                       return get_iter(arg->get.result, basicblocks_iter_func, state->jd, jd);
+                                       return get_iter(arg->get.result, basicblocks_iter_func, state->root, jd);
                                case F_METHOD:
-                                       return get_obj(arg->get.result, methodinfo_func, state->jd, jd->m);
+                                       return get_obj(arg->get.result, methodinfo_func, state->root, jd->m);
                                case F_VARS:
-                                       return get_iter(arg->get.result, vars_func, state->jd, jd);
+                                       return get_iter(arg->get.result, vars_iter_func, state->root, jd);
                                case F_LOCAL_MAP:
-                                       return get_iter(arg->get.result, local_map_iter_func, state->jd, jd);
+                                       return get_iter(arg->get.result, local_map_iter_func, state->root, jd);
+                               case F_INTERFACE_MAP:
+                                       return get_iter(arg->get.result, interface_map_iter_func, state->root, jd);
+                               case F_EXCEPTION_TABLE:
+                                       return get_iter(arg->get.result, exception_table_iter_func, state->root, jd);
                        }
        }
 
@@ -1171,6 +1858,7 @@ void pythonpass_init() {
 
        if (PyType_Ready(&wrapper_type) < 0) return;
        if (PyType_Ready(&iterator_type) < 0) return;
+       if (PyType_Ready(&method_type) < 0) return;
 
        m = Py_InitModule3("cacao", NULL, NULL);
        if (m != NULL) {
@@ -1196,20 +1884,25 @@ int pythonpass_run(jitdata *jd, const char *module, const char *function) {
        PyObject *pyargs = NULL;
        PyObject *pyret = NULL;
        PyObject *pyarg = NULL;
+       PyObject *objcache = NULL;
        int success = 0;
+       root_state root;
 
        LOCK_MONITOR_ENTER(python_global_lock);
 
        pymodname = PyString_FromString(module);
        pymod = PyImport_Import(pymodname);
 
+       root.jd = jd;
+       root.object_cache = objcache = PyDict_New();
+
        if (pymod != NULL) {
                pydict = PyModule_GetDict(pymod);
                pyfunc = PyDict_GetItemString(pydict, function);
                if (pyfunc != NULL && PyCallable_Check(pyfunc)) {
                        pyargs = PyTuple_New(1);
 
-                       if (get_obj(&pyarg, jd_func, jd, jd) != -1) {
+                       if (get_obj(&pyarg, jd_func, &root, jd) != -1) {
                        }
 
                        /* */
@@ -1234,6 +1927,7 @@ int pythonpass_run(jitdata *jd, const char *module, const char *function) {
        Py_XDECREF(pymod);
        Py_XDECREF(pyargs);
        Py_XDECREF(pyret);
+       Py_XDECREF(objcache);
 
        LOCK_MONITOR_EXIT(python_global_lock);
 
index d4e7309dca52f870c1ed07f728c6cbf39bf88137..56a44d4294751dac3ba81bd1636fc663a4dcea8d 100644 (file)
@@ -1,9 +1,7 @@
 /* src/vm/jit/python.h - Python pass
 
-   Copyright (C) 1996-2005, 2006, 2007 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
+   Copyright (C) 2007, 2008
+   CACAOVM - Verein zu Foerderung der freien virtuellen Machine CACAO
 
    This file is part of CACAO.
 
 
 #ifndef _VM_JIT_PYTHON_H
 #define _VM_JIT_PYTHON_H
+#if defined(ENABLE_PYTHON)
 
 #include "vm/jit/jit.h"
 
 void pythonpass_init();
-int pythonpass_run(jitdata *jd, const char *module, const char *function);
 void pythonpass_cleanup();
+int pythonpass_run(jitdata *jd, const char *module, const char *function);
 
+#endif
 #endif
 
 /*
index b6539c7960aa7266b41bb5cbebaed507e121f04d..cd18c9a6ed89da08a43026b499e64dc849384ce4 100644 (file)
@@ -537,7 +537,10 @@ void show_basicblock(jitdata *jd, basicblock *bptr, int stage)
                        printf("IN:  ");
                        show_variable_array(jd, bptr->invars, bptr->indepth, irstage);
                        printf(" javalocals: ");
-                       show_javalocals_array(jd, bptr->javalocals, bptr->method->maxlocals, irstage);
+                       if (bptr->javalocals)
+                               show_javalocals_array(jd, bptr->javalocals, bptr->method->maxlocals, irstage);
+                       else
+                               printf("null");
                        printf("\n");
                }