[pypy-svn] r36518 - in pypy/dist/pypy/translator: cli jvm jvm/src jvm/src/pypy jvm/test oosupport oosupport/test_template

niko at codespeak.net niko at codespeak.net
Thu Jan 11 18:15:13 CET 2007


Author: niko
Date: Thu Jan 11 18:15:11 2007
New Revision: 36518

Added:
   pypy/dist/pypy/translator/jvm/src/pypy/
   pypy/dist/pypy/translator/jvm/src/pypy/DictItemsIterator.java
   pypy/dist/pypy/translator/jvm/src/pypy/ExceptionWrapper.java
   pypy/dist/pypy/translator/jvm/src/pypy/PyPy.java
   pypy/dist/pypy/translator/jvm/test/test_dict.py
   pypy/dist/pypy/translator/oosupport/test_template/dict.py
Removed:
   pypy/dist/pypy/translator/jvm/src/ExceptionWrapper.java
   pypy/dist/pypy/translator/jvm/src/PyPy.java
Modified:
   pypy/dist/pypy/translator/cli/class_.py
   pypy/dist/pypy/translator/cli/function.py
   pypy/dist/pypy/translator/jvm/builtin.py
   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/test/runtest.py
   pypy/dist/pypy/translator/jvm/typesystem.py
   pypy/dist/pypy/translator/oosupport/constant.py
   pypy/dist/pypy/translator/oosupport/genoo.py
Log:
(antocuni, niko)

fix a number of errors from test_dict



Modified: pypy/dist/pypy/translator/cli/class_.py
==============================================================================
--- pypy/dist/pypy/translator/cli/class_.py	(original)
+++ pypy/dist/pypy/translator/cli/class_.py	Thu Jan 11 18:15:11 2007
@@ -132,6 +132,7 @@
             f_name = self.cts.escape_name(f_name)
             if cts_type != 'void':
                 self.ilasm.opcode('ldarg.0')
+                print "%s f_default=%s" % (self.name, f_default)
                 push_constant(self.db, F_TYPE, f_default, self.gen)
                 class_name = self.db.class_name(self.INSTANCE)
                 self.ilasm.set_field((cts_type, class_name, f_name))

Modified: pypy/dist/pypy/translator/cli/function.py
==============================================================================
--- pypy/dist/pypy/translator/cli/function.py	(original)
+++ pypy/dist/pypy/translator/cli/function.py	Thu Jan 11 18:15:11 2007
@@ -17,7 +17,7 @@
 from pypy.translator.cli.support import log
 from pypy.translator.cli.ilgenerator import CLIBaseGenerator
 
-USE_LAST = True
+USE_LAST = False
 
 class NativeExceptionHandler(object):
     def begin_try(self):

Modified: pypy/dist/pypy/translator/jvm/builtin.py
==============================================================================
--- pypy/dist/pypy/translator/jvm/builtin.py	(original)
+++ pypy/dist/pypy/translator/jvm/builtin.py	Thu Jan 11 18:15:11 2007
@@ -3,7 +3,7 @@
 from pypy.rpython.ootypesystem import ootype
 from pypy.translator.jvm.typesystem import \
      jInt, jVoid, jStringBuilder, jString, jPyPy, jChar, jArrayList, jObject, \
-     jBool
+     jBool, jHashMap, jPyPyDictItemsIterator, Generifier
 
 # ______________________________________________________________________
 # Mapping of built-in OOTypes to JVM types
@@ -19,20 +19,9 @@
     def __init__(self, db, classty, OOTYPE):
         jvmtype.JvmClassType.__init__(self, classty.name)
         self.db = db
-        self.OOTYPE = OOTYPE           # might be None
+        self.OOTYPE = OOTYPE
+        self.gen = Generifier(OOTYPE)
     
-        # We need to create a mapping for any generic parameters this
-        # OOTYPE may have. Other than SELFTYPE_T, we map each generic
-        # argument to ootype.ROOT.  We use a hack here where we assume
-        # that the only generic parameters are named SELFTYPE_T,
-        # ITEMTYPE_T, KEYTYPE_T, or VALUETYPE_T.
-        self.generics = {}
-        if hasattr(self.OOTYPE, 'SELFTYPE_T'):
-            self.generics[self.OOTYPE.SELFTYPE_T] = self.OOTYPE
-        for param in ('ITEMTYPE_T', 'KEYTYPE_T', 'VALUETYPE_T'):
-            if hasattr(self.OOTYPE, param):
-                self.generics[getattr(self.OOTYPE, param)] = ootype.ROOT
-
     def __eq__(self, other):
         return isinstance(other, JvmBuiltInType) and other.name == self.name
 
