[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