* configure.ac: Added tests for python.
authorPeter Molnar <pm@complang.tuwien.ac.at>
Thu, 20 Dec 2007 15:47:16 +0000 (16:47 +0100)
committerPeter Molnar <pm@complang.tuwien.ac.at>
Thu, 20 Dec 2007 15:47:16 +0000 (16:47 +0100)
* m4/az_python.m4: New file.
* src/cacao/Makefile.am
src/vm/jit/Makefile.am: [ENABLE_PYTHON] Building python module and linking with python libs.
* src/vm/jit/jit.c [ENABLE_PYTHON] Calling some python function.
* src/vm/jit/python.c,
src/vm/jit/python.h: New files.
* src/vm/vm.c [ENABLE_PYTHON] Initializing python module.

configure.ac
m4/az_python.m4 [new file with mode: 0644]
src/cacao/Makefile.am
src/vm/jit/Makefile.am
src/vm/jit/jit.c
src/vm/jit/python.c [new file with mode: 0644]
src/vm/jit/python.h [new file with mode: 0644]
src/vm/vm.c

index 352f6772642c834fddeb9cd0e9e49ed9618fd49b..1efef64d5243a4d848310c2b2cbf95fb86106239 100644 (file)
@@ -800,6 +800,16 @@ AC_CHECK_HEADERS(
        ]
 )
 
+dnl python
+
+AZ_PYTHON_DEFAULT
+AZ_PYTHON_ENABLE
+AZ_PYTHON_WITH
+AZ_PYTHON_VERSION_ENSURE( [2.4] )
+AZ_PYTHON_CSPEC
+AZ_PYTHON_LSPEC
+
+
 dnl finally pass CFLAGS to Makefiles via AM_CFLAGS
 CFLAGS=$OPT_CFLAGS
 AM_CFLAGS=$ARCH_CFLAGS