@@ -46,16 +35,10 @@
         return jvmgen.Field(
             self.descriptor.class_name(), fieldnm, jfieldty, False)
 
-    def _map(self, ARG):
-        """ Maps ootype ARG to a java type.  If arg is one of our
-        generic arguments, substitutes the appropriate type before
-        performing the mapping. """
-        return self.db.lltype_to_cts(self.generics.get(ARG,ARG))
-
     def lookup_method(self, methodnm):
         """ Given the method name, returns a jvmgen.Method object """
 
-        # Look for a shortcut method
+        # Look for a shortcut method in our table of remappings:
         try:
             key = (self.OOTYPE.__class__, methodnm)
             print "key=%r" % (key,)
@@ -63,20 +46,33 @@
             return built_in_methods[key]
         except KeyError: pass
 
-        # Lookup the generic method by name.
-        GENMETH = self.OOTYPE._GENERIC_METHODS[methodnm]
-
-        # By default, we assume it is a static method on the PyPy
-        # object, that takes an instance of this object as the first
-        # argument.  The other arguments we just convert to java versions,
-        # except for generics.
-        jargtypes = [self] + [self._map(P) for P in GENMETH.ARGS]
-        jrettype = self._map(GENMETH.RESULT)
-        return jvmgen.Method.s(jPyPy, methodnm, jargtypes, jrettype)
-
-# When we lookup a method on a  BuiltInClassNode, we first check
-# the 'built_in_methods' table.  This allows us to redirect to other
-# methods if we like.
+        # Otherwise, determine the Method object automagically
+        #   First, map the OOTYPE arguments and results to
+        #   the java types they will be at runtime.  Note that
+        #   we must use the erased types for this.
+        ARGS, RESULT = self.gen.erased_types(methodnm)
+        jargtypes = [self.db.lltype_to_cts(P) for P in ARGS]
+        jrettype = self.db.lltype_to_cts(RESULT)
+
+        if self.OOTYPE.__class__ in bridged_objects:
+            # Bridged objects are ones where we have written a java class
+            # that has methods with the correct names and types already
+            return jvmgen.Method.v(self, methodnm, jargtypes, jrettype)
+        else:
+            # By default, we assume it is a static method on the PyPy
+            # object, that takes an instance of this object as the first
+            # argument.  The other arguments we just convert to java versions,
+            # except for generics.
+            jargtypes = [self] + jargtypes
+            return jvmgen.Method.s(jPyPy, methodnm, jargtypes, jrettype)
+
+# When we lookup a method on a BuiltInClassNode, we first check the
+# 'built_in_methods' and 'bridged_objects' tables.  This allows us to
+# redirect to other methods if we like.
+
+bridged_objects = (
+    ootype.DictItemsIterator,
+    )
 
 built_in_methods = {
 
@@ -94,6 +90,24 @@
 
     (ootype.String.__class__, "ll_strlen"):
     jvmgen.Method.v(jString, "length", (), jInt),
+    
+    (ootype.String.__class__, "ll_stritem_nonneg"):
+    jvmgen.Method.v(jString, "charAt", (jInt,), jChar),
+
+    (ootype.Dict, "ll_set"):
+    jvmgen.Method.v(jHashMap, "put", (jObject, jObject), jObject),
+    
+    (ootype.Dict, "ll_get"):
+    jvmgen.Method.v(jHashMap, "get", (jObject,), jObject),
+
+    (ootype.Dict, "ll_contains"):
+    jvmgen.Method.v(jHashMap, "containsKey", (jObject,), jBool),
+
+    (ootype.Dict, "ll_length"):
+    jvmgen.Method.v(jHashMap, "size", (), jInt),
+    
+    (ootype.Dict, "ll_clear"):
+    jvmgen.Method.v(jHashMap, "clear", (), jVoid),
 
     (ootype.List, "ll_length"):
     jvmgen.Method.v(jArrayList, "size", (), jInt),

Modified: pypy/dist/pypy/translator/jvm/database.py
==============================================================================
--- pypy/dist/pypy/translator/jvm/database.py	(original)
+++ pypy/dist/pypy/translator/jvm/database.py	Thu Jan 11 18:15:11 2007
@@ -293,7 +293,7 @@
         ootype.UnsignedLongLong: jvmtype.jLong,
         ootype.Bool:             jvmtype.jBool,
         ootype.Float:            jvmtype.jDouble,
-        ootype.Char:             jvmtype.jByte,
+        ootype.Char:             jvmtype.jChar,    # byte would be sufficient, but harder
         ootype.UniChar:          jvmtype.jChar,
         ootype.Class:            jvmtype.jClass,
         ootype.ROOT:             jvmtype.jObject,  # count this as a scalar...
@@ -304,7 +304,9 @@
     ootype_to_builtin = {
         ootype.String:           jvmtype.jString,
         ootype.StringBuilder:    jvmtype.jStringBuilder,
-        ootype.List:             jvmtype.jArrayList
+        ootype.List:             jvmtype.jArrayList,
+        ootype.Dict:             jvmtype.jHashMap,
+        ootype.DictItemsIterator:jvmtype.jPyPyDictItemsIterator,
         }
 
     def lltype_to_cts(self, OOT):

Modified: pypy/dist/pypy/translator/jvm/generator.py
==============================================================================
--- pypy/dist/pypy/translator/jvm/generator.py	(original)
+++ pypy/dist/pypy/translator/jvm/generator.py	Thu Jan 11 18:15:11 2007
@@ -851,6 +851,16 @@
         mthd = clsobj.lookup_method(method_name)
         mthd.invoke(self)
 
+        # Check if we have to convert the result type at all:
+        gener = jvmtype.Generifier(OOCLASS)
+        RETTYPE = gener.full_types(method_name)[1]
+        jrettype = self.db.lltype_to_cts(RETTYPE)
+        if jrettype != mthd.return_type:
+            # if the intended return type is not the same as the
+            # actual return type in the JVM (mthd.return_type),
+            # we have to "deal with it"
+            self.prepare_generic_result(RETTYPE)
+
     def call_primitive(self, graph):
         raise NotImplementedError
 

Modified: pypy/dist/pypy/translator/jvm/genjvm.py
==============================================================================
--- pypy/dist/pypy/translator/jvm/genjvm.py	(original)
+++ pypy/dist/pypy/translator/jvm/genjvm.py	Thu Jan 11 18:15:11 2007
@@ -95,17 +95,22 @@
             raise JvmSubprogramError(res, args, stdout, stderr)
         return stdout, stderr
 
-    def _compile_helper(self, clsnm):
+    def _compile_helper(self, clsnms):
         # HACK: compile the Java helper class.  Should eventually
         # use rte.py
-        pypycls = self.classdir.join(clsnm + '.class')
-        if not os.path.exists(str(pypycls)):
+        tocompile = []
+        for clsnm in clsnms:
+            pypycls = self.classdir.join(clsnm + '.class')
+            if not os.path.exists(str(pypycls)):
+                tocompile.append(clsnm)
+        if tocompile:
             sl = __file__.rindex('/')
-            javasrc = __file__[:sl]+("/src/%s.java" % clsnm)
+            javasrcs = [__file__[:sl]+("/src/pypy/%s.java" % clsnm) for
+                        clsnm in tocompile]
             self._invoke([getoption('javac'),
                           '-nowarn',
-                          '-d', str(self.classdir),
-                          javasrc],
+                          '-d', str(self.classdir)]+
+                         javasrcs,
                          True)
         
 
