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

niko at codespeak.net niko at codespeak.net
Sun Mar 30 19:23:04 CEST 2008


Author: niko
Date: Sun Mar 30 19:23:03 2008
New Revision: 53149

Added:
   pypy/dist/pypy/translator/jvm/cmpopcodes.py
Modified:
   pypy/dist/pypy/translator/jvm/generator.py
   pypy/dist/pypy/translator/jvm/metavm.py
   pypy/dist/pypy/translator/jvm/node.py
   pypy/dist/pypy/translator/jvm/opcodes.py
   pypy/dist/pypy/translator/jvm/src/pypy/PyPy.java
   pypy/dist/pypy/translator/jvm/test/runtest.py
   pypy/dist/pypy/translator/jvm/test/test_builtin.py
   pypy/dist/pypy/translator/oosupport/test_template/snippets.py
Log:
rework the way that comparisons work in the JVM backend: we now detect when the
branch depends on a boolean variable defined by the last instruction, and try
to inline the comparison.  Since the jvm doesn't have opcodes to load the
result of a comparison onto the stack, this means that instead of generating
code for "if (x<y) f1 else f2" like

	if (x < y)
		b = 1;
	else
		b = 0;
	if (b) 
		goto l1;
	else 
		goto l2;

we generate

	if (x < y)
		goto l1;
	else
		goto l2;

which is much shorter and easier to read.



Added: pypy/dist/pypy/translator/jvm/cmpopcodes.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/translator/jvm/cmpopcodes.py	Sun Mar 30 19:23:03 2008
@@ -0,0 +1,112 @@
+from pypy.translator.jvm.generator import \
+     IFLT, IFLE, IFEQ, IFNE, IFGT, IFGE, \
+     IFNONNULL, IF_ACMPEQ, GOTO, ICONST, \
+     DCONST_0, DCMPG, LCONST_0, LCMP, \
+     IF_ICMPLT, IF_ICMPLE, IF_ICMPEQ, IF_ICMPNE, IF_ICMPGT, IF_ICMPGE, \
+     PYPYUINTCMP, PYPYULONGCMP, \
+     Label
+
+##### Branch directly as the result of a comparison
+
+# A table mapping the kind of numeric type to the opcode or method
+# needed to compare two values of that type.  The result of this
+# opcode of method is that a -1, 0, or 1 is pushed on the stack,
+# like the cmp() method in Python.  Used to prepare the cmp_opname
+# table below.
+cmp_numeric_prep = {
+    'uint': PYPYUINTCMP,
+    'float': DCMPG,
+    'llong': LCMP,
+    'ullong': PYPYULONGCMP,
+    }
+
+# A table mapping the kind of comparison to the opcode which
+# performs that comparison and then branches.  Used to prepare the
+# cmp_opname table below.
+cmp_numeric_branch = {
+    'lt': IFLT,
+    'le': IFLE,
+    'eq': IFEQ,
+    'ne': IFNE,
+    'gt': IFGT,
+    'ge': IFGE,
+    }
+
+# A table that maps an opname to a set of instructions for
+# performing a comparison.  Some entries are inserted
+# automatically, either because they do not fit the numeric
+# pattern or are exceptions, and others are created from the
+# cmp_numeric_{prep,branch} tables above.  In all cases, the
+# instructions are a list of opcode/functions which will be
+# emitted.  The last one must be a branching instruction.
+cmp_opname = {
+    # Single operand entries:
+    'bool_not': [IFEQ],
+    'int_is_true': [IFNE],
+    'uint_is_true': [IFNE],
+    'float_is_true': [DCONST_0, DCMPG, IFNE],
+    'llong_is_true': [LCONST_0, LCMP, IFNE],
+    'ullong_is_true': [LCONST_0, LCMP, IFNE],
+
+    # Double operand entries:
+    'oononnull': [IFNONNULL],
+    'oois': [IF_ACMPEQ],
+
+    'unichar_eq': [IF_ICMPEQ],
+    'unichar_ne': [IF_ICMPNE],
+
+    'char_eq': [IF_ICMPEQ],
+    'char_ne': [IF_ICMPNE],
+    'char_lt': [IF_ICMPLT],
+    'char_le': [IF_ICMPLE],
+    'char_gt': [IF_ICMPGT],
+    'char_ge': [IF_ICMPGE],
+    
+    'int_eq': [IF_ICMPEQ],
+    'int_ne': [IF_ICMPNE],
+    'int_lt': [IF_ICMPLT],
+    'int_le': [IF_ICMPLE],
+    'int_gt': [IF_ICMPGT],
+    'int_ge': [IF_ICMPGE],
+
+    'int_eq_ovf': [IF_ICMPEQ],
+    'int_ne_ovf': [IF_ICMPNE],
+    'int_lt_ovf': [IF_ICMPLT],
+    'int_le_ovf': [IF_ICMPLE],
+    'int_gt_ovf': [IF_ICMPGT],
+    'int_ge_ovf': [IF_ICMPGE],
+
+    'uint_eq': [IF_ICMPEQ],
+    'uint_ne': [IF_ICMPNE],    
+    }
+
+# fill in the default entries like uint_lt, llong_eq:
+for (prepnm, prepfn) in cmp_numeric_prep.items():
+    for (brnm, brfn) in cmp_numeric_branch.items():
+        opname = "%s_%s" % (prepnm, brnm)
+        if opname not in cmp_opname:
+            cmp_opname[opname] = [prepfn, brfn]
+
+def can_branch_directly(opname):
+    """
+    Returns true if opname is the kind of instruction where we can
+    branch directly based on its result without storing it into a
+    variable anywhere.  For example, int_lt is such an instruction.
+    This is used to optimize away intermediate boolean values, which
+    otherwise force us to generate very inefficient and hard-to-read
+    code.
+    """
+    return opname in cmp_opname
+
+def branch_if(gen, opname, truelabel):
+    """
+    Branches to 'truelabel' if 'opname' would return true.
+    'opname' must be something like int_lt, float_ne, etc,
+    as determined by can_branch_directly().  
+    """
+    assert can_branch_directly(opname)
+    assert isinstance(truelabel, Label)
+    instrs = cmp_opname[opname]
+    for i in instrs[:-1]: gen.emit(i)
+    gen.emit(instrs[-1], truelabel)
+