diff --git a/m4/az_python.m4 b/m4/az_python.m4
new file mode 100644 (file)
index 0000000..4b082de
--- /dev/null
@@ -0,0 +1,518 @@
+##### http://autoconf-archive.cryp.to/az_python.html
+#
+# SYNOPSIS
+#
+#   AZ_PYTHON_DEFAULT
+#   AZ_PYTHON_ENABLE
+#   AZ_PYTHON_WITH
+#   AZ_PYTHON_PATH
+#   AZ_PYTHON_VERSION_ENSURE( [2.2] )
+#   AZ_PYTHON_CSPEC
+#   AZ_PYTHON_LSPEC
+#
+# DESCRIPTION
+#
+#   This file provides autoconf support for those applications that
+#   want to embed python. It supports all pythons >= 2.2 which is the
+#   first official release containing distutils. Version 2.2 of python
+#   was released December 21, 2001. Since it actually executes the
+#   python, cross platform configuration will probably not work. Also,
+#   most of the platforms supported are consistent until you look into
+#   MacOSX. The python included with it is installed as a framework
+#   which is a very different environment to set up the normal tools
+#   such as gcc and libtool to deal with. Therefore, once we establish
+#   which python that we are going to use, we use its distutils to
+#   actually compile and link our modules or applications.
+#
+#   At this time, it does NOT support linking with Python statically.
+#   It does support dynamic linking.
+#
+#   This set of macros help define $PYTHON, $ENABLE_PYTHON, $PYTHON_CSPEC
+#   and $PYTHON_LSPEC. $PYTHON defines the full executable path for the
+#   Python being linked to and is used within these macros to determine
+#   if that has been specified or found. These macros do execute this
+#   python version so it must be present on the system at configure
+#   time.
+#
+#   $ENABLE_PYTHON is an automake variable that defines whether Python
+#   support should be included or not in your application.
+#   $PYTHON_CSPEC is a variable that supplies additional CFLAGS for the
+#   compilation of the application/shared library. $PYTHON_LSPEC is a
+#   variable that supplies additional LDFLAGS for linking the
+#   application/shared library.
+#
+#   The following is an example of how to set up for python usage
+#   within your application in your configure.in:
+#
+#     AZ_PYTHON_DEFAULT( )
+#     AZ_PYTHON_ENABLE( )             # Optional
+#     AZ_PYTHON_WITH( )               # Optional
+#     AZ_PYTHON_PATH( )               # or AZ_PYTHON_INSIST( )
+#     # if $PYTHON is not defined, then the following do nothing.
+#     AZ_PYTHON_VERSION_ENSURE( [2.2] )
+#     AZ_PYTHON_CSPEC
+#     AZ_PYTHON_LSPEC
+#
+#   The AZ_PYTHON_DEFAULT sets the $ENABLE_PYTHON to false. Thereby,
+#   excluding it if it was optional.
+#
+#   The AZ_PYTHON_ENABLE looks for the optional configure parameters of
+#   --enable-python/--disable-python and establishes the $PYTHON and
+#   $ENABLE_PYTHON variables accordingly.
+#
+#   The AZ_PYTHON_WITH looks for the optional configure parameters of
+#   --with-python/--without-python and establishes the $PYTHON and
+#   $ENABLE_PYTHON variables accordingly.
+#
+#   The AZ_PYTHON_PATH looks for python assuming that none has been
+#   previously found or defined and issues an error if it does not find
+#   it. If it does find it, it establishes the $PYTHON and $ENABLE_PYTHON
+#   variables accordingly. AZ_PYTHON_INSIST could be used here instead
+#   if you want to insist that Python support be included using the
+#   --enable-python or --with-python checks previously done.
+#
+#   The AZ_PYTHON_VERSION_ENSURE issues an error if the Python
+#   previously found is not of version 2.2 or greater.
+#
+#   Once that these macros have be run, we can use ENABLE_PYTHON within
+#   the makefile.am file to conditionally add the Python support such
+#   as:
+#
+#   Makefile.am example showing optional inclusion of directories:
+#
+#    if ENABLE_PYTHON
+#    plugins = plugins
+#    src = src
+#    else
+#    plugins =
+#    src =
+#    endif
+#
+#    SUBDIRS = . $(plugins) $(src)
+#
+#   Makefile.am example showing optional shared library build:
+#
+#    if ENABLE_PYTHON
+#    lib_LTLIBRARIES        = libElemList.la
+#    libElemList_la_SOURCES = libElemList.c
+#    libElemList_la_CFLAGS  = @PYTHON_CSPEC@
+#    libElemList_la_LDFLAGS = @PYTHON_LSPEC@
+#    endif
+#
+#   Makefile.am example showing optional program build:
+#
+#    if ENABLE_PYTHON
+#    bin_PROGRAMS    = runFunc
+#    runFunc_SOURCES = runFunc.c
+#    runFunc_CFLAGS  = @PYTHON_CSPEC@
+#    runFunc_LDFLAGS = @PYTHON_LSPEC@
+#    endif
+#
+#   The above compiles the modules only if ENABLE_PYTHON was specified as
+#   true. Also, the else portion of the if was optional.
+#
+# LAST MODIFICATION
+#
+#   2007-08-04
+#
+# COPYLEFT
+#
+#   Copyright (c) 2007 Robert White <kranki@mac.com>
+#   Copyright (c) 2007 Dustin J. Mitchell <dustin@cs.uchicago.edu>
+#
+#   Copying and distribution of this file, with or without
+#   modification, are permitted in any medium without royalty provided
+#   the copyright notice and this notice are preserved.
+
+# AZ_PYTHON_DEFAULT( )
+# -----------------
+# Sets the default to not include Python support.
+
+AC_DEFUN([AZ_PYTHON_DEFAULT],
+[
+    az_python_use=false
+    AM_CONDITIONAL(ENABLE_PYTHON, test x"$az_python_use" = x"true")
+])
+
+
+
+# AZ_PYTHON_ENABLE( [path] )
+# -----------------------------------------------------------------
+# Handles the various --enable-python commands.
+# Input:
+#   $1 is the optional search path for the python executable if needed
+# Ouput:
+#   ENABLE_PYTHON (AM_CONDITIONAL) is true if python executable found
+#   and --enable-python was requested; otherwise false.
+#   $PYTHON contains the full executable path to python if PYTHON_ENABLE_USE
+#   is true.
+#
+# Example:
+#   AZ_PYTHON_ENABLE( )
+#   or
+#   AZ_PYTHON_ENABLE( "/usr/bin" )
+
+AC_DEFUN([AZ_PYTHON_ENABLE],
+[
+    AC_ARG_VAR([PYTHON],[Python Executable Path])
+
+    # unless PYTHON was supplied to us (as a precious variable),
+    # see if --enable-python[=PythonExecutablePath], --enable-python,
+    # --disable-python or --enable-python=no was given.
+    if test -z "$PYTHON"
+    then
+        AC_MSG_CHECKING(for --enable-python)
+        AC_ARG_ENABLE(
+            python,
+            AC_HELP_STRING([--enable-python@<:@=PYTHON@:>@],
+                [absolute path name of Python executable]
+            ),
+            [
+                if test "$enableval" = "yes"
+                then
+                    # "yes" was specified, but we don't have a path
+                    # for the executable.
+                    # So, let's searth the PATH Environment Variable.
+                    AC_MSG_RESULT(yes)
+                    AC_PATH_PROG(
+                        [PYTHON],
+                        python,
+                        [],
+                        $1
+                    )
+                    if test -z "$PYTHON"
+                    then
+                        AC_MSG_ERROR(no path to python found)
+                    fi
+                    az_python_use=true
+                    AM_CONDITIONAL(ENABLE_PYTHON, test x"$az_python_use" = x"true")
+                    AZ_PYTHON_PREFIX( )
+                elif test "$enableval" = "no"
+                then
+                    AC_MSG_RESULT(no)
+                    az_python_use=false
+                    AM_CONDITIONAL(ENABLE_PYTHON, test x"$az_python_use" = x"true")
+                else
+                    # $enableval must be the executable path then.
+                    AC_SUBST([PYTHON], ["${enableval}"])
+                    AC_MSG_RESULT($withval)
+                    az_python_use=true
+                    AM_CONDITIONAL(ENABLE_PYTHON, test x"$az_python_use" = x"true")
+                    AZ_PYTHON_PREFIX( )
+                fi
+            ],
+            [
+                # --with-python was not specified.
+                AC_MSG_RESULT(no)
+                az_python_use=false
+                AM_CONDITIONAL(ENABLE_PYTHON, test x"$az_python_use" = x"true")
+            ]
+        )
+    fi
+])
+
+
+
+# AZ_PYTHON_CSPEC( )
+# -----------------
+# Set up the c compiler options to compile Python
+# embedded programs/libraries in $PYTHON_CSPEC if
+# $PYTHON has been defined.
+
+AC_DEFUN([AZ_PYTHON_CSPEC],
+[
+    AC_ARG_VAR( [PYTHON], [Python Executable Path] )
+    if test -n "$PYTHON"
+    then
+        az_python_prefix=`${PYTHON} -c "import sys; print sys.prefix"`
+        if test -z "$az_python_prefix"
+        then
+            AC_MSG_ERROR([Python Prefix is not known])
+        fi
+        az_python_execprefix=`${PYTHON} -c "import sys; print sys.exec_prefix"`
+        az_python_version=`$PYTHON -c "import sys; print sys.version[[:3]]"`
+        az_python_includespec="-I${az_python_prefix}/include/python${az_python_version}"
+        if test x"$python_prefix" != x"$python_execprefix"; then
+            az_python_execspec="-I${az_python_execprefix}/include/python${az_python_version}"
+            az_python_includespec="${az_python_includespec} $az_python_execspec"
+        fi
+        az_python_ccshared=`${PYTHON} -c "import distutils.sysconfig; print distutils.sysconfig.get_config_var('CFLAGSFORSHARED')"`
+        az_python_cspec="${az_python_ccshared} ${az_python_includespec}"
+        AC_SUBST([PYTHON_CSPEC], [${az_python_cspec}])
+        AC_MSG_NOTICE([PYTHON_CSPEC=${az_python_cspec}])
+               AC_DEFINE(ENABLE_PYTHON, 1, [enabled python pass])
+    fi
+])
+
+
+
+# AZ_PYTHON_INSIST( )
+# -----------------
+# Look for Python and set the output variable 'PYTHON'
+# to 'python' if found, empty otherwise.
+
+AC_DEFUN([AZ_PYTHON_PATH],
+[
+    AC_ARG_VAR( [PYTHON], [Python Executable Path] )
+    if test -z "$PYTHON"
+    then
+        AC_MSG_ERROR([Python Executable not found])
+    fi
+])
+
+
+
+# AZ_PYTHON_LSPEC( )
+# -----------------
+# Set up the linker options to link Python embedded
+# programs/libraries in $PYTHON_LSPEC if $PYTHON
+# has been defined.
+
+AC_DEFUN([AZ_PYTHON_LSPEC],
+[
+    AC_ARG_VAR( [PYTHON], [Python Executable Path] )
+    if test -n "$PYTHON"
+    then
+        AZ_PYTHON_RUN([
+import sys
+import distutils.sysconfig
+strUseFrameWork = "--enable-framework"
+dictConfig = distutils.sysconfig.get_config_vars( )
+strConfigArgs = dictConfig.get("CONFIG_ARGS")
+strLinkSpec =  dictConfig.get('LDFLAGS')
+if -1 ==  strConfigArgs.find(strUseFrameWork):
+    strLibPL = dictConfig.get("LIBPL")
+    if strLibPL and (strLibPL != ""):
+        strLinkSpec += " -L%s" % (strLibPL)
+    strSys = dictConfig.get("SYSLIBS")
+    if strSys and (strSys != ""):
+        strLinkSpec += " %s" % (strSys)
+    strSHL = dictConfig.get("SHLIBS")
+    if strSHL and (strSHL != ""):
+        strLinkSpec += " %s" % (strSHL)
+    # Construct the Python Library Name.
+    strTmplte = " -lpython%d.%d"
+    if (sys.platform == "win32") or (sys.platform == "os2emx"):
+        strTmplte = " -lpython%d%d"
+    strWrk = strTmplte % ( (sys.hexversion >> 24),
+                            ((sys.hexversion >> 16) & 0xff))
+    strLinkSpec += strWrk
+else:
+    # This is not ideal since it changes the search path
+    # for Frameworks which could have side-effects on
+    # other included Frameworks.  However, it is necessary
+    # where someone has installed more than one frameworked
+    # Python.  Frameworks are really only used in MacOSX.
+    strLibFW = dictConfig.get("PYTHONFRAMEWORKPREFIX")
+    if strLibFW and (strLibFW != ""):
+        strLinkSpec += " -F%s" % (strLibFW)
+strLinkSpec += " %s" % (dictConfig.get('LINKFORSHARED'))
+print strLinkSpec
+        ])
+        AC_SUBST([PYTHON_LSPEC], [${az_python_output}])
+        AC_MSG_NOTICE([PYTHON_LSPEC=${az_python_output}])
+    fi
+])
+
+
+
+# AZ_PYTHON_PATH( )
+# -----------------
+# Look for Python and set the output variable 'PYTHON'
+# to 'python' if found, empty otherwise.
+
+AC_DEFUN([AZ_PYTHON_PATH],
+[
+    AC_ARG_VAR( [PYTHON], [Python Executable Path] )
+    AC_PATH_PROG( PYTHON, python, [], $1 )
+    if test -z "$PYTHON"
+    then
+        AC_MSG_ERROR([Python Executable not found])
+    else
+        az_python_use=true
+    fi
+    AM_CONDITIONAL(ENABLE_PYTHON, test "$az_python_use" = "true")
+])
+
+
+
+# AZ_PYTHON_PREFIX( )
+# -------------------
+# Use the values of $prefix and $exec_prefix for the corresponding
+# values of PYTHON_PREFIX and PYTHON_EXEC_PREFIX.
+
+AC_DEFUN([AZ_PYTHON_PREFIX],
+[
+    if test -z "$PYTHON"
+    then
+        AC_MSG_ERROR([Python Executable Path is not known])
+    fi
+    ax_python_prefix=`${PYTHON} -c "import sys; print sys.prefix"`
+    ax_python_execprefix=`${PYTHON} -c "import sys; print sys.exec_prefix"`
+    AC_SUBST([PYTHON_PREFIX], ["${ax_python_prefix}"])
+    AC_SUBST([PYTHON_EXECPREFIX], ["${ax_python_execprefix}"])
+])
+
+
+
+# AZ_PYTHON_RUN( PYTHON_PROGRAM )
+# -----------------
+# Run a Python Test Program saving its output
+# in az_python_output and its condition code
+# in az_python_cc.
+
+AC_DEFUN([AZ_PYTHON_RUN],
+[
+    AC_ARG_VAR( [PYTHON], [Python Executable Path] )
+    if test -z "$PYTHON"
+    then
+        AC_MSG_ERROR([Python Executable not found])
+    else
+        cat >conftest.py <<_ACEOF
+$1
+_ACEOF
+        az_python_output=`$PYTHON conftest.py`
+        az_python_cc=$?
+        rm conftest.py
+        if test -f "conftest.pyc"
+        then
+            rm conftest.pyc
+        fi
+    fi
+])
+
+
+
+# AZ_PYTHON_VERSION_CHECK( VERSION, [ACTION-IF-TRUE], [ACTION-IF-FALSE] )
+# -----------------------------------------------------------------------------
+# Run ACTION-IF-TRUE if the Python interpreter has version >= VERSION.
+# Run ACTION-IF-FALSE otherwise.
+# This test uses sys.hexversion instead of the string equivalant (first
+# word of sys.version), in order to cope with versions such as 2.2c1.
+# hexversion has been introduced in Python 1.5.2; it's probably not
+# worth to support older versions (1.5.1 was released on October 31, 1998).
+
+AC_DEFUN([AZ_PYTHON_VERSION_CHECK],
+ [
+    AC_ARG_VAR( [PYTHON], [Python Executable Path] )
+    if test -n "$PYTHON"
+    then
+        AC_MSG_CHECKING([whether $PYTHON version >= $1])
+        AZ_PYTHON_RUN([
+import sys, string
+# split strings by '.' and convert to numeric.  Append some zeros
+# because we need at least 4 digits for the hex conversion.
+minver = map(int, string.split('$1', '.')) + [[0, 0, 0]]
+minverhex = 0
+for i in xrange(0, 4): minverhex = (minverhex << 8) + minver[[i]]
+if sys.hexversion >= minverhex:
+    sys.exit( 0 )
+else:
+    sys.exit( 1 )
+        ])
+        if test $az_python_cc -eq 0
+        then
+            $2
+        m4_ifvaln(
+            [$3],
+            [else $3]
+        )
+        fi
+    fi
+])
+
+
+
+# AZ_PYTHON_VERSION_ENSURE( VERSION )
+# -----------------
+# Insure that the Python Interpreter Version
+# is greater than or equal to the VERSION
+# parameter.
+
+AC_DEFUN([AZ_PYTHON_VERSION_ENSURE],
+[
+    AZ_PYTHON_VERSION_CHECK(
+        [$1],
+        [AC_MSG_RESULT(yes)],
+        [AC_MSG_ERROR(too old)]
+    )
+])
+
+
+
+# AZ_PYTHON_WITH( [path] )
+# -----------------------------------------------------------------
+# Handles the various --with-python commands.
+# Input:
+#   $1 is the optional search path for the python executable if needed
+# Ouput:
+#   ENABLE_PYTHON (AM_CONDITIONAL) is true if python executable found
+#   and --with-python was requested; otherwise false.
+#   $PYTHON contains the full executable path to python if ENABLE_PYTHON
+#   is true.
+#
+# Example:
+#   AZ_PYTHON_WITH( )
+#   or
+#   AZ_PYTHON_WITH("/usr/bin")
+
+AC_DEFUN([AZ_PYTHON_WITH],
+[
+    AC_ARG_VAR([PYTHON],[Python Executable Path])
+
+    # unless PYTHON was supplied to us (as a precious variable),
+    # see if --with-python[=PythonExecutablePath], --with-python,
+    # --without-python or --with-python=no was given.
+    if test -z "$PYTHON"
+    then
+        AC_MSG_CHECKING(for --with-python)
+        AC_ARG_WITH(
+            python,
+            AC_HELP_STRING([--with-python@<:@=PYTHON@:>@],
+                [absolute path name of Python executable]
+            ),
+            [
+                if test "$withval" = "yes"
+                then
+                    # "yes" was specified, but we don't have a path
+                    # for the executable.
+                    # So, let's searth the PATH Environment Variable.
+                    AC_MSG_RESULT(yes)
+                    AC_PATH_PROG(
+                        [PYTHON],
+                        python,
+                        [],
+                        $1
+                    )
+                    if test -z "$PYTHON"
+                    then
+                        AC_MSG_ERROR(no path to python found)
+                    fi
+                    az_python_use=true
+                    AM_CONDITIONAL(ENABLE_PYTHON, test x"$az_python_use" = x"true")
+                    AZ_PYTHON_PREFIX( )
+                elif test "$withval" = "no"
+                then
+                    AC_MSG_RESULT(no)
+                    az_python_use=false
+                    AM_CONDITIONAL(ENABLE_PYTHON, test x"$az_python_use" = x"true")
+                else
+                    # $withval must be the executable path then.
+                    AC_SUBST([PYTHON], ["${withval}"])
+                    AC_MSG_RESULT($withval)
+                    az_python_use=true
+                    AM_CONDITIONAL(ENABLE_PYTHON, test x"$az_python_use" = x"true")
+                    AZ_PYTHON_PREFIX( )
+                fi
+            ],
+            [
+                # --with-python was not specified.
+                AC_MSG_RESULT(no)
+                az_python_use=false
+                AM_CONDITIONAL(ENABLE_PYTHON, test x"$az_python_use" = x"true")
+            ]
+        )
+    fi
+
+])
+
index 16529cdceba3c2d99abd757a7e83f6adb2e9be1b..19f09ece08ccafeda2e7965ba675a033ca48e8da 100644 (file)
@@ -71,6 +71,11 @@ if ENABLE_RT_TIMING
 cacao_LDFLAGS += -lrt
 endif
 
