From: Peter Molnar Date: Thu, 14 Feb 2008 13:49:34 +0000 (+0100) Subject: * src/toolbox/Makefile.am (libtoolbox_la_SOURCES): Added set.[ch] X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=commitdiff_plain;h=f7fb911586d9f26d5ffe11cab0f504490caaf561;p=cacao.git * src/toolbox/Makefile.am (libtoolbox_la_SOURCES): Added set.[ch] * 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. --- diff --git a/src/toolbox/Makefile.am b/src/toolbox/Makefile.am index 0a5d3377c..e6d1085cd 100644 --- a/src/toolbox/Makefile.am +++ b/src/toolbox/Makefile.am @@ -47,6 +47,8 @@ libtoolbox_la_SOURCES = \ list.h \ logging.c \ logging.h \ + set.h \ + set.c \ tree.c \ tree.h \ util.c \ diff --git a/src/toolbox/bitvector.h b/src/toolbox/bitvector.h index a9428c226..9ca46ea47 100644 --- a/src/toolbox/bitvector.h +++ b/src/toolbox/bitvector.h @@ -33,6 +33,8 @@ #ifndef _BITVECTOR_H #define _BITVECTOR_H +#include "vm/global.h" + #if !defined(NDEBUG) #include diff --git a/src/toolbox/set.c b/src/toolbox/set.c new file mode 100644 index 000000000..b4fd7e71e --- /dev/null +++ b/src/toolbox/set.c @@ -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 + +#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 index 000000000..491ce4f17 --- /dev/null +++ b/src/toolbox/set.h @@ -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: + */ diff --git a/src/vm/jit/allocator/simplereg.c b/src/vm/jit/allocator/simplereg.c index d400406f0..f5cd6fce9 100644 --- a/src/vm/jit/allocator/simplereg.c +++ b/src/vm/jit/allocator/simplereg.c @@ -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 diff --git a/src/vm/jit/cfg.c b/src/vm/jit/cfg.c index 607261eae..2df6dd7ba 100644 --- a/src/vm/jit/cfg.c +++ b/src/vm/jit/cfg.c @@ -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. diff --git a/src/vm/jit/cfg.h b/src/vm/jit/cfg.h index 18adc1d86..a82b75ad7 100644 --- a/src/vm/jit/cfg.h +++ b/src/vm/jit/cfg.h @@ -44,6 +44,8 @@ bool cfg_build(jitdata *jd); +void cfg_add_root(jitdata *jd); + #endif /* _CFG_H */ diff --git a/src/vm/jit/jit.c b/src/vm/jit/jit.c index 09fc0c089..a08de3de6 100644 --- a/src/vm/jit/jit.c +++ b/src/vm/jit/jit.c @@ -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. diff --git a/src/vm/jit/jit.h b/src/vm/jit/jit.h index d98a72661..c097c32ed 100644 --- a/src/vm/jit/jit.h +++ b/src/vm/jit/jit.h @@ -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 *********************************/ diff --git a/src/vm/jit/optimizing/Makefile.am b/src/vm/jit/optimizing/Makefile.am index 4e9d34a72..02b29221b 100644 --- a/src/vm/jit/optimizing/Makefile.am +++ b/src/vm/jit/optimizing/Makefile.am @@ -64,7 +64,8 @@ SSA_SOURCES = \ dominators.c \ dominators.h \ lifetimes.c \ - lifetimes.h + lifetimes.h \ + ssa2.c endif noinst_LTLIBRARIES = \ diff --git a/src/vm/jit/optimizing/dominators.c b/src/vm/jit/optimizing/dominators.c index 82768c341..71352b762 100644 --- a/src/vm/jit/optimizing/dominators.c +++ b/src/vm/jit/optimizing/dominators.c @@ -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 diff --git a/src/vm/jit/optimizing/dominators.h b/src/vm/jit/optimizing/dominators.h index 13ac48c0c..376b78e4a 100644 --- a/src/vm/jit/optimizing/dominators.h +++ b/src/vm/jit/optimizing/dominators.h @@ -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 */ /* diff --git a/src/vm/jit/optimizing/ssa.c b/src/vm/jit/optimizing/ssa.c index e7dcbe02e..1e443e387 100644 --- a/src/vm/jit/optimizing/ssa.c +++ b/src/vm/jit/optimizing/ssa.c @@ -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 index 000000000..9bcc51853 --- /dev/null +++ b/src/vm/jit/optimizing/ssa2.c @@ -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 index 000000000..f4bd3b0ae --- /dev/null +++ b/src/vm/jit/optimizing/ssa2.h @@ -0,0 +1,4 @@ +#ifndef _VM_JIT_OPTIMIZING_SSA2 +#define _VM_JIT_OPTIMIZING_SSA2 + +#endif diff --git a/src/vm/jit/python.c b/src/vm/jit/python.c index e78f7b8ed..4f5926bf7 100644 --- a/src/vm/jit/python.c +++ b/src/vm/jit/python.c @@ -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 @@ -58,13 +56,24 @@ * 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 +#include #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); diff --git a/src/vm/jit/python.h b/src/vm/jit/python.h index d4e7309dc..56a44d429 100644 --- a/src/vm/jit/python.h +++ b/src/vm/jit/python.h @@ -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. @@ -26,13 +24,15 @@ #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 /* diff --git a/src/vm/jit/show.c b/src/vm/jit/show.c index b6539c796..cd18c9a6e 100644 --- a/src/vm/jit/show.c +++ b/src/vm/jit/show.c @@ -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"); }