Modified: pypy/dist/pypy/translator/jvm/generator.py
==============================================================================
--- pypy/dist/pypy/translator/jvm/generator.py	(original)
+++ pypy/dist/pypy/translator/jvm/generator.py	Sun Mar 30 19:23:03 2008
@@ -1247,86 +1247,6 @@
     def goto_if_false(self, label):
         """ Jumps if the top of stack is false """
         self._instr(IFEQ, label)
-
-    ##### Comparison methods
-    
-    def _compare_op(self, cmpopcode):
-        """
-        Converts a comparison operation into a boolean value on the
-        stack.  For example, compare_op(IFEQ) emits the instructions
-        to perform a logical inversion [because it is true if the
-        instruction equals zero].  Consumes as many operands from the
-        stack as the cmpopcode consumes, typically 1 or 2.
-        """
-        midlbl = self.unique_label('cmpop')
-        endlbl = self.unique_label('cmpop')
-        self._instr(cmpopcode, midlbl)
-        self._instr(ICONST, 0)
-        self._instr(GOTO, endlbl)
-        self.mark(midlbl)
-        self._instr(ICONST, 1)
-        self.mark(endlbl)
-
-    is_null = lambda self: self._compare_op(IFNULL)
-    is_not_null = lambda self: self._compare_op(IFNONNULL)
-
-    ref_is_eq = lambda self: self._compare_op(IF_ACMPEQ)
-    ref_is_neq = lambda self: self._compare_op(IF_ACMPNEQ)
-
-    logical_not = lambda self: self._compare_op(IFEQ)
-    equals_zero = logical_not
-    not_equals_zero = lambda self: self._compare_op(IFNE)
-    equals = lambda self: self._compare_op(IF_ICMPEQ)
-    not_equals = lambda self: self._compare_op(IF_ICMPNE)
-    less_than = lambda self: self._compare_op(IF_ICMPLT)
-    greater_than = lambda self: self._compare_op(IF_ICMPGT)
-    less_equals = lambda self: self._compare_op(IF_ICMPLE)
-    greater_equals = lambda self: self._compare_op(IF_ICMPGE)
-
-    def _uint_compare_op(self, cmpopcode):
-        PYPYUINTCMP.invoke(self)
-        self._compare_op(cmpopcode)
-
-    u_equals = equals
-    u_not_equals = not_equals
-    u_less_than = lambda self: self._uint_compare_op(IFLT)
-    u_greater_than = lambda self: self._uint_compare_op(IFGT)
-    u_less_equals = lambda self: self._uint_compare_op(IFLE)
-    u_greater_equals = lambda self: self._uint_compare_op(IFGE)
-
-    def _dbl_compare_op(self, cmpopcode):
-        # XXX --- NaN behavior?
-        self.emit(DCMPG)
-        self._compare_op(cmpopcode)
-
-    dbl_equals = lambda self: self._dbl_compare_op(IFEQ)
-    dbl_not_equals = lambda self: self._dbl_compare_op(IFNE)
-    dbl_less_than = lambda self: self._dbl_compare_op(IFLT)
-    dbl_greater_than = lambda self: self._dbl_compare_op(IFGT)
-    dbl_less_equals = lambda self: self._dbl_compare_op(IFLE)
-    dbl_greater_equals = lambda self: self._dbl_compare_op(IFGE)
-
-    def _long_compare_op(self, cmpopcode):
-        self.emit(LCMP)
-        self._compare_op(cmpopcode)
-
-    long_equals = lambda self: self._long_compare_op(IFEQ)
-    long_not_equals = lambda self: self._long_compare_op(IFNE)
-    long_less_than = lambda self: self._long_compare_op(IFLT)
-    long_greater_than = lambda self: self._long_compare_op(IFGT)
-    long_less_equals = lambda self: self._long_compare_op(IFLE)
-    long_greater_equals = lambda self: self._long_compare_op(IFGE)
-
-    def _ulong_compare_op(self, cmpopcode):
-        PYPYULONGCMP.invoke(self)
-        self._compare_op(cmpopcode)
-
-    ulong_equals = long_equals
-    ulong_not_equals = long_not_equals
-    ulong_less_than = lambda self: self._ulong_compare_op(IFLT)
-    ulong_greater_than = lambda self: self._ulong_compare_op(IFGT)
-    ulong_less_equals = lambda self: self._ulong_compare_op(IFLE)
-    ulong_greater_equals = lambda self: self._ulong_compare_op(IFGE)
         
 class JasminGenerator(JVMGenerator):
 