+if ENABLE_PYTHON
+cacao_LDFLAGS += \
+    @PYTHON_LSPEC@
+endif
+
 libjvm_la_SOURCES =
 
 libjvm_la_LIBADD = \
index 51956cdc2bf45f1f4518c4f6e0e9bac592842ed8..8ed1915d48cc883ca97902d1002df9a23bd50a0b 100644 (file)
@@ -187,6 +187,15 @@ libjit_la_LIBADD = \
        $(INTRP_LIB) \
        $(ARCH_LIB)
 
+if ENABLE_PYTHON
+libjit_la_SOURCES += \
+       python.c
+AM_CPPFLAGS += \
+       @PYTHON_CSPEC@
+LIBS += \
+       @PYTHON_LSPEC@
+endif
+
 
 ## Local variables:
 ## mode: Makefile
index 488103b81a61cd416cb1b26687df5944538065c2..5fa661aac7820da7f796d8d80579946075181ff9 100644 (file)
 
 #include "vm/jit/optimizing/reorder.h"
 
+#if defined(ENABLE_PYTHON)
+# include "vm/jit/python.h"
+#endif
+
 #include "vm/jit/verify/typecheck.h"
 
 #include "vmcore/class.h"
@@ -1456,6 +1460,12 @@ static u1 *jit_compile_intern(jitdata *jd)
                }
 #endif
 
