[pypy-svn] r35533 - in pypy/dist/pypy/translator/jvm: . src test

niko at codespeak.net niko at codespeak.net
Sat Dec 9 08:35:05 CET 2006


Author: niko
Date: Sat Dec  9 08:35:03 2006
New Revision: 35533

Added:
   pypy/dist/pypy/translator/jvm/src/ExceptionWrapper.java
Modified:
   pypy/dist/pypy/translator/jvm/database.py
   pypy/dist/pypy/translator/jvm/generator.py
   pypy/dist/pypy/translator/jvm/genjvm.py
   pypy/dist/pypy/translator/jvm/node.py
   pypy/dist/pypy/translator/jvm/src/PyPy.java
   pypy/dist/pypy/translator/jvm/test/runtest.py
   pypy/dist/pypy/translator/jvm/typesystem.py
Log:
put in the "least resistance" way to make exceptions work: introduce a 
wrapper class that descends from RuntimeException.  we can improve it
later either by not using exception mechanism at all or by making it possible
for RPython exceptions to descend from Throwable



Modified: pypy/dist/pypy/translator/jvm/database.py
==============================================================================
--- pypy/dist/pypy/translator/jvm/database.py	(original)
+++ pypy/dist/pypy/translator/jvm/database.py	Sat Dec  9 08:35:03 2006
@@ -100,10 +100,8 @@
         assert OOTYPE._superclass
         supercls = self.pending_class(OOTYPE._superclass)
 