Modified: pypy/dist/pypy/translator/jvm/metavm.py
==============================================================================
--- pypy/dist/pypy/translator/jvm/metavm.py	(original)
+++ pypy/dist/pypy/translator/jvm/metavm.py	Sun Mar 30 19:23:03 2008
@@ -4,6 +4,7 @@
 import pypy.translator.jvm.generator as jvmgen
 import pypy.translator.jvm.typesystem as jvmtype
 from pypy.translator.jvm.builtin import JvmBuiltInType
+from pypy.translator.jvm import cmpopcodes
 
 class _IndirectCall(MicroInstruction):
     def render(self, gen, op):
@@ -110,3 +111,16 @@
     def render(self, generator, op):
         generator.push_pypy()
 PushPyPy = _PushPyPy()
+
+class _PushComparisonResult(MicroInstruction):
+    def render(self, generator, op):
+        assert cmpopcodes.can_branch_directly(op.opname)
+        truelbl = generator.unique_label('load_comparision_result_true')
+        endlbl = generator.unique_label('load_comparision_result_end')
+        cmpopcodes.branch_if(generator, op.opname, truelbl)
+        generator.emit(jvmgen.ICONST, 0)
+        generator.goto(endlbl)
+        generator.mark(truelbl)
+        generator.emit(jvmgen.ICONST, 1)
+        generator.mark(endlbl)
+PushComparisonResult = _PushComparisonResult()

Modified: pypy/dist/pypy/translator/jvm/node.py
==============================================================================
--- pypy/dist/pypy/translator/jvm/node.py	(original)
+++ pypy/dist/pypy/translator/jvm/node.py	Sun Mar 30 19:23:03 2008
@@ -28,11 +28,16 @@
 from pypy.translator.jvm.option import \
      getoption
 from pypy.translator.jvm.methods import \
-     BaseDumpMethod, InstanceDumpMethod, RecordDumpMethod, ConstantStringDumpMethod
+     BaseDumpMethod, InstanceDumpMethod, RecordDumpMethod, \
+     ConstantStringDumpMethod
 from pypy.translator.oosupport.function import \
      Function as OOFunction
 from pypy.translator.oosupport.constant import \
      push_constant
