list.h \
logging.c \
logging.h \
+ set.h \
+ set.c \
tree.c \
tree.h \
util.c \
#ifndef _BITVECTOR_H
#define _BITVECTOR_H
+#include "vm/global.h"
+
#if !defined(NDEBUG)
#include <assert.h>
--- /dev/null
+/* 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:
+ */
--- /dev/null
+/* 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:
+ */
/* 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
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 *******************************************************************
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;
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++;
}
break;
- case ICMD_LOOKUPSWITCH:
+ case CF_LOOKUP:
lookup = iptr->dst.lookup;
bptr->successorcount++;
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;
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;
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;
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);
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.
bool cfg_build(jitdata *jd);
+void cfg_add_root(jitdata *jd);
+
#endif /* _CFG_H */
return r;
}
+#if defined(ENABLE_PM_HACKS)
+#include "vm/jit/jit_pm_1.inc"
+#endif
/* jit_compile_intern **********************************************************
}
#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
}
#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)
/* 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++);
}
#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.
#include "vm/jit/verify/typeinfo.h"
+#include "vmcore/descriptor.h"
#include "vmcore/method.h"
#include "vmcore/references.h"
((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 {
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 ***************************/
md = iptr->sx.s23.s3.fmiref->parseddesc.md; \
} while (0)
-
/* additional info structs for special instructions ***************************/
/* for ICMD_INLINE_START and ICMD_INLINE_END */
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 */
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 *********************************/
dominators.c \
dominators.h \
lifetimes.c \
- lifetimes.h
+ lifetimes.h \
+ ssa2.c
endif
noinst_LTLIBRARIES = \
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
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 */
/*
#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
W <- W join {Y}
******************************************************************************/
+void xssa(jitdata *jd);
void ssa(jitdata *jd) {
struct dominatordata *dd;
lsradata *ls;
}
#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);
--- /dev/null
+#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");
+}
+
--- /dev/null
+#ifndef _VM_JIT_OPTIMIZING_SSA2
+#define _VM_JIT_OPTIMIZING_SSA2
+
+#endif
/* 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.
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"
* 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;
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;
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;
};
PyObject **result;
} subscript;
int length;
+ struct {
+ unsigned int index;
+ PyObject *value;
+ } setitem;
};
typedef union iterator_arg iterator_arg;
ITERATOR_FORWARD,
ITERATOR_END,
ITERATOR_SUBSCRIPT,
- ITERATOR_LENGTH
+ ITERATOR_LENGTH,
+ ITERATOR_SETITEM
};
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;
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,
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 },
{ "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 }
};
* 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;
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) {
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;
}
long wrapper_hash(wrapper *a) {
- return (long)a->state.vp;
+ return (long)wrapper_key(a);
}
PyObject *wrapper_call(wrapper *w, PyObject *args, PyObject *kw) {
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 */
}
}
+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) {
PyMappingMethods iterator_mapping = {
iterator_length,
iterator_getitem,
- 0
+ iterator_setitem
};
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;
}
int get_int(PyObject **o, int p) {
- *o = Py_BuildValue("i", p);
+ *o = PyInt_FromLong(p);
return 0;
}
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;
}
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;
}
}
+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
*/
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) {
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;
}
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);
}
}
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);
}
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;
}
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)) {
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:
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;
}
}
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)) ||
case ITERATOR_FORWARD:
state->pos = ((basicblock **)state->pos) + 1;
return 0;
+ case ITERATOR_LENGTH:
+ arg->length = bptr->predecessorcount;
+ return 0;
}
return -1;
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)) ||
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;
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;
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;
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) {
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;
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;
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;
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) {
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) {
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;
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:
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;
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);
}
}
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) {
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) {
}
/* */
Py_XDECREF(pymod);
Py_XDECREF(pyargs);
Py_XDECREF(pyret);
+ Py_XDECREF(objcache);
LOCK_MONITOR_EXIT(python_global_lock);
/* 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
/*
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");
}