@@ -119,8 +124,9 @@
         self._invoke(jascmd+list(self.jasmin_files), False)
                            
         self.compiled = True
-        self._compile_helper('PyPy')
-        self._compile_helper('ExceptionWrapper')
+        self._compile_helper(('DictItemsIterator',
+                              'PyPy',
+                              '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	Thu Jan 11 18:15:11 2007
@@ -367,7 +367,7 @@
     """ Represents a class to be emitted.  Note that currently, classes
     are emitted all in one shot, not piecemeal. """
 
-    def __init__(self, name, supercls=None):
+    def __init__(self, name, supercls=None, initialize_fields=True):
         """
         'name' should be a fully qualified Java class name like
         "java.lang.String", supercls is a Class object
@@ -435,6 +435,8 @@
             if field.jtype is not jVoid:
                 gen.load_jvm_var(self, 0) # load this ptr
                 # load default value of field
+                print "%s f_name=%s f_default=%s" % (
+                    self.name, field.field_name, f_default)
                 push_constant(gen.db, field.OOTYPE, f_default, gen)
                 field.store(gen)           # store value into field
         gen.end_constructor()
@@ -495,24 +497,21 @@
         # Start the dump
         genprint("InstanceWrapper(")
         genprint("'" + self.OOCLASS._name + "', ")
-        genprint("[")
+        genprint("{")
 
         for fieldnm, (FIELDOOTY, fielddef) in self.OOCLASS._fields.iteritems():
 
             if FIELDOOTY is ootype.Void: continue
 
-            genprint("(")
-            genprint('"'+fieldnm+'",')
+            genprint('"'+fieldnm+'":')
 
             print "fieldnm=%r fieldty=%r" % (fieldnm, FIELDOOTY)
 
             # Print the value of the field:
             self._print_field_value(fieldnm, FIELDOOTY)
 
-            genprint(")")
-
         # Dump close
-        genprint("])")
+        genprint("})")
         
 class RecordDumpMethod(BaseDumpMethod):
 

Added: pypy/dist/pypy/translator/jvm/src/pypy/DictItemsIterator.java
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/translator/jvm/src/pypy/DictItemsIterator.java	Thu Jan 11 18:15:11 2007
@@ -0,0 +1,29 @@
+package pypy;
+
+import java.util.Map;
+import java.util.Iterator;
+
+public class DictItemsIterator
+{
+    private Iterator<Map.Entry> iterator;
+    private Map.Entry current;
+
+    public DictItemsIterator(Map map) {
+        this.iterator = map.entrySet().iterator();
+    }
+
+    public boolean ll_go_next() {
+        if (!this.iterator.hasNext())
+            return false;
+        this.current = this.iterator.next();
+        return true;
+    }
+
+    public Object ll_current_key() {
+        return this.current.getKey();
+    }
+
+    public Object ll_current_value() {
+        return this.current.getValue();
+    }
+}
\ No newline at end of file

Added: pypy/dist/pypy/translator/jvm/src/pypy/ExceptionWrapper.java
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/translator/jvm/src/pypy/ExceptionWrapper.java	Thu Jan 11 18:15:11 2007
@@ -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

Added: pypy/dist/pypy/translator/jvm/src/pypy/PyPy.java
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/translator/jvm/src/pypy/PyPy.java	Thu Jan 11 18:15:11 2007
@@ -0,0 +1,475 @@
+package pypy;
+
+import java.util.List;
+import java.util.ArrayList;
+import java.util.HashMap;
+
+/**
+ * Class with a number of utility routines.
+ * 
+ * I apologize for the Python-esque naming conventions, but it seems
+ * I can't switch my mind to camelCase when working so closely with 
+ * Python mere minutes before.
+ */
+public class PyPy {
+    /** 
+     * Compares two unsigned integers (value1 and value2) and returns
+     * a value greater than, equal to, or less than zero if value 1 is
+     * respectively greater than, equal to, or less than value2.  The
+     * idea is that you can do the following:
+     * 
+     * Call uint_cmp(value1, value2)
+     * IFLT ... // jumps if value1 < value2
+     * IFEQ ... // jumps if value1 == value2
+     * IFGT ... // jumps if value1 > value2
+     * etc 
+     */
+    public static int uint_cmp(int value1, int value2) {
+        final int VALUE1BIGGER = 1;
+        final int VALUE2BIGGER = -1;
+        final int EQUAL = 0;
+
+        if (((value1 | value2) & Integer.MIN_VALUE) == 0) {
+            // neither is negative, presumably the common case
+            return value1 - value2;
+        }
+
+        if (value1 == value2)
+            return EQUAL;
+
+        if (value1 < 0) {
+            if (value2 < 0) {
+                // both are negative
+                if (value1 > value2)
+                    // example: value1 == -1 (0xFFFF), value2 == -2 (0xFFFE)
+                    return VALUE1BIGGER;
+                return VALUE2BIGGER;
+            }
+            else {
+                // value1 is neg, value 2 is not
+                return VALUE1BIGGER;
+            }
+        }
+
+        // value1 is not neg, value2 is neg
+        return VALUE2BIGGER;
+    }
+
+    public static int ulong_cmp(long value1, long value2) {
+        final int VALUE2BIGGER = -1;
+        final int VALUE1BIGGER = 1;
+        final int EQUAL = 0;
+
+        if (value1 == value2)
+            return EQUAL;
+
+        if (value1 < 0) {
+            if (value2 < 0) {
+                // both are negative
+                if (value1 > value2)
+                    // example: value1 == -1 (0xFFFF), value2 == -2 (0xFFFE)
+                    return VALUE1BIGGER;
+                return VALUE2BIGGER;
+            }
+            else {
+                // value1 is neg, value 2 is not
+                return VALUE1BIGGER;
+            }
+        }
+        else if (value2 < 0) {
+            // value1 is not neg, value2 is neg
+            return VALUE2BIGGER;
+        }
+        
+        if (value1 > value2)
+            return VALUE1BIGGER;
+        return VALUE2BIGGER;
+    }
+
+    public static final double BITS16 = (double)0xFFFF;
+
+    public static double uint_to_double(int value) {
+        if (value >= 0)
+            return value;
+        else {
+            int loword = value & 0xFFFF;
+            double result = loword;
+            int hiword = value >>> 16;
+            result += hiword * BITS16;
+            return result;
+        }
+    }
+
+    public static int double_to_uint(double value) {
+        if (value <= Integer.MAX_VALUE)
+            return (int)value;
+
+        int loword = (int)(value % BITS16);
+        int hiword = (int)(Math.floor(value / BITS16));
+        assert (loword & 0xFFFF0000) == 0;
+        assert (hiword & 0xFFFF0000) == 0;
+        return (hiword << 16) + loword;
+    }
+
+    public static long long_bitwise_negate(long value) {
+        return ~value;
+    }
+
+    public static List<?> array_to_list(Object[] array) {
+        List l = new ArrayList();
+        for (Object o : array) {
+            l.add(o);
+        }
+        return l;
+    }
+
+    public static int str_to_int(String s) {
+        try {
+            return Integer.parseInt(s);
+        } catch (NumberFormatException fe) {
+            throw new RuntimeException(fe);
+        }
+    }
+
+    public static int str_to_uint(String s) {
+        try {
+            long l = Long.parseLong(s);
+            if (l < Integer.MAX_VALUE)
+                return (int)l;
+            int lowerword = (int)(l & 0xFFFF);
+            int upperword = (int)(l >> 16);
+            return lowerword + (upperword << 16);
+        } catch (NumberFormatException fe) {
+            throw new RuntimeException(fe);
+        }
+    }
+
+    public static long str_to_long(String s) {
+        try {
+            return Long.parseLong(s);
+        } catch (NumberFormatException fe) {
+            throw new RuntimeException(fe);
+        }
+    }
+
+    public static long str_to_ulong(String s) {
+        // oh bother
+        throw new RuntimeException("TODO--- str to ulong");
+    }
+
+    public static boolean str_to_bool(String s) {
+        // not sure what are considered valid boolean values...
+        // let's be very accepting and take both strings and numbers
+        if (s.equalsIgnoreCase("true"))
+            return true;
+        if (s.equalsIgnoreCase("false"))
+            return false;
+
+        try {
+            int i = Integer.parseInt(s);
+            return i != 0;
+        } catch (NumberFormatException ex) {
+            throw new RuntimeException(ex);
+        }
+    }
+
+    public static double str_to_double(String s) {
+        try {
+            return Double.parseDouble(s);
+        } catch (NumberFormatException ex) {
+            throw new RuntimeException(ex);
+        }
+    }
+
+    public static char str_to_char(String s) {
+        if (s.length() != 1)
+            throw new RuntimeException("String not single character: '"+s+"'");
+        return s.charAt(0);
+    }
+
+    // Used in testing:
+
+    public static void dump(String text) {
+        System.out.println(text);
+    }
+
+    public static String serialize_void() {
+        return "None";
+    }
+
+    public static String serialize_uint(int i) {
+        if (i >= 0)
+            return Integer.toString(i);
+        else {
+            int loword = i & 0xFFFF;
+            int hiword = i >>> 16;
+            long res = loword + (hiword*0xFFFF);
+            return Long.toString(res);
+        }
+    }
+
+    public static String serialize_boolean(boolean l) {
+        if (l)
+            return "True";
+        else
+            return "False";
+    }
+
+    public static void _append_char(StringBuffer sb, char c) {
+        if (c == '"') 
+            sb.append("\\\"");
+        else
+            sb.append(c);
+    }
+
+    public static String escaped_char(char c) {
+        StringBuffer sb = new StringBuffer();
+        sb.append('"');
+        _append_char(sb, c);
+        sb.append('"');
+        return sb.toString();
+    }
+
+    public static String escaped_string(String b) {
+        if (b == null)
+            return "None";
+        StringBuffer sb = new StringBuffer();
+        sb.append('"');
+        for (int i = 0; i < b.length(); i++) {
+            char c = b.charAt(i);
+            _append_char(sb, c);
+        }
+        sb.append('"');
+        return sb.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(sb.toString());
+    }
+
+    public static String serializeObject(Object o) {
+        if (o == null)
+            return "None";
+        return o.toString();
+    }
+
+    // ----------------------------------------------------------------------
+    // String
+
+    public static String ll_strconcat(String str1, String str2) {
+        return str1 + str2;
+    }
+
+    // ----------------------------------------------------------------------
+    // StringBuffer
+
+    public static void ll_append_char(StringBuilder sb, byte c) {
+        // annoyingly, the actual return code is StringBuilder, so I have
+        // to make this wrapper to ignore the return value
+        sb.append((char)c);
+    }
+
+    public static void ll_append_char(StringBuilder sb, char c) {
+        // annoyingly, the actual return code is StringBuilder, so I have
+        // to make this wrapper to ignore the return value
+        sb.append(c);
+    }
+
+    public static void ll_append(StringBuilder sb, String s) {
+        // annoyingly, the actual return code is StringBuilder, so I have
+        // to make this wrapper to ignore the return value
+        sb.append(s);
+    }
+
+    public static void ll_append(StringBuilder sb, byte[] s) {
+        // This is only used when we are using byte arrays instead of
+        // strings.  We should really replace StringBuilder with some
+        // kind of ByteBuilder in that case...
+        for (byte b : s) {
+            sb.append((char)b);
+        }
+    }
+
+    public static byte[] ll_build(StringBuilder sb) {
+        // This is only used when we are using byte arrays instead of
+        // strings.  We should really replace StringBuilder with some
+        // kind of ByteBuilder in that case...
+        return string2bytes(sb.toString());
+    }
+
+    // ----------------------------------------------------------------------
+    // Type Manipulation Routines
+
+    public static Object RuntimeNew(Class c) {
+        // all classes in our system have constructors w/ no arguments
+        try {
+            return c.getConstructor().newInstance();
+        } catch (Exception exc) {
+            throw new RuntimeException("Unexpected", exc);
+        }
+    }
+
+    // ----------------------------------------------------------------------
+    // Helpers
+    
+    public static byte[] string2bytes(String s) {
+    	return s.getBytes();
+    }
+
+    public static void append(StringBuilder sb, String s) {
+        // avoid the annoying return value of StringBuilder.append
+        sb.append(s);
+    }
+
+    // ----------------------------------------------------------------------
+    // OOString support
+    
+    public static String oostring(int n, int base_) {
+    	// XXX needs special case for unsigned ints
+        if (base_ == -1)
+            base_ = 10;
+        if (n < 0 && base_ != 10)
+            return "-" + Integer.toString(-n, base_);
+        else
+            return Integer.toString(n, base_);
+    }
+
+    public static String oostring(double d, int base_) {
+        return new Double(d).toString();
+    }
+
+    public static String oostring(Object obj, int base_)
+    {
+        String clnm = obj.getClass().getName();
+        int underscore = clnm.lastIndexOf('_');
+        // strip "pypy." from the start, and _NN from the end
+        clnm = clnm.substring(5, underscore);
+        return String.format("<%s object>", new Object[] { clnm });
+    }
+
+    public static String oostring(char ch, int base_)
+    {
+        return new Character(ch).toString();
+    }
+
+    public static byte[] oostring(byte[] s, int base_)
+    {
+        return s;
+    }
+
+    public static String oostring(String s, int base_)
+    {
+        return s;
+    }
+
+    public static String oostring(boolean b, int base_)
+    {
+        if (b) return "True";
+        return "False";
+    }
+
+    // ----------------------------------------------------------------------
+    // 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();
+    }
+*/
+
+    // ----------------------------------------------------------------------
+    // Dicts
+
+    public static boolean ll_remove(HashMap map, Object key) {
+        return map.remove(key) != null;
+    }
+
+    public static DictItemsIterator ll_get_items_iterator(HashMap map) {
+        return new DictItemsIterator(map);
+    }
+
+    // ----------------------------------------------------------------------
+    // Lists
+
+    public static void ll_setitem_fast(ArrayList self, int index, Object val)
+    {
+        // need a wrapper because set returns the old value
+        self.set(index, val);
+    }
+
+    public static void _ll_resize_ge(ArrayList self, int length) {
+        while (self.size() < length) {
+            self.add(null);
+        }
+    }
+
+    public static void _ll_resize_le(ArrayList self, int length) {
+        while (self.size() > length) {
+            self.remove(self.size()-1);
+        }
+    }
+
+    public static void _ll_resize(ArrayList self, int length) {
+        if (length > self.size())
+            _ll_resize_ge(self, length);
+        else if (length < self.size())
+            _ll_resize_le(self, length);
+    }
+
+    // ----------------------------------------------------------------------
+    // Self Test
+
+    public static int __counter = 0, __failures = 0;
+    public static void ensure(boolean f) {
+        if (f) {
+            System.out.println("Test #"+__counter+": OK");
+        }
+        else {
+            System.out.println("Test #"+__counter+": FAILED");
+            __failures++;
+        }
+        __counter++;
+    }
+
+    public static void main(String args[]) {
+        // Small self test:
+
+        ensure(uint_cmp(0xFFFFFFFF, 0) > 0);
+        ensure(uint_cmp(0, 0xFFFFFFFF) < 0);
+        ensure(uint_cmp(0x80000000, 0) > 0);
+        ensure(uint_cmp(0, 0x80000000) < 0);
+        ensure(uint_cmp(0xFFFF, 0) > 0);
+        ensure(uint_cmp(0, 0xFFFF) < 0);
+        ensure(uint_cmp(0xFFFFFFFF, 0xFFFF) > 0);
+        ensure(uint_cmp(0xFFFF, 0xFFFFFFFF) < 0);
+
+        ensure(ulong_cmp(0xFFFFFFFFFFFFFFFFL, 0) > 0);
+        ensure(ulong_cmp(0, 0xFFFFFFFFFFFFFFFFL) < 0);
+        ensure(ulong_cmp(0xFFFFFFFFFFFFFFFFL, 0xFFFF) > 0);
+        ensure(ulong_cmp(0xFFFF, 0xFFFFFFFFFFFFFFFFL) < 0);
+        ensure(ulong_cmp(0x8000000000000000L, 0xFFFF) > 0);
+        ensure(ulong_cmp(0xFFFF, 0x8000000000000000L) < 0);
+        
+        System.out.println("Total Failures: "+__failures);
+    }
+}
\ No newline at end of file

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	Thu Jan 11 18:15:11 2007
@@ -138,4 +138,7 @@
         return isinstance(val, InstanceWrapper)
 
     def read_attr(self, obj, name):
-        py.test.skip('read_attr not supported on genjvm tests')
+        py.test.skip("read_attr not supported on JVM")
+        # TODO --- this "almost works": I think the problem is that our
+        # dump methods don't dump fields of the super class??
+        #return obj.fields["o"+name]

Added: pypy/dist/pypy/translator/jvm/test/test_dict.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/translator/jvm/test/test_dict.py	Thu Jan 11 18:15:11 2007
@@ -0,0 +1,13 @@
+from pypy.translator.jvm.test.runtest import JvmTest
+import pypy.translator.oosupport.test_template.dict as oodict
+
+class TestJvmDict(JvmTest, oodict.BaseTestDict):
+    pass
+
+class TestJvmEmptyDict(JvmTest, oodict.BaseTestEmptyDict):
+    pass
+
+class TestJvmConstantDict(JvmTest, oodict.BaseTestConstantDict):
+    pass
+
+

Modified: pypy/dist/pypy/translator/jvm/typesystem.py
==============================================================================
--- pypy/dist/pypy/translator/jvm/typesystem.py	(original)
+++ pypy/dist/pypy/translator/jvm/typesystem.py	Thu Jan 11 18:15:11 2007
@@ -165,6 +165,7 @@
 jPyPyExcWrap = JvmClassType('pypy.ExceptionWrapper')
 jPyPyConst = JvmClassType('pypy.Constant')
 jPyPyMain = JvmClassType('pypy.Main')
+jPyPyDictItemsIterator = JvmClassType('pypy.DictItemsIterator')
 
 class JvmScalarType(JvmType):
     """
@@ -202,4 +203,60 @@
 jObjectArray = JvmArrayType(jObject)
 jStringArray = JvmArrayType(jString)
 
+class Generifier(object):
 
+    """
+
+    A utility class for working with generic methods in the OOTYPE
+    system.  You instantiate it with a given type, and you can ask it
+    for the actual or erased types of any method of that type.
+    
+    """
+
+    def __init__(self, OOTYPE):
+        self.OOTYPE = OOTYPE
+
+        # Make a hashtable mapping the generic parameter to a tuple:
+        #    (actual type, erased type)
+        
+        self.generics = {}
+        
+        if hasattr(self.OOTYPE, 'SELFTYPE_T'):
+            self.generics[self.OOTYPE.SELFTYPE_T] = (self.OOTYPE,self.OOTYPE)
+            
+        for pname,pval in (('ITEMTYPE_T', '_ITEMTYPE'),
+                           ('KEYTYPE_T', '_KEYTYPE'),
+                           ('VALUETYPE_T', '_VALUETYPE')):
+            if hasattr(self.OOTYPE, pname):
+                placeholder = getattr(self.OOTYPE, pname)
+                placeholder_val = getattr(self.OOTYPE, pval)
+                self.generics[placeholder] = (placeholder_val, ootype.ROOT)
+
+    def full_types(self, method_name):
+        """
+        Returns a tuple of argument and return types for the method
+        named 'method_name'.  These are the actual generic types.  The set method for
+        a list of strings, for example, might return:
+          ( [INT, STRING], VOID )
+        """
+        GENMETH = self.OOTYPE._GENERIC_METHODS[method_name]
+        ARGS, RESULT = (GENMETH.ARGS, GENMETH.RESULT)
+        ARGS = [self.generics.get(X,(X,))[0] for X in ARGS]
+        RESULT = self.generics.get(RESULT, (RESULT,))[0]
+        return (ARGS, RESULT)
+
+    def erased_types(self, method_name):
+        """
+        Returns a tuple of argument and return types for the method
+        named 'method_name'.  These are the erased generic types.  The set method for
+        a list of strings, for example, might return:
+          ( [INT, OBJECT], VOID )
+        """
+        GENMETH = self.OOTYPE._GENERIC_METHODS[method_name]
+        ARGS, RESULT = (GENMETH.ARGS, GENMETH.RESULT)
+        ARGS = [self.generics.get(X,(None,X))[1] for X in ARGS]
+        RESULT = self.generics.get(RESULT, (None,RESULT))[1]
+        return (ARGS, RESULT)
+
+    
+    

Modified: pypy/dist/pypy/translator/oosupport/constant.py
==============================================================================
--- pypy/dist/pypy/translator/oosupport/constant.py	(original)
+++ pypy/dist/pypy/translator/oosupport/constant.py	Thu Jan 11 18:15:11 2007
@@ -212,6 +212,11 @@
             return genoo.DictConst(self.db, value, uniq)
         elif isinstance(value, llmemory.fakeweakaddress):
             return genoo.WeakRefConst(self.db, value, uniq)
+        elif value is ootype.null(value._TYPE):
+            # for NULL values, we can just use "NULL" const.  This is
+            # a fallback since we sometimes have constants of
+            # unhandled types which are equal to NULL.
+            return genoo.NullConst(self.db, value, uniq)
         else:
             assert False, 'Unknown constant: %s' % value        
 
@@ -407,6 +412,21 @@
 
 
 # ______________________________________________________________________
+# Null Values
+#
+# NULL constants of types for which we have no better class use this
+# class.  For example, dict item iterators and the like.
+    
+class NullConst(AbstractConst):
+    def __init__(self, db, value, count):
+        AbstractConst.__init__(self, db, value, count)
+        self.name = 'NULL__%d' % count
+        assert self.is_null() and self.is_inline()
+
+    def record_dependencies(self):
+        return
+    
+# ______________________________________________________________________
 # Records
     
 class RecordConst(AbstractConst):
@@ -627,11 +647,13 @@
             gen.dup(SELFTYPE)
             gen.add_comment('  key=%r value=%r' % (key,value))
             push_constant(self.db, KEYTYPE, key, gen)
+            gen.prepare_generic_argument(KEYTYPE)
             if VALUETYPE is ootype.Void:
                 # special case dict of Void; for now store the key as value?
                 gen.dup(KEYTYPE)
             else:
                 push_constant(self.db, VALUETYPE, value, gen)
+            gen.prepare_generic_argument(VALUETYPE)
             gen.call_method(SELFTYPE, 'll_set')
 
 class CustomDictConst(DictConst):

Modified: pypy/dist/pypy/translator/oosupport/genoo.py
==============================================================================
--- pypy/dist/pypy/translator/oosupport/genoo.py	(original)
+++ pypy/dist/pypy/translator/oosupport/genoo.py	Thu Jan 11 18:15:11 2007
@@ -13,6 +13,7 @@
     # _create_complex_const:
     
     ConstantGenerator = None
+    NullConst = ooconst.NullConst
     InstanceConst = ooconst.InstanceConst
     RecordConst = ooconst.RecordConst
     ClassConst = ooconst.ClassConst

Added: pypy/dist/pypy/translator/oosupport/test_template/dict.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/translator/oosupport/test_template/dict.py	Thu Jan 11 18:15:11 2007
@@ -0,0 +1,42 @@
+import py
+from pypy.rpython.test.test_rdict import TestOOtype as _TestOOtype
+from pypy.rpython.test.test_remptydict import BaseTestRemptydict
+from pypy.rpython.test.test_rconstantdict import BaseTestRconstantdict
+
+class BaseTestDict(_TestOOtype):
+    def test_dict_of_void(self):
+        class A: pass
+        def f():
+            d2 = {A(): None, A(): None}
+            return len(d2)
+        res = self.interpret(f, [])
+        assert res == 2
+
+    def test_dict_of_void_iter(self):
+        def f():
+            d = {1: None, 2: None, 3: None}
+            total = 0
+            for key, value in d.iteritems():
+                total += key
+            return total
+        assert self.interpret(f, []) == 6
+
+    def test_dict_of_dict(self):
+        py.test.skip("CLI doesn't support recursive dicts")
+
+    def test_recursive(self):
+        py.test.skip("CLI doesn't support recursive dicts")
+
+class BaseTestEmptyDict(BaseTestRemptydict):
+    def test_iterate_over_empty_dict(self):
+        py.test.skip("Iteration over empty dict is not supported, yet")
+
+class BaseTestConstantDict(BaseTestRconstantdict):
+    def test_constant_r_dict(self):
+        py.test.skip('r_dict is not supported, yet')
+
+    def test_tuple_as_key(self):
+        mydict = {('r',): 42}
+        def fn(ch):
+            return mydict[(ch,)]
+        assert self.interpret(fn, ['r']) == 42



More information about the Pypy-commit mailing list