+from pypy.translator.oosupport.treebuilder import \
+     SubOperation
+from pypy.translator.jvm.cmpopcodes import \
+     can_branch_directly, branch_if
 
 import py
 import pypy.translator.jvm.generator as jvmgen
@@ -390,6 +395,77 @@
                 self.ilasm.store(link.last_exc_value)
             self._setup_link(link)
 
+    def render_normal_block(self, block):
+        """
+        Overload OOFunction.render_normal_block: we intercept blocks where the
+        exitcase tests a bool variable with one use so as to generate more
+        efficient code.  For example, the naive code generation for a test
+        like 'if x < y' yields something like:
+        
+           push x
+           push y
+           jump_if_less_than true
+        false:
+           push 0
+           jump done
+        true:
+           push 1
+        done:
+           store_into_local_var
+           load_from_local_var
+           jump_if_true true_destination
+           jump false_destination
+
+        when it could (should) be
+
+           push x
+           push y
+           jump_if_less_than true_destination
+           jump false_destination
+        """
+
+        def not_in_link_args(v):
+            for link in block.exits:
+                if v in link.args: return False
+            return True
+
+        def true_false_exits():
+            if block.exits[0].exitcase:
+                return block.exits[0], block.exits[1]
+            return block.exits[1], block.exits[0]
+
+        if block.operations:
+            # Look for a case where the block switches on a bool variable
+            # which is produced by the last operation and not used
+            # anywhere else, and where the last operation is a comparison.
+
+            # Watch out for a last operation like:
+            #   v1 = same_as([int_lt(i, j)])
+            last_op = block.operations[-1]
+            while (last_op.opname == "same_as" and
+                   isinstance(last_op.args[0], SubOperation)):
+                last_op = last_op.args[0].op
+            
+            if (block.exitswitch is not None and
+                block.exitswitch.concretetype is ootype.Bool and
+                block.operations[-1].result is block.exitswitch and
+                can_branch_directly(last_op.opname) and
+                not_in_link_args(block.exitswitch)):
+
+                for op in block.operations[:-1]:
+                    self._render_op(op)
+                for arg in last_op.args:
+                    self.ilasm.load(arg)
+                truelink, falselink = true_false_exits()
+                true_label = self.next_label('link_true')
+                branch_if(self.ilasm, last_op.opname, true_label)
+                self._follow_link(falselink)
+                self.set_label(true_label)
+                self._follow_link(truelink)
+                return
+
+        return OOFunction.render_normal_block(self, block)
+
     def render_numeric_switch(self, block):
         if block.exitswitch.concretetype in (ootype.SignedLongLong, ootype.UnsignedLongLong):
             # TODO: it could be faster to check is the values fit in

Modified: pypy/dist/pypy/translator/jvm/opcodes.py
==============================================================================
--- pypy/dist/pypy/translator/jvm/opcodes.py	(original)
+++ pypy/dist/pypy/translator/jvm/opcodes.py	Sun Mar 30 19:23:03 2008
@@ -11,8 +11,9 @@
      CastTo, PushPrimitive
 from pypy.translator.jvm.metavm import \
      IndirectCall, JvmCallMethod, NewCustomDict, \
-     CastPrimitive, PushPyPy
+     CastPrimitive, PushPyPy, PushComparisonResult
 from pypy.rpython.ootypesystem import ootype
+from pypy.translator.jvm.cmpopcodes import cmp_opname
 
 import pypy.translator.jvm.generator as jvmgen
 import pypy.translator.jvm.typesystem as jvmtype
