[pypy-commit] pypy gc_no_cleanup_nursery: merge default
fijal
noreply at buildbot.pypy.org
Mon Sep 1 21:16:22 CEST 2014
Author: Maciej Fijalkowski <fijall at gmail.com>
Branch: gc_no_cleanup_nursery
Changeset: r73277:a9dc0d3a9f93
Date: 2014-09-01 13:15 -0600
http://bitbucket.org/pypy/pypy/changeset/a9dc0d3a9f93/
Log: merge default
diff --git a/_pytest/README-BEFORE-UPDATING b/_pytest/README-BEFORE-UPDATING
new file mode 100644
--- /dev/null
+++ b/_pytest/README-BEFORE-UPDATING
@@ -0,0 +1,17 @@
+This is PyPy's code of the pytest lib. We don't expect to upgrade it
+very often, but once we do:
+
+ WARNING!
+
+ WE HAVE MADE A FEW TWEAKS HERE!
+
+Please be sure that you don't just copy the newer version from
+upstream without checking the few changes that we did. This
+can be done like this:
+
+ cd <this directory>
+ hg log . -v | less
+
+then search for all " _pytest/" in that list to know which are the
+relevant checkins. (Look for the checkins that only edit one
+or two files in this directory.)
diff --git a/_pytest/resultlog.py b/_pytest/resultlog.py
--- a/_pytest/resultlog.py
+++ b/_pytest/resultlog.py
@@ -53,16 +53,23 @@
self.config = config
self.logfile = logfile # preferably line buffered
- def write_log_entry(self, testpath, lettercode, longrepr):
+ def write_log_entry(self, testpath, lettercode, longrepr, sections=None):
py.builtin.print_("%s %s" % (lettercode, testpath), file=self.logfile)
for line in longrepr.splitlines():
py.builtin.print_(" %s" % line, file=self.logfile)
+ if sections is not None:
+ for title, content in sections:
+ py.builtin.print_(" ---------- %s ----------" % (title,),
+ file=self.logfile)
+ for line in content.splitlines():
+ py.builtin.print_(" %s" % line, file=self.logfile)
def log_outcome(self, report, lettercode, longrepr):
testpath = getattr(report, 'nodeid', None)
if testpath is None:
testpath = report.fspath
- self.write_log_entry(testpath, lettercode, longrepr)
+ self.write_log_entry(testpath, lettercode, longrepr,
+ getattr(report, 'sections', None))
def pytest_runtest_logreport(self, report):
if report.when != "call" and report.passed:
diff --git a/py/README-BEFORE-UPDATING b/py/README-BEFORE-UPDATING
new file mode 100644
--- /dev/null
+++ b/py/README-BEFORE-UPDATING
@@ -0,0 +1,17 @@
+This is PyPy's code of the py lib. We don't expect to upgrade it
+very often, but once we do:
+
+ WARNING!
+
+ WE HAVE MADE A FEW TWEAKS HERE!
+
+Please be sure that you don't just copy the newer version from
+upstream without checking the few changes that we did. This
+can be done like this:
+
+ cd <this directory>
+ hg log . -v | less
+
+then search for all " py/" in that list to know which are the
+relevant checkins. (Look for the checkins that only edit one
+or two files in this directory.)
diff --git a/py/_path/local.py b/py/_path/local.py
--- a/py/_path/local.py
+++ b/py/_path/local.py
@@ -750,7 +750,8 @@
mkdtemp = classmethod(mkdtemp)
def make_numbered_dir(cls, prefix='session-', rootdir=None, keep=3,
- lock_timeout = 172800): # two days
+ lock_timeout = 172800, # two days
+ min_timeout = 300): # five minutes
""" return unique directory with a number greater than the current
maximum one. The number is assumed to start directly after prefix.
if keep is true directories with a number less than (maxnum-keep)
@@ -818,6 +819,20 @@
for path in rootdir.listdir():
num = parse_num(path)
if num is not None and num <= (maxnum - keep):
+ if min_timeout:
+ # NB: doing this is needed to prevent (or reduce
+ # a lot the chance of) the following situation:
+ # 'keep+1' processes call make_numbered_dir() at
+ # the same time, they create dirs, but then the
+ # last process notices the first dir doesn't have
+ # (yet) a .lock in it and kills it.
+ try:
+ t1 = path.lstat().mtime
+ t2 = lockfile.lstat().mtime
+ if abs(t2-t1) < min_timeout:
+ continue # skip directories too recent
+ except py.error.Error:
+ continue # failure to get a time, better skip
lf = path.join('.lock')
try:
t1 = lf.lstat().mtime
diff --git a/pypy/module/_pypyjson/interp_encoder.py b/pypy/module/_pypyjson/interp_encoder.py
--- a/pypy/module/_pypyjson/interp_encoder.py
+++ b/pypy/module/_pypyjson/interp_encoder.py
@@ -37,16 +37,14 @@
sb = StringBuilder(len(u))
sb.append_slice(s, 0, first)
else:
+ # We used to check if 'u' contains only safe characters, and return
+ # 'w_string' directly. But this requires an extra pass over all
+ # characters, and the expected use case of this function, from
+ # json.encoder, will anyway re-encode a unicode result back to
+ # a string (with the ascii encoding). This requires two passes
+ # over the characters. So we may as well directly turn it into a
+ # string here --- only one pass.
u = space.unicode_w(w_string)
- for i in range(len(u)):
- c = u[i]
- if c >= u' ' and c <= u'~' and c != u'"' and c != u'\\':
- pass
- else:
- break
- else:
- # the input is a unicode with only non-special ascii chars
- return w_string
sb = StringBuilder(len(u))
first = 0
diff --git a/pypy/module/_pypyjson/test/test__pypyjson.py b/pypy/module/_pypyjson/test/test__pypyjson.py
--- a/pypy/module/_pypyjson/test/test__pypyjson.py
+++ b/pypy/module/_pypyjson/test/test__pypyjson.py
@@ -192,14 +192,14 @@
def test_raw_encode_basestring_ascii(self):
import _pypyjson
- def check(s, expected_type=str):
+ def check(s):
s = _pypyjson.raw_encode_basestring_ascii(s)
- assert type(s) is expected_type
+ assert type(s) is str
return s
assert check("") == ""
- assert check(u"", expected_type=unicode) == u""
+ assert check(u"") == ""
assert check("abc ") == "abc "
- assert check(u"abc ", expected_type=unicode) == u"abc "
+ assert check(u"abc ") == "abc "
raises(UnicodeDecodeError, check, "\xc0")
assert check("\xc2\x84") == "\\u0084"
assert check("\xf0\x92\x8d\x85") == "\\ud808\\udf45"
diff --git a/pypy/module/pypyjit/test_pypy_c/test_call.py b/pypy/module/pypyjit/test_pypy_c/test_call.py
--- a/pypy/module/pypyjit/test_pypy_c/test_call.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_call.py
@@ -17,13 +17,18 @@
# now we can inline it as call assembler
i = 0
j = 0
- while i < 20:
+ while i < 25:
i += 1
j += rec(100) # ID: call_rec
return j
#
- log = self.run(fn, [], threshold=18)
- loop, = log.loops_by_filename(self.filepath)
+ # NB. the parameters below are a bit ad-hoc. After 16 iterations,
+ # the we trace from the "while" and reach a "trace too long". Then
+ # in the next execution, we trace the "rec" function from start;
+ # that's "functrace" below. Then after one or two extra iterations
+ # we try again from "while", and this time we succeed.
+ log = self.run(fn, [], threshold=20)
+ functrace, loop = log.loops_by_filename(self.filepath)
assert loop.match_by_id('call_rec', """
...
p53 = call_assembler(..., descr=...)
diff --git a/pypy/module/pypyjit/test_pypy_c/test_ffi.py b/pypy/module/pypyjit/test_pypy_c/test_ffi.py
--- a/pypy/module/pypyjit/test_pypy_c/test_ffi.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_ffi.py
@@ -340,30 +340,19 @@
guard_value(p166, ConstPtr(ptr72), descr=...)
p167 = call(ConstClass(_ll_0_alloc_with_del___), descr=<Callr . EF=4>)
guard_no_exception(descr=...)
- i168 = call(ConstClass(_ll_1_raw_malloc_varsize__Signed), 6, descr=<Calli . i EF=4 OS=110>)
- i169 = int_add(i168, i97)
- i170 = int_sub(i160, i106)
- setfield_gc(p167, i168, descr=<FieldU pypy.module._cffi_backend.cdataobj.W_CData.inst__cdata .>)
+ i112 = int_sub(i160, -32768)
setfield_gc(p167, ConstPtr(null), descr=<FieldP pypy.module._cffi_backend.cdataobj.W_CData.inst__lifeline_ .+>)
- setfield_gc(p167, ConstPtr(ptr89), descr=<FieldP pypy.module._cffi_backend.cdataobj.W_CData.inst_ctype .+>)
- i171 = uint_gt(i170, i108)
- guard_false(i171, descr=...)
- i172 = int_sub(i160, -32768)
- i173 = int_and(i172, 65535)
- i174 = int_add(i173, -32768)
- setarrayitem_raw(i169, 0, i174, descr=<ArrayS 2>)
- i175 = int_add(i168, i121)
- i176 = int_sub(i160, i130)
- i177 = uint_gt(i176, i132)
- guard_false(i177, descr=...)
- setarrayitem_raw(i175, 0, i174, descr=<ArrayS 2>)
- i178 = int_add(i168, i140)
- i179 = int_sub(i160, i149)
- i180 = uint_gt(i179, i151)
- guard_false(i180, descr=...)
- setarrayitem_raw(i178, 0, i174, descr=<ArrayS 2>)
+ setfield_gc(p167, ConstPtr(ptr85), descr=<FieldP pypy.module._cffi_backend.cdataobj.W_CData.inst_ctype .+>)
+ i114 = uint_gt(i112, 65535)
+ guard_false(i114, descr=...)
+ i115 = int_and(i112, 65535)
+ i116 = int_add(i115, -32768)
--TICK--
- i183 = arraylen_gc(p67, descr=<ArrayP .>)
- i184 = arraylen_gc(p92, descr=<ArrayP .>)
+ i119 = call(ConstClass(_ll_1_raw_malloc_varsize__Signed), 6, descr=<Calli . i EF=4 OS=110>)
+ raw_store(i119, 0, i116, descr=<ArrayS 2>)
+ raw_store(i119, 2, i116, descr=<ArrayS 2>)
+ raw_store(i119, 4, i116, descr=<ArrayS 2>)
+ setfield_gc(p167, i119, descr=<FieldU pypy.module._cffi_backend.cdataobj.W_CData.inst__cdata .+>)
+ i123 = arraylen_gc(p67, descr=<ArrayP .>)
jump(..., descr=...)
""")
diff --git a/pypy/module/sys/initpath.py b/pypy/module/sys/initpath.py
--- a/pypy/module/sys/initpath.py
+++ b/pypy/module/sys/initpath.py
@@ -18,6 +18,13 @@
_WIN32 = sys.platform == 'win32'
+def _exists_and_is_executable(fn):
+ # os.access checks using the user's real uid and gid.
+ # Since pypy should not be run setuid/setgid, this
+ # should be sufficient.
+ return os.path.isfile(fn) and os.access(fn, os.X_OK)
+
+
def find_executable(executable):
"""
Return the absolute path of the executable, by looking into PATH and
@@ -34,14 +41,14 @@
if path:
for dir in path.split(os.pathsep):
fn = os.path.join(dir, executable)
- if os.path.isfile(fn):
+ if _exists_and_is_executable(fn):
executable = fn
break
executable = rpath.rabspath(executable)
# 'sys.executable' should not end up being an non-existing file;
# just use '' in this case. (CPython issue #7774)
- return executable if os.path.isfile(executable) else ''
+ return executable if _exists_and_is_executable(executable) else ''
def _readlink_maybe(filename):
diff --git a/pypy/module/sys/test/test_initpath.py b/pypy/module/sys/test/test_initpath.py
--- a/pypy/module/sys/test/test_initpath.py
+++ b/pypy/module/sys/test/test_initpath.py
@@ -57,6 +57,7 @@
a.join('pypy').ensure(file=True)
b.join('pypy').ensure(file=True)
#
+ monkeypatch.setattr(os, 'access', lambda x, y: True)
# if there is already a slash, don't do anything
monkeypatch.chdir(tmpdir)
assert find_executable('a/pypy') == a.join('pypy')
@@ -82,7 +83,11 @@
# if pypy is found but it's not a file, ignore it
c.join('pypy').ensure(dir=True)
assert find_executable('pypy') == a.join('pypy')
+ # if pypy is found but it's not executable, ignore it
+ monkeypatch.setattr(os, 'access', lambda x, y: False)
+ assert find_executable('pypy') == ''
#
+ monkeypatch.setattr(os, 'access', lambda x, y: True)
monkeypatch.setattr(initpath, 'we_are_translated', lambda: True)
monkeypatch.setattr(initpath, '_WIN32', True)
monkeypatch.setenv('PATH', str(a))
diff --git a/rpython/jit/backend/arm/callbuilder.py b/rpython/jit/backend/arm/callbuilder.py
--- a/rpython/jit/backend/arm/callbuilder.py
+++ b/rpython/jit/backend/arm/callbuilder.py
@@ -80,15 +80,6 @@
self.mc.gen_load_int(r.ip.value, n)
self.mc.SUB_rr(r.sp.value, r.sp.value, r.ip.value)
- def _must_remap_fnloc(self):
- fnloc = self.fnloc
- if fnloc.is_stack():
- return True
- if self.is_call_release_gil:
- if fnloc is r.r5 or fnloc is r.r6 or fnloc is r.r7:
- return True
- return False
-
def call_releasegil_addr_and_move_real_arguments(self, fastgil):
assert self.is_call_release_gil
assert not self.asm._is_asmgcc()
@@ -121,7 +112,7 @@
self.mc.STREX(r.r3.value, r.ip.value, r.r6.value, c=c.EQ)
# try to claim the lock
self.mc.CMP_ri(r.r3.value, 0, cond=c.EQ) # did this succeed?
- self.mc.DMB(c=c.EQ)
+ self.mc.DMB()
# the success of the lock acquisition is defined by
# 'EQ is true', or equivalently by 'r3 == 0'.
#
@@ -182,6 +173,13 @@
class SoftFloatCallBuilder(ARMCallbuilder):
+ # XXX Maybe we could kill this class and unify the remaining two
+ # XXX classes, by carefully checking if all methods here are doing
+ # XXX the exact same thing as the methods from HardFloatCallBuilder,
+ # XXX but simply forcing all BoxFloat arguments to be longlongs
+ # XXX (i.e. ignoring 'f' in favour of 'L'), and the same with
+ # XXX single-float arguments (ignoring 'S' in favour of 'i');
+ # XXX and the same for the return value.
def get_result_locs(self):
if self.resloc is None:
@@ -268,7 +266,7 @@
# or on the stack, which we can not access later
# If this happens to be the case we remap the register to r4 and use r4
# to call the function
- if self.fnloc in r.argument_regs or self._must_remap_fnloc():
+ if not self.fnloc.is_imm():
non_float_locs.append(self.fnloc)
non_float_regs.append(r.r4)
self.fnloc = r.r4
@@ -285,29 +283,23 @@
def get_next_vfp(self, tp):
assert tp in 'fS'
- if self.next_arg_vfp == -1:
- return None
- if tp == 'S':
+ if tp == 'f':
+ # 64bit double
+ i = max(self.next_arg_vfp, (self.next_arg_svfp + 1) >> 1)
+ if i >= len(r.vfp_argument_regs):
+ self.next_arg_svfp = 1000 # stop that sequence too
+ return None
+ self.next_arg_vfp = i + 1
+ return r.vfp_argument_regs[i]
+ else:
+ # 32bit float
i = self.next_arg_svfp
- next_vfp = (i >> 1) + 1
- if not (i + 1) & 1: # i is even
- self.next_arg_vfp = max(self.next_arg_vfp, next_vfp)
- self.next_arg_svfp = self.next_arg_vfp << 1
- else:
- self.next_arg_svfp += 1
- self.next_arg_vfp = next_vfp
- lst = r.svfp_argument_regs
- else: # 64bit double
- i = self.next_arg_vfp
- self.next_arg_vfp += 1
- if self.next_arg_svfp >> 1 == i:
- self.next_arg_svfp = self.next_arg_vfp << 1
- lst = r.vfp_argument_regs
- try:
- return lst[i]
- except IndexError:
- self.next_arg_vfp = self.next_arg_svfp = -1
- return None
+ if not (i & 1): # if i is even
+ i = max(i, self.next_arg_vfp << 1)
+ if i >= len(r.svfp_argument_regs):
+ return None
+ self.next_arg_svfp = i + 1
+ return r.svfp_argument_regs[i]
def prepare_arguments(self):
non_float_locs = []
@@ -316,34 +308,64 @@
float_regs = []
stack_args = []
singlefloats = None
+ longlong_mask = 0
arglocs = self.arglocs
argtypes = self.argtypes
- count = 0 # stack alignment counter
+ r_register_count = 0
on_stack = 0
+
for i in range(len(arglocs)):
argtype = INT
if i < len(argtypes) and argtypes[i] == 'S':
argtype = argtypes[i]
arg = arglocs[i]
+
if arg.is_float():
- argtype = FLOAT
- reg = self.get_next_vfp(argtype)
- if reg:
- assert len(float_regs) < len(r.vfp_argument_regs)
- float_locs.append(arg)
- assert reg not in float_regs
- float_regs.append(reg)
- else: # float argument that needs to go on the stack
- if count % 2 != 0:
- stack_args.append(None)
- count = 0
- on_stack += 1
- stack_args.append(arg)
- on_stack += 2
+ if i < len(argtypes) and argtypes[i] == 'L':
+ # A longlong argument. It uses two regular argument
+ # positions, but aligned to an even number. This is
+ # a bit strange, but it is the case even for registers:
+ # it can be in r0-r1 or in r2-r3 but not in r1-r2.
+ assert arg.is_float()
+ if r_register_count == 0:
+ # will temporarily load the register into d8
+ float_locs.append(arg)
+ float_regs.append(r.d8)
+ longlong_mask |= 1
+ r_register_count = 2
+ continue
+ elif r_register_count <= 2:
+ # will temporarily load the register into d9
+ float_locs.append(arg)
+ float_regs.append(r.d9)
+ longlong_mask |= 2
+ r_register_count = 4
+ continue
+ elif r_register_count == 3:
+ r_register_count = 4
+ else:
+ # A 64-bit float argument. Goes into the next free v#
+ # register, or if none, to the stack aligned to an
+ # even number of words.
+ argtype = FLOAT
+ reg = self.get_next_vfp(argtype)
+ if reg:
+ float_locs.append(arg)
+ assert reg not in float_regs
+ float_regs.append(reg)
+ continue
+ # float or longlong argument that needs to go on the stack
+ if on_stack & 1: # odd: realign
+ stack_args.append(None)
+ on_stack += 1
+ stack_args.append(arg)
+ on_stack += 2
+
elif argtype == 'S':
- # Singlefloat argument
+ # Singlefloat (32-bit) argument. Goes into the next free
+ # v# register, or if none, to the stack in a single word.
if singlefloats is None:
singlefloats = []
tgt = self.get_next_vfp(argtype)
@@ -351,32 +373,36 @@
singlefloats.append((arg, tgt))
else: # Singlefloat argument that needs to go on the stack
# treated the same as a regular core register argument
- count += 1
+ stack_args.append(arg)
on_stack += 1
- stack_args.append(arg)
else:
- if len(non_float_regs) < len(r.argument_regs):
- reg = r.argument_regs[len(non_float_regs)]
+ # Regular one-word argument. Goes into the next register
+ # free from the list r0, r1, r2, r3, or to the stack.
+ if r_register_count < len(r.argument_regs):
+ reg = r.argument_regs[r_register_count]
+ r_register_count += 1
non_float_locs.append(arg)
non_float_regs.append(reg)
else: # non-float argument that needs to go on the stack
- count += 1
+ stack_args.append(arg)
on_stack += 1
- stack_args.append(arg)
+
# align the stack
- if count % 2 != 0:
+ if on_stack & 1: # odd: realign
stack_args.append(None)
on_stack += 1
self._push_stack_args(stack_args, on_stack*WORD)
+
# Check that the address of the function we want to call is not
# currently stored in one of the registers used to pass the arguments
# or on the stack, which we can not access later
# If this happens to be the case we remap the register to r4 and use r4
# to call the function
- if self.fnloc in non_float_regs or self._must_remap_fnloc():
+ if not self.fnloc.is_imm():
non_float_locs.append(self.fnloc)
non_float_regs.append(r.r4)
self.fnloc = r.r4
+
# remap values stored in vfp registers
remap_frame_layout(self.asm, float_locs, float_regs, r.vfp_ip)
if singlefloats:
@@ -392,13 +418,22 @@
src = r.ip
if src.is_core_reg():
self.mc.VMOV_cs(dest.value, src.value)
+
# remap values stored in core registers
remap_frame_layout(self.asm, non_float_locs, non_float_regs, r.ip)
+ if longlong_mask & 1:
+ self.mc.FMRRD(r.r0.value, r.r1.value, r.d8.value)
+ if longlong_mask & 2:
+ self.mc.FMRRD(r.r2.value, r.r3.value, r.d9.value)
+
def load_result(self):
resloc = self.resloc
if self.restype == 'S':
self.mc.VMOV_sc(resloc.value, r.s0.value)
+ elif self.restype == 'L':
+ assert resloc.is_vfp_reg()
+ self.mc.FMDRR(resloc.value, r.r0.value, r.r1.value)
# ensure the result is wellformed and stored in the correct location
if resloc is not None and resloc.is_core_reg():
self._ensure_result_bit_extension(resloc,
@@ -408,7 +443,10 @@
if self.resloc is None:
return [], []
if self.resloc.is_vfp_reg():
- return [], [r.d0]
+ if self.restype == 'L': # long long
+ return [r.r0, r.r1], []
+ else:
+ return [], [r.d0]
assert self.resloc.is_core_reg()
return [r.r0], []
diff --git a/rpython/jit/backend/arm/codebuilder.py b/rpython/jit/backend/arm/codebuilder.py
--- a/rpython/jit/backend/arm/codebuilder.py
+++ b/rpython/jit/backend/arm/codebuilder.py
@@ -332,13 +332,17 @@
| (rd & 0xF) << 12
| (rn & 0xF) << 16)
- def DMB(self, c=cond.AL):
- self.write32(c << 28 | 0x157ff05f)
+ def DMB(self):
+ # note: 'cond' is only permitted on Thumb here
+ self.write32(0xf57ff05f)
DIV = binary_helper_call('int_div')
MOD = binary_helper_call('int_mod')
UDIV = binary_helper_call('uint_div')
+ FMDRR = VMOV_cr # uh, there are synonyms?
+ FMRRD = VMOV_rc
+
def _encode_reg_list(self, instr, regs):
for reg in regs:
instr |= 0x1 << reg
diff --git a/rpython/jit/backend/arm/runner.py b/rpython/jit/backend/arm/runner.py
--- a/rpython/jit/backend/arm/runner.py
+++ b/rpython/jit/backend/arm/runner.py
@@ -20,7 +20,7 @@
IS_64_BIT = False
supports_floats = True
- supports_longlong = False # incomplete, notably in callbuilder.py
+ supports_longlong = True
supports_singlefloats = True
from rpython.jit.backend.arm.arch import JITFRAME_FIXED_SIZE
diff --git a/rpython/jit/backend/arm/test/test_callbuilder.py b/rpython/jit/backend/arm/test/test_callbuilder.py
new file mode 100644
--- /dev/null
+++ b/rpython/jit/backend/arm/test/test_callbuilder.py
@@ -0,0 +1,47 @@
+from rpython.jit.backend.arm.callbuilder import HardFloatCallBuilder
+from rpython.jit.backend.arm import registers as r
+
+
+
+def test_hf_vfp_registers_all_singlefloat():
+ hf = HardFloatCallBuilder.__new__(HardFloatCallBuilder)
+ got = [hf.get_next_vfp('S') for i in range(18)]
+ assert got == [r.s0, r.s1, r.s2, r.s3, r.s4, r.s5, r.s6, r.s7,
+ r.s8, r.s9, r.s10, r.s11, r.s12, r.s13, r.s14, r.s15,
+ None, None]
+
+def test_hf_vfp_registers_all_doublefloat():
+ hf = HardFloatCallBuilder.__new__(HardFloatCallBuilder)
+ got = [hf.get_next_vfp('f') for i in range(10)]
+ assert got == [r.d0, r.d1, r.d2, r.d3, r.d4, r.d5, r.d6, r.d7,
+ None, None]
+
+def test_hf_vfp_registers_mixture():
+ hf = HardFloatCallBuilder.__new__(HardFloatCallBuilder)
+ got = [hf.get_next_vfp('S'), hf.get_next_vfp('f'),
+ hf.get_next_vfp('S'), hf.get_next_vfp('f'),
+ hf.get_next_vfp('S'), hf.get_next_vfp('f'),
+ hf.get_next_vfp('S'), hf.get_next_vfp('f'),
+ hf.get_next_vfp('S'), hf.get_next_vfp('f'),
+ hf.get_next_vfp('S'), hf.get_next_vfp('f'),
+ hf.get_next_vfp('S'), hf.get_next_vfp('f')]
+ assert got == [r.s0, r.d1,
+ r.s1, r.d2,
+ r.s6, r.d4,
+ r.s7, r.d5,
+ r.s12, r.d7,
+ r.s13, None,
+ None, None]
+
+def test_hf_vfp_registers_mixture_2():
+ hf = HardFloatCallBuilder.__new__(HardFloatCallBuilder)
+ got = [hf.get_next_vfp('f'), hf.get_next_vfp('f'),
+ hf.get_next_vfp('f'), hf.get_next_vfp('f'),
+ hf.get_next_vfp('f'), hf.get_next_vfp('f'),
+ hf.get_next_vfp('f'), hf.get_next_vfp('S'),
+ hf.get_next_vfp('f'), hf.get_next_vfp('S')]
+ assert got == [r.d0, r.d1,
+ r.d2, r.d3,
+ r.d4, r.d5,
+ r.d6, r.s14,
+ None, None] # <- and not r.s15 for the last item
diff --git a/rpython/jit/backend/arm/test/test_instr_codebuilder.py b/rpython/jit/backend/arm/test/test_instr_codebuilder.py
--- a/rpython/jit/backend/arm/test/test_instr_codebuilder.py
+++ b/rpython/jit/backend/arm/test/test_instr_codebuilder.py
@@ -199,6 +199,14 @@
self.cb.DMB()
self.assert_equal('DMB')
+ def test_fmdrr(self):
+ self.cb.FMDRR(r.d11.value, r.r9.value, r.r14.value)
+ self.assert_equal('FMDRR d11, r9, r14')
+
+ def test_fmrrd(self):
+ self.cb.FMRRD(r.r9.value, r.r14.value, r.d11.value)
+ self.assert_equal('FMRRD r9, r14, d11')
+
def test_size_of_gen_load_int():
for v, n in [(5, 4), (6, 4), (7, 2)]:
diff --git a/rpython/jit/backend/llsupport/assembler.py b/rpython/jit/backend/llsupport/assembler.py
--- a/rpython/jit/backend/llsupport/assembler.py
+++ b/rpython/jit/backend/llsupport/assembler.py
@@ -294,10 +294,16 @@
struct = self.loop_run_counters[i]
if struct.type == 'l':
prefix = 'TargetToken(%d)' % struct.number
- elif struct.type == 'b':
- prefix = 'bridge ' + str(struct.number)
else:
- prefix = 'entry ' + str(struct.number)
+ num = struct.number
+ if num == -1:
+ num = '-1'
+ else:
+ num = str(r_uint(num))
+ if struct.type == 'b':
+ prefix = 'bridge %s' % num
+ else:
+ prefix = 'entry %s' % num
debug_print(prefix + ':' + str(struct.i))
debug_stop('jit-backend-counts')
diff --git a/rpython/jit/backend/test/runner_test.py b/rpython/jit/backend/test/runner_test.py
--- a/rpython/jit/backend/test/runner_test.py
+++ b/rpython/jit/backend/test/runner_test.py
@@ -2718,12 +2718,11 @@
assert r == result
def test_call_release_gil_variable_function_and_arguments(self):
- # NOTE NOTE NOTE
- # This also works as a test for ctypes and libffi.
- # On some platforms, one of these is buggy...
+ from rpython.translator.tool.cbuild import ExternalCompilationInfo
from rpython.rlib.libffi import types
from rpython.rlib.rarithmetic import r_uint, r_longlong, r_ulonglong
from rpython.rlib.rarithmetic import r_singlefloat
+ from rpython.translator.c import primitive
cpu = self.cpu
rnd = random.Random(525)
@@ -2752,25 +2751,76 @@
(types.float, rffi.FLOAT),
] * 4
- for k in range(100):
+ NB_TESTS = 100
+ c_source = []
+ all_tests = []
+ export_symbols = []
+
+ def prepare_c_source():
+ """Pick a random choice of argument types and length,
+ and build a C function with these arguments. The C
+ function will simply copy them all into static global
+ variables. There are then additional functions to fetch
+ them, one per argument, with a signature 'void(ARG *)'.
+ """
POSSIBLE_TYPES = [rnd.choice(ALL_TYPES)
for i in range(random.randrange(2, 5))]
load_factor = rnd.random()
keepalive_factor = rnd.random()
#
- def pseudo_c_function(*args):
- seen.append(list(args))
- #
ffitypes = []
ARGTYPES = []
for i in range(rnd.randrange(4, 20)):
ffitype, TP = rnd.choice(POSSIBLE_TYPES)
ffitypes.append(ffitype)
ARGTYPES.append(TP)
+ fn_name = 'vartest%d' % k
+ all_tests.append((ARGTYPES, ffitypes, fn_name))
#
- FPTR = self.Ptr(self.FuncType(ARGTYPES, lltype.Void))
- func_ptr = llhelper(FPTR, pseudo_c_function)
- funcbox = self.get_funcbox(cpu, func_ptr)
+ fn_args = []
+ for i, ARG in enumerate(ARGTYPES):
+ arg_decl = primitive.cdecl(primitive.PrimitiveType[ARG],
+ 'x%d' % i)
+ fn_args.append(arg_decl)
+ var_name = 'argcopy_%s_x%d' % (fn_name, i)
+ var_decl = primitive.cdecl(primitive.PrimitiveType[ARG],
+ var_name)
+ c_source.append('static %s;' % var_decl)
+ getter_name = '%s_get%d' % (fn_name, i)
+ export_symbols.append(getter_name)
+ c_source.append('void %s(%s) { *p = %s; }' % (
+ getter_name,
+ primitive.cdecl(primitive.PrimitiveType[ARG], '*p'),
+ var_name))
+ export_symbols.append(fn_name)
+ c_source.append('')
+ c_source.append('static void real%s(%s)' % (
+ fn_name, ', '.join(fn_args)))
+ c_source.append('{')
+ for i in range(len(ARGTYPES)):
+ c_source.append(' argcopy_%s_x%d = x%d;' % (fn_name, i, i))
+ c_source.append('}')
+ c_source.append('void *%s(void)' % fn_name)
+ c_source.append('{')
+ c_source.append(' return (void *)&real%s;' % fn_name)
+ c_source.append('}')
+ c_source.append('')
+
+ for k in range(NB_TESTS):
+ prepare_c_source()
+
+ eci = ExternalCompilationInfo(
+ separate_module_sources=['\n'.join(c_source)],
+ export_symbols=export_symbols)
+
+ for k in range(NB_TESTS):
+ ARGTYPES, ffitypes, fn_name = all_tests[k]
+ func_getter_ptr = rffi.llexternal(fn_name, [], lltype.Signed,
+ compilation_info=eci, _nowrapper=True)
+ load_factor = rnd.random()
+ keepalive_factor = rnd.random()
+ #
+ func_raw = func_getter_ptr()
calldescr = cpu._calldescr_dynamic_for_tests(ffitypes, types.void)
faildescr = BasicFailDescr(1)
#
@@ -2790,7 +2840,7 @@
print
print codes
#
- argvalues = [funcbox.getint()]
+ argvalues = [func_raw]
for TP in ARGTYPES:
r = (rnd.random() - 0.5) * 999999999999.9
r = rffi.cast(TP, r)
@@ -2840,16 +2890,26 @@
looptoken = JitCellToken()
self.cpu.compile_loop(argboxes, ops, looptoken)
#
- seen = []
deadframe = self.cpu.execute_token(looptoken, *argvalues_normal)
fail = self.cpu.get_latest_descr(deadframe)
assert fail.identifier == 0
expected = argvalues[1:]
- [got] = seen
- different_values = ['%r != %r' % (a, b)
- for a, b in zip(got, expected)
- if a != b]
- assert got == expected, ', '.join(different_values)
+ got = []
+ for i, ARG in enumerate(ARGTYPES):
+ PARG = rffi.CArrayPtr(ARG)
+ getter_name = '%s_get%d' % (fn_name, i)
+ getter_ptr = rffi.llexternal(getter_name, [PARG], lltype.Void,
+ compilation_info=eci,
+ _nowrapper=True)
+ my_arg = lltype.malloc(PARG.TO, 1, zero=True, flavor='raw')
+ getter_ptr(my_arg)
+ got.append(my_arg[0])
+ lltype.free(my_arg, flavor='raw')
+ different_values = ['x%d: got %r, expected %r' % (i, a, b)
+ for i, (a, b) in enumerate(zip(got, expected))
+ if a != b]
+ assert got == expected, '\n'.join(
+ ['bad args, signature %r' % codes[1:]] + different_values)
def test_guard_not_invalidated(self):
diff --git a/rpython/jit/codewriter/effectinfo.py b/rpython/jit/codewriter/effectinfo.py
--- a/rpython/jit/codewriter/effectinfo.py
+++ b/rpython/jit/codewriter/effectinfo.py
@@ -36,6 +36,7 @@
OS_STREQ_NONNULL_CHAR = 29 # s1 == char (assert s1!=NULL)
OS_STREQ_CHECKNULL_CHAR = 30 # s1!=NULL and s1==char
OS_STREQ_LENGTHOK = 31 # s1 == s2 (assert len(s1)==len(s2))
+ OS_STR_CMP = 32 # "stroruni.cmp"
#
OS_UNI_CONCAT = 42 #
OS_UNI_SLICE = 43 #
@@ -47,6 +48,7 @@
OS_UNIEQ_NONNULL_CHAR = 49 # (must be the same amount as for
OS_UNIEQ_CHECKNULL_CHAR = 50 # STR, in the same order)
OS_UNIEQ_LENGTHOK = 51 #
+ OS_UNI_CMP = 52
_OS_offset_uni = OS_UNI_CONCAT - OS_STR_CONCAT
#
OS_LIBFFI_CALL = 62
diff --git a/rpython/jit/codewriter/jtransform.py b/rpython/jit/codewriter/jtransform.py
--- a/rpython/jit/codewriter/jtransform.py
+++ b/rpython/jit/codewriter/jtransform.py
@@ -1767,6 +1767,7 @@
dict = {"stroruni.concat": EffectInfo.OS_STR_CONCAT,
"stroruni.slice": EffectInfo.OS_STR_SLICE,
"stroruni.equal": EffectInfo.OS_STR_EQUAL,
+ "stroruni.cmp": EffectInfo.OS_STR_CMP,
"stroruni.copy_string_to_raw": EffectInfo.OS_STR_COPY_TO_RAW,
}
CHR = lltype.Char
@@ -1774,6 +1775,7 @@
dict = {"stroruni.concat": EffectInfo.OS_UNI_CONCAT,
"stroruni.slice": EffectInfo.OS_UNI_SLICE,
"stroruni.equal": EffectInfo.OS_UNI_EQUAL,
+ "stroruni.cmp": EffectInfo.OS_UNI_CMP,
"stroruni.copy_string_to_raw": EffectInfo.OS_UNI_COPY_TO_RAW
}
CHR = lltype.UniChar
diff --git a/rpython/jit/metainterp/optimizeopt/vstring.py b/rpython/jit/metainterp/optimizeopt/vstring.py
--- a/rpython/jit/metainterp/optimizeopt/vstring.py
+++ b/rpython/jit/metainterp/optimizeopt/vstring.py
@@ -733,6 +733,25 @@
return True
return False
+ def opt_call_stroruni_STR_CMP(self, op, mode):
+ v1 = self.getvalue(op.getarg(1))
+ v2 = self.getvalue(op.getarg(2))
+ l1box = v1.getstrlen(None, mode, None)
+ l2box = v2.getstrlen(None, mode, None)
+ if (l1box is not None and l2box is not None and
+ isinstance(l1box, ConstInt) and
+ isinstance(l2box, ConstInt) and
+ l1box.value == l2box.value == 1):
+ # comparing two single chars
+ vchar1 = self.strgetitem(v1, optimizer.CVAL_ZERO, mode)
+ vchar2 = self.strgetitem(v2, optimizer.CVAL_ZERO, mode)
+ seo = self.optimizer.send_extra_operation
+ seo(ResOperation(rop.INT_SUB, [vchar1.force_box(self),
+ vchar2.force_box(self)],
+ op.result))
+ return True
+ return False
+
def opt_call_SHRINK_ARRAY(self, op):
v1 = self.getvalue(op.getarg(1))
v2 = self.getvalue(op.getarg(2))
diff --git a/rpython/jit/metainterp/test/test_string.py b/rpython/jit/metainterp/test/test_string.py
--- a/rpython/jit/metainterp/test/test_string.py
+++ b/rpython/jit/metainterp/test/test_string.py
@@ -846,6 +846,27 @@
'jump': 1, 'guard_true': 2, 'int_ge': 2, 'int_add': 2, 'int_sub': 2
})
+ def test_compare_single_char_for_ordering(self):
+ jitdriver = JitDriver(reds=['result', 'n'], greens=[])
+ _str = self._str
+ constant1 = _str("abcdefghij")
+
+ def cmpstr(x, y):
+ return x > _str(y)
+
+ def f(n):
+ cmpstr(_str("abc"), "def") # force x and y to be annot as strings
+ result = 0
+ while n >= 0:
+ jitdriver.jit_merge_point(n=n, result=result)
+ c = constant1[n]
+ result += cmpstr(c, "c")
+ n -= 1
+ return result
+
+ res = self.meta_interp(f, [9])
+ assert res == f(9)
+ self.check_resops(newstr=0, newunicode=0, call=0)
class TestLLtype(StringTests, LLJitMixin):
diff --git a/rpython/rlib/rStringIO.py b/rpython/rlib/rStringIO.py
--- a/rpython/rlib/rStringIO.py
+++ b/rpython/rlib/rStringIO.py
@@ -125,19 +125,19 @@
assert result >= 0
return result
- def read(self, n=-1):
+ def read(self, size=-1):
p = self.__pos
- if p == 0 and n < 0:
+ if p == 0 and size < 0:
self.__pos = AT_END
return self.getvalue() # reading everything
- if p == AT_END or n == 0:
+ if p == AT_END or size == 0:
return ''
assert p >= 0
self.__copy_into_bigbuffer()
mysize = len(self.__bigbuffer)
count = mysize - p
- if n >= 0:
- count = min(n, count)
+ if size >= 0:
+ count = min(size, count)
if count <= 0:
return ''
if p == 0 and count == mysize:
diff --git a/rpython/rtyper/lltypesystem/rstr.py b/rpython/rtyper/lltypesystem/rstr.py
--- a/rpython/rtyper/lltypesystem/rstr.py
+++ b/rpython/rtyper/lltypesystem/rstr.py
@@ -531,6 +531,7 @@
return diff
i += 1
return len1 - len2
+ ll_strcmp.oopspec = 'stroruni.cmp(s1, s2)'
@jit.elidable
def ll_streq(s1, s2):
diff --git a/rpython/rtyper/rstr.py b/rpython/rtyper/rstr.py
--- a/rpython/rtyper/rstr.py
+++ b/rpython/rtyper/rstr.py
@@ -3,6 +3,7 @@
from rpython.rtyper import rint
from rpython.rtyper.error import TyperError
from rpython.rtyper.lltypesystem.lltype import Signed, Bool, Void, UniChar
+from rpython.rtyper.lltypesystem import lltype
from rpython.rtyper.rmodel import IteratorRepr, inputconst, Repr
from rpython.rtyper.rint import IntegerRepr
from rpython.rtyper.rfloat import FloatRepr
@@ -384,10 +385,10 @@
unicode_encode_utf_8_impl, 'runicode_encode_utf_8')
def rtype_method_upper(self, hop):
- raise TypeError("Cannot do toupper on unicode string")
+ raise TyperError("Cannot do toupper on unicode string")
def rtype_method_lower(self, hop):
- raise TypeError("Cannot do tolower on unicode string")
+ raise TyperError("Cannot do tolower on unicode string")
@jit.elidable
def ll_encode_utf8(self, ll_s):
@@ -711,6 +712,11 @@
pairtype(AbstractUniCharRepr, AbstractCharRepr)):
def rtype_eq(_, hop): return _rtype_unchr_compare_template(hop, 'eq')
def rtype_ne(_, hop): return _rtype_unchr_compare_template(hop, 'ne')
+ def rtype_lt(_, hop): return _rtype_unchr_compare_template_ord(hop, 'lt')
+ def rtype_le(_, hop): return _rtype_unchr_compare_template_ord(hop, 'le')
+ def rtype_gt(_, hop): return _rtype_unchr_compare_template_ord(hop, 'gt')
+ def rtype_ge(_, hop): return _rtype_unchr_compare_template_ord(hop, 'ge')
+
#Helper functions for comparisons
@@ -719,6 +725,18 @@
vlist = hop.inputargs(unichar_repr, unichar_repr)
return hop.genop('unichar_' + func, vlist, resulttype=Bool)
+def _rtype_unchr_compare_template_ord(hop, func):
+ vlist = hop.inputargs(*hop.args_r)
+ vlist2 = []
+ for v in vlist:
+ if v.concretetype == lltype.Char:
+ v = hop.genop('cast_char_to_int', [v], resulttype=lltype.Signed)
+ elif v.concretetype == lltype.UniChar:
+ v = hop.genop('cast_unichar_to_int', [v], resulttype=lltype.Signed)
+ else:
+ assert 0, v.concretetype
+ vlist2.append(v)
+ return hop.genop('int_' + func, vlist2, resulttype=Bool)
#
# _________________________ Conversions _________________________
diff --git a/rpython/rtyper/test/test_runicode.py b/rpython/rtyper/test/test_runicode.py
--- a/rpython/rtyper/test/test_runicode.py
+++ b/rpython/rtyper/test/test_runicode.py
@@ -296,3 +296,13 @@
res = self.interpret(f, [5])
assert res == 0
+
+ def test_unicode_char_comparison(self):
+ const = u'abcdef'
+ def f(n):
+ return const[n] >= u'c'
+
+ res = self.interpret(f, [1])
+ assert res == False
+ res = self.interpret(f, [2])
+ assert res == True
More information about the pypy-commit
mailing list