-        # TODO --- make package of java class reflect the package of the
-        # OO class?
-        clsnm = self._pkg(
-            self._uniq(OOTYPE._name.replace('.','_')))
+        # Create the class object
+        clsnm = self._pkg(self._uniq(OOTYPE._name))
         clsobj = node.Class(clsnm, supercls)
 
         print "Class %s has super %s" % (

Modified: pypy/dist/pypy/translator/jvm/generator.py
==============================================================================
--- pypy/dist/pypy/translator/jvm/generator.py	(original)
+++ pypy/dist/pypy/translator/jvm/generator.py	Sat Dec  9 08:35:03 2006
@@ -6,12 +6,7 @@
 from pypy.translator.jvm.typesystem import \
      JvmType, jString, jInt, jLong, jDouble, jBool, jString, \
      jPyPy, jVoid, jMath, desc_for_method, jPrintStream, jClass, jChar, \
-     jObject, jByteArray
-
-# ___________________________________________________________________________
-# Helper class string constants
-
-PYPYJAVA = jPyPy.name
+     jObject, jByteArray, jPyPyExcWrap
 
 # ___________________________________________________________________________
 # Miscellaneous helper functions
@@ -236,6 +231,7 @@
 DUP2 =      Opcode('dup2')
 POP =       Opcode('pop')
 POP2 =      Opcode('pop2')
+SWAP =      Opcode('swap')
 INSTANCEOF= IntClassNameOpcode('instanceof')
 # Loading/storing local variables
 LOAD =      OpcodeFamily(VarOpcode, "load")
@@ -353,9 +349,12 @@
 PYPYDUMPBOOLEAN =       Method.s(jPyPy, 'dump_boolean', (jBool,jInt), jVoid)
 PYPYDUMPOBJECT =        Method.s(jPyPy, 'dump_object', (jObject,jInt,), jVoid)
 PYPYDUMPVOID =          Method.s(jPyPy, 'dump_void', (jInt,), jVoid)
+PYPYDUMPEXCWRAPPER =    Method.s(jPyPy, 'dump_exc_wrapper', (jObject,), jVoid)
 PYPYRUNTIMENEW =        Method.s(jPyPy, 'RuntimeNew', (jClass,), jObject)
 PYPYSTRING2BYTES =      Method.s(jPyPy, 'string2bytes', (jString,), jByteArray)
-
+OBJECTGETCLASS =        Method.v(jObject, 'getClass', (), jClass)
+CLASSGETNAME =          Method.v(jClass, 'getName', (), jString)
+EXCWRAPWRAP =           Method.s(jPyPyExcWrap, 'wrap', (jObject,), jPyPyExcWrap)
 
 # ___________________________________________________________________________
 # Fields
@@ -391,6 +390,8 @@
 DOUBLEPOSINF = Field('java.lang.Double', 'POSITIVE_INFINITY', jDouble, True)
 DOUBLENEGINF = Field('java.lang.Double', 'NEGATIVE_INFINITY', jDouble, True)
 
+EXCWRAPOBJ =   Field(jPyPyExcWrap.name, 'object', jObject, False)
+
 # ___________________________________________________________________________
 # Generator State
 
@@ -557,6 +558,13 @@
         """ Returns a value from top of stack of the JvmType 'vartype' """
         self._instr(RETURN.for_type(vartype))
 
+    def load_class_name(self):
+        """ Loads the name of the *Java* class of the object on the top of
+        the stack as a Java string.  Note that the result for a PyPy
+        generated class will look something like 'pypy.some.pkg.cls' """
+        self.emit(OBJECTGETCLASS)
+        self.emit(CLASSGETNAME)
+
     def load_string(self, str):
         """ Pushes a Java version of a Python string onto the stack.
         'str' should be a Python string encoded in UTF-8 (I think) """
@@ -647,10 +655,24 @@
         try region is reused.
         'excclsty' --- a JvmType for the class of exception to be caught
         """
-        catchlbl = self.unique_label("catch")
-        self.mark(catchlbl, mark=True)
-        self.try_catch_region(
-            excclsty, self.begintrylbl, send.endtrylbl, catchlbl)
+        catchlbl = self.unique_label("catch", mark=True)
+        self._try_catch_region(
+            jPyPyExcWrap, self.begintrylbl, self.endtrylbl, catchlbl)
+
+        # emit the code to unwrap the exception, check the type
+        # of the unwrapped object, and re-throw the exception
+        # if it not the right type
+        catch = self.unique_label('catch')
+        self.emit(DUP)
+        EXCWRAPOBJ.load(self)
+        self.emit(INSTANCEOF, excclsty)
+        self.emit(IFNE, catch)
+        self.emit(ATHROW)
+
+        # If it IS the right type, just dereference and get the
+        # wrapped Python object 
+        self.mark(catch)
+        EXCWRAPOBJ.load(self)
 
     def end_catch(self):
         """
@@ -659,7 +681,7 @@
         """
         return
         
-    def try_catch_region(self, excclsty, trystartlbl, tryendlbl, catchlbl):
+    def _try_catch_region(self, excclsty, trystartlbl, tryendlbl, catchlbl):
         """
         Indicates a try/catch region:
         'excclsty' --- a JvmType for the class of exception to be caught
@@ -737,7 +759,7 @@
         self._instr(INSTANCEOF, jtype)
 
     def branch_unconditionally(self, target_label):
-        self._instr(GOTO, target_label)
+        self.goto(target_label)
 
     def branch_conditionally(self, cond, target_label):
         if cond:
@@ -846,6 +868,12 @@
 
     def throw(self):
         """ Throw the object from top of the stack as an exception """
+
+        # We have to deal with the problem that exceptions must
+        # derive from Throwable, but our exception hierarchy in OOTYPE
+        # does not (today).  For now, we use a wrapper class, which is
+        # probably the worst answer of all, but an easy one.
+        self.emit(EXCWRAPWRAP)
         self._instr(ATHROW)
 
     def iabs(self):
@@ -859,6 +887,10 @@
         self._instr(ICONST, -1)
         self._instr(IXOR)
 
+    def goto(self, label):
+        """ Jumps unconditionally """
+        self._instr(GOTO, label)
+
     def goto_if_true(self, label):
         """ Jumps if the top of stack is true """
         self._instr(IFNE, label)
@@ -1016,7 +1048,10 @@
             instr_text, self.curfunc.instr_counter))
         self.curfunc.instr_counter+=1
 