@@ -39,11 +40,17 @@
 def _proc_dict(original):
     
     """ Function which is used to post-process each entry in the
-    opcodes table."""
+    opcodes table.  It also adds the entries for comparison operations
+    from the cmpopcodes module. """
 
     res = {}
-    for key, val in original.items():
-        res[key] = _proc(val)
+    
+    for opname, val in original.items():
+        res[opname] = _proc(val)
+
+    for opname in cmp_opname.keys():
+        res[opname] = _proc(PushComparisonResult)
+        
     return res
 
 def _check_zer(op):
@@ -70,8 +77,6 @@
     'oosend':                   [JvmCallMethod, StoreResult],
     'ooupcast':                 DoNothing,
     'oodowncast':               [DownCast, StoreResult],
-    'oois':                     'ref_is_eq',
-    'oononnull':                'is_not_null',
     'instanceof':               [CastTo, StoreResult],
     'subclassof':               [PushAllArgs, jvmgen.SWAP, jvmgen.CLASSISASSIGNABLEFROM, StoreResult],
     'ooidentityhash':           [PushAllArgs, jvmgen.OBJHASHCODE, StoreResult], 
@@ -95,17 +100,6 @@
 
     'bool_not':                 'logical_not',
 
-    'char_lt':                  'less_than',
-    'char_le':                  'less_equals',
-    'char_eq':                  'equals',
-    'char_ne':                  'not_equals',
-    'char_gt':                  'greater_than',
-    'char_ge':                  'greater_equals',
-
-    'unichar_eq':               'equals',
-    'unichar_ne':               'not_equals',
-
-    'int_is_true':              'not_equals_zero',
     'int_neg':                  jvmgen.INEG,
     'int_neg_ovf':              jvmgen.INEGOVF,
     'int_abs':                  'iabs',
@@ -118,12 +112,6 @@
     'int_floordiv':             jvmgen.IDIV,
     'int_floordiv_zer':         _check_zer(jvmgen.IDIV),
     'int_mod':                  jvmgen.IREM,
-    'int_lt':                   'less_than',
-    'int_le':                   'less_equals',
-    'int_eq':                   'equals',
-    'int_ne':                   'not_equals',
-    'int_gt':                   'greater_than',
-    'int_ge':                   'greater_equals',
     'int_and':                  jvmgen.IAND,
     'int_or':                   jvmgen.IOR,
     'int_lshift':               jvmgen.ISHL,
@@ -136,12 +124,6 @@
     'int_floordiv_ovf':         jvmgen.IDIV, # these can't overflow!
     'int_mod_zer':              _check_zer(jvmgen.IREM),
     'int_mod_ovf':              jvmgen.IREMOVF,
-    'int_lt_ovf':               'less_than',
-    'int_le_ovf':               'less_equals',
-    'int_eq_ovf':               'equals',
-    'int_ne_ovf':               'not_equals',
-    'int_gt_ovf':               'greater_than',
-    'int_ge_ovf':               'greater_equals',
     'int_and_ovf':              jvmgen.IAND,
     'int_or_ovf':               jvmgen.IOR,
 
@@ -153,7 +135,6 @@
     'int_floordiv_ovf_zer':     _check_zer(jvmgen.IDIV),
     'int_mod_ovf_zer':          _check_zer(jvmgen.IREMOVF),
 
-    'uint_is_true':             'not_equals_zero',
     'uint_invert':              'bitwise_negate',
 
     'uint_add':                 jvmgen.IADD,
@@ -163,19 +144,12 @@
     'uint_truediv':             None,    # TODO
     'uint_floordiv':            jvmgen.PYPYUINTDIV,
     'uint_mod':                 jvmgen.PYPYUINTMOD,
-    'uint_lt':                  'u_less_than',
-    'uint_le':                  'u_less_equals',
-    'uint_eq':                  'u_equals',
-    'uint_ne':                  'u_not_equals',
-    'uint_gt':                  'u_greater_than',
-    'uint_ge':                  'u_greater_equals',
     'uint_and':                 jvmgen.IAND,
     'uint_or':                  jvmgen.IOR,
     'uint_lshift':              jvmgen.ISHL,
     'uint_rshift':              jvmgen.IUSHR,
     'uint_xor':                 jvmgen.IXOR,
 
-    'float_is_true':            [PushAllArgs, jvmgen.DCONST_0, 'dbl_not_equals', StoreResult],
     'float_neg':                jvmgen.DNEG,
     'float_abs':                'dbl_abs',
 
@@ -183,14 +157,7 @@
     'float_sub':                jvmgen.DSUB,
     'float_mul':                jvmgen.DMUL,
     'float_truediv':            jvmgen.DDIV,
-    'float_lt':                 'dbl_less_than',     
-    'float_le':                 'dbl_less_equals',   
-    'float_eq':                 'dbl_equals',        
-    'float_ne':                 'dbl_not_equals',    
-    'float_gt':                 'dbl_greater_than',  
-    'float_ge':                 'dbl_greater_equals',
 
-    'llong_is_true':            [PushAllArgs, jvmgen.LCONST_0, 'long_not_equals', StoreResult],
     'llong_neg':                jvmgen.LNEG,
     'llong_neg_ovf':            jvmgen.LNEGOVF,
     'llong_abs':                jvmgen.MATHLABS,
@@ -206,12 +173,6 @@
     'llong_floordiv_zer':       _check_zer(jvmgen.LDIV),
     'llong_mod':                jvmgen.LREM,
     'llong_mod_zer':            _check_zer(jvmgen.LREM),
-    'llong_lt':                 'long_less_than',     
-    'llong_le':                 'long_less_equals',   
-    'llong_eq':                 'long_equals',        
-    'llong_ne':                 'long_not_equals',    
-    'llong_gt':                 'long_greater_than',  
-    'llong_ge':                 'long_greater_equals',
     'llong_and':                jvmgen.LAND,
     'llong_or':                 jvmgen.LOR,
     'llong_lshift':             [PushAllArgs, jvmgen.L2I, jvmgen.LSHL, StoreResult], # XXX - do we care about shifts of >(1<<32) bits??
@@ -221,7 +182,6 @@
     'llong_mod_ovf':            jvmgen.LREMOVF,
     'llong_lshift_ovf':         jvmgen.LSHLOVF,
 
-    'ullong_is_true':           [PushAllArgs, jvmgen.LCONST_0, 'long_not_equals', StoreResult],
     'ullong_invert':            jvmgen.PYPYLONGBITWISENEGATE,
 
     'ullong_add':               jvmgen.LADD,
@@ -231,12 +191,6 @@
     'ullong_truediv':           None, # TODO
     'ullong_floordiv':          jvmgen.LDIV, # valid?
     'ullong_mod':               jvmgen.PYPYULONGMOD,
-    'ullong_lt':                'ulong_less_than',     
-    'ullong_le':                'ulong_less_equals',   
-    'ullong_eq':                'ulong_equals',        
-    'ullong_ne':                'ulong_not_equals',    
-    'ullong_gt':                'ulong_greater_than',  
-    'ullong_ge':                'ulong_greater_equals',
     'ullong_lshift':            [PushAllArgs, jvmgen.L2I, jvmgen.LSHL, StoreResult],
     'ullong_rshift':            [PushAllArgs, jvmgen.L2I, jvmgen.LUSHR, StoreResult],
     'ullong_mod_zer':           jvmgen.PYPYULONGMOD,

Modified: pypy/dist/pypy/translator/jvm/src/pypy/PyPy.java
==============================================================================
--- pypy/dist/pypy/translator/jvm/src/pypy/PyPy.java	(original)
+++ pypy/dist/pypy/translator/jvm/src/pypy/PyPy.java	Sun Mar 30 19:23:03 2008
@@ -256,9 +256,18 @@
 
     public double str_to_double(String s) {
         try {
-            return Double.parseDouble(s);
+            s = s.trim();
+            if (s.equalsIgnoreCase("inf"))
+                return Double.POSITIVE_INFINITY;
+            else if (s.equalsIgnoreCase("-inf"))
+                return Double.NEGATIVE_INFINITY;
+            else if (s.equalsIgnoreCase("nan"))
+                return Double.NaN;
+            else
+                return Double.parseDouble(s);
         } catch (NumberFormatException ex) {
-            throw new RuntimeException(ex);
+            interlink.throwValueError();
+            return 0.0;
         }
     }
 
@@ -621,6 +630,15 @@
     // ----------------------------------------------------------------------
     // String
 
+    private static String substring(String str, int start, int end) {
+        if (end >= str.length())
+            if (start == 0)
+                return str;
+            else
+                end = str.length();
+        return str.substring(start, end);
+    }
+
     public static String ll_strconcat(String str1, String str2) {
         return str1 + str2;
     }
@@ -636,23 +654,23 @@
         if (start > haystack.length())
             return -1;
 
-        int res = haystack.indexOf(needle, start);
-        if (res + needle.length() > end) 
-            return -1;
-        return res;
+        haystack = substring(haystack, start, end);
+        int res = haystack.indexOf(needle);
+        if (res == -1) return res;
+        return res + start;
     }
 
     public static int ll_rfind(String haystack, String needle, 
                                int start, int end) {
-        int res = haystack.lastIndexOf(needle, end-1);
-        if (res >= start) 
-            return res;
-        return -1;
+        haystack = substring(haystack, start, end);
+        int res = haystack.lastIndexOf(needle);
+        if (res == -1) return res;
+        return res + start;
     }
 
     public static int ll_count(String haystack, String needle, 
                                int start, int end) {
-        haystack = haystack.substring(start, end);
+        haystack = substring(haystack, start, end);
 
         if (needle.length() == 0) {
             return haystack.length()+1;
@@ -669,27 +687,26 @@
 
     public static int ll_find_char(String haystack, char needle, 
                                    int start, int end) {
-        // see ll_find
+        // see ll_find for why this if is needed
         if (start > haystack.length())
             return -1;
-
-        int res = haystack.indexOf(needle, start);
-        if (res >= end) 
-            return -1;
-        return res;
+        haystack = substring(haystack, start, end);
+        int res = haystack.indexOf(needle);
+        if (res == -1) return res;
+        return res + start;
     }
 
     public static int ll_rfind_char(String haystack, char needle, 
                                     int start, int end) {
-        int res = haystack.lastIndexOf(needle, end-1);
-        if (res >= start) 
-            return res;
-        return -1;
+        haystack = substring(haystack, start, end);
+        int res = haystack.lastIndexOf(needle);
+        if (res == -1) return res;
+        return res + start;
     }
 
     public static int ll_count_char(String haystack, char needle, 
                                     int start, int end) {
-        haystack = haystack.substring(start, end);
+        haystack = substring(haystack, start, end);
         int cnt = 0;
         int idx = -1;
         while ((idx = haystack.indexOf(needle, idx+1)) != -1) {
@@ -808,7 +825,14 @@
     }
 
     public String oostring(double d, int base_) {
-        return new Double(d).toString();
+        if (d == Double.POSITIVE_INFINITY)
+            return "inf";
+        else if (d == Double.NEGATIVE_INFINITY)
+            return "-inf";
+        else if (Double.isNaN(d)) 
+            return "nan";
+        else
+            return Double.toString(d);
     }
 
     public String oostring(Object obj, int base_)
@@ -822,7 +846,7 @@
 
     public String oostring(char ch, int base_)
     {
-        return new Character(ch).toString();
+        return Character.toString(ch);
     }
 
     public byte[] oostring(byte[] s, int base_)

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	Sun Mar 30 19:23:03 2008
@@ -118,11 +118,11 @@
             return JvmGeneratedSourceWrapper(self._jvm_src)
 
     def _skip_win(self, reason):
-        if platform.system() == 'Windows':
+        if hasattr(platform, 'system') and platform.system() == 'Windows':
             py.test.skip('Windows --> %s' % reason)
             
     def _skip_powerpc(self, reason):
-        if platform.processor() == 'powerpc':
+        if hasattr(platform, 'processor') and platform.processor() == 'powerpc':
             py.test.skip('PowerPC --> %s' % reason)
 
     def _skip_llinterpreter(self, reason, skipLL=True, skipOO=True):

Modified: pypy/dist/pypy/translator/jvm/test/test_builtin.py
==============================================================================
--- pypy/dist/pypy/translator/jvm/test/test_builtin.py	(original)
+++ pypy/dist/pypy/translator/jvm/test/test_builtin.py	Sun Mar 30 19:23:03 2008
@@ -3,15 +3,10 @@
 from pypy.translator.oosupport.test_template.builtin import BaseTestBuiltin, BaseTestTime
 from pypy.translator.jvm.test.runtest import JvmTest
 
-def skip_win():
-    import platform
-    if platform.system() == 'Windows':
-        py.test.skip("Doesn't work on Windows, yet")
-
 class TestJavaBuiltin(JvmTest, BaseTestBuiltin):
 
     def test_os_write_magic(self):
-        skip_win()
+        self._skip_win('os_write_magic not on windows')
         BaseTestBuiltin.test_os_write_magic(self)
 
     def test_os_path_exists(self):

Modified: pypy/dist/pypy/translator/oosupport/test_template/snippets.py
==============================================================================
--- pypy/dist/pypy/translator/oosupport/test_template/snippets.py	(original)
+++ pypy/dist/pypy/translator/oosupport/test_template/snippets.py	Sun Mar 30 19:23:03 2008
@@ -68,3 +68,12 @@
         res = self.interpret(fn, [])
         expected = fn()
         assert res == expected
+
+    def test_branch(self):
+        def fn(i, j):
+            if i < j:
+                return "foo"
+            else:
+                return "bar"
+        assert self.interpret(fn, [1, 2]) == "foo"
+        assert self.interpret(fn, [2, 1]) == "bar"



More information about the Pypy-commit mailing list