[pypy-commit] pypy win64-stage1: hg merge default
ctismer
noreply at buildbot.pypy.org
Fri Mar 30 12:17:02 CEST 2012
Author: Christian Tismer <tismer at stackless.com>
Branch: win64-stage1
Changeset: r54094:f8828970a964
Date: 2012-03-30 12:16 +0200
http://bitbucket.org/pypy/pypy/changeset/f8828970a964/
Log: hg merge default
diff --git a/pypy/doc/project-ideas.rst b/pypy/doc/project-ideas.rst
--- a/pypy/doc/project-ideas.rst
+++ b/pypy/doc/project-ideas.rst
@@ -149,6 +149,22 @@
exported. This would give us a one-size-fits-all generic .so file to be
imported by any application that wants to load .so files :-)
+Optimising cpyext (CPython C-API compatibility layer)
+-----------------------------------------------------
+
+A lot of work has gone into PyPy's implementation of CPython's C-API over
+the last years to let it reach a practical level of compatibility, so that
+C extensions for CPython work on PyPy without major rewrites. However,
+there are still many edges and corner cases where it misbehaves, and it has
+not received any substantial optimisation so far.
+
+The objective of this project is to fix bugs in cpyext and to optimise
+several performance critical parts of it, such as the reference counting
+support and other heavily used C-API functions. The net result would be to
+have CPython extensions run much faster on PyPy than they currently do, or
+to make them work at all if they currently don't. A part of this work would
+be to get cpyext into a shape where it supports running Cython generated
+extensions.
.. _`issue tracker`: http://bugs.pypy.org
.. _`mailing list`: http://mail.python.org/mailman/listinfo/pypy-dev
diff --git a/pypy/doc/stackless.rst b/pypy/doc/stackless.rst
--- a/pypy/doc/stackless.rst
+++ b/pypy/doc/stackless.rst
@@ -199,17 +199,11 @@
The following features (present in some past Stackless version of PyPy)
are for the time being not supported any more:
-* Tasklets and channels (currently ``stackless.py`` seems to import,
- but you have tasklets on top of coroutines on top of greenlets on
- top of continulets on top of stacklets, and it's probably not too
- hard to cut two of these levels by adapting ``stackless.py`` to
- use directly continulets)
-
* Coroutines (could be rewritten at app-level)
-* Pickling and unpickling continulets (*)
-
-* Continuing execution of a continulet in a different thread (*)
+* Continuing execution of a continulet in a different thread
+ (but if it is "simple enough", you can pickle it and unpickle it
+ in the other thread).
* Automatic unlimited stack (must be emulated__ so far)
@@ -217,15 +211,6 @@
.. __: `recursion depth limit`_
-(*) Pickling, as well as changing threads, could be implemented by using
-a "soft" stack switching mode again. We would get either "hard" or
-"soft" switches, similarly to Stackless Python 3rd version: you get a
-"hard" switch (like now) when the C stack contains non-trivial C frames
-to save, and a "soft" switch (like previously) when it contains only
-simple calls from Python to Python. Soft-switched continulets would
-also consume a bit less RAM, and the switch might be a bit faster too
-(unsure about that; what is the Stackless Python experience?).
-
Recursion depth limit
+++++++++++++++++++++
diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py
--- a/pypy/interpreter/baseobjspace.py
+++ b/pypy/interpreter/baseobjspace.py
@@ -296,6 +296,7 @@
self.check_signal_action = None # changed by the signal module
self.user_del_action = UserDelAction(self)
self.frame_trace_action = FrameTraceAction(self)
+ self._code_of_sys_exc_info = None
from pypy.interpreter.pycode import cpython_magic, default_magic
self.our_magic = default_magic
@@ -467,9 +468,9 @@
if name not in modules:
modules.append(name)
- # a bit of custom logic: time2 or rctime take precedence over time
+ # a bit of custom logic: rctime take precedence over time
# XXX this could probably be done as a "requires" in the config
- if ('time2' in modules or 'rctime' in modules) and 'time' in modules:
+ if 'rctime' in modules and 'time' in modules:
modules.remove('time')
if not self.config.objspace.nofaking:
diff --git a/pypy/interpreter/executioncontext.py b/pypy/interpreter/executioncontext.py
--- a/pypy/interpreter/executioncontext.py
+++ b/pypy/interpreter/executioncontext.py
@@ -154,6 +154,7 @@
#operationerr.print_detailed_traceback(self.space)
def _convert_exc(self, operr):
+ # Only for the flow object space
return operr
def sys_exc_info(self): # attn: the result is not the wrapped sys.exc_info() !!!
diff --git a/pypy/interpreter/function.py b/pypy/interpreter/function.py
--- a/pypy/interpreter/function.py
+++ b/pypy/interpreter/function.py
@@ -113,6 +113,12 @@
from pypy.interpreter.pycode import PyCode
code = self.getcode() # hook for the jit
+ #
+ if (jit.we_are_jitted() and code is self.space._code_of_sys_exc_info
+ and nargs == 0):
+ from pypy.module.sys.vm import exc_info_direct
+ return exc_info_direct(self.space, frame)
+ #
fast_natural_arity = code.fast_natural_arity
if nargs == fast_natural_arity:
if nargs == 0:
diff --git a/pypy/interpreter/gateway.py b/pypy/interpreter/gateway.py
--- a/pypy/interpreter/gateway.py
+++ b/pypy/interpreter/gateway.py
@@ -874,6 +874,12 @@
fn.add_to_table()
if gateway.as_classmethod:
fn = ClassMethod(space.wrap(fn))
+ #
+ from pypy.module.sys.vm import exc_info
+ if code._bltin is exc_info:
+ assert space._code_of_sys_exc_info is None
+ space._code_of_sys_exc_info = code
+ #
return fn
diff --git a/pypy/interpreter/pyparser/parsestring.py b/pypy/interpreter/pyparser/parsestring.py
--- a/pypy/interpreter/pyparser/parsestring.py
+++ b/pypy/interpreter/pyparser/parsestring.py
@@ -2,34 +2,39 @@
from pypy.interpreter import unicodehelper
from pypy.rlib.rstring import StringBuilder
-def parsestr(space, encoding, s, unicode_literals=False):
- # compiler.transformer.Transformer.decode_literal depends on what
- # might seem like minor details of this function -- changes here
- # must be reflected there.
+def parsestr(space, encoding, s, unicode_literal=False):
+ """Parses a string or unicode literal, and return a wrapped value.
+
+ If encoding=iso8859-1, the source string is also in this encoding.
+ If encoding=None, the source string is ascii only.
+ In other cases, the source string is in utf-8 encoding.
+
+ When a bytes string is returned, it will be encoded with the
+ original encoding.
+
+ Yes, it's very inefficient.
+ Yes, CPython has very similar code.
+ """
# we use ps as "pointer to s"
# q is the virtual last char index of the string
ps = 0
quote = s[ps]
rawmode = False
- unicode = unicode_literals
# string decoration handling
- o = ord(quote)
- isalpha = (o>=97 and o<=122) or (o>=65 and o<=90)
- if isalpha or quote == '_':
- if quote == 'b' or quote == 'B':
- ps += 1
- quote = s[ps]
- unicode = False
- elif quote == 'u' or quote == 'U':
- ps += 1
- quote = s[ps]
- unicode = True
- if quote == 'r' or quote == 'R':
- ps += 1
- quote = s[ps]
- rawmode = True
+ if quote == 'b' or quote == 'B':
+ ps += 1
+ quote = s[ps]
+ unicode_literal = False
+ elif quote == 'u' or quote == 'U':
+ ps += 1
+ quote = s[ps]
+ unicode_literal = True
+ if quote == 'r' or quote == 'R':
+ ps += 1
+ quote = s[ps]
+ rawmode = True
if quote != "'" and quote != '"':
raise_app_valueerror(space,
'Internal error: parser passed unquoted literal')
@@ -46,21 +51,28 @@
'unmatched triple quotes in literal')
q -= 2
- if unicode: # XXX Py_UnicodeFlag is ignored for now
+ if unicode_literal: # XXX Py_UnicodeFlag is ignored for now
if encoding is None or encoding == "iso-8859-1":
+ # 'unicode_escape' expects latin-1 bytes, string is ready.
buf = s
bufp = ps
bufq = q
u = None
else:
- # "\XX" may become "\u005c\uHHLL" (12 bytes)
+ # String is utf8-encoded, but 'unicode_escape' expects
+ # latin-1; So multibyte sequences must be escaped.
lis = [] # using a list to assemble the value
end = q
+ # Worst case: "\XX" may become "\u005c\uHHLL" (12 bytes)
while ps < end:
if s[ps] == '\\':
lis.append(s[ps])
ps += 1
if ord(s[ps]) & 0x80:
+ # A multibyte sequence will follow, it will be
+ # escaped like \u1234. To avoid confusion with
+ # the backslash we just wrote, we emit "\u005c"
+ # instead.
lis.append("u005c")
if ord(s[ps]) & 0x80: # XXX inefficient
w, ps = decode_utf8(space, s, ps, end, "utf-16-be")
@@ -86,13 +98,11 @@
need_encoding = (encoding is not None and
encoding != "utf-8" and encoding != "iso-8859-1")
- # XXX add strchr like interface to rtyper
assert 0 <= ps <= q
substr = s[ps : q]
if rawmode or '\\' not in s[ps:]:
if need_encoding:
w_u = space.wrap(unicodehelper.PyUnicode_DecodeUTF8(space, substr))
- #w_v = space.wrap(space.unwrap(w_u).encode(encoding)) this works
w_v = unicodehelper.PyUnicode_AsEncodedString(space, w_u, space.wrap(encoding))
return w_v
else:
diff --git a/pypy/jit/backend/test/runner_test.py b/pypy/jit/backend/test/runner_test.py
--- a/pypy/jit/backend/test/runner_test.py
+++ b/pypy/jit/backend/test/runner_test.py
@@ -27,6 +27,12 @@
def constfloat(x):
return ConstFloat(longlong.getfloatstorage(x))
+def boxlonglong(ll):
+ if longlong.is_64_bit:
+ return BoxInt(ll)
+ else:
+ return BoxFloat(ll)
+
class Runner(object):
@@ -1623,6 +1629,11 @@
[boxfloat(2.5)], t).value
assert res == longlong2float.float2longlong(2.5)
+ bytes = longlong2float.float2longlong(2.5)
+ res = self.execute_operation(rop.CONVERT_LONGLONG_BYTES_TO_FLOAT,
+ [boxlonglong(res)], 'float').value
+ assert longlong.getrealfloat(res) == 2.5
+
def test_ooops_non_gc(self):
x = lltype.malloc(lltype.Struct('x'), flavor='raw')
v = heaptracker.adr2int(llmemory.cast_ptr_to_adr(x))
diff --git a/pypy/jit/backend/test/test_random.py b/pypy/jit/backend/test/test_random.py
--- a/pypy/jit/backend/test/test_random.py
+++ b/pypy/jit/backend/test/test_random.py
@@ -328,6 +328,15 @@
def produce_into(self, builder, r):
self.put(builder, [r.choice(builder.intvars)])
+class CastLongLongToFloatOperation(AbstractFloatOperation):
+ def produce_into(self, builder, r):
+ if longlong.is_64_bit:
+ self.put(builder, [r.choice(builder.intvars)])
+ else:
+ if not builder.floatvars:
+ raise CannotProduceOperation
+ self.put(builder, [r.choice(builder.floatvars)])
+
class CastFloatToIntOperation(AbstractFloatOperation):
def produce_into(self, builder, r):
if not builder.floatvars:
@@ -450,6 +459,7 @@
OPERATIONS.append(CastFloatToIntOperation(rop.CAST_FLOAT_TO_INT))
OPERATIONS.append(CastIntToFloatOperation(rop.CAST_INT_TO_FLOAT))
OPERATIONS.append(CastFloatToIntOperation(rop.CONVERT_FLOAT_BYTES_TO_LONGLONG))
+OPERATIONS.append(CastLongLongToFloatOperation(rop.CONVERT_LONGLONG_BYTES_TO_FLOAT))
OperationBuilder.OPERATIONS = OPERATIONS
diff --git a/pypy/jit/backend/x86/assembler.py b/pypy/jit/backend/x86/assembler.py
--- a/pypy/jit/backend/x86/assembler.py
+++ b/pypy/jit/backend/x86/assembler.py
@@ -1251,6 +1251,15 @@
else:
self.mov(loc0, resloc)
+ def genop_convert_longlong_bytes_to_float(self, op, arglocs, resloc):
+ loc0, = arglocs
+ if longlong.is_64_bit:
+ assert isinstance(resloc, RegLoc)
+ assert isinstance(loc0, RegLoc)
+ self.mc.MOVD(resloc, loc0)
+ else:
+ self.mov(loc0, resloc)
+
def genop_guard_int_is_true(self, op, guard_op, guard_token, arglocs, resloc):
guard_opnum = guard_op.getopnum()
self.mc.CMP(arglocs[0], imm0)
diff --git a/pypy/jit/backend/x86/regalloc.py b/pypy/jit/backend/x86/regalloc.py
--- a/pypy/jit/backend/x86/regalloc.py
+++ b/pypy/jit/backend/x86/regalloc.py
@@ -773,10 +773,24 @@
self.Perform(op, [loc0], loc1)
self.xrm.possibly_free_var(op.getarg(0))
else:
- loc0 = self.xrm.loc(op.getarg(0))
+ arg0 = op.getarg(0)
+ loc0 = self.xrm.loc(arg0)
+ loc1 = self.xrm.force_allocate_reg(op.result, forbidden_vars=[arg0])
+ self.Perform(op, [loc0], loc1)
+ self.xrm.possibly_free_var(arg0)
+
+ def consider_convert_longlong_bytes_to_float(self, op):
+ if longlong.is_64_bit:
+ loc0 = self.rm.make_sure_var_in_reg(op.getarg(0))
loc1 = self.xrm.force_allocate_reg(op.result)
self.Perform(op, [loc0], loc1)
- self.xrm.possibly_free_var(op.getarg(0))
+ self.rm.possibly_free_var(op.getarg(0))
+ else:
+ arg0 = op.getarg(0)
+ loc0 = self.xrm.make_sure_var_in_reg(arg0)
+ loc1 = self.xrm.force_allocate_reg(op.result, forbidden_vars=[arg0])
+ self.Perform(op, [loc0], loc1)
+ self.xrm.possibly_free_var(arg0)
def _consider_llong_binop_xx(self, op):
# must force both arguments into xmm registers, because we don't
diff --git a/pypy/jit/codewriter/jtransform.py b/pypy/jit/codewriter/jtransform.py
--- a/pypy/jit/codewriter/jtransform.py
+++ b/pypy/jit/codewriter/jtransform.py
@@ -295,6 +295,7 @@
return op
rewrite_op_convert_float_bytes_to_longlong = _noop_rewrite
+ rewrite_op_convert_longlong_bytes_to_float = _noop_rewrite
# ----------
# Various kinds of calls
diff --git a/pypy/jit/codewriter/test/test_flatten.py b/pypy/jit/codewriter/test/test_flatten.py
--- a/pypy/jit/codewriter/test/test_flatten.py
+++ b/pypy/jit/codewriter/test/test_flatten.py
@@ -968,20 +968,22 @@
int_return %i2
""", transform=True)
- def test_convert_float_bytes_to_int(self):
- from pypy.rlib.longlong2float import float2longlong
+ def test_convert_float_bytes(self):
+ from pypy.rlib.longlong2float import float2longlong, longlong2float
def f(x):
- return float2longlong(x)
+ ll = float2longlong(x)
+ return longlong2float(ll)
if longlong.is_64_bit:
- result_var = "%i0"
- return_op = "int_return"
+ tmp_var = "%i0"
+ result_var = "%f1"
else:
- result_var = "%f1"
- return_op = "float_return"
+ tmp_var = "%f1"
+ result_var = "%f2"
self.encoding_test(f, [25.0], """
- convert_float_bytes_to_longlong %%f0 -> %(result_var)s
- %(return_op)s %(result_var)s
- """ % {"result_var": result_var, "return_op": return_op})
+ convert_float_bytes_to_longlong %%f0 -> %(tmp_var)s
+ convert_longlong_bytes_to_float %(tmp_var)s -> %(result_var)s
+ float_return %(result_var)s
+ """ % {"result_var": result_var, "tmp_var": tmp_var}, transform=True)
def check_force_cast(FROM, TO, operations, value):
diff --git a/pypy/jit/metainterp/blackhole.py b/pypy/jit/metainterp/blackhole.py
--- a/pypy/jit/metainterp/blackhole.py
+++ b/pypy/jit/metainterp/blackhole.py
@@ -672,6 +672,11 @@
a = longlong.getrealfloat(a)
return longlong2float.float2longlong(a)
+ @arguments(LONGLONG_TYPECODE, returns="f")
+ def bhimpl_convert_longlong_bytes_to_float(a):
+ a = longlong2float.longlong2float(a)
+ return longlong.getfloatstorage(a)
+
# ----------
# control flow operations
diff --git a/pypy/jit/metainterp/pyjitpl.py b/pypy/jit/metainterp/pyjitpl.py
--- a/pypy/jit/metainterp/pyjitpl.py
+++ b/pypy/jit/metainterp/pyjitpl.py
@@ -224,6 +224,7 @@
'float_neg', 'float_abs',
'cast_ptr_to_int', 'cast_int_to_ptr',
'convert_float_bytes_to_longlong',
+ 'convert_longlong_bytes_to_float',
]:
exec py.code.Source('''
@arguments("box")
diff --git a/pypy/jit/metainterp/resoperation.py b/pypy/jit/metainterp/resoperation.py
--- a/pypy/jit/metainterp/resoperation.py
+++ b/pypy/jit/metainterp/resoperation.py
@@ -420,6 +420,7 @@
'CAST_FLOAT_TO_SINGLEFLOAT/1',
'CAST_SINGLEFLOAT_TO_FLOAT/1',
'CONVERT_FLOAT_BYTES_TO_LONGLONG/1',
+ 'CONVERT_LONGLONG_BYTES_TO_FLOAT/1',
#
'INT_LT/2b',
'INT_LE/2b',
diff --git a/pypy/jit/metainterp/test/test_ajit.py b/pypy/jit/metainterp/test/test_ajit.py
--- a/pypy/jit/metainterp/test/test_ajit.py
+++ b/pypy/jit/metainterp/test/test_ajit.py
@@ -1,3 +1,4 @@
+import math
import sys
import py
@@ -15,7 +16,7 @@
loop_invariant, elidable, promote, jit_debug, assert_green,
AssertGreenFailed, unroll_safe, current_trace_length, look_inside_iff,
isconstant, isvirtual, promote_string, set_param, record_known_class)
-from pypy.rlib.longlong2float import float2longlong
+from pypy.rlib.longlong2float import float2longlong, longlong2float
from pypy.rlib.rarithmetic import ovfcheck, is_valid_int
from pypy.rpython.lltypesystem import lltype, llmemory, rffi
from pypy.rpython.ootypesystem import ootype
@@ -3795,15 +3796,15 @@
res = self.interp_operations(g, [1])
assert res == 3
- def test_float2longlong(self):
+ def test_float_bytes(self):
def f(n):
- return float2longlong(n)
+ ll = float2longlong(n)
+ return longlong2float(ll)
for x in [2.5, float("nan"), -2.5, float("inf")]:
# There are tests elsewhere to verify the correctness of this.
- expected = float2longlong(x)
res = self.interp_operations(f, [x])
- assert longlong.getfloatstorage(res) == expected
+ assert res == x or math.isnan(x) and math.isnan(res)
class TestLLtype(BaseLLtypeTests, LLJitMixin):
diff --git a/pypy/module/cpyext/bufferobject.py b/pypy/module/cpyext/bufferobject.py
--- a/pypy/module/cpyext/bufferobject.py
+++ b/pypy/module/cpyext/bufferobject.py
@@ -4,6 +4,8 @@
PyObjectFields, PyObject)
from pypy.module.cpyext.pyobject import make_typedescr, Py_DecRef
from pypy.interpreter.buffer import Buffer, StringBuffer, SubBuffer
+from pypy.interpreter.error import OperationError
+from pypy.module.array.interp_array import ArrayBuffer
PyBufferObjectStruct = lltype.ForwardReference()
@@ -43,10 +45,15 @@
if isinstance(w_obj, StringBuffer):
py_buf.c_b_base = rffi.cast(PyObject, 0) # space.wrap(w_obj.value)
- py_buf.c_b_ptr = rffi.cast(rffi.VOIDP, rffi.str2charp(w_obj.as_str()))
+ py_buf.c_b_ptr = rffi.cast(rffi.VOIDP, rffi.str2charp(w_obj.value))
+ py_buf.c_b_size = w_obj.getlength()
+ elif isinstance(w_obj, ArrayBuffer):
+ py_buf.c_b_base = rffi.cast(PyObject, 0) # space.wrap(w_obj.value)
+ py_buf.c_b_ptr = rffi.cast(rffi.VOIDP, w_obj.data)
py_buf.c_b_size = w_obj.getlength()
else:
- raise Exception("Fail fail fail fail fail")
+ raise OperationError(space.w_NotImplementedError, space.wrap(
+ "buffer flavor not supported"))
def buffer_realize(space, py_obj):
diff --git a/pypy/module/cpyext/test/test_bufferobject.py b/pypy/module/cpyext/test/test_bufferobject.py
--- a/pypy/module/cpyext/test/test_bufferobject.py
+++ b/pypy/module/cpyext/test/test_bufferobject.py
@@ -48,3 +48,17 @@
])
b = module.buffer_new()
raises(AttributeError, getattr, b, 'x')
+
+ def test_array_buffer(self):
+ module = self.import_extension('foo', [
+ ("roundtrip", "METH_O",
+ """
+ PyBufferObject *buf = (PyBufferObject *)args;
+ return PyString_FromStringAndSize(buf->b_ptr, buf->b_size);
+ """),
+ ])
+ import array
+ a = array.array('c', 'text')
+ b = buffer(a)
+ assert module.roundtrip(b) == 'text'
+
diff --git a/pypy/module/micronumpy/__init__.py b/pypy/module/micronumpy/__init__.py
--- a/pypy/module/micronumpy/__init__.py
+++ b/pypy/module/micronumpy/__init__.py
@@ -99,6 +99,8 @@
("exp2", "exp2"),
("expm1", "expm1"),
("fabs", "fabs"),
+ ("fmax", "fmax"),
+ ("fmin", "fmin"),
("fmod", "fmod"),
("floor", "floor"),
("ceil", "ceil"),
@@ -122,12 +124,14 @@
("sinh", "sinh"),
("subtract", "subtract"),
('sqrt', 'sqrt'),
+ ('square', 'square'),
("tan", "tan"),
("tanh", "tanh"),
('bitwise_and', 'bitwise_and'),
('bitwise_or', 'bitwise_or'),
('bitwise_xor', 'bitwise_xor'),
('bitwise_not', 'invert'),
+ ('invert', 'invert'),
('isnan', 'isnan'),
('isinf', 'isinf'),
('isneginf', 'isneginf'),
diff --git a/pypy/module/micronumpy/interp_ufuncs.py b/pypy/module/micronumpy/interp_ufuncs.py
--- a/pypy/module/micronumpy/interp_ufuncs.py
+++ b/pypy/module/micronumpy/interp_ufuncs.py
@@ -3,9 +3,11 @@
from pypy.interpreter.gateway import interp2app, unwrap_spec, NoneNotWrapped
from pypy.interpreter.typedef import TypeDef, GetSetProperty, interp_attrproperty
from pypy.module.micronumpy import interp_boxes, interp_dtype, support, loop
+from pypy.rlib import jit
from pypy.rlib.rarithmetic import LONG_BIT
from pypy.tool.sourcetools import func_with_new_name
+
class W_Ufunc(Wrappable):
_attrs_ = ["name", "promote_to_float", "promote_bools", "identity"]
_immutable_fields_ = ["promote_to_float", "promote_bools", "name"]
@@ -28,7 +30,7 @@
return self.identity
def descr_call(self, space, __args__):
- from interp_numarray import BaseArray
+ from interp_numarray import BaseArray
args_w, kwds_w = __args__.unpack()
# it occurs to me that we don't support any datatypes that
# require casting, change it later when we do
@@ -179,7 +181,7 @@
elif out.shape != shape:
raise operationerrfmt(space.w_ValueError,
'output parameter shape mismatch, expecting [%s]' +
- ' , got [%s]',
+ ' , got [%s]',
",".join([str(x) for x in shape]),
",".join([str(x) for x in out.shape]),
)
@@ -204,7 +206,7 @@
else:
arr = ReduceArray(self.func, self.name, self.identity, obj, dtype)
val = loop.compute(arr)
- return val
+ return val
def do_axis_reduce(self, obj, dtype, axis, result):
from pypy.module.micronumpy.interp_numarray import AxisReduce
@@ -253,7 +255,7 @@
if isinstance(w_obj, Scalar):
arr = self.func(calc_dtype, w_obj.value.convert_to(calc_dtype))
if isinstance(out,Scalar):
- out.value=arr
+ out.value = arr
elif isinstance(out, BaseArray):
out.fill(space, arr)
else:
@@ -265,7 +267,7 @@
if not broadcast_shape or broadcast_shape != out.shape:
raise operationerrfmt(space.w_ValueError,
'output parameter shape mismatch, could not broadcast [%s]' +
- ' to [%s]',
+ ' to [%s]',
",".join([str(x) for x in w_obj.shape]),
",".join([str(x) for x in out.shape]),
)
@@ -292,10 +294,11 @@
self.func = func
self.comparison_func = comparison_func
+ @jit.unroll_safe
def call(self, space, args_w):
from pypy.module.micronumpy.interp_numarray import (Call2,
convert_to_array, Scalar, shape_agreement, BaseArray)
- if len(args_w)>2:
+ if len(args_w) > 2:
[w_lhs, w_rhs, w_out] = args_w
else:
[w_lhs, w_rhs] = args_w
@@ -326,7 +329,7 @@
w_rhs.value.convert_to(calc_dtype)
)
if isinstance(out,Scalar):
- out.value=arr
+ out.value = arr
elif isinstance(out, BaseArray):
out.fill(space, arr)
else:
@@ -337,7 +340,7 @@
if out and out.shape != shape_agreement(space, new_shape, out.shape):
raise operationerrfmt(space.w_ValueError,
'output parameter shape mismatch, could not broadcast [%s]' +
- ' to [%s]',
+ ' to [%s]',
",".join([str(x) for x in new_shape]),
",".join([str(x) for x in out.shape]),
)
@@ -347,7 +350,6 @@
w_lhs.add_invalidates(w_res)
w_rhs.add_invalidates(w_res)
if out:
- #out.add_invalidates(w_res) #causes a recursion loop
w_res.get_concrete()
return w_res
@@ -539,6 +541,8 @@
("reciprocal", "reciprocal", 1),
("fabs", "fabs", 1, {"promote_to_float": True}),
+ ("fmax", "fmax", 2, {"promote_to_float": True}),
+ ("fmin", "fmin", 2, {"promote_to_float": True}),
("fmod", "fmod", 2, {"promote_to_float": True}),
("floor", "floor", 1, {"promote_to_float": True}),
("ceil", "ceil", 1, {"promote_to_float": True}),
@@ -547,6 +551,7 @@
("expm1", "expm1", 1, {"promote_to_float": True}),
('sqrt', 'sqrt', 1, {'promote_to_float': True}),
+ ('square', 'square', 1, {'promote_to_float': True}),
("sin", "sin", 1, {"promote_to_float": True}),
("cos", "cos", 1, {"promote_to_float": True}),
diff --git a/pypy/module/micronumpy/strides.py b/pypy/module/micronumpy/strides.py
--- a/pypy/module/micronumpy/strides.py
+++ b/pypy/module/micronumpy/strides.py
@@ -1,6 +1,7 @@
from pypy.rlib import jit
from pypy.interpreter.error import OperationError
+ at jit.look_inside_iff(lambda chunks: jit.isconstant(len(chunks)))
def enumerate_chunks(chunks):
result = []
i = -1
@@ -85,9 +86,9 @@
space.isinstance_w(w_item_or_slice, space.w_slice)):
raise OperationError(space.w_IndexError,
space.wrap('unsupported iterator index'))
-
+
start, stop, step, lngth = space.decode_index4(w_item_or_slice, size)
-
+
coords = [0] * len(shape)
i = start
if order == 'C':
diff --git a/pypy/module/micronumpy/support.py b/pypy/module/micronumpy/support.py
--- a/pypy/module/micronumpy/support.py
+++ b/pypy/module/micronumpy/support.py
@@ -1,3 +1,7 @@
+from pypy.rlib import jit
+
+
+ at jit.look_inside_iff(lambda s: jit.isconstant(len(s)))
def product(s):
i = 1
for x in s:
diff --git a/pypy/module/micronumpy/test/test_ufuncs.py b/pypy/module/micronumpy/test/test_ufuncs.py
--- a/pypy/module/micronumpy/test/test_ufuncs.py
+++ b/pypy/module/micronumpy/test/test_ufuncs.py
@@ -135,6 +135,38 @@
assert fabs(float('-inf')) == float('inf')
assert isnan(fabs(float('nan')))
+ def test_fmax(self):
+ from _numpypy import fmax
+ import math
+
+ nnan, nan, inf, ninf = float('-nan'), float('nan'), float('inf'), float('-inf')
+
+ a = [ninf, -5, 0, 5, inf]
+ assert (fmax(a, [ninf]*5) == a).all()
+ assert (fmax(a, [inf]*5) == [inf]*5).all()
+ assert (fmax(a, [1]*5) == [1, 1, 1, 5, inf]).all()
+ assert math.isnan(fmax(nan, 0))
+ assert math.isnan(fmax(0, nan))
+ assert math.isnan(fmax(nan, nan))
+ # The numpy docs specify that the FIRST NaN should be used if both are NaN
+ assert math.copysign(1.0, fmax(nnan, nan)) == -1.0
+
+ def test_fmin(self):
+ from _numpypy import fmin
+ import math
+
+ nnan, nan, inf, ninf = float('-nan'), float('nan'), float('inf'), float('-inf')
+
+ a = [ninf, -5, 0, 5, inf]
+ assert (fmin(a, [ninf]*5) == [ninf]*5).all()
+ assert (fmin(a, [inf]*5) == a).all()
+ assert (fmin(a, [1]*5) == [ninf, -5, 0, 1, 1]).all()
+ assert math.isnan(fmin(nan, 0))
+ assert math.isnan(fmin(0, nan))
+ assert math.isnan(fmin(nan, nan))
+ # The numpy docs specify that the FIRST NaN should be used if both are NaN
+ assert math.copysign(1.0, fmin(nnan, nan)) == -1.0
+
def test_fmod(self):
from _numpypy import fmod
import math
@@ -455,6 +487,19 @@
assert math.isnan(sqrt(-1))
assert math.isnan(sqrt(nan))
+ def test_square(self):
+ import math
+ from _numpypy import square
+
+ nan, inf, ninf = float("nan"), float("inf"), float("-inf")
+
+ assert math.isnan(square(nan))
+ assert math.isinf(square(inf))
+ assert math.isinf(square(ninf))
+ assert square(ninf) > 0
+ assert [square(x) for x in range(-5, 5)] == [x*x for x in range(-5, 5)]
+ assert math.isinf(square(1e300))
+
def test_radians(self):
import math
from _numpypy import radians, array
@@ -546,10 +591,11 @@
raises(TypeError, 'array([1.0]) & 1')
def test_unary_bitops(self):
- from _numpypy import bitwise_not, array
+ from _numpypy import bitwise_not, invert, array
a = array([1, 2, 3, 4])
assert (~a == [-2, -3, -4, -5]).all()
assert (bitwise_not(a) == ~a).all()
+ assert (invert(a) == ~a).all()
def test_comparisons(self):
import operator
diff --git a/pypy/module/micronumpy/types.py b/pypy/module/micronumpy/types.py
--- a/pypy/module/micronumpy/types.py
+++ b/pypy/module/micronumpy/types.py
@@ -631,6 +631,22 @@
return math.fabs(v)
@simple_binary_op
+ def fmax(self, v1, v2):
+ if math.isnan(v1):
+ return v1
+ elif math.isnan(v2):
+ return v2
+ return max(v1, v2)
+
+ @simple_binary_op
+ def fmin(self, v1, v2):
+ if math.isnan(v1):
+ return v1
+ elif math.isnan(v2):
+ return v2
+ return min(v1, v2)
+
+ @simple_binary_op
def fmod(self, v1, v2):
try:
return math.fmod(v1, v2)
@@ -741,6 +757,10 @@
except ValueError:
return rfloat.NAN
+ @simple_unary_op
+ def square(self, v):
+ return v*v
+
@raw_unary_op
def isnan(self, v):
return rfloat.isnan(v)
diff --git a/pypy/module/pypyjit/test_pypy_c/test_misc.py b/pypy/module/pypyjit/test_pypy_c/test_misc.py
--- a/pypy/module/pypyjit/test_pypy_c/test_misc.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_misc.py
@@ -351,3 +351,23 @@
# the following assertion fails if the loop was cancelled due
# to "abort: vable escape"
assert len(log.loops_by_id("eval")) == 1
+
+ def test_sys_exc_info(self):
+ def main():
+ i = 1
+ lst = [i]
+ while i < 1000:
+ try:
+ return lst[i]
+ except:
+ e = sys.exc_info()[1] # ID: exc_info
+ if not isinstance(e, IndexError):
+ raise
+ i += 1
+ return 42
+
+ log = self.run(main)
+ assert log.result == 42
+ # the following assertion fails if the loop was cancelled due
+ # to "abort: vable escape"
+ assert len(log.loops_by_id("exc_info")) == 1
diff --git a/pypy/module/sys/test/test_sysmodule.py b/pypy/module/sys/test/test_sysmodule.py
--- a/pypy/module/sys/test/test_sysmodule.py
+++ b/pypy/module/sys/test/test_sysmodule.py
@@ -595,3 +595,121 @@
assert len(frames) == 1
_, other_frame = frames.popitem()
assert other_frame.f_code.co_name in ('other_thread', '?')
+
+
+class AppTestSysExcInfoDirect:
+
+ def setup_method(self, meth):
+ self.seen = []
+ from pypy.module.sys import vm
+ def exc_info_with_tb(*args):
+ self.seen.append("n") # not optimized
+ return self.old[0](*args)
+ def exc_info_without_tb(*args):
+ self.seen.append("y") # optimized
+ return self.old[1](*args)
+ self.old = [vm.exc_info_with_tb, vm.exc_info_without_tb]
+ vm.exc_info_with_tb = exc_info_with_tb
+ vm.exc_info_without_tb = exc_info_without_tb
+ #
+ from pypy.rlib import jit
+ self.old2 = [jit.we_are_jitted]
+ jit.we_are_jitted = lambda: True
+
+ def teardown_method(self, meth):
+ from pypy.module.sys import vm
+ from pypy.rlib import jit
+ vm.exc_info_with_tb = self.old[0]
+ vm.exc_info_without_tb = self.old[1]
+ jit.we_are_jitted = self.old2[0]
+ #
+ assert ''.join(self.seen) == meth.expected
+
+ def test_returns_none(self):
+ import sys
+ assert sys.exc_info() == (None, None, None)
+ assert sys.exc_info()[0] is None
+ assert sys.exc_info()[1] is None
+ assert sys.exc_info()[2] is None
+ assert sys.exc_info()[:2] == (None, None)
+ assert sys.exc_info()[:3] == (None, None, None)
+ assert sys.exc_info()[0:2] == (None, None)
+ assert sys.exc_info()[2:4] == (None,)
+ test_returns_none.expected = 'nnnnnnnn'
+
+ def test_returns_subscr(self):
+ import sys
+ e = KeyError("boom")
+ try:
+ raise e
+ except:
+ assert sys.exc_info()[0] is KeyError # y
+ assert sys.exc_info()[1] is e # y
+ assert sys.exc_info()[2] is not None # n
+ assert sys.exc_info()[-3] is KeyError # y
+ assert sys.exc_info()[-2] is e # y
+ assert sys.exc_info()[-1] is not None # n
+ test_returns_subscr.expected = 'yynyyn'
+
+ def test_returns_slice_2(self):
+ import sys
+ e = KeyError("boom")
+ try:
+ raise e
+ except:
+ foo = sys.exc_info() # n
+ assert sys.exc_info()[:0] == () # y
+ assert sys.exc_info()[:1] == foo[:1] # y
+ assert sys.exc_info()[:2] == foo[:2] # y
+ assert sys.exc_info()[:3] == foo # n
+ assert sys.exc_info()[:4] == foo # n
+ assert sys.exc_info()[:-1] == foo[:2] # y
+ assert sys.exc_info()[:-2] == foo[:1] # y
+ assert sys.exc_info()[:-3] == () # y
+ test_returns_slice_2.expected = 'nyyynnyyy'
+
+ def test_returns_slice_3(self):
+ import sys
+ e = KeyError("boom")
+ try:
+ raise e
+ except:
+ foo = sys.exc_info() # n
+ assert sys.exc_info()[2:2] == () # y
+ assert sys.exc_info()[0:1] == foo[:1] # y
+ assert sys.exc_info()[1:2] == foo[1:2] # y
+ assert sys.exc_info()[0:3] == foo # n
+ assert sys.exc_info()[2:4] == foo[2:] # n
+ assert sys.exc_info()[0:-1] == foo[:2] # y
+ assert sys.exc_info()[0:-2] == foo[:1] # y
+ assert sys.exc_info()[5:-3] == () # y
+ test_returns_slice_3.expected = 'nyyynnyyy'
+
+ def test_strange_invocation(self):
+ import sys
+ e = KeyError("boom")
+ try:
+ raise e
+ except:
+ a = []; k = {}
+ assert sys.exc_info(*a)[:0] == ()
+ assert sys.exc_info(**k)[:0] == ()
+ test_strange_invocation.expected = 'nn'
+
+ def test_call_in_subfunction(self):
+ import sys
+ def g():
+ # this case is not optimized, because we need to search the
+ # frame chain. it's probably not worth the complications
+ return sys.exc_info()[1]
+ e = KeyError("boom")
+ try:
+ raise e
+ except:
+ assert g() is e
+ test_call_in_subfunction.expected = 'n'
+
+
+class AppTestSysExcInfoDirectCallMethod(AppTestSysExcInfoDirect):
+ def setup_class(cls):
+ cls.space = gettestobjspace(**{"objspace.opcodes.CALL_METHOD": True})
diff --git a/pypy/module/sys/vm.py b/pypy/module/sys/vm.py
--- a/pypy/module/sys/vm.py
+++ b/pypy/module/sys/vm.py
@@ -89,6 +89,9 @@
"""Return the (type, value, traceback) of the most recent exception
caught by an except clause in the current stack frame or in an older stack
frame."""
+ return exc_info_with_tb(space) # indirection for the tests
+
+def exc_info_with_tb(space):
operror = space.getexecutioncontext().sys_exc_info()
if operror is None:
return space.newtuple([space.w_None,space.w_None,space.w_None])
@@ -96,6 +99,59 @@
return space.newtuple([operror.w_type, operror.get_w_value(space),
space.wrap(operror.get_traceback())])
+def exc_info_without_tb(space, frame):
+ operror = frame.last_exception
+ return space.newtuple([operror.w_type, operror.get_w_value(space),
+ space.w_None])
+
+def exc_info_direct(space, frame):
+ from pypy.tool import stdlib_opcode
+ # In order to make the JIT happy, we try to return (exc, val, None)
+ # instead of (exc, val, tb). We can do that only if we recognize
+ # the following pattern in the bytecode:
+ # CALL_FUNCTION/CALL_METHOD <-- invoking me
+ # LOAD_CONST 0, 1, -2 or -3
+ # BINARY_SUBSCR
+ # or:
+ # CALL_FUNCTION/CALL_METHOD
+ # LOAD_CONST <=2
+ # SLICE_2
+ # or:
+ # CALL_FUNCTION/CALL_METHOD
+ # LOAD_CONST any integer
+ # LOAD_CONST <=2
+ # SLICE_3
+ need_all_three_args = True
+ co = frame.getcode().co_code
+ p = frame.last_instr
+ if (ord(co[p]) == stdlib_opcode.CALL_FUNCTION or
+ ord(co[p]) == stdlib_opcode.CALL_METHOD):
+ if ord(co[p+3]) == stdlib_opcode.LOAD_CONST:
+ lo = ord(co[p+4])
+ hi = ord(co[p+5])
+ w_constant = frame.getconstant_w((hi * 256) | lo)
+ if space.isinstance_w(w_constant, space.w_int):
+ constant = space.int_w(w_constant)
+ if ord(co[p+6]) == stdlib_opcode.BINARY_SUBSCR:
+ if -3 <= constant <= 1 and constant != -1:
+ need_all_three_args = False
+ elif ord(co[p+6]) == stdlib_opcode.SLICE+2:
+ if constant <= 2:
+ need_all_three_args = False
+ elif (ord(co[p+6]) == stdlib_opcode.LOAD_CONST and
+ ord(co[p+9]) == stdlib_opcode.SLICE+3):
+ lo = ord(co[p+7])
+ hi = ord(co[p+8])
+ w_constant = frame.getconstant_w((hi * 256) | lo)
+ if space.isinstance_w(w_constant, space.w_int):
+ if space.int_w(w_constant) <= 2:
+ need_all_three_args = False
+ #
+ if need_all_three_args or frame.last_exception is None or frame.hide():
+ return exc_info_with_tb(space)
+ else:
+ return exc_info_without_tb(space, frame)
+
def exc_clear(space):
"""Clear global information on the current exception. Subsequent calls
to exc_info() will return (None,None,None) until another exception is
diff --git a/pypy/rlib/longlong2float.py b/pypy/rlib/longlong2float.py
--- a/pypy/rlib/longlong2float.py
+++ b/pypy/rlib/longlong2float.py
@@ -21,7 +21,7 @@
FLOAT_ARRAY_PTR = lltype.Ptr(lltype.Array(rffi.FLOAT))
# these definitions are used only in tests, when not translated
-def longlong2float_emulator(llval):
+def longlong2float(llval):
with lltype.scoped_alloc(DOUBLE_ARRAY_PTR.TO, 1) as d_array:
ll_array = rffi.cast(LONGLONG_ARRAY_PTR, d_array)
ll_array[0] = llval
@@ -51,12 +51,6 @@
eci = ExternalCompilationInfo(includes=['string.h', 'assert.h'],
post_include_bits=["""
-static double pypy__longlong2float(long long x) {
- double dd;
- assert(sizeof(double) == 8 && sizeof(long long) == 8);
- memcpy(&dd, &x, 8);
- return dd;
-}
static float pypy__uint2singlefloat(unsigned int x) {
float ff;
assert(sizeof(float) == 4 && sizeof(unsigned int) == 4);
@@ -71,12 +65,6 @@
}
"""])
-longlong2float = rffi.llexternal(
- "pypy__longlong2float", [rffi.LONGLONG], rffi.DOUBLE,
- _callable=longlong2float_emulator, compilation_info=eci,
- _nowrapper=True, elidable_function=True, sandboxsafe=True,
- oo_primitive="pypy__longlong2float")
-
uint2singlefloat = rffi.llexternal(
"pypy__uint2singlefloat", [rffi.UINT], rffi.FLOAT,
_callable=uint2singlefloat_emulator, compilation_info=eci,
@@ -99,4 +87,17 @@
def specialize_call(self, hop):
[v_float] = hop.inputargs(lltype.Float)
- return hop.genop("convert_float_bytes_to_longlong", [v_float], resulttype=hop.r_result)
+ hop.exception_cannot_occur()
+ return hop.genop("convert_float_bytes_to_longlong", [v_float], resulttype=lltype.SignedLongLong)
+
+class LongLong2FloatEntry(ExtRegistryEntry):
+ _about_ = longlong2float
+
+ def compute_result_annotation(self, s_longlong):
+ assert annmodel.SomeInteger(knowntype=r_int64).contains(s_longlong)
+ return annmodel.SomeFloat()
+
+ def specialize_call(self, hop):
+ [v_longlong] = hop.inputargs(lltype.SignedLongLong)
+ hop.exception_cannot_occur()
+ return hop.genop("convert_longlong_bytes_to_float", [v_longlong], resulttype=lltype.Float)
diff --git a/pypy/rlib/test/test_longlong2float.py b/pypy/rlib/test/test_longlong2float.py
--- a/pypy/rlib/test/test_longlong2float.py
+++ b/pypy/rlib/test/test_longlong2float.py
@@ -2,6 +2,7 @@
from pypy.rlib.longlong2float import longlong2float, float2longlong
from pypy.rlib.longlong2float import uint2singlefloat, singlefloat2uint
from pypy.rlib.rarithmetic import r_singlefloat
+from pypy.rpython.test.test_llinterp import interpret
def fn(f1):
@@ -31,6 +32,18 @@
res = fn2(x)
assert repr(res) == repr(x)
+def test_interpreted():
+ def f(f1):
+ try:
+ ll = float2longlong(f1)
+ return longlong2float(ll)
+ except Exception:
+ return 500
+
+ for x in enum_floats():
+ res = interpret(f, [x])
+ assert repr(res) == repr(x)
+
# ____________________________________________________________
def fnsingle(f1):
diff --git a/pypy/rpython/lltypesystem/lloperation.py b/pypy/rpython/lltypesystem/lloperation.py
--- a/pypy/rpython/lltypesystem/lloperation.py
+++ b/pypy/rpython/lltypesystem/lloperation.py
@@ -350,6 +350,7 @@
'truncate_longlong_to_int':LLOp(canfold=True),
'force_cast': LLOp(sideeffects=False), # only for rffi.cast()
'convert_float_bytes_to_longlong': LLOp(canfold=True),
+ 'convert_longlong_bytes_to_float': LLOp(canfold=True),
# __________ pointer operations __________
diff --git a/pypy/rpython/lltypesystem/opimpl.py b/pypy/rpython/lltypesystem/opimpl.py
--- a/pypy/rpython/lltypesystem/opimpl.py
+++ b/pypy/rpython/lltypesystem/opimpl.py
@@ -431,6 +431,10 @@
from pypy.rlib.longlong2float import float2longlong
return float2longlong(a)
+def op_convert_longlong_bytes_to_float(a):
+ from pypy.rlib.longlong2float import longlong2float
+ return longlong2float(a)
+
def op_unichar_eq(x, y):
assert isinstance(x, unicode) and len(x) == 1
diff --git a/pypy/rpython/lltypesystem/rstr.py b/pypy/rpython/lltypesystem/rstr.py
--- a/pypy/rpython/lltypesystem/rstr.py
+++ b/pypy/rpython/lltypesystem/rstr.py
@@ -765,7 +765,11 @@
def _ll_stringslice(s1, start, stop):
lgt = stop - start
assert start >= 0
- assert lgt >= 0
+ # If start > stop, return a empty string. This can happen if the start
+ # is greater than the length of the string. Use < instead of <= to avoid
+ # creating another path for the JIT when start == stop.
+ if lgt < 0:
+ return s1.empty()
newstr = s1.malloc(lgt)
s1.copy_contents(s1, newstr, start, 0, lgt)
return newstr
diff --git a/pypy/rpython/ootypesystem/rstr.py b/pypy/rpython/ootypesystem/rstr.py
--- a/pypy/rpython/ootypesystem/rstr.py
+++ b/pypy/rpython/ootypesystem/rstr.py
@@ -222,6 +222,10 @@
length = s.ll_strlen()
if stop > length:
stop = length
+ # If start > stop, return a empty string. This can happen if the start
+ # is greater than the length of the string.
+ if start > stop:
+ start = stop
return s.ll_substring(start, stop-start)
def ll_stringslice_minusone(s):
diff --git a/pypy/rpython/test/test_rstr.py b/pypy/rpython/test/test_rstr.py
--- a/pypy/rpython/test/test_rstr.py
+++ b/pypy/rpython/test/test_rstr.py
@@ -477,7 +477,11 @@
s1 = s[:3]
s2 = s[3:]
s3 = s[3:10]
- return s1+s2 == s and s2+s1 == const('lohel') and s1+s3 == s
+ s4 = s[42:44]
+ return (s1+s2 == s and
+ s2+s1 == const('lohel') and
+ s1+s3 == s and
+ s4 == const(''))
res = self.interpret(fn, [0])
assert res
diff --git a/pypy/tool/clean_old_branches.py b/pypy/tool/clean_old_branches.py
--- a/pypy/tool/clean_old_branches.py
+++ b/pypy/tool/clean_old_branches.py
@@ -38,7 +38,7 @@
closed_heads.reverse()
for head, branch in closed_heads:
- print '\t', branch
+ print '\t', head, '\t', branch
print
print 'The branches listed above will be merged to "closed-branches".'
print 'You need to run this script in a clean working copy where you'
diff --git a/pypy/translator/c/src/float.h b/pypy/translator/c/src/float.h
--- a/pypy/translator/c/src/float.h
+++ b/pypy/translator/c/src/float.h
@@ -43,5 +43,6 @@
#define OP_CAST_FLOAT_TO_LONGLONG(x,r) r = (long long)(x)
#define OP_CAST_FLOAT_TO_ULONGLONG(x,r) r = (unsigned long long)(x)
#define OP_CONVERT_FLOAT_BYTES_TO_LONGLONG(x,r) memcpy(&r, &x, sizeof(double))
+#define OP_CONVERT_LONGLONG_BYTES_TO_FLOAT(x,r) memcpy(&r, &x, sizeof(long long))
#endif
diff --git a/pypy/translator/jvm/opcodes.py b/pypy/translator/jvm/opcodes.py
--- a/pypy/translator/jvm/opcodes.py
+++ b/pypy/translator/jvm/opcodes.py
@@ -243,4 +243,5 @@
'force_cast': [PushAllArgs, CastPrimitive, StoreResult],
'convert_float_bytes_to_longlong': jvm.PYPYDOUBLEBYTESTOLONG,
+ 'convert_longlong_bytes_to_float': jvm.PYPYLONGBYTESTODOUBLE,
})
diff --git a/pypy/translator/jvm/typesystem.py b/pypy/translator/jvm/typesystem.py
--- a/pypy/translator/jvm/typesystem.py
+++ b/pypy/translator/jvm/typesystem.py
@@ -942,6 +942,7 @@
PYPYULONGTODOUBLE = Method.s(jPyPy, 'ulong_to_double', (jLong,), jDouble)
PYPYLONGBITWISENEGATE = Method.v(jPyPy, 'long_bitwise_negate', (jLong,), jLong)
PYPYDOUBLEBYTESTOLONG = Method.v(jPyPy, 'pypy__float2longlong', (jDouble,), jLong)
+PYPYLONGBYTESTODOUBLE = Method.v(jPyPy, 'pypy__longlong2float', (jLong,), jDouble)
PYPYSTRTOINT = Method.v(jPyPy, 'str_to_int', (jString,), jInt)
PYPYSTRTOUINT = Method.v(jPyPy, 'str_to_uint', (jString,), jInt)
PYPYSTRTOLONG = Method.v(jPyPy, 'str_to_long', (jString,), jLong)
More information about the pypy-commit
mailing list