-    def try_catch_region(self, excclsty, trystartlbl, tryendlbl, catchlbl):
+    def _try_catch_region(self, excclsty, trystartlbl, tryendlbl, catchlbl):
         self.curclass.out('  .catch %s from %s to %s using %s\n' % (
-            excclsty.int_class_name(), trystartlbl, tryendlbl, catchlbl))
+            excclsty.descriptor.int_class_name(),
+            trystartlbl.jasmin_syntax(),
+            tryendlbl.jasmin_syntax(),
+            catchlbl.jasmin_syntax()))
                        

Modified: pypy/dist/pypy/translator/jvm/genjvm.py
==============================================================================
--- pypy/dist/pypy/translator/jvm/genjvm.py	(original)
+++ pypy/dist/pypy/translator/jvm/genjvm.py	Sat Dec  9 08:35:03 2006
@@ -94,28 +94,32 @@
             raise JvmSubprogramError(res, args, stdout, stderr)
         return stdout, stderr
 
-    def compile(self):
-        """
-        Compiles the .java sources into .class files, ready for execution.
-        """
-        jascmd = [getoption('jasmin'), '-d', str(self.javadir)]
-        for jasfile in self.jasmin_files:
-            print "Invoking jasmin on %s" % jasfile
-            self._invoke(jascmd+[jasfile], False)
-
+    def _compile_helper(self, clsnm):
         # HACK: compile the Java helper class.  Should eventually
         # use rte.py
-        pypycls = self.classdir.join('PyPy.class')
+        pypycls = self.classdir.join(clsnm + '.class')
         if not os.path.exists(str(pypycls)):
             sl = __file__.rindex('/')
-            javasrc = __file__[:sl]+"/src/PyPy.java"
+            javasrc = __file__[:sl]+("/src/%s.java" % clsnm)
             self._invoke([getoption('javac'),
                           '-nowarn',
                           '-d', str(self.classdir),
                           javasrc],
                          True)
+        
+
+    def compile(self):
+        """
+        Compiles the .java sources into .class files, ready for execution.
+        """
+        jascmd = [getoption('jasmin'), '-d', str(self.javadir)]
+        for jasfile in self.jasmin_files:
+            print "Invoking jasmin on %s" % jasfile
+            self._invoke(jascmd+[jasfile], False)
                            
         self.compiled = True