+#if defined(ENABLE_PYTHON)
+               if (!pythonpass_run(jd, "ssa", "ssa")) {
+                       /*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
diff --git a/src/vm/jit/python.c b/src/vm/jit/python.c
new file mode 100644 (file)
index 0000000..15a8b0b
--- /dev/null
@@ -0,0 +1,1057 @@
+/* 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
+
+   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.
+
+   Note: this code is currently alpha and needs to be documented.
+
+   This code wraps the jitdata structure into a python object and
+   makes it possible to implement a compiler pass as python function.
+
+   The wrapping of cacao types to python objects is meant to be easy and
+   straight-forward.
+   Cacao structs a wrapped into a python ``wrapper'' object, the state of 
+   which consists of:
+
+    * A void pointer.
+       * A pointer to a class function (see class_func), which implements the
+         object's behaviour.
+
+   Arrays and collection-like data structures are wrapped into a python
+   ``iterator'' object, the state of wich consists of:
+
+    * A void pointer.
+       * Another void pointer that is the cursor.
+       * A pointer to a iterator function (see iterator_func) which implements
+         the iterator's behaviour.
+
+   Because in python field names are identified as strings, to avoid a lot
+   of string comparisons, we translate the field as early as possible into 
+   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
+   to do it rather high level and in a pythonic way. Examples:
+
+    * Bad: instruction.flags and cacao.FLAG_UNRESOLVED == 0
+       * Good: instruction.is_unresolved
+       * Bad: for i in range(0, bb.icount): instr = bb.instructions[i]
+       * Good: for instr in bb.instructions
+*/
+
+#include <Python.h>
+
+#include "vm/jit/python.h"
+
+/*
+ * Defs
+ */
+
+union class_arg {
+       struct {
+               int field;
+               PyObject **result;
+       } get;
+       struct {
+               int field;
+               PyObject *value;
+       } set;
+};
+
+typedef union class_arg class_arg;
+
+enum class_op {
+       SET_FIELD,
+       GET_FIELD
+};
+
+typedef enum class_op class_op;
+
+typedef int(*class_func)(void *, class_op, class_arg *);
+#define CLASS_FUNC(name) int name(void *vp, class_op op, class_arg *arg)
+
+struct iterator_state {
+       void *data;
+       void *pos;
+};
+
+union iterator_arg {
+       struct {
+               PyObject **result;
+       } get;
+       struct {
+               unsigned int index;
+               PyObject **result;
+       } subscript;
+       int length;
+};
+
+typedef union iterator_arg iterator_arg;
+
+typedef struct iterator_state iterator_state;
+
+enum iterator_op {
+       ITERATOR_INIT,
+       ITERATOR_GET,
+       ITERATOR_FORWARD,
+       ITERATOR_END,
+       ITERATOR_SUBSCRIPT,
+       ITERATOR_LENGTH
+};
+
+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
+
+struct field_map_entry {
+       const char *name;
+       int tag;
+};
+
+typedef struct field_map_entry field_map_entry;
+
+enum field {
+       F_BASIC_BLOCKS,
+       F_CALL_RETURN_TYPE,
+       F_CALL_ARGS,
+       F_CLASSREF,
+       F_DST,
+       F_DESCRIPTOR,
+       F_EXCEPTION_HANDLER,
+       F_FIELD_TYPE,
+       F_FIELD,
+       F_INSTRUCTIONS,
+       F_IS_CLASS_CONSTANT,
+       F_IS_UNRESOLVED,
+       F_LOCAL_METHODINFO,
+       F_KLASS,
+       F_LINE,
+       F_LOCAL_MAP,
+       F_METHOD,
+       F_NAME,
+       F_NAME_EX,
+       F_NR,
+       F_OFFSET,
+       F_OPCODE,
+       F_OPCODE_EX,
+       F_PARAM_TYPES,
+       F_PREDECESSORS,
+       F_REACHED,
+       F_RETURN_TYPE,
+       F_S1,
+       F_S2,
+       F_S3,
+       F_SUCCESSORS,
+       F_TYPE,
+       F_UNRESOLVED_FIELD,
+       F_VARS
+};
+
+/* Keep it soreted alphabetically, so we can support binary search in future. */
+struct field_map_entry field_map[] = {
+       { "basic_blocks", F_BASIC_BLOCKS },
+       { "call_return_type", F_CALL_RETURN_TYPE },
+       { "call_args", F_CALL_ARGS },
+       { "classref", F_CLASSREF },
+       { "dst", F_DST },
+       { "descriptor", F_DESCRIPTOR },
+       { "exception_handler", F_EXCEPTION_HANDLER },
+       { "field", F_FIELD },
+       { "field_type", F_FIELD_TYPE },
+       { "instructions", F_INSTRUCTIONS },
+       { "is_unresolved", F_IS_UNRESOLVED },
+       { "is_class_constant", F_IS_CLASS_CONSTANT },
+       { "klass", F_KLASS },
+       { "line", F_LINE },
+       { "local_map", F_LOCAL_MAP },
+       { "local_methodinfo", F_LOCAL_METHODINFO },
+       { "method", F_METHOD },
+       { "name", F_NAME },
+       { "name_ex", F_NAME_EX },
+       { "nr", F_NR },
+       { "offset", F_OFFSET },
+       { "opcode", F_OPCODE },
+       { "opcode_ex", F_OPCODE_EX },
+       { "param_types", F_PARAM_TYPES },
+       { "predecessors", F_PREDECESSORS },
+       { "reached", F_REACHED },
+       { "return_type", F_RETURN_TYPE },
+       { "s1", F_S1 },
+       { "s2", F_S2 },
+       { "s3", F_S3 },
+       { "successors", F_SUCCESSORS },
+       { "type", F_TYPE },
+       { "unresolved_field", F_UNRESOLVED_FIELD },
+       { "vars", F_VARS },
+       { NULL, 0 }
+};
+
+int field_find(const char *key) {
+       field_map_entry *it;
+
+       for (it = field_map; it->name; ++it) {
+               if (strcmp(it->name, key) == 0) {
+                       return it->tag;
+               }
+       }
+
+       return -1;
+}
+
+/*
+ * Python
+ */
+
+struct wrapper {
+       PyObject_HEAD
+       void *data;
+       class_func func;
+};
+
+typedef struct wrapper wrapper;
+
+PyObject *wrapper_getattr(wrapper *w, PyObject *fld) {
+       class_arg arg;
+       PyObject *result;
+
+       arg.get.field = field_find(PyString_AsString(fld));
+       if (arg.get.field == -1) {
+               return NULL;
+       }
+
+       arg.get.result = &result;
+
+       if (w->func(w->data, GET_FIELD, &arg) == -1) {
+               return NULL;
+       }
+
+       return result;
+}
+
+int wrapper_setattr(wrapper *w, PyObject *fld, PyObject *value) {
+       class_arg arg;
+
+       arg.set.field = field_find(PyString_AsString(fld));
+       if (arg.set.field == -1) {
+               return -1;
+       }
+       arg.set.value = value;
+
+       if (w->func(w->data, SET_FIELD, &arg) == -1) {
+               return -1;
+       }
+
+       return 0;
+}
+
+extern PyTypeObject wrapper_type;
+
+int wrapper_compare(wrapper *a, wrapper *b) {
+       if (PyObject_TypeCheck(b, &wrapper_type)) {
+               if (a->data < b->data) {
+                       return -1;
+               } else if (a->data > b->data) {
+                       return 1;
+               } else {
+                       return 0;
+               }
+       } else {
+               /* If classes differ, compare classes */
+               return PyObject_Compare(a->ob_type, b->ob_type);
+       }
+}
+
+long wrapper_hash(wrapper *a) {
+       return (long)a->data;
+}
+
+PyTypeObject wrapper_type = {
+       PyObject_HEAD_INIT(NULL)
+       0, /* ob_size */
+       "wrapper", /* tp_name */
+       sizeof(wrapper), /* tp_basicsize */
+       0, /* tp_itemsize */
+       0, /* tp_dealloc */
+       0, /* tp_print */
+       0, /* tp_getattr */
+       0, /* tp_setattr */
+       wrapper_compare, /* tp_compare */
+       0, /* tp_repr */
+       0, /* tp_as_number */
+       0, /* tp_as_sequence */
+       0, /* tp_as_mapping */
+       wrapper_hash, /* tp_hash */
+       0, /* tp_call */
+       0, /* tp_str */
+       wrapper_getattr, /* tp_getattro */
+       wrapper_setattr, /* 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 iterator {
+       PyObject_HEAD
+       iterator_func func;
+       iterator_state state;
+};
+
+typedef struct iterator iterator;
+
+PyObject *iterator_iter(struct iterator *it) {
+       Py_INCREF(it);
+       return (PyObject *)it;
+}
+
+PyObject *iterator_iternext(struct iterator *it) {
+       PyObject *ret;
+       iterator_arg arg;
+
+       if (it->func(ITERATOR_END, &it->state, NULL)) {
+               return NULL;
+       } else {
+               arg.get.result = &ret;
+               it->func(ITERATOR_GET, &it->state, &arg);
+               it->func(ITERATOR_FORWARD, &it->state, NULL);
+               return ret;
+       }
+}
+
+PyObject *iterator_getitem(struct iterator *it, PyObject* item) {
+       iterator_arg arg;
+       PyObject *ret;
+
+       if (PyInt_Check(item)) {
+               arg.subscript.index = PyInt_AS_LONG(item);
+               arg.subscript.result = &ret;
+               if (index < 0) { 
+                       return NULL;
+               } else if (it->func(ITERATOR_SUBSCRIPT, &it->state, &arg) != -1) {
+                       return ret;
+               } else {
+                       return NULL;
+               }
+       } else {
+               return NULL;
+       }
+}
+
+int iterator_length(struct iterator *it) {
+       iterator_arg arg;
+       if (it->func(ITERATOR_LENGTH, &it->state, &arg) == -1) {
+               return -1;
+       } else {
+               return arg.length;
+       }
+}
+
+PyMappingMethods iterator_mapping = {
+       iterator_length,
+       iterator_getitem,
+       0
+};
+
+PyTypeObject iterator_type = {
+       PyObject_HEAD_INIT(NULL)
+       0, /* ob_size */
+       "iterator", /* tp_name */
+       sizeof(iterator), /* 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 */
+       &iterator_mapping, /* tp_as_mapping */
+       0, /* tp_hash */
+       0, /* 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 */
+       iterator_iter, /* tp_iter */
+       iterator_iternext, /* 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 */
+};
+
+/*
+ * Utils
+ */
+
+int set_int(int *p, PyObject *o) {
+       if (PyInt_Check(o)) {
+               *p = PyInt_AsLong(o);   
+               return 0;
+       } else {
+               return -1;
+       }
+}
+
+int get_int(PyObject **o, int p) {
+       *o = Py_BuildValue("i", p);
+       return 0;
+}
+
+int get_string(PyObject **o, const char *str) {
+       *o = PyString_FromString(str);
+       return 0;
+}
+
+int get_obj(PyObject **res, class_func f, 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->data = p;
+               *res = o;
+               return 0;
+       }
+}
+
+int get_true(PyObject **res) {
+       Py_INCREF(Py_True);
+       *res = Py_True;
+       return 0;
+}
+
+int get_false(PyObject **res) {
+       Py_INCREF(Py_False);
+       *res = Py_False;
+       return 0;
+}
+
+int get_none(PyObject **res) {
+       Py_INCREF(Py_None);
+       *res = Py_None;
+       return 0;
+}
+
+int get_bool(PyObject **res, int cond) {
+       return cond ? get_true(res) : get_false(res);
+}
+       
+int get_iter(PyObject **res, iterator_func f, void *p) {
+       PyObject *o = PyObject_CallObject((PyObject *)&iterator_type, NULL);
+       struct iterator * it = (struct iterator *)o;
+       it->func = f;
+       it->state.data = p;
+       f(ITERATOR_INIT, &it->state, NULL);
+       *res = o;
+       return 0;
+}
+
+int add_const(PyObject *module, const char *name, int value) {
+       PyObject *pyvalue = PyInt_FromLong(value);
+       if (pyvalue != NULL) {
+               PyModule_AddObject(module, name, pyvalue);
+       }
+}
+
+/*
+ * Implemnetation
+ */
+
+CLASS_FUNC(basicblock_func);
+CLASS_FUNC(classinfo_func);
+CLASS_FUNC(constant_classref_func);
+CLASS_FUNC(methodinfo_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;
+       }
+}
+
+ITERATOR_FUNC(call_args_iter_func) {
+       instruction *iptr = (instruction *)state->data;
+       switch (op) {
+               case ITERATOR_INIT:
+                       state->pos = iptr->sx.s23.s2.args;
+                       return 0;
+               case ITERATOR_LENGTH:
+                       arg->length = instruction_call_site(iptr)->paramcount;
+                       return 0;
+               case ITERATOR_GET:
+                       return get_int(arg->get.result, *(int *)state->pos);
+               case ITERATOR_END:
+                       return state->pos == (iptr->sx.s23.s2.args + instruction_call_site(iptr)->paramcount);
+               case ITERATOR_FORWARD:
+                       state->pos = ((int *)state->pos) + 1;
+                       return 0;
+               case ITERATOR_SUBSCRIPT:
+                       ITERATOR_SUBSCRIPT_CHECK(instruction_call_site(iptr)->paramcount);
+                       return get_int(arg->subscript.result, iptr->sx.s23.s2.args[arg->subscript.index]);
+       }
+       return -1;
+}
+
+CLASS_FUNC(fieldinfo_func) {
+       fieldinfo *fi = (fieldinfo *)vp;
+
+       switch (op) {
+               case GET_FIELD:
+                       switch (arg->get.field) {
+                               case F_TYPE:
+                                       return get_int(arg->get.result, fi->type);
+                               case F_OFFSET:
+                                       return get_int(arg->get.result, fi->offset);
+                               case F_NAME:
+                                       return get_string(arg->get.result, fi->name->text);
+                               case F_KLASS:
+                                       return get_obj(arg->get.result, classinfo_func, fi->class);
+                       }
+       }
+
+       return -1;
+}
+
+CLASS_FUNC(unresolved_field_func) {
+       unresolved_field *uf = (unresolved_field *)vp;
+       switch (op) {
+               case GET_FIELD:
+                       switch (arg->get.field) {
+                               case F_NAME:
+                                       return get_string(arg->get.result, uf->fieldref->name->text);
+                               case F_CLASSREF:
+                                       if (IS_FMIREF_RESOLVED(uf->fieldref)) {
+                                               return get_none(arg->get.result);
+                                       } else {
+                                               return get_obj(arg->get.result, constant_classref_func, 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, uf->fieldref->p.field);
+                                       } else {
+                                               return get_none(arg->get.result);
+                                       }
+                               case F_IS_UNRESOLVED:
+                                       return get_bool(arg->get.result, !IS_FMIREF_RESOLVED(uf->fieldref));
+                       }
+       }
+       return -1;
+}
+
+CLASS_FUNC(instruction_func) {
+
+       instruction *iptr = (instruction *)vp;
+
+       switch (op) {
+               case GET_FIELD:
+                       switch (arg->get.field) {
+                               case F_OPCODE:
+                                       return get_int(arg->get.result, iptr->opc);
+                               case F_OPCODE_EX:
+                                       if (iptr->opc == ICMD_BUILTIN) {
+                                               return get_int(arg->get.result, iptr->sx.s23.s3.bte->opcode);
+                                       } else {
+                                               return get_int(arg->get.result, iptr->opc);
+                                       }
+                               case F_NAME:
+                                       return get_string(arg->get.result, icmd_table[iptr->opc].name);
+                               case F_NAME_EX:
+                                       if (iptr->opc == ICMD_BUILTIN) {
+                                               return get_string(arg->get.result, icmd_table[iptr->sx.s23.s3.bte->opcode].name);
+                                       } else {
+                                               return get_string(arg->get.result, icmd_table[iptr->opc].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_DST:
+                                       return get_int(arg->get.result, iptr->dst.varindex);
+                               case F_CALL_RETURN_TYPE:
+                                       return get_int(arg->get.result, instruction_call_site(iptr)->returntype.type);
+                               case F_CALL_ARGS:
+                                       return get_iter(arg->get.result, call_args_iter_func, iptr);    
+                               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, iptr->sx.val.c.cls);
+                               case F_CLASSREF:
+                                       return get_obj(arg->get.result, constant_classref_func, 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, 
+                                                       iptr->sx.s23.s3.fmiref->p.method);
+                                       }
+                               case F_FIELD_TYPE:
+                                       if (INSTRUCTION_IS_UNRESOLVED(iptr)) {
+                                               return get_int(arg->get.result,
+                                                       iptr->sx.s23.s3.uf->fieldref->parseddesc.fd->type);
+                                       } else {
+                                               return get_int(arg->get.result,
+                                                       iptr->sx.s23.s3.fmiref->p.field->type);
+                                       }
+                               case F_FIELD:
+                                       if (INSTRUCTION_IS_UNRESOLVED(iptr)) {
+                                               return get_none(arg->get.result);
+                                       } else {
+                                               return get_obj(arg->get.result, fieldinfo_func, 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, iptr->sx.s23.s3.uf);
+                                       } else {
+                                               return get_none(arg->get.result);
+                                       }
+                                       break;
+                               case F_LINE:
+                                       return get_int(arg->get.result, iptr->line);
+                       }
+       }
+
+       return -1;
+}
+
+ITERATOR_FUNC(predecessors_iter_func) {
+       basicblock *bptr = (basicblock *)state->data;
+
+       switch (op) {
+               case ITERATOR_INIT:
+                       state->pos = bptr->predecessors;
+                       return 0;
+               case ITERATOR_GET:
+                       return get_obj(arg->get.result, basicblock_func, *(basicblock **)state->pos);
+               case ITERATOR_END:
+                       return 
+                               (state->pos == (bptr->predecessors + bptr->predecessorcount)) ||
+                               (bptr->predecessorcount < 0);
+               case ITERATOR_FORWARD:
+                       state->pos = ((basicblock **)state->pos) + 1;
+                       return 0;
+       }
+
+       return -1;
+}
+
+ITERATOR_FUNC(successors_iter_func) {
+       basicblock *bptr = (basicblock *)state->data;
+
+       switch (op) {
+               case ITERATOR_INIT:
+                       state->pos = bptr->successors;
+                       return 0;
+               case ITERATOR_GET:
+                       return get_obj(arg->get.result, basicblock_func, *(basicblock **)state->pos);
+               case ITERATOR_END:
+                       return 
+                               (state->pos == (bptr->successors + bptr->successorcount)) || 
+                               (bptr->successorcount < 0);
+               case ITERATOR_FORWARD:
+                       state->pos = ((basicblock **)state->pos) + 1;
+                       return 0;
+       }
+
+       return  -1;
+}
+
+ITERATOR_FUNC(instruction_iter_func) {
+       basicblock *bptr = (basicblock *)state->data;
+
+       switch (op) {
+               case ITERATOR_INIT:
+                       state->pos = bptr->iinstr;
+                       return 0;
+               case ITERATOR_GET:
+                       return get_obj(arg->get.result, instruction_func, state->pos);
+               case ITERATOR_FORWARD:
+                       state->pos = ((instruction *)state->pos) + 1;
+                       return 0;
+               case ITERATOR_END:
+                       return state->pos == (bptr->iinstr + bptr->icount);
+               case ITERATOR_SUBSCRIPT:
+                       ITERATOR_SUBSCRIPT_CHECK(bptr->icount);
+                       return get_obj(arg->subscript.result, instruction_func, bptr->iinstr + arg->subscript.index);
+               case ITERATOR_LENGTH:
+                       arg->length = bptr->icount;
+                       return 0;
+       }
+       return -1;
+}
+
+CLASS_FUNC(basicblock_func) {
+       basicblock *bptr = (basicblock *)vp;
+
+       switch (op) {
+               case GET_FIELD:
+                       switch (arg->get.field) {
+                               case F_INSTRUCTIONS:
+                                       return get_iter(arg->get.result, instruction_iter_func, bptr);
+                               case F_NR:
+                                       return get_int(arg->get.result, bptr->nr);
+                               case F_PREDECESSORS:
+                                       return get_iter(arg->get.result, predecessors_iter_func, bptr);
+                               case F_SUCCESSORS:
+                                       return get_iter(arg->get.result, successors_iter_func, 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);
+                       }
+       }
+
+       return -1;
+}
+
+ITERATOR_FUNC(basicblocks_iter_func) {
+       jitdata *jd = (jitdata *)state->data;
+
+       switch (op) {
+               case ITERATOR_INIT:
+                       state->pos = jd->basicblocks;
+                       return 0;       
+               case ITERATOR_GET:
+                       return get_obj(arg->get.result, basicblock_func, state->pos);
+               case ITERATOR_FORWARD:
+                       state->pos = ((basicblock *)(state->pos))->next;
+                       return 0;
+               case ITERATOR_END:
+                       return (state->pos == NULL);
+               case ITERATOR_SUBSCRIPT:
+                       if (arg->subscript.index == 0 && jd->basicblocks != NULL) {
+                               return get_obj(arg->subscript.result, basicblock_func, jd->basicblocks);
+                       } else {
+                               return -1;
+                       }
+       }
+
+       return -1;
+}
+
+CLASS_FUNC(classinfo_func) {
+       classinfo *c = (classinfo *)vp;
+       switch (op) {
+               case GET_FIELD:
+                       switch (arg->get.field) {
+                               case F_NAME:
+                                       return get_string(arg->get.result, c->name->text);
+                       }
+       }
+       return -1;
+}
+
+CLASS_FUNC(constant_classref_func) {
+       constant_classref *cr = (constant_classref *)vp;
+       switch (op) {
+               case GET_FIELD:
+                       switch (arg->get.field) {
+                               case F_NAME:
+                                       return get_string(arg->get.result, cr->name->text);
+                       }
+       }
+       return -1;
+}
+
+ITERATOR_FUNC(param_types_iter_func) {
+       methodinfo *m = (methodinfo *)state->data;
+
+       switch (op) {
+               case ITERATOR_INIT:
+                       state->pos = m->parseddesc->paramtypes;
+                       return 0;
+               case ITERATOR_END:
+                       return state->pos == (m->parseddesc->paramtypes + m->parseddesc->paramcount);
+               case ITERATOR_FORWARD:
+                       state->pos = ((typedesc *)state->pos) + 1;
+                       return 0;
+               case ITERATOR_GET:
+                       return get_int(arg->get.result, ((typedesc *)state->pos)->type);
+               case ITERATOR_LENGTH:
+                       arg->length = m->parseddesc->paramcount;
+                       return 0;
+               case ITERATOR_SUBSCRIPT:
+                       ITERATOR_SUBSCRIPT_CHECK(m->parseddesc->paramcount);
+                       return get_int(arg->subscript.result, m->parseddesc->paramtypes[arg->subscript.index].type);
+       }
+
+       return -1;
+}
+
+CLASS_FUNC(methodinfo_func) {
+       methodinfo *m = (methodinfo *)vp;
+       switch (op) {
+               case GET_FIELD:
+                       switch (arg->get.field) {
+                               case F_NAME:
+                                       return get_string(arg->get.result, m->name->text);
+                               case F_KLASS:
+                                       return get_obj(arg->get.result, classinfo_func, m->class);
+                               case F_PARAM_TYPES:
+                                       return get_iter(arg->get.result, param_types_iter_func, m);
+                               case F_RETURN_TYPE:
+                                       return get_int(arg->get.result, m->parseddesc->returntype.type);
+                       }
+       }
+       return -1;
+}
+
+
+CLASS_FUNC(varinfo_func) {
+       varinfo *var = (varinfo *)vp;
+       switch (op) {
+               case GET_FIELD:
+                       switch (arg->get.field) {
+                               case F_TYPE:
+                                       return get_int(arg->get.result, var->type);
+                       }
+       }
+       return -1;
+}
+
+ITERATOR_FUNC(vars_func) {
+       jitdata *jd = (jitdata *)state->data;
+       switch (op) {
+               case ITERATOR_INIT:
+                       state->pos = jd->var;
+                       return 0;
+               case ITERATOR_FORWARD:
+                       state->pos = ((varinfo *)state->pos) + 1;
+                       return 0;
+               case ITERATOR_END:
+                       return state->pos == (jd->var + jd->varcount);
+               case ITERATOR_GET:
+                       return get_obj(arg->get.result, varinfo_func, state->pos);
+               case ITERATOR_LENGTH:
+                       arg->length = jd->varcount;
+                       return 0;
+               case ITERATOR_SUBSCRIPT:
+                       ITERATOR_SUBSCRIPT_CHECK(jd->varcount);
+                       return get_obj(arg->subscript.result, varinfo_func, jd->var + arg->subscript.index);
+       }
+       return -1;
+}
+
+ITERATOR_FUNC(local_map_2_iter_func) {
+       int *arr = (int *)state->data;
+       switch (op) {
+               case ITERATOR_SUBSCRIPT:
+                       ITERATOR_SUBSCRIPT_CHECK(5);
+                       return get_int(arg->subscript.result, arr[arg->subscript.index]);
+               case ITERATOR_LENGTH:
+                       arg->length = 5;
+                       return 0;
+       }
+       return -1;
+}
+
+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, 
+                               jd->local_map + (5 * arg->subscript.index));
+       }
+       return -1;
+}
+
+CLASS_FUNC(jd_func) {
+       jitdata *jd = (jitdata *)vp;
+
+       switch (op) {
+               case GET_FIELD:
+                       switch (arg->get.field) {
+                               case F_BASIC_BLOCKS:
+                                       return get_iter(arg->get.result, basicblocks_iter_func, jd);
+                               case F_METHOD:
+                                       return get_obj(arg->get.result, methodinfo_func, jd->m);
+                               case F_VARS:
+                                       return get_iter(arg->get.result, vars_func, jd);
+                               case F_LOCAL_MAP:
+                                       return get_iter(arg->get.result, local_map_iter_func, jd);
+                       }
+       }
+
+       return -1;
+}
+
+void constants(PyObject *m) {
+       char buf[32];
+       char *pos;
+       int i;
+
+       /* icmds */
+
+       for (i = 0; i < sizeof(icmd_table) / sizeof(icmd_table[0]); ++i) {
+               snprintf(buf, sizeof(buf), "ICMD_%s", icmd_table[i].name);
+               pos = strchr(buf, ' ');
+               if (pos != NULL) {
+                       *pos = '\0';
+               }
+               add_const(m, buf, i);
+       }
+
+#      define c(x) add_const(m, #x, x)
+
+       /* types */
+
+       c(TYPE_INT);
+       c(TYPE_LNG);
+       c(TYPE_ADR);
+       c(TYPE_FLT);
+       c(TYPE_DBL);
+       c(TYPE_VOID);
+       c(UNUSED);
+
+#      undef c
+}
+
+/*
+ * Pythonpass
+ */
+
+void pythonpass_init() {
+       PyObject *m;
+       
+       Py_Initialize();
+       PyEval_InitThreads();
+
+       if (PyType_Ready(&wrapper_type) < 0) return;
+       if (PyType_Ready(&iterator_type) < 0) return;
+
+       m = Py_InitModule3("cacao", NULL, NULL);
+       if (m != NULL) {
+               constants(m);
+       }
+
+}
+
+void pythonpass_cleanup() {
+       Py_Finalize();
+}
+
+int pythonpass_run(jitdata *jd, const char *module, const char *function) {
+       PyObject *pymodname = NULL;
+       PyObject *pymod = NULL;
+       PyObject *pydict = NULL;
+       PyObject *pyfunc = NULL;
+       PyObject *pyargs = NULL;
+       PyObject *pyret = NULL;
+       PyObject *pyarg = NULL;
+       int success = 0;
+
+       pymodname = PyString_FromString(module);
+       pymod = PyImport_Import(pymodname);
+
+       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) != -1) {
+                       }
+
+                       /* */
+
+                       PyTuple_SetItem(pyargs, 0, pyarg);
+
+                       pyret = PyObject_CallObject(pyfunc, pyargs);
+                       if (pyret == NULL) {
+                PyErr_Print();
+                       } else {
+                               success = 1;
+                       }
+               } else {
+                       if (PyErr_Occurred())
+                               PyErr_Print();
+               }
+       } else {
+               PyErr_Print();
+       }
+
+       Py_XDECREF(pymodname);
+       Py_XDECREF(pymod);
+       Py_XDECREF(pyargs);
+       Py_XDECREF(pyret);
+
+       return (success == 1 ? 1 : 0);
+}
+
+/*
+ * 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/python.h b/src/vm/jit/python.h
new file mode 100644 (file)
index 0000000..d4e7309
--- /dev/null
@@ -0,0 +1,50 @@
+/* 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
+
+   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 _VM_JIT_PYTHON_H
+#define _VM_JIT_PYTHON_H
+
+#include "vm/jit/jit.h"
+
+void pythonpass_init();
+int pythonpass_run(jitdata *jd, const char *module, const char *function);
+void pythonpass_cleanup();
+
+#endif
+
+/*
+ * These are local overrides for various environment variables in Emacs.
+ * Please do not remove this and leave it at the end of the file, where
+ * Emacs will automagically detect them.
+ * ---------------------------------------------------------------------
+ * Local variables:
+ * mode: c
+ * indent-tabs-mode: t
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ * vim:noexpandtab:sw=4:ts=4:
+ */
index e1d7dafb2b76e01841113d728e3119865fb4249e..af21d693d82db24d6cc8f07853b47e1b66a22b52 100644 (file)
 
 #include "vm/jit/optimizing/recompile.h"
 
+#if defined(ENABLE_PYTHON)
+# include "vm/jit/python.h"
+#endif
+
 #include "vmcore/classcache.h"
 #include "vmcore/options.h"
 #include "vmcore/statistics.h"
@@ -1501,6 +1505,10 @@ bool vm_create(JavaVMInitArgs *vm_args)
 
        jit_init();
 
+#if defined(ENABLE_PYTHON)
+       pythonpass_init();
+#endif
+
        /* BEFORE: loader_preinit */
 
        package_init();