+        self._compile_helper('PyPy')
+        self._compile_helper('ExceptionWrapper')
 
     def execute(self, args):
         """

Modified: pypy/dist/pypy/translator/jvm/node.py
==============================================================================
--- pypy/dist/pypy/translator/jvm/node.py	(original)
+++ pypy/dist/pypy/translator/jvm/node.py	Sat Dec  9 08:35:03 2006
@@ -78,6 +78,9 @@
         gen.begin_function(
             'main', (), [jStringArray], jVoid, static=True)
 
+        if self.print_result:
+            gen.begin_try()
+
         # Handle arguments:
         if self.expand_arguments:
             # Convert each entry into the array to the desired type by
@@ -101,11 +104,25 @@
         gen.emit(self.db.pending_function(self.graph))
 
         # Print result?
+        #
+        #   Use the dump method for non-exceptional results
+        #
+        #   For exceptions, just print the runtime type
+        #
         if self.print_result:
+            done_printing = gen.unique_label('done_printing')
             gen.emit(jvmgen.ICONST, 0)
             RESOOTYPE = self.graph.getreturnvar().concretetype
             dumpmethod = self.db.generate_dump_method_for_ootype(RESOOTYPE)
             dumpmethod.invoke(gen)
+            gen.goto(done_printing)
+            gen.end_try()
+
+            gen.begin_catch(jObject)
+            gen.emit(jvmgen.PYPYDUMPEXCWRAPPER)
+            gen.end_catch()
+
+            gen.mark(done_printing)
 
         # And finish up
         gen.return_val(jVoid)

Added: pypy/dist/pypy/translator/jvm/src/ExceptionWrapper.java
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/translator/jvm/src/ExceptionWrapper.java	Sat Dec  9 08:35:03 2006
@@ -0,0 +1,13 @@
+package pypy;
+
+public class ExceptionWrapper extends RuntimeException {
+    public final Object object;
+
+    ExceptionWrapper (Object object) {
+        this.object = object;
+    }
+
+    public static ExceptionWrapper wrap(Object object) {
+        return new ExceptionWrapper(object);
+    }
+}
\ No newline at end of file

Modified: pypy/dist/pypy/translator/jvm/src/PyPy.java
==============================================================================
--- pypy/dist/pypy/translator/jvm/src/PyPy.java	(original)
+++ pypy/dist/pypy/translator/jvm/src/PyPy.java	Sat Dec  9 08:35:03 2006
@@ -245,7 +245,7 @@
         dump_indented(indent, sb.toString());
     }
 
-    public static void dump_string(String b, int indent) {
+    public static String escaped_string(String b) {
         StringBuffer sb = new StringBuffer();
         sb.append('"');
         for (int i = 0; i < b.length(); i++) {
@@ -253,13 +253,29 @@
             _append_char(sb, c);
         }
         sb.append('"');
-        dump_indented(indent, sb.toString());
+        return sb.toString();
+    }
+
+    public static void dump_string(String b, int indent) {
+        dump_indented(indent, escaped_string(b));
     }
 
     public static void dump_object(Object o, int indent) {
         dump_indented(indent, o.toString());
     }
 
+    // used in running unit tests
+    // not really part of the dump_XXX set of objects, hence the lack
+    // of an indent parameter
+    public static void dump_exc_wrapper(Object o) {
+        String clnm = o.getClass().getName();
+        StringBuffer sb = new StringBuffer();
+        sb.append("ExceptionWrapper(");
+        sb.append(escaped_string(clnm));
+        sb.append(")");
+        dump_indented(0, sb.toString());
+    }
+
     // ----------------------------------------------------------------------
     // StringBuffer
 
@@ -354,6 +370,27 @@
     }
 
     // ----------------------------------------------------------------------
+    // Exceptions
+    //
+    // If we don't use true Java exceptions, then this 
+
+/*
+    static private ThreadLocal<Object> excObject  = new ThreadLocal();
+
+    public static int startTry() {
+        return excCounter.get();
+    }
+
+    public void throw(Object o) {
+        excObject.put(o);
+    }
+
+    public static Object catch(int ctr) {
+        return excObject.get();
+    }
+*/
+
+    // ----------------------------------------------------------------------
     // Self Test
 
     public static int __counter = 0, __failures = 0;

Modified: pypy/dist/pypy/translator/jvm/test/runtest.py
==============================================================================
--- pypy/dist/pypy/translator/jvm/test/runtest.py	(original)
+++ pypy/dist/pypy/translator/jvm/test/runtest.py	Sat Dec  9 08:35:03 2006
@@ -35,7 +35,14 @@
 # CLI duplicate
 class ExceptionWrapper:
     def __init__(self, class_name):
-        self.class_name = class_name
+        # We put all of our classes into some package like 'pypy':
+        # strip the initial 'pypy.' that results from the class name,
+        # and we append a number to make the class name unique. Strip
+        # those.
+        pkg = getoption('package')+'.'
+        assert class_name.startswith(pkg)
+        uniqidx = class_name.rindex('_')
+        self.class_name = class_name[len(pkg):uniqidx]
 
     def __repr__(self):
         return 'ExceptionWrapper(%s)' % repr(self.class_name)

Modified: pypy/dist/pypy/translator/jvm/typesystem.py
==============================================================================
--- pypy/dist/pypy/translator/jvm/typesystem.py	(original)
+++ pypy/dist/pypy/translator/jvm/typesystem.py	Sat Dec  9 08:35:03 2006
@@ -173,6 +173,7 @@
 jMath = JvmClassType('java.lang.Math')
 jList = JvmClassType('java.util.List')
 jPyPy = JvmClassType('pypy.PyPy')
+jPyPyExcWrap = JvmClassType('pypy.ExceptionWrapper')
 jPyPyConst = JvmClassType('pypy.Constant')
 jPyPyMain = JvmClassType('pypy.Main')
 



More information about the Pypy-commit mailing list