[pypy-svn] pypy 32ptr-on-64bit: hg merge default
arigo
commits-noreply at bitbucket.org
Tue Apr 12 22:19:44 CEST 2011
Author: Armin Rigo <arigo at tunes.org>
Branch: 32ptr-on-64bit
Changeset: r43314:1fb8995fe302
Date: 2011-04-12 21:14 +0200
http://bitbucket.org/pypy/pypy/changeset/1fb8995fe302/
Log: hg merge default
diff --git a/pypy/module/cpyext/pyerrors.py b/pypy/module/cpyext/pyerrors.py
--- a/pypy/module/cpyext/pyerrors.py
+++ b/pypy/module/cpyext/pyerrors.py
@@ -39,6 +39,10 @@
state = space.fromcache(State)
state.clear_exception()
+ at cpython_api([PyObject], PyObject)
+def PyExceptionInstance_Class(space, w_obj):
+ return space.type(w_obj)
+
@cpython_api([PyObjectP, PyObjectP, PyObjectP], lltype.Void)
def PyErr_Fetch(space, ptype, pvalue, ptraceback):
"""Retrieve the error indicator into three variables whose addresses are passed.
@@ -303,3 +307,11 @@
operror = state.clear_exception()
if operror:
operror.write_unraisable(space, space.str_w(space.repr(w_where)))
+
+ at cpython_api([], lltype.Void)
+def PyErr_SetInterrupt(space):
+ """This function simulates the effect of a SIGINT signal arriving --- the
+ next time PyErr_CheckSignals() is called, KeyboardInterrupt will be raised.
+ It may be called without holding the interpreter lock."""
+ space.check_signal_action.set_interrupt()
+
diff --git a/pypy/interpreter/test/test_eval.py b/pypy/interpreter/test/test_eval.py
--- a/pypy/interpreter/test/test_eval.py
+++ b/pypy/interpreter/test/test_eval.py
@@ -13,7 +13,8 @@
def __init__(self, space, code, numlocals):
self.code = code
- Frame.__init__(self, space, numlocals=numlocals)
+ Frame.__init__(self, space)
+ self.numlocals = numlocals
self.fastlocals_w = [None] * self.numlocals
def getcode(self):
@@ -24,7 +25,10 @@
def getfastscope(self):
return self.fastlocals_w
-
+
+ def getfastscopelength(self):
+ return self.numlocals
+
self.f = ConcreteFastscopeFrame(self.space, code, numlocals=5)
diff --git a/pypy/jit/metainterp/history.py b/pypy/jit/metainterp/history.py
--- a/pypy/jit/metainterp/history.py
+++ b/pypy/jit/metainterp/history.py
@@ -179,6 +179,9 @@
"""
raise NotImplementedError
+ def count_fields_if_immutable(self):
+ return -1
+
def _clone_if_mutable(self):
return self
def clone_if_mutable(self):
diff --git a/pypy/translator/backendopt/constfold.py b/pypy/translator/backendopt/constfold.py
--- a/pypy/translator/backendopt/constfold.py
+++ b/pypy/translator/backendopt/constfold.py
@@ -1,19 +1,16 @@
from pypy.objspace.flow.model import Constant, Variable, SpaceOperation
from pypy.objspace.flow.model import c_last_exception
from pypy.objspace.flow.model import mkentrymap
-from pypy.translator.backendopt.support import split_block_with_keepalive
from pypy.translator.backendopt.support import log
from pypy.translator.simplify import eliminate_empty_blocks
-from pypy.translator.unsimplify import insert_empty_block
+from pypy.translator.unsimplify import insert_empty_block, split_block
from pypy.rpython.lltypesystem.lloperation import llop
from pypy.rpython.lltypesystem import lltype
def fold_op_list(operations, constants, exit_early=False, exc_catch=False):
newops = []
- keepalives = []
folded_count = 0
- first_sideeffect_index = None
for spaceop in operations:
vargsmodif = False
vargs = []
@@ -29,10 +26,9 @@
try:
op = getattr(llop, spaceop.opname)
except AttributeError:
- sideeffects = True
+ pass
else:
- sideeffects = op.sideeffects
- if not sideeffects and len(args) == len(vargs):
+ if not op.sideeffects and len(args) == len(vargs):
RESTYPE = spaceop.result.concretetype
try:
result = op(RESTYPE, *args)
@@ -53,10 +49,6 @@
# failed to fold an operation, exit early if requested
if exit_early:
return folded_count
- if spaceop.opname == 'keepalive' and first_sideeffect_index is None:
- if vargsmodif:
- continue # keepalive(constant) is not useful
- keepalives.append(spaceop)
else:
if vargsmodif:
if (spaceop.opname == 'indirect_call'
@@ -66,20 +58,11 @@
else:
spaceop = SpaceOperation(spaceop.opname, vargs,
spaceop.result)
- if sideeffects and first_sideeffect_index is None:
- first_sideeffect_index = len(newops)
newops.append(spaceop)
# end
if exit_early:
return folded_count
else:
- # move the keepalives to the end of the block, which makes the life
- # of prepare_constant_fold_link() easier. Don't put them past the
- # exception-raising operation, though. There is also no point in
- # moving them past the first sideeffect-ing operation.
- if first_sideeffect_index is None:
- first_sideeffect_index = len(newops) - exc_catch
- newops[first_sideeffect_index:first_sideeffect_index] = keepalives
return newops
def constant_fold_block(block):
@@ -177,33 +160,23 @@
if block.exitswitch == c_last_exception:
n -= 1
# is the next, non-folded operation an indirect_call?
- m = folded_count
- while m < n and block.operations[m].opname == 'keepalive':
- m += 1
- if m < n:
- nextop = block.operations[m]
+ if folded_count < n:
+ nextop = block.operations[folded_count]
if nextop.opname == 'indirect_call' and nextop.args[0] in constants:
# indirect_call -> direct_call
callargs = [constants[nextop.args[0]]]
constants1 = constants.copy()
complete_constants(link, constants1)
- newkeepalives = []
- for i in range(folded_count, m):
- [v] = block.operations[i].args
- v = constants1.get(v, v)
- v_void = Variable()
- v_void.concretetype = lltype.Void
- newkeepalives.append(SpaceOperation('keepalive', [v], v_void))
for v in nextop.args[1:-1]:
callargs.append(constants1.get(v, v))
v_result = Variable(nextop.result)
v_result.concretetype = nextop.result.concretetype
constants[nextop.result] = v_result
callop = SpaceOperation('direct_call', callargs, v_result)
- newblock = insert_empty_block(None, link, newkeepalives + [callop])
+ newblock = insert_empty_block(None, link, [callop])
[link] = newblock.exits
assert link.target is block
- folded_count = m+1
+ folded_count += 1
if folded_count > 0:
splits = splitblocks.setdefault(block, [])
@@ -226,7 +199,7 @@
splitlink = block.exits[0]
else:
# split the block at the given position
- splitlink = split_block_with_keepalive(block, position)
+ splitlink = split_block(None, block, position)
assert list(block.exits) == [splitlink]
assert link.target is block
assert splitlink.prevblock is block
diff --git a/LICENSE b/LICENSE
--- a/LICENSE
+++ b/LICENSE
@@ -108,6 +108,7 @@
Anders Qvist
Alan McIntyre
Bert Freudenberg
+ Tav
Heinrich-Heine University, Germany
Open End AB (formerly AB Strakt), Sweden
@@ -118,13 +119,16 @@
Impara, Germany
Change Maker, Sweden
+The PyPy Logo as used by http://speed.pypy.org and others was created
+by Samuel Reis and is distributed on terms of Creative Commons Share Alike
+License.
-License for 'lib-python/2.5.2' and 'lib-python/2.5.2-modified'
+License for 'lib-python/2.7.0' and 'lib-python/2.7.0-modified'
==============================================================
Except when otherwise stated (look for LICENSE files or
copyright/license information at the beginning of each file) the files
-in the 'lib-python/2.5.2' and 'lib-python/2.5.2-modified' directories
+in the 'lib-python/2.7.0' and 'lib-python/2.7.0-modified' directories
are all copyrighted by the Python Software Foundation and licensed under
the Python Software License of which you can find a copy here:
http://www.python.org/doc/Copyright.html
@@ -157,21 +161,12 @@
======================================
The following files are from the website of The Unicode Consortium
-at http://www.unicode.org/. For the terms of use of these files, see
-http://www.unicode.org/terms_of_use.html
+at http://www.unicode.org/. For the terms of use of these files, see
+http://www.unicode.org/terms_of_use.html . Or they are derived from
+files from the above website, and the same terms of use apply.
- CompositionExclusions-3.2.0.txt
- CompositionExclusions-4.1.0.txt
- CompositionExclusions-5.0.0.txt
- EastAsianWidth-3.2.0.txt
- EastAsianWidth-4.1.0.txt
- EastAsianWidth-5.0.0.txt
- UnicodeData-3.2.0.txt
- UnicodeData-4.1.0.txt
- UnicodeData-5.0.0.txt
-
-The following files are derived from files from the above website. The same
-terms of use apply.
- UnihanNumeric-3.2.0.txt
- UnihanNumeric-4.1.0.txt
- UnihanNumeric-5.0.0.txt
+ CompositionExclusions-*.txt
+ EastAsianWidth-*.txt
+ LineBreak-*.txt
+ UnicodeData-*.txt
+ UnihanNumeric-*.txt
diff --git a/pypy/rpython/llinterp.py b/pypy/rpython/llinterp.py
--- a/pypy/rpython/llinterp.py
+++ b/pypy/rpython/llinterp.py
@@ -870,6 +870,9 @@
def op_gc_adr_of_nursery_free(self):
raise NotImplementedError
+ def op_gc_adr_of_root_stack_top(self):
+ raise NotImplementedError
+
def op_gc_call_rtti_destructor(self, rtti, addr):
if hasattr(rtti._obj, 'destructor_funcptr'):
d = rtti._obj.destructor_funcptr
diff --git a/pypy/interpreter/typedef.py b/pypy/interpreter/typedef.py
--- a/pypy/interpreter/typedef.py
+++ b/pypy/interpreter/typedef.py
@@ -103,6 +103,7 @@
except KeyError:
subcls = _getusercls(config, cls, hasdict, wants_slots, needsdel,
weakrefable)
+ assert key not in _subclass_cache
_subclass_cache[key] = subcls
return subcls
get_unique_interplevel_subclass._annspecialcase_ = "specialize:memo"
diff --git a/pypy/module/sys/interp_encoding.py b/pypy/module/sys/interp_encoding.py
--- a/pypy/module/sys/interp_encoding.py
+++ b/pypy/module/sys/interp_encoding.py
@@ -37,6 +37,10 @@
base_encoding = None
def _getfilesystemencoding(space):
+ if (space.config.translation.type_system == 'ootype'):
+ # XXX: fix this for ootype
+ return base_encoding
+ #
encoding = base_encoding
if rlocale.HAVE_LANGINFO and rlocale.CODESET:
oldlocale = rlocale.setlocale(rlocale.LC_CTYPE, None)
diff --git a/pypy/translator/jvm/database.py b/pypy/translator/jvm/database.py
--- a/pypy/translator/jvm/database.py
+++ b/pypy/translator/jvm/database.py
@@ -4,7 +4,7 @@
"""
from cStringIO import StringIO
-from pypy.rpython.lltypesystem import lltype
+from pypy.rpython.lltypesystem import lltype, rffi
from pypy.rpython.ootypesystem import ootype, rclass
from pypy.rpython.ootypesystem.module import ll_os
from pypy.translator.jvm import node, methods
@@ -229,9 +229,15 @@
if not ootype.isSubclass(OOTYPE, SELF): continue
mobj = self._function_for_graph(
clsobj, mname, False, mimpl.graph)
- graphs = OOTYPE._lookup_graphs(mname)
- if len(graphs) == 1:
- mobj.is_final = True
+ # XXX: this logic is broken: it might happen that there are
+ # ootype.Instance which contains a meth whose graph is exactly
+ # the same as the meth in the superclass: in this case,
+ # len(graphs) == 1 but we cannot just mark the method as final
+ # (or we can, but we should avoid to emit the method in the
+ # subclass, then)
+ ## graphs = OOTYPE._lookup_graphs(mname)
+ ## if len(graphs) == 1:
+ ## mobj.is_final = True
clsobj.add_method(mobj)
# currently, we always include a special "dump" method for debugging
@@ -359,6 +365,7 @@
ootype.UniChar:jvm.PYPYESCAPEDUNICHAR,
ootype.String:jvm.PYPYESCAPEDSTRING,
ootype.Unicode:jvm.PYPYESCAPEDUNICODE,
+ rffi.SHORT:jvm.SHORTTOSTRINGS,
}
def toString_method_for_ootype(self, OOTYPE):
@@ -406,6 +413,7 @@
ootype.UniChar: jvm.jChar,
ootype.Class: jvm.jClass,
ootype.ROOT: jvm.jObject, # treat like a scalar
+ rffi.SHORT: jvm.jShort,
}
# Dictionary for non-scalar types; in this case, if we see the key, we
diff --git a/lib-python/TODO b/lib-python/TODO
--- a/lib-python/TODO
+++ b/lib-python/TODO
@@ -2,7 +2,7 @@
===================
You can find the results of the most recent buildbot run at:
-http://buildbot.pypy.org/summary?branch=fast-forward
+http://buildbot.pypy.org/
Probably easy tasks
@@ -39,18 +39,8 @@
Medium tasks
------------
-- Ast objects should be picklable, see in pypy/module/_ast/test/test_ast.py:
- test_pickle()
-
- socket module has a couple of changes (including AF_TIPC packet range)
-- (test_lib2to3) When a "for" loop runs a generator function, if the loop is
- exited before the end, the "finally" clause of the generator is not called
- until the next gc collection. In our case, in lib2to3/pytree.py,
- WildcardPattern.match_seq() does not exhaust the generate_matches() generator,
- and stderr is not restored.
-
-
Longer tasks
------------
diff --git a/pypy/module/imp/test/test_import.py b/pypy/module/imp/test/test_import.py
--- a/pypy/module/imp/test/test_import.py
+++ b/pypy/module/imp/test/test_import.py
@@ -6,6 +6,7 @@
from pypy.tool.udir import udir
from pypy.rlib import streamio
from pypy.conftest import gettestobjspace
+import pytest
import sys, os
import tempfile, marshal
@@ -109,6 +110,14 @@
p.join('lone.pyc').write(p.join('x.pyc').read(mode='rb'),
mode='wb')
+ # create a .pyw file
+ p = setuppkg("windows", x = "x = 78")
+ try:
+ p.join('x.pyw').remove()
+ except py.error.ENOENT:
+ pass
+ p.join('x.py').rename(p.join('x.pyw'))
+
return str(root)
@@ -177,6 +186,14 @@
import a
assert a == a0
+ def test_trailing_slash(self):
+ import sys
+ try:
+ sys.path[0] += '/'
+ import a
+ finally:
+ sys.path[0] = sys.path[0].rstrip('/')
+
def test_import_pkg(self):
import sys
import pkg
@@ -325,6 +342,11 @@
import compiled.x
assert compiled.x == sys.modules.get('compiled.x')
+ @pytest.mark.skipif("sys.platform != 'win32'")
+ def test_pyw(self):
+ import windows.x
+ assert windows.x.__file__.endswith('x.pyw')
+
def test_cannot_write_pyc(self):
import sys, os
p = os.path.join(sys.path[-1], 'readonly')
@@ -985,7 +1007,8 @@
class AppTestPyPyExtension(object):
def setup_class(cls):
- cls.space = gettestobjspace(usemodules=['imp', 'zipimport'])
+ cls.space = gettestobjspace(usemodules=['imp', 'zipimport',
+ '__pypy__'])
cls.w_udir = cls.space.wrap(str(udir))
def test_run_compiled_module(self):
diff --git a/pypy/jit/metainterp/test/test_send.py b/pypy/jit/metainterp/test/test_send.py
--- a/pypy/jit/metainterp/test/test_send.py
+++ b/pypy/jit/metainterp/test/test_send.py
@@ -1,7 +1,7 @@
import py
from pypy.rlib.jit import JitDriver, hint, purefunction
from pypy.jit.codewriter.policy import StopAtXPolicy
-from pypy.jit.metainterp.test.test_basic import LLJitMixin, OOJitMixin
+from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin
class SendTests(object):
diff --git a/pypy/rlib/jit.py b/pypy/rlib/jit.py
--- a/pypy/rlib/jit.py
+++ b/pypy/rlib/jit.py
@@ -457,6 +457,12 @@
args_s.append(s_arg)
bk.emulate_pbc_call(uniquekey, s_func, args_s)
+ def get_getfield_op(self, rtyper):
+ if rtyper.type_system.name == 'ootypesystem':
+ return 'oogetfield'
+ else:
+ return 'getfield'
+
def specialize_call(self, hop, **kwds_i):
# XXX to be complete, this could also check that the concretetype
# of the variables are the same for each of the calls.
@@ -471,8 +477,8 @@
r_green = hop.args_r[i]
v_green = hop.inputarg(r_green, arg=i)
else:
- if hop.rtyper.type_system.name == 'ootypesystem':
- py.test.skip("lltype only")
+ #if hop.rtyper.type_system.name == 'ootypesystem':
+ #py.test.skip("lltype only")
objname, fieldname = name.split('.') # see test_green_field
assert objname in driver.reds
i = kwds_i['i_' + objname]
@@ -488,7 +494,10 @@
"field %r not found in %r" % (name,
r_red.lowleveltype.TO))
r_red = r_red.rbase
- GTYPE = r_red.lowleveltype.TO
+ if hop.rtyper.type_system.name == 'ootypesystem':
+ GTYPE = r_red.lowleveltype
+ else:
+ GTYPE = r_red.lowleveltype.TO
assert GTYPE._immutable_field(mangled_name), (
"field %r must be declared as immutable" % name)
if not hasattr(driver, 'll_greenfields'):
@@ -497,7 +506,8 @@
#
v_red = hop.inputarg(r_red, arg=i)
c_llname = hop.inputconst(lltype.Void, mangled_name)
- v_green = hop.genop('getfield', [v_red, c_llname],
+ getfield_op = self.get_getfield_op(hop.rtyper)
+ v_green = hop.genop(getfield_op, [v_red, c_llname],
resulttype = r_field)
s_green = s_red.classdef.about_attribute(fieldname)
assert s_green is not None
diff --git a/pypy/jit/metainterp/test/test_dict.py b/pypy/jit/metainterp/test/test_dict.py
--- a/pypy/jit/metainterp/test/test_dict.py
+++ b/pypy/jit/metainterp/test/test_dict.py
@@ -1,6 +1,7 @@
import py
-from pypy.jit.metainterp.test.test_basic import LLJitMixin, OOJitMixin
+from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin
from pypy.rlib.jit import JitDriver
+from pypy.rlib import objectmodel
class DictTests:
@@ -69,6 +70,66 @@
res = self.meta_interp(f, [10], listops=True)
assert res == expected
+ def test_dict_trace_hash(self):
+ myjitdriver = JitDriver(greens = [], reds = ['total', 'dct'])
+ def key(x):
+ return x % 2
+ def eq(x, y):
+ return (x % 2) == (y % 2)
+
+ def f(n):
+ dct = objectmodel.r_dict(eq, key)
+ total = n
+ while total:
+ myjitdriver.jit_merge_point(total=total, dct=dct)
+ if total not in dct:
+ dct[total] = []
+ dct[total].append(total)
+ total -= 1
+ return len(dct[0])
+
+ res1 = f(100)
+ res2 = self.meta_interp(f, [100], listops=True)
+ assert res1 == res2
+ self.check_loops(int_mod=1) # the hash was traced
+
+ def test_dict_setdefault(self):
+ myjitdriver = JitDriver(greens = [], reds = ['total', 'dct'])
+ def f(n):
+ dct = {}
+ total = n
+ while total:
+ myjitdriver.jit_merge_point(total=total, dct=dct)
+ dct.setdefault(total % 2, []).append(total)
+ total -= 1
+ return len(dct[0])
+
+ assert f(100) == 50
+ res = self.meta_interp(f, [100], listops=True)
+ assert res == 50
+ self.check_loops(new=0, new_with_vtable=0)
+
+ def test_dict_as_counter(self):
+ myjitdriver = JitDriver(greens = [], reds = ['total', 'dct'])
+ def key(x):
+ return x % 2
+ def eq(x, y):
+ return (x % 2) == (y % 2)
+
+ def f(n):
+ dct = objectmodel.r_dict(eq, key)
+ total = n
+ while total:
+ myjitdriver.jit_merge_point(total=total, dct=dct)
+ dct[total] = dct.get(total, 0) + 1
+ total -= 1
+ return dct[0]
+
+ assert f(100) == 50
+ res = self.meta_interp(f, [100], listops=True)
+ assert res == 50
+ self.check_loops(int_mod=1)
+
class TestOOtype(DictTests, OOJitMixin):
pass
diff --git a/pypy/rpython/memory/test/test_transformed_gc.py b/pypy/rpython/memory/test/test_transformed_gc.py
--- a/pypy/rpython/memory/test/test_transformed_gc.py
+++ b/pypy/rpython/memory/test/test_transformed_gc.py
@@ -13,7 +13,6 @@
from pypy.rlib import rgc
from pypy import conftest
from pypy.rlib.rstring import StringBuilder
-from pypy.rlib.objectmodel import keepalive_until_here
from pypy.rlib.rarithmetic import LONG_BIT
WORD = LONG_BIT // 8
diff --git a/pypy/translator/backendopt/test/test_support.py b/pypy/translator/backendopt/test/test_support.py
--- a/pypy/translator/backendopt/test/test_support.py
+++ b/pypy/translator/backendopt/test/test_support.py
@@ -1,94 +1,7 @@
-from pypy.translator.unsimplify import varoftype
from pypy.translator.translator import TranslationContext, graphof
from pypy.translator.backendopt.support import \
- needs_conservative_livevar_calculation, split_block_with_keepalive, \
find_loop_blocks, find_backedges, compute_reachability
-from pypy.rpython.rtyper import LowLevelOpList
-from pypy.rpython.lltypesystem import lltype
-from pypy.objspace.flow import model
-
-NonGcB = lltype.Struct("B", ('x', lltype.Signed))
-GcA = lltype.GcStruct("A", ('b', NonGcB), ('c', lltype.Ptr(lltype.FuncType([], lltype.Void))))
-
-def test_nclc_should_be_true():
- # this is testing a block like:
- # +--- inputargs: pointer_to_gc
- # | v0 <- op_getsubstruct pointer_to_gc 'b'
- # +--- exitargs: v0 (i.e. pointer to non-gc)
- llops = LowLevelOpList()
- ptr_a = varoftype(lltype.Ptr(GcA))
- v_res = llops.genop("getsubstruct", [ptr_a, model.Constant('b', lltype.Void)],
- resulttype=lltype.Ptr(NonGcB))
- block = model.Block([ptr_a])
- block.operations.extend(llops)
- block.closeblock(model.Link([v_res], None))
- assert needs_conservative_livevar_calculation(block)
-
-def test_nclc_nongc_not_passed_on():
- # +--- inputargs: pointer_to_gc
- # | v0 <- op_getsubstruct pointer_to_gc 'b'
- # +--- exitargs: pointer_to_gc (i.e. the pointer to non-gc doesn't leave the block)
- llops = LowLevelOpList()
- ptr_a = varoftype(lltype.Ptr(GcA))
- v_res = llops.genop("getsubstruct", [ptr_a, model.Constant('b', lltype.Void)],
- resulttype=lltype.Ptr(NonGcB))
- block = model.Block([ptr_a])
- block.operations.extend(llops)
- block.closeblock(model.Link([ptr_a], None))
- assert not needs_conservative_livevar_calculation(block)
-
-def test_nclc_ignore_functype():
- # +--- inputargs: pointer_to_gc
- # | v0 <- op_getfield pointer_to_gc 'c'
- # +--- exitargs: v0 (i.e. a pointer to function)
- # pointers to functions are 'not gc' but functions are also
- # immortal so you don't need to muck around inserting keepalives
- # so *they* don't die!
- llops = LowLevelOpList()
- ptr_a = varoftype(lltype.Ptr(GcA))
- v_res = llops.genop("getfield", [ptr_a, model.Constant('c', lltype.Void)],
- resulttype=GcA.c)
- block = model.Block([ptr_a])
- block.operations.extend(llops)
- block.closeblock(model.Link([v_res], None))
- assert not needs_conservative_livevar_calculation(block)
-
-def test_sbwk_should_insert_keepalives():
- # this is testing something like:
- # v0 <- op_producing_non_gc
- # v1 <- op_using_v0 <- split here
- llops = LowLevelOpList()
- ptr_a = varoftype(lltype.Ptr(GcA))
- v_res = llops.genop("getfield", [ptr_a, model.Constant('b', lltype.Void)],
- resulttype=lltype.Ptr(NonGcB))
- llops.genop("direct_call", [model.Constant(None, lltype.Void), v_res],
- resulttype=lltype.Void)
- block = model.Block([ptr_a])
- block.operations.extend(llops)
- block.closeblock(model.Link([], None))
- link = split_block_with_keepalive(block, 1)
- assert 'keepalive' in [op.opname for op in link.target.operations]
-
-def test_sbwk_should_insert_keepalives_2():
- # this is testing something like:
- # v0 <- op_producing_non_gc
- # v1 <- op_not_using_v0 <- split here
- # v2 <- op_using_v0
- llops = LowLevelOpList()
- ptr_a = varoftype(lltype.Ptr(GcA))
- v_res = llops.genop("getfield", [ptr_a, model.Constant('b', lltype.Void)],
- resulttype=lltype.Ptr(NonGcB))
- llops.genop("direct_call", [model.Constant(None, lltype.Void)],
- resulttype=lltype.Void)
- llops.genop("direct_call", [model.Constant(None, lltype.Void), v_res],
- resulttype=lltype.Void)
- block = model.Block([ptr_a])
- block.operations.extend(llops)
- block.closeblock(model.Link([], None))
- link = split_block_with_keepalive(block, 1)
- assert 'keepalive' in [op.opname for op in link.target.operations]
-
#__________________________________________________________
# test compute_reachability
diff --git a/pypy/jit/metainterp/test/test_optimizeutil.py b/pypy/jit/metainterp/test/test_optimizeutil.py
--- a/pypy/jit/metainterp/test/test_optimizeutil.py
+++ b/pypy/jit/metainterp/test/test_optimizeutil.py
@@ -68,6 +68,16 @@
nodeobjvalue = lltype.cast_opaque_ptr(llmemory.GCREF, nodeobj)
refdescr = cpu.fielddescrof(NODEOBJ, 'ref')
+ INTOBJ_NOIMMUT = lltype.GcStruct('INTOBJ_NOIMMUT', ('parent', OBJECT),
+ ('intval', lltype.Signed))
+ INTOBJ_IMMUT = lltype.GcStruct('INTOBJ_IMMUT', ('parent', OBJECT),
+ ('intval', lltype.Signed),
+ hints={'immutable': True})
+ intobj_noimmut_vtable = lltype.malloc(OBJECT_VTABLE, immortal=True)
+ intobj_immut_vtable = lltype.malloc(OBJECT_VTABLE, immortal=True)
+ noimmut_intval = cpu.fielddescrof(INTOBJ_NOIMMUT, 'intval')
+ immut_intval = cpu.fielddescrof(INTOBJ_IMMUT, 'intval')
+
arraydescr = cpu.arraydescrof(lltype.GcArray(lltype.Signed))
floatarraydescr = cpu.arraydescrof(lltype.GcArray(lltype.Float))
@@ -147,7 +157,6 @@
FakeWarmRunnerDesc.cpu = cpu
vrefinfo = VirtualRefInfo(FakeWarmRunnerDesc)
virtualtokendescr = vrefinfo.descr_virtual_token
- virtualrefindexdescr = vrefinfo.descr_virtualref_index
virtualforceddescr = vrefinfo.descr_forced
jit_virtual_ref_vtable = vrefinfo.jit_virtual_ref_vtable
jvr_vtable_adr = llmemory.cast_ptr_to_adr(jit_virtual_ref_vtable)
@@ -156,6 +165,8 @@
register_known_gctype(cpu, node_vtable2, NODE2)
register_known_gctype(cpu, u_vtable, U)
register_known_gctype(cpu, jit_virtual_ref_vtable,vrefinfo.JIT_VIRTUAL_REF)
+ register_known_gctype(cpu, intobj_noimmut_vtable, INTOBJ_NOIMMUT)
+ register_known_gctype(cpu, intobj_immut_vtable, INTOBJ_IMMUT)
namespace = locals()
diff --git a/pypy/jit/backend/llsupport/gc.py b/pypy/jit/backend/llsupport/gc.py
--- a/pypy/jit/backend/llsupport/gc.py
+++ b/pypy/jit/backend/llsupport/gc.py
@@ -1,6 +1,8 @@
+import os
from pypy.rlib import rgc
from pypy.rlib.objectmodel import we_are_translated
from pypy.rlib.debug import fatalerror
+from pypy.rlib.rarithmetic import ovfcheck
from pypy.rpython.lltypesystem import lltype, llmemory, rffi, rclass, rstr
from pypy.rpython.lltypesystem import llgroup
from pypy.rpython.lltypesystem.lloperation import llop
@@ -21,6 +23,8 @@
class GcLLDescription(GcCache):
minimal_size_in_nursery = 0
+ get_malloc_slowpath_addr = None
+
def __init__(self, gcdescr, translator=None, rtyper=None):
GcCache.__init__(self, translator is not None, rtyper)
self.gcdescr = gcdescr
@@ -34,6 +38,8 @@
pass
def can_inline_malloc(self, descr):
return False
+ def can_inline_malloc_varsize(self, descr, num_elem):
+ return False
def has_write_barrier_class(self):
return None
def freeing_block(self, start, stop):
@@ -212,10 +218,12 @@
return addr_ref
-class GcRootMap_asmgcc:
+class GcRootMap_asmgcc(object):
"""Handles locating the stack roots in the assembler.
This is the class supporting --gcrootfinder=asmgcc.
"""
+ is_shadow_stack = False
+
LOC_REG = 0
LOC_ESP_PLUS = 1
LOC_EBP_PLUS = 2
@@ -224,7 +232,7 @@
GCMAP_ARRAY = rffi.CArray(lltype.Signed)
CALLSHAPE_ARRAY_PTR = rffi.CArrayPtr(rffi.UCHAR)
- def __init__(self):
+ def __init__(self, gcdescr=None):
# '_gcmap' is an array of length '_gcmap_maxlength' of addresses.
# '_gcmap_curlength' tells how full the array really is.
# The addresses are actually grouped in pairs:
@@ -237,6 +245,13 @@
self._gcmap_deadentries = 0
self._gcmap_sorted = True
+ def add_jit2gc_hooks(self, jit2gc):
+ jit2gc.update({
+ 'gcmapstart': lambda: self.gcmapstart(),
+ 'gcmapend': lambda: self.gcmapend(),
+ 'gcmarksorted': lambda: self.gcmarksorted(),
+ })
+
def initialize(self):
# hack hack hack. Remove these lines and see MissingRTypeAttribute
# when the rtyper tries to annotate these methods only when GC-ing...
@@ -365,7 +380,7 @@
number >>= 7
shape.append(chr(number | flag))
- def add_ebp_offset(self, shape, offset):
+ def add_frame_offset(self, shape, offset):
assert (offset & 3) == 0
if offset >= 0:
num = self.LOC_EBP_PLUS | offset
@@ -388,6 +403,126 @@
return rawaddr
+class GcRootMap_shadowstack(object):
+ """Handles locating the stack roots in the assembler.
+ This is the class supporting --gcrootfinder=shadowstack.
+ """
+ is_shadow_stack = True
+ MARKER = 8
+
+ # The "shadowstack" is a portable way in which the GC finds the
+ # roots that live in the stack. Normally it is just a list of
+ # pointers to GC objects. The pointers may be moved around by a GC
+ # collection. But with the JIT, an entry can also be MARKER, in
+ # which case the next entry points to an assembler stack frame.
+ # During a residual CALL from the assembler (which may indirectly
+ # call the GC), we use the force_index stored in the assembler
+ # stack frame to identify the call: we can go from the force_index
+ # to a list of where the GC pointers are in the frame (this is the
+ # purpose of the present class).
+ #
+ # Note that across CALL_MAY_FORCE or CALL_ASSEMBLER, we can also go
+ # from the force_index to a ResumeGuardForcedDescr instance, which
+ # is used if the virtualizable or the virtualrefs need to be forced
+ # (see pypy.jit.backend.model). The force_index number in the stack
+ # frame is initially set to a non-negative value x, but it is
+ # occasionally turned into (~x) in case of forcing.
+
+ INTARRAYPTR = rffi.CArrayPtr(rffi.INT)
+ CALLSHAPES_ARRAY = rffi.CArray(INTARRAYPTR)
+
+ def __init__(self, gcdescr):
+ self._callshapes = lltype.nullptr(self.CALLSHAPES_ARRAY)
+ self._callshapes_maxlength = 0
+ self.force_index_ofs = gcdescr.force_index_ofs
+
+ def add_jit2gc_hooks(self, jit2gc):
+ #
+ def collect_jit_stack_root(callback, gc, addr):
+ if addr.signed[0] != GcRootMap_shadowstack.MARKER:
+ # common case
+ if gc.points_to_valid_gc_object(addr):
+ callback(gc, addr)
+ return WORD
+ else:
+ # case of a MARKER followed by an assembler stack frame
+ follow_stack_frame_of_assembler(callback, gc, addr)
+ return 2 * WORD
+ #
+ def follow_stack_frame_of_assembler(callback, gc, addr):
+ frame_addr = addr.signed[1]
+ addr = llmemory.cast_int_to_adr(frame_addr + self.force_index_ofs)
+ force_index = addr.signed[0]
+ if force_index < 0:
+ force_index = ~force_index
+ callshape = self._callshapes[force_index]
+ n = 0
+ while True:
+ offset = rffi.cast(lltype.Signed, callshape[n])
+ if offset == 0:
+ break
+ addr = llmemory.cast_int_to_adr(frame_addr + offset)
+ if gc.points_to_valid_gc_object(addr):
+ callback(gc, addr)
+ n += 1
+ #
+ jit2gc.update({
+ 'rootstackhook': collect_jit_stack_root,
+ })
+
+ def initialize(self):
+ pass
+
+ def get_basic_shape(self, is_64_bit=False):
+ return []
+
+ def add_frame_offset(self, shape, offset):
+ assert offset != 0
+ shape.append(offset)
+
+ def add_callee_save_reg(self, shape, register):
+ msg = "GC pointer in %s was not spilled" % register
+ os.write(2, '[llsupport/gc] %s\n' % msg)
+ raise AssertionError(msg)
+
+ def compress_callshape(self, shape, datablockwrapper):
+ length = len(shape)
+ SZINT = rffi.sizeof(rffi.INT)
+ rawaddr = datablockwrapper.malloc_aligned((length + 1) * SZINT, SZINT)
+ p = rffi.cast(self.INTARRAYPTR, rawaddr)
+ for i in range(length):
+ p[i] = rffi.cast(rffi.INT, shape[i])
+ p[length] = rffi.cast(rffi.INT, 0)
+ return p
+
+ def write_callshape(self, p, force_index):
+ if force_index >= self._callshapes_maxlength:
+ self._enlarge_callshape_list(force_index + 1)
+ self._callshapes[force_index] = p
+
+ def _enlarge_callshape_list(self, minsize):
+ newlength = 250 + (self._callshapes_maxlength // 3) * 4
+ if newlength < minsize:
+ newlength = minsize
+ newarray = lltype.malloc(self.CALLSHAPES_ARRAY, newlength,
+ flavor='raw', track_allocation=False)
+ if self._callshapes:
+ i = self._callshapes_maxlength - 1
+ while i >= 0:
+ newarray[i] = self._callshapes[i]
+ i -= 1
+ lltype.free(self._callshapes, flavor='raw')
+ self._callshapes = newarray
+ self._callshapes_maxlength = newlength
+
+ def freeing_block(self, start, stop):
+ pass # nothing needed here
+
+ def get_root_stack_top_addr(self):
+ rst_addr = llop.gc_adr_of_root_stack_top(llmemory.Address)
+ return rffi.cast(lltype.Signed, rst_addr)
+
+
class WriteBarrierDescr(AbstractDescr):
def __init__(self, gc_ll_descr):
self.llop1 = gc_ll_descr.llop1
@@ -437,7 +572,7 @@
except KeyError:
raise NotImplementedError("--gcrootfinder=%s not implemented"
" with the JIT" % (name,))
- gcrootmap = cls()
+ gcrootmap = cls(gcdescr)
self.gcrootmap = gcrootmap
self.gcrefs = GcRefList()
self.single_gcref_descr = GcPtrFieldDescr('', 0)
@@ -446,12 +581,9 @@
# where it can be fished and reused by the FrameworkGCTransformer
self.layoutbuilder = framework.TransformerLayoutBuilder(translator)
self.layoutbuilder.delay_encoding()
- self.translator._jit2gc = {
- 'layoutbuilder': self.layoutbuilder,
- 'gcmapstart': lambda: gcrootmap.gcmapstart(),
- 'gcmapend': lambda: gcrootmap.gcmapend(),
- 'gcmarksorted': lambda: gcrootmap.gcmarksorted(),
- }
+ self.translator._jit2gc = {'layoutbuilder': self.layoutbuilder}
+ gcrootmap.add_jit2gc_hooks(self.translator._jit2gc)
+
self.GCClass = self.layoutbuilder.GCClass
self.moving_gc = self.GCClass.moving_gc
self.HDRPTR = lltype.Ptr(self.GCClass.HDR)
@@ -461,6 +593,10 @@
self.max_size_of_young_obj = self.GCClass.JIT_max_size_of_young_obj()
self.minimal_size_in_nursery=self.GCClass.JIT_minimal_size_in_nursery()
+ # for the fast path of mallocs, the following must be true, at least
+ assert self.GCClass.inline_simple_malloc
+ assert self.GCClass.inline_simple_malloc_varsize
+
# make a malloc function, with three arguments
def malloc_basic(size, tid):
type_id = llop.extract_ushort(llgroup.HALFWORD, tid)
@@ -539,20 +675,23 @@
x3 = x0 * 0.3
for_test_only.x = x0 + x1 + x2 + x3
#
- def malloc_fixedsize_slowpath(size):
+ def malloc_slowpath(size):
if self.DEBUG:
random_usage_of_xmm_registers()
assert size >= self.minimal_size_in_nursery
try:
+ # NB. although we call do_malloc_fixedsize_clear() here,
+ # it's a bit of a hack because we set tid to 0 and may
+ # also use it to allocate varsized objects. The tid
+ # and possibly the length are both set afterward.
gcref = llop1.do_malloc_fixedsize_clear(llmemory.GCREF,
0, size, True, False, False)
except MemoryError:
fatalerror("out of memory (from JITted code)")
return 0
return rffi.cast(lltype.Signed, gcref)
- self.malloc_fixedsize_slowpath = malloc_fixedsize_slowpath
- self.MALLOC_FIXEDSIZE_SLOWPATH = lltype.FuncType([lltype.Signed],
- lltype.Signed)
+ self.malloc_slowpath = malloc_slowpath
+ self.MALLOC_SLOWPATH = lltype.FuncType([lltype.Signed], lltype.Signed)
def get_nursery_free_addr(self):
nurs_addr = llop.gc_adr_of_nursery_free(llmemory.Address)
@@ -562,9 +701,8 @@
nurs_top_addr = llop.gc_adr_of_nursery_top(llmemory.Address)
return rffi.cast(lltype.Signed, nurs_top_addr)
- def get_malloc_fixedsize_slowpath_addr(self):
- fptr = llhelper(lltype.Ptr(self.MALLOC_FIXEDSIZE_SLOWPATH),
- self.malloc_fixedsize_slowpath)
+ def get_malloc_slowpath_addr(self):
+ fptr = llhelper(lltype.Ptr(self.MALLOC_SLOWPATH), self.malloc_slowpath)
return rffi.cast(lltype.Signed, fptr)
def initialize(self):
@@ -710,6 +848,16 @@
return True
return False
+ def can_inline_malloc_varsize(self, arraydescr, num_elem):
+ assert isinstance(arraydescr, BaseArrayDescr)
+ basesize = arraydescr.get_base_size(self.translate_support_code)
+ itemsize = arraydescr.get_item_size(self.translate_support_code)
+ try:
+ size = ovfcheck(basesize + ovfcheck(itemsize * num_elem))
+ return size < self.max_size_of_young_obj
+ except OverflowError:
+ return False
+
def has_write_barrier_class(self):
return WriteBarrierDescr
diff --git a/pypy/translator/backendopt/malloc.py b/pypy/translator/backendopt/malloc.py
--- a/pypy/translator/backendopt/malloc.py
+++ b/pypy/translator/backendopt/malloc.py
@@ -1,5 +1,5 @@
from pypy.objspace.flow.model import Variable, Constant, Block, Link
-from pypy.objspace.flow.model import SpaceOperation, traverse
+from pypy.objspace.flow.model import SpaceOperation
from pypy.tool.algo.unionfind import UnionFind
from pypy.rpython.lltypesystem import lltype
from pypy.rpython.ootypesystem import ootype
@@ -67,7 +67,6 @@
# in this 'block', follow where the 'var' goes to and replace
# it by a flattened-out family of variables. This family is given
# by newvarsmap, whose keys are the 'flatnames'.
- self.last_removed_access = None
def list_newvars():
return [newvarsmap[key] for key in self.flatnames]
@@ -115,7 +114,6 @@
newargs.append(arg)
link.args[:] = newargs
- self.insert_keepalives(list_newvars())
block.operations[:] = self.newops
def compute_lifetimes(self, graph):
@@ -149,8 +147,7 @@
set_use_point(graph.exceptblock, graph.exceptblock.inputargs[0], "except")
set_use_point(graph.exceptblock, graph.exceptblock.inputargs[1], "except")
- def visit(node):
- if isinstance(node, Block):
+ for node in graph.iterblocks():
for op in node.operations:
if op.opname in self.IDENTITY_OPS:
# special-case these operations to identify their input
@@ -167,7 +164,7 @@
if isinstance(node.exitswitch, Variable):
set_use_point(node, node.exitswitch, "exitswitch", node)
- if isinstance(node, Link):
+ for node in graph.iterlinks():
if isinstance(node.last_exception, Variable):
set_creation_point(node.prevblock, node.last_exception,
"last_exception")
@@ -187,7 +184,6 @@
else:
d[arg] = True
- traverse(visit, graph)
return lifetimes.infos()
def _try_inline_malloc(self, info):
@@ -213,7 +209,7 @@
STRUCT = self.get_STRUCT(lltypes.keys()[0])
# must be only ever accessed via getfield/setfield/getsubstruct/
- # direct_fieldptr, or touched by keepalive or ptr_iszero/ptr_nonzero.
+ # direct_fieldptr, or touched by ptr_iszero/ptr_nonzero.
# Note that same_as and cast_pointer are not recorded in usepoints.
self.accessed_substructs = {}
@@ -333,7 +329,6 @@
MALLOC_OP = "malloc"
FIELD_ACCESS = dict.fromkeys(["getfield",
"setfield",
- "keepalive",
"ptr_iszero",
"ptr_nonzero",
"getarrayitem",
@@ -484,7 +479,6 @@
[newvarsmap[key]],
op.result)
self.newops.append(newop)
- self.last_removed_access = len(self.newops)
elif op.opname in ("setfield", "setarrayitem"):
S = op.args[0].concretetype.TO
fldname = op.args[1].value
@@ -500,15 +494,12 @@
self.newops.append(newop)
else:
newvarsmap[key] = op.args[2]
- self.last_removed_access = len(self.newops)
elif op.opname in ("same_as", "cast_pointer"):
vars[op.result] = True
# Consider the two pointers (input and result) as
# equivalent. We can, and indeed must, use the same
# flattened list of variables for both, as a "setfield"
# via one pointer must be reflected in the other.
- elif op.opname == 'keepalive':
- self.last_removed_access = len(self.newops)
elif op.opname in ("getsubstruct", "getarraysubstruct",
"direct_fieldptr"):
S = op.args[0].concretetype.TO
@@ -546,18 +537,6 @@
else:
raise AssertionError, op.opname
-
- def insert_keepalives(self, newvars):
- if self.last_removed_access is not None:
- keepalives = []
- for v in newvars:
- T = v.concretetype
- if isinstance(T, lltype.Ptr) and T._needsgc():
- v0 = Variable()
- v0.concretetype = lltype.Void
- newop = SpaceOperation('keepalive', [v], v0)
- keepalives.append(newop)
- self.newops[self.last_removed_access:self.last_removed_access] = keepalives
class OOTypeMallocRemover(BaseMallocRemover):
@@ -616,14 +595,12 @@
[newvarsmap[key]],
op.result)
self.newops.append(newop)
- last_removed_access = len(self.newops)
elif op.opname == "oosetfield":
S = op.args[0].concretetype
fldname = op.args[1].value
key = self.key_for_field_access(S, fldname)
assert key in newvarsmap
newvarsmap[key] = op.args[2]
- last_removed_access = len(self.newops)
elif op.opname in ("same_as", "oodowncast", "ooupcast"):
vars[op.result] = True
# Consider the two pointers (input and result) as
@@ -639,8 +616,6 @@
else:
raise AssertionError, op.opname
- def insert_keepalives(self, newvars):
- pass
def remove_simple_mallocs(graph, type_system='lltypesystem', verbose=True):
if type_system == 'lltypesystem':
diff --git a/pypy/doc/getting-started-python.rst b/pypy/doc/getting-started-python.rst
--- a/pypy/doc/getting-started-python.rst
+++ b/pypy/doc/getting-started-python.rst
@@ -79,7 +79,8 @@
possibly replacing ``--opt=jit`` with another `optimization level`_
of your choice like ``--opt=2`` if you do not want the included JIT
- compiler. As of March 2011, Intel **32-bit** environment needs ``4GB``.
+ compiler. As of March 2011, Intel 32-bit environment needs **at
+ least** 2GB, and 64-bit needs 4GB.
.. _`optimization level`: config/opt.html
diff --git a/pypy/rlib/rlocale.py b/pypy/rlib/rlocale.py
--- a/pypy/rlib/rlocale.py
+++ b/pypy/rlib/rlocale.py
@@ -7,6 +7,7 @@
from pypy.rpython.lltypesystem import rffi, lltype
from pypy.translator.tool.cbuild import ExternalCompilationInfo
from pypy.rpython.tool import rffi_platform as platform
+from pypy.rpython.extfunc import register_external
class LocaleError(Exception):
def __init__(self, message):
@@ -156,23 +157,35 @@
HAVE_BIND_TEXTDOMAIN_CODESET = cConfig.HAVE_BIND_TEXTDOMAIN_CODESET
-def external(name, args, result, calling_conv='c'):
+def external(name, args, result, calling_conv='c', **kwds):
return rffi.llexternal(name, args, result,
compilation_info=CConfig._compilation_info_,
calling_conv=calling_conv,
- sandboxsafe=True)
+ sandboxsafe=True, **kwds)
_lconv = lltype.Ptr(cConfig.lconv)
localeconv = external('localeconv', [], _lconv)
def numeric_formatting():
"""Specialized function to get formatting for numbers"""
+ return numeric_formatting_impl()
+
+def numeric_formatting_impl():
conv = localeconv()
decimal_point = rffi.charp2str(conv.c_decimal_point)
thousands_sep = rffi.charp2str(conv.c_thousands_sep)
grouping = rffi.charp2str(conv.c_grouping)
return decimal_point, thousands_sep, grouping
+def oo_numeric_formatting():
+ return '.', '', ''
+
+register_external(numeric_formatting, [], (str, str, str),
+ llimpl=numeric_formatting_impl,
+ ooimpl=oo_numeric_formatting,
+ sandboxsafe=True)
+
+
_setlocale = external('setlocale', [rffi.INT, rffi.CCHARP], rffi.CCHARP)
def setlocale(category, locale):
@@ -184,11 +197,11 @@
raise LocaleError("unsupported locale setting")
return rffi.charp2str(ll_result)
-isalpha = external('isalpha', [rffi.INT], rffi.INT)
-isupper = external('isupper', [rffi.INT], rffi.INT)
-islower = external('islower', [rffi.INT], rffi.INT)
-tolower = external('tolower', [rffi.INT], rffi.INT)
-isalnum = external('isalnum', [rffi.INT], rffi.INT)
+isalpha = external('isalpha', [rffi.INT], rffi.INT, oo_primitive='locale_isalpha')
+isupper = external('isupper', [rffi.INT], rffi.INT, oo_primitive='locale_isupper')
+islower = external('islower', [rffi.INT], rffi.INT, oo_primitive='locale_islower')
+tolower = external('tolower', [rffi.INT], rffi.INT, oo_primitive='locale_tolower')
+isalnum = external('isalnum', [rffi.INT], rffi.INT, oo_primitive='locale_isalnum')
if HAVE_LANGINFO:
_nl_langinfo = external('nl_langinfo', [rffi.INT], rffi.CCHARP)
diff --git a/pypy/jit/metainterp/test/test_jitprof.py b/pypy/jit/metainterp/test/test_jitprof.py
--- a/pypy/jit/metainterp/test/test_jitprof.py
+++ b/pypy/jit/metainterp/test/test_jitprof.py
@@ -1,7 +1,7 @@
from pypy.jit.metainterp.warmspot import ll_meta_interp
from pypy.rlib.jit import JitDriver, dont_look_inside, purefunction
-from pypy.jit.metainterp.test.test_basic import LLJitMixin
+from pypy.jit.metainterp.test.support import LLJitMixin
from pypy.jit.metainterp import pyjitpl
from pypy.jit.metainterp.jitprof import *
diff --git a/pypy/translator/backendopt/test/test_constfold.py b/pypy/translator/backendopt/test/test_constfold.py
--- a/pypy/translator/backendopt/test/test_constfold.py
+++ b/pypy/translator/backendopt/test/test_constfold.py
@@ -185,27 +185,6 @@
check_graph(graph, [0], 61, t)
-def test_keepalive_const_substruct():
- py.test.skip("do we want partial folding of getinteriorfield?")
- S2 = lltype.Struct('S2', ('x', lltype.Signed))
- S1 = lltype.GcStruct('S1', ('sub', S2))
- s1 = lltype.malloc(S1)
- s1.sub.x = 1234
- def fn():
- return s1.sub.x
- graph, t = get_graph(fn, [])
- assert summary(graph) == {'getinteriorfield': 1}
- constant_fold_graph(graph)
-
- # kill all references to 's1'
- s1 = fn = None
- del graph.func
- import gc; gc.collect()
-
- assert summary(graph) == {'getfield': 1}
- check_graph(graph, [], 1234, t)
-
-
def test_keepalive_const_fieldptr():
S1 = lltype.GcStruct('S1', ('x', lltype.Signed))
s1 = lltype.malloc(S1)
diff --git a/pypy/interpreter/test/test_typedef.py b/pypy/interpreter/test/test_typedef.py
--- a/pypy/interpreter/test/test_typedef.py
+++ b/pypy/interpreter/test/test_typedef.py
@@ -127,12 +127,15 @@
checks[2], checks[3]))
subclasses = {}
for key, subcls in typedef._subclass_cache.items():
+ if key[0] is not space.config:
+ continue
cls = key[1]
subclasses.setdefault(cls, {})
- subclasses[cls][subcls] = True
+ prevsubcls = subclasses[cls].setdefault(subcls.__name__, subcls)
+ assert subcls is prevsubcls
for cls, set in subclasses.items():
assert len(set) <= 6, "%s has %d subclasses:\n%r" % (
- cls, len(set), [subcls.__name__ for subcls in set])
+ cls, len(set), list(set))
def test_getsetproperty(self):
class W_SomeType(Wrappable):
diff --git a/.gitignore b/.gitignore
--- a/.gitignore
+++ b/.gitignore
@@ -12,6 +12,8 @@
pypy/doc/*.html
pypy/doc/config/*.html
pypy/doc/discussion/*.html
+pypy/module/cpyext/src/*.o
+pypy/module/cpyext/test/*.o
pypy/module/test_lib_pypy/ctypes_tests/*.o
pypy/translator/c/src/dtoa.o
pypy/translator/goal/pypy-c
diff --git a/_pytest/resultlog.py b/_pytest/resultlog.py
--- a/_pytest/resultlog.py
+++ b/_pytest/resultlog.py
@@ -74,7 +74,7 @@
elif report.failed:
longrepr = str(report.longrepr)
elif report.skipped:
- longrepr = str(report.longrepr[2])
+ longrepr = str(report.longrepr)
self.log_outcome(report, code, longrepr)
def pytest_collectreport(self, report):
diff --git a/pypy/translator/c/test/test_lltyped.py b/pypy/translator/c/test/test_lltyped.py
--- a/pypy/translator/c/test/test_lltyped.py
+++ b/pypy/translator/c/test/test_lltyped.py
@@ -895,3 +895,10 @@
fn = self.getcompiled(llf)
assert fn() == 45
+ def test_rstring_to_float(self):
+ from pypy.rlib.rfloat import rstring_to_float
+ def llf(i):
+ s = ['42.3', '123.4'][i]
+ return rstring_to_float(s)
+ fn = self.getcompiled(llf, [int])
+ assert fn(0) == 42.3
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
@@ -717,6 +717,7 @@
def test_random_function(BuilderClass=OperationBuilder):
r = Random()
cpu = get_cpu()
+ cpu.setup_once()
if pytest.config.option.repeat == -1:
while 1:
check_random_function(cpu, BuilderClass, r)
diff --git a/pypy/jit/backend/llsupport/test/test_gc.py b/pypy/jit/backend/llsupport/test/test_gc.py
--- a/pypy/jit/backend/llsupport/test/test_gc.py
+++ b/pypy/jit/backend/llsupport/test/test_gc.py
@@ -9,7 +9,6 @@
from pypy.jit.tool.oparser import parse
from pypy.rpython.lltypesystem.rclass import OBJECT, OBJECT_VTABLE
from pypy.jit.metainterp.test.test_optimizeopt import equaloplists
-from pypy.rpython.memory.gctransform import asmgcroot
def test_boehm():
gc_ll_descr = GcLLDescr_boehm(None, None, None)
@@ -75,8 +74,8 @@
num2a = ((-num2|3) >> 7) | 128
num2b = (-num2|3) & 127
shape = gcrootmap.get_basic_shape()
- gcrootmap.add_ebp_offset(shape, num1)
- gcrootmap.add_ebp_offset(shape, num2)
+ gcrootmap.add_frame_offset(shape, num1)
+ gcrootmap.add_frame_offset(shape, num2)
assert shape == map(chr, [6, 7, 11, 15, 2, 0, num1a, num2b, num2a])
gcrootmap.add_callee_save_reg(shape, 1)
assert shape == map(chr, [6, 7, 11, 15, 2, 0, num1a, num2b, num2a,
@@ -228,6 +227,33 @@
gc.asmgcroot = saved
+class TestGcRootMapShadowStack:
+ class FakeGcDescr:
+ force_index_ofs = 92
+
+ def test_make_shapes(self):
+ gcrootmap = GcRootMap_shadowstack(self.FakeGcDescr())
+ shape = gcrootmap.get_basic_shape()
+ gcrootmap.add_frame_offset(shape, 16)
+ gcrootmap.add_frame_offset(shape, -24)
+ assert shape == [16, -24]
+
+ def test_compress_callshape(self):
+ class FakeDataBlockWrapper:
+ def malloc_aligned(self, size, alignment):
+ assert alignment == 4 # even on 64-bits
+ assert size == 12 # 4*3, even on 64-bits
+ return rffi.cast(lltype.Signed, p)
+ datablockwrapper = FakeDataBlockWrapper()
+ p = lltype.malloc(rffi.CArray(rffi.INT), 3, immortal=True)
+ gcrootmap = GcRootMap_shadowstack(self.FakeGcDescr())
+ shape = [16, -24]
+ gcrootmap.compress_callshape(shape, datablockwrapper)
+ assert rffi.cast(lltype.Signed, p[0]) == 16
+ assert rffi.cast(lltype.Signed, p[1]) == -24
+ assert rffi.cast(lltype.Signed, p[2]) == 0
+
+
class FakeLLOp(object):
def __init__(self):
self.record = []
diff --git a/pypy/jit/backend/x86/test/test_zrpy_gc.py b/pypy/jit/backend/x86/test/test_zrpy_gc.py
--- a/pypy/jit/backend/x86/test/test_zrpy_gc.py
+++ b/pypy/jit/backend/x86/test/test_zrpy_gc.py
@@ -5,8 +5,8 @@
soon as possible (at least in a simple case).
"""
-import weakref, random, sys
-import py
+import weakref, sys
+import py, os
from pypy.annotation import policy as annpolicy
from pypy.rlib import rgc
from pypy.rpython.lltypesystem import lltype, llmemory, rffi
@@ -71,6 +71,20 @@
return entrypoint
+def get_functions_to_patch():
+ from pypy.jit.backend.llsupport import gc
+ #
+ can_inline_malloc1 = gc.GcLLDescr_framework.can_inline_malloc
+ def can_inline_malloc2(*args):
+ try:
+ if os.environ['PYPY_NO_INLINE_MALLOC']:
+ return False
+ except KeyError:
+ pass
+ return can_inline_malloc1(*args)
+ #
+ return {(gc.GcLLDescr_framework, 'can_inline_malloc'): can_inline_malloc2}
+
def compile(f, gc, **kwds):
from pypy.annotation.listdef import s_list_of_strings
from pypy.translator.translator import TranslationContext
@@ -86,8 +100,21 @@
ann = t.buildannotator(policy=annpolicy.StrictAnnotatorPolicy())
ann.build_types(f, [s_list_of_strings], main_entry_point=True)
t.buildrtyper().specialize()
+
if kwds['jit']:
- apply_jit(t, enable_opts='')
+ patch = get_functions_to_patch()
+ old_value = {}
+ try:
+ for (obj, attr), value in patch.items():
+ old_value[obj, attr] = getattr(obj, attr)
+ setattr(obj, attr, value)
+ #
+ apply_jit(t, enable_opts='')
+ #
+ finally:
+ for (obj, attr), oldvalue in old_value.items():
+ setattr(obj, attr, oldvalue)
+
cbuilder = genc.CStandaloneBuilder(t, f, t.config)
cbuilder.generate_source()
cbuilder.compile()
@@ -126,7 +153,7 @@
# ______________________________________________________________________
-class TestCompileFramework(object):
+class CompileFrameworkTests(object):
# Test suite using (so far) the minimark GC.
EXTRA_PARAMS = {}
@@ -179,16 +206,22 @@
try:
GcLLDescr_framework.DEBUG = True
cls.cbuilder = compile(get_entry(allfuncs), DEFL_GC,
- gcrootfinder="asmgcc", jit=True,
+ gcrootfinder=cls.gcrootfinder, jit=True,
**cls.EXTRA_PARAMS)
finally:
GcLLDescr_framework.DEBUG = OLD_DEBUG
+ def _run(self, name, n, env):
+ res = self.cbuilder.cmdexec("%s %d" %(name, n), env=env)
+ assert int(res) == 20
+
def run(self, name, n=2000):
pypylog = udir.join('TestCompileFramework.log')
- res = self.cbuilder.cmdexec("%s %d" %(name, n),
- env={'PYPYLOG': ':%s' % pypylog})
- assert int(res) == 20
+ env = {'PYPYLOG': ':%s' % pypylog,
+ 'PYPY_NO_INLINE_MALLOC': '1'}
+ self._run(name, n, env)
+ env['PYPY_NO_INLINE_MALLOC'] = ''
+ self._run(name, n, env)
def run_orig(self, name, n, x):
self.main_allfuncs(name, n, x)
@@ -580,10 +613,15 @@
self.run('compile_framework_minimal_size_in_nursery')
-class TestCompressPtr(TestCompileFramework):
+class TestShadowStack(CompileFrameworkTests):
+ gcrootfinder = "shadowstack"
+
+class TestCompressPtr(TestShadowStack):
EXTRA_PARAMS = {'compressptr': True}
-
def setup_class(cls):
if sys.maxint == 2147483647:
py.test.skip("for 64-bit only")
- TestCompileFramework.setup_class.im_func(cls)
+ TestShadowStack.setup_class.im_func(cls)
+
+class TestAsmGcc(CompileFrameworkTests):
+ gcrootfinder = "asmgcc"
diff --git a/pypy/rlib/rdtoa.py b/pypy/rlib/rdtoa.py
--- a/pypy/rlib/rdtoa.py
+++ b/pypy/rlib/rdtoa.py
@@ -5,16 +5,33 @@
from pypy.rpython.lltypesystem import lltype, rffi
from pypy.rlib import jit
from pypy.rlib.rstring import StringBuilder
-import py
+import py, sys
cdir = py.path.local(pypydir) / 'translator' / 'c'
include_dirs = [cdir]
+# set the word endianness based on the host's endianness
+# and the C double's endianness (which should be equal)
+if hasattr(float, '__getformat__'):
+ assert float.__getformat__('double') == 'IEEE, %s-endian' % sys.byteorder
+if sys.byteorder == 'little':
+ source_file = ['#define DOUBLE_IS_LITTLE_ENDIAN_IEEE754']
+elif sys.byteorder == 'big':
+ source_file = ['#define WORDS_BIGENDIAN',
+ '#define DOUBLE_IS_BIG_ENDIAN_IEEE754']
+else:
+ raise AssertionError(sys.byteorder)
+
+source_file.append('#include "src/dtoa.c"')
+source_file = '\n\n'.join(source_file)
+
+# ____________________________________________________________
+
eci = ExternalCompilationInfo(
include_dirs = [cdir],
includes = ['src/dtoa.h'],
libraries = [],
- separate_module_files = [cdir / 'src' / 'dtoa.c'],
+ separate_module_sources = [source_file],
export_symbols = ['_PyPy_dg_strtod',
'_PyPy_dg_dtoa',
'_PyPy_dg_freedtoa',
diff --git a/pypy/translator/goal/targetpypystandalone.py b/pypy/translator/goal/targetpypystandalone.py
--- a/pypy/translator/goal/targetpypystandalone.py
+++ b/pypy/translator/goal/targetpypystandalone.py
@@ -105,13 +105,6 @@
return parser
def handle_config(self, config, translateconfig):
- if config.translation.type_system == 'ootype':
- print
- print 'Translation to cli and jvm is known to be broken at the moment'
- print 'Please try the "cli-jit" branch at:'
- print 'http://codespeak.net/svn/pypy/branch/cli-jit/'
- sys.exit(1)
-
self.translateconfig = translateconfig
# set up the objspace optimizations based on the --opt argument
from pypy.config.pypyoption import set_pypy_opt_level
@@ -159,8 +152,8 @@
from pypy.config.pypyoption import enable_translationmodules
enable_translationmodules(config)
- if config.translation.type_system == 'ootype':
- config.objspace.usemodules.suggest(rbench=True)
+ ## if config.translation.type_system == 'ootype':
+ ## config.objspace.usemodules.suggest(rbench=True)
if config.translation.thread:
config.objspace.usemodules.thread = True
diff --git a/pypy/jit/metainterp/test/test_del.py b/pypy/jit/metainterp/test/test_del.py
--- a/pypy/jit/metainterp/test/test_del.py
+++ b/pypy/jit/metainterp/test/test_del.py
@@ -1,6 +1,6 @@
import py
from pypy.rlib.jit import JitDriver
-from pypy.jit.metainterp.test.test_basic import LLJitMixin, OOJitMixin
+from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin
class DelTests:
diff --git a/pypy/module/thread/__init__.py b/pypy/module/thread/__init__.py
--- a/pypy/module/thread/__init__.py
+++ b/pypy/module/thread/__init__.py
@@ -12,12 +12,13 @@
'get_ident': 'os_thread.get_ident',
'exit': 'os_thread.exit',
'exit_thread': 'os_thread.exit', # obsolete synonym
+ 'interrupt_main': 'os_thread.interrupt_main',
'stack_size': 'os_thread.stack_size',
'_count': 'os_thread._count',
'allocate_lock': 'os_lock.allocate_lock',
'allocate': 'os_lock.allocate_lock', # obsolete synonym
- 'LockType': 'os_lock.getlocktype(space)',
- '_local': 'os_local.getlocaltype(space)',
+ 'LockType': 'os_lock.Lock',
+ '_local': 'os_local.Local',
'error': 'space.fromcache(error.Cache).w_error',
}
diff --git a/lib_pypy/_pypy_wait.py b/lib_pypy/_pypy_wait.py
new file mode 100644
--- /dev/null
+++ b/lib_pypy/_pypy_wait.py
@@ -0,0 +1,51 @@
+from ctypes import CDLL, c_int, POINTER, byref
+from ctypes.util import find_library
+from resource import _struct_rusage, struct_rusage
+
+__all__ = ["wait3", "wait4"]
+
+libc = CDLL(find_library("c"))
+c_wait3 = libc.wait3
+
+c_wait3.argtypes = [POINTER(c_int), c_int, POINTER(_struct_rusage)]
+
+c_wait4 = libc.wait4
+
+c_wait4.argtypes = [c_int, POINTER(c_int), c_int, POINTER(_struct_rusage)]
+
+def create_struct_rusage(c_struct):
+ return struct_rusage((
+ float(c_struct.ru_utime),
+ float(c_struct.ru_stime),
+ c_struct.ru_maxrss,
+ c_struct.ru_ixrss,
+ c_struct.ru_idrss,
+ c_struct.ru_isrss,
+ c_struct.ru_minflt,
+ c_struct.ru_majflt,
+ c_struct.ru_nswap,
+ c_struct.ru_inblock,
+ c_struct.ru_oublock,
+ c_struct.ru_msgsnd,
+ c_struct.ru_msgrcv,
+ c_struct.ru_nsignals,
+ c_struct.ru_nvcsw,
+ c_struct.ru_nivcsw))
+
+def wait3(options):
+ status = c_int()
+ _rusage = _struct_rusage()
+ pid = c_wait3(byref(status), c_int(options), byref(_rusage))
+
+ rusage = create_struct_rusage(_rusage)
+
+ return pid, status.value, rusage
+
+def wait4(pid, options):
+ status = c_int()
+ _rusage = _struct_rusage()
+ pid = c_wait4(c_int(pid), byref(status), c_int(options), byref(_rusage))
+
+ rusage = create_struct_rusage(_rusage)
+
+ return pid, status.value, rusage
diff --git a/pypy/objspace/std/celldict.py b/pypy/objspace/std/celldict.py
--- a/pypy/objspace/std/celldict.py
+++ b/pypy/objspace/std/celldict.py
@@ -34,11 +34,7 @@
@jit.purefunction
def _getcell_makenew(self, key):
- res = self.content.get(key, None)
- if res is not None:
- return res
- result = self.content[key] = ModuleCell()
- return result
+ return self.content.setdefault(key, ModuleCell())
def impl_setitem(self, w_key, w_value):
space = self.space
@@ -50,6 +46,16 @@
def impl_setitem_str(self, name, w_value):
self.getcell(name, True).w_value = w_value
+ def impl_setdefault(self, w_key, w_default):
+ space = self.space
+ if space.is_w(space.type(w_key), space.w_str):
+ cell = self.getcell(space.str_w(w_key), True)
+ if cell.w_value is None:
+ cell.w_value = w_default
+ return cell.w_value
+ else:
+ return self._as_rdict().impl_fallback_setdefault(w_key, w_default)
+
def impl_delitem(self, w_key):
space = self.space
w_key_type = space.type(w_key)
diff --git a/pypy/module/cpyext/pyobject.py b/pypy/module/cpyext/pyobject.py
--- a/pypy/module/cpyext/pyobject.py
+++ b/pypy/module/cpyext/pyobject.py
@@ -7,6 +7,7 @@
CANNOT_FAIL, Py_TPFLAGS_HEAPTYPE, PyTypeObjectPtr)
from pypy.module.cpyext.state import State
from pypy.objspace.std.typeobject import W_TypeObject
+from pypy.objspace.std.objectobject import W_ObjectObject
from pypy.rlib.objectmodel import specialize, we_are_translated
from pypy.rlib.rweakref import RWeakKeyDictionary
from pypy.rpython.annlowlevel import llhelper
@@ -370,6 +371,15 @@
@cpython_api([PyObject], lltype.Void)
def _Py_NewReference(space, obj):
obj.c_ob_refcnt = 1
+ w_type = from_ref(space, rffi.cast(PyObject, obj.c_ob_type))
+ assert isinstance(w_type, W_TypeObject)
+ if w_type.is_cpytype():
+ w_obj = space.allocate_instance(W_ObjectObject, w_type)
+ track_reference(space, obj, w_obj)
+ state = space.fromcache(RefcountState)
+ state.set_lifeline(w_obj, obj)
+ else:
+ assert False, "Please add more cases in _Py_NewReference()"
def _Py_Dealloc(space, obj):
from pypy.module.cpyext.api import generic_cpy_call_dont_decref
diff --git a/lib_pypy/pyrepl/unix_console.py b/lib_pypy/pyrepl/unix_console.py
--- a/lib_pypy/pyrepl/unix_console.py
+++ b/lib_pypy/pyrepl/unix_console.py
@@ -27,7 +27,10 @@
from pyrepl.console import Console, Event
from pyrepl import unix_eventqueue
-_error = (termios.error, curses.error)
+class InvalidTerminal(RuntimeError):
+ pass
+
+_error = (termios.error, curses.error, InvalidTerminal)
# there are arguments for changing this to "refresh"
SIGWINCH_EVENT = 'repaint'
@@ -38,7 +41,7 @@
def _my_getstr(cap, optional=0):
r = curses.tigetstr(cap)
if not optional and r is None:
- raise RuntimeError, \
+ raise InvalidTerminal, \
"terminal doesn't have the required '%s' capability"%cap
return r
@@ -289,6 +292,12 @@
self.__write_code(self._el)
self.__write(newline[x:])
self.__posxy = len(newline), y
+
+ if '\x1b' in newline:
+ # ANSI escape characters are present, so we can't assume
+ # anything about the position of the cursor. Moving the cursor
+ # to the left margin should work to get to a known position.
+ self.move_cursor(0, y)
def __write(self, text):
self.__buffer.append((text, 0))
diff --git a/pypy/module/cpyext/test/test_object.py b/pypy/module/cpyext/test/test_object.py
--- a/pypy/module/cpyext/test/test_object.py
+++ b/pypy/module/cpyext/test/test_object.py
@@ -174,6 +174,17 @@
assert api.PyObject_Compare(space.wrap(72), space.wrap(42)) == 1
assert api.PyObject_Compare(space.wrap("a"), space.wrap("a")) == 0
+ def test_cmp(self, space, api):
+ w = space.wrap
+ with lltype.scoped_alloc(rffi.INTP.TO, 1) as ptr:
+ assert api.PyObject_Cmp(w(42), w(72), ptr) == 0
+ assert ptr[0] == -1
+ assert api.PyObject_Cmp(w("a"), w("a"), ptr) == 0
+ assert ptr[0] == 0
+ assert api.PyObject_Cmp(w(u"\xe9"), w("\xe9"), ptr) < 0
+ assert api.PyErr_Occurred()
+ api.PyErr_Clear()
+
def test_unicode(self, space, api):
assert space.unwrap(api.PyObject_Unicode(space.wrap([]))) == u"[]"
assert space.unwrap(api.PyObject_Unicode(space.wrap("e"))) == u"e"
diff --git a/pypy/jit/backend/x86/rx86.py b/pypy/jit/backend/x86/rx86.py
--- a/pypy/jit/backend/x86/rx86.py
+++ b/pypy/jit/backend/x86/rx86.py
@@ -278,6 +278,22 @@
rex_mem_reg_plus_scaled_reg_plus_const)
# ____________________________________________________________
+# Emit a mod/rm referencing an immediate address that fits in 32-bit
+# (the immediate address itself must be explicitely encoded as well,
+# with immediate(argnum)).
+
+def encode_abs(mc, _1, _2, orbyte):
+ # expands to either '\x05' on 32-bit, or '\x04\x25' or 64-bit
+ if mc.WORD == 8:
+ mc.writechar(chr(0x04 | orbyte))
+ mc.writechar(chr(0x25))
+ else:
+ mc.writechar(chr(0x05 | orbyte))
+ return 0
+
+abs_ = encode_abs, 0, None, None
+
+# ____________________________________________________________
# For 64-bits mode: the REX.W, REX.R, REX.X, REG.B prefixes
REX_W = 8
@@ -348,7 +364,9 @@
INSN_br = insn(rex_w, chr(base+1), register(2,8), stack_bp(1))
INSN_rb = insn(rex_w, chr(base+3), register(1,8), stack_bp(2))
INSN_rm = insn(rex_w, chr(base+3), register(1,8), mem_reg_plus_const(2))
- INSN_rj = insn(rex_w, chr(base+3), register(1,8), '\x05', immediate(2))
+ INSN_rj = insn(rex_w, chr(base+3), register(1,8), abs_, immediate(2))
+ INSN_ji8 = insn(rex_w, '\x83', orbyte(base), abs_, immediate(1),
+ immediate(2,'b'))
INSN_bi8 = insn(rex_w, '\x83', orbyte(base), stack_bp(1), immediate(2,'b'))
INSN_bi32= insn(rex_w, '\x81', orbyte(base), stack_bp(1), immediate(2))
@@ -366,7 +384,8 @@
INSN_bi32(mc, offset, immed)
INSN_bi._always_inline_ = True # try to constant-fold single_byte()
- return INSN_ri, INSN_rr, INSN_rb, INSN_bi, INSN_br, INSN_rm, INSN_rj
+ return (INSN_ri, INSN_rr, INSN_rb, INSN_bi, INSN_br, INSN_rm, INSN_rj,
+ INSN_ji8)
def select_8_or_32_bit_immed(insn_8, insn_32):
def INSN(*args):
@@ -444,23 +463,25 @@
# ------------------------------ Arithmetic ------------------------------
- ADD_ri, ADD_rr, ADD_rb, _, _, ADD_rm, ADD_rj = common_modes(0)
- OR_ri, OR_rr, OR_rb, _, _, OR_rm, OR_rj = common_modes(1)
- AND_ri, AND_rr, AND_rb, _, _, AND_rm, AND_rj = common_modes(4)
- SUB_ri, SUB_rr, SUB_rb, _, _, SUB_rm, SUB_rj = common_modes(5)
- SBB_ri, SBB_rr, SBB_rb, _, _, SBB_rm, SBB_rj = common_modes(3)
- XOR_ri, XOR_rr, XOR_rb, _, _, XOR_rm, XOR_rj = common_modes(6)
- CMP_ri, CMP_rr, CMP_rb, CMP_bi, CMP_br, CMP_rm, CMP_rj = common_modes(7)
+ ADD_ri, ADD_rr, ADD_rb, _, _, ADD_rm, ADD_rj, _ = common_modes(0)
+ OR_ri, OR_rr, OR_rb, _, _, OR_rm, OR_rj, _ = common_modes(1)
+ AND_ri, AND_rr, AND_rb, _, _, AND_rm, AND_rj, _ = common_modes(4)
+ SUB_ri, SUB_rr, SUB_rb, _, _, SUB_rm, SUB_rj, SUB_ji8 = common_modes(5)
+ SBB_ri, SBB_rr, SBB_rb, _, _, SBB_rm, SBB_rj, _ = common_modes(3)
+ XOR_ri, XOR_rr, XOR_rb, _, _, XOR_rm, XOR_rj, _ = common_modes(6)
+ CMP_ri, CMP_rr, CMP_rb, CMP_bi, CMP_br, CMP_rm, CMP_rj, _ = common_modes(7)
CMP_mi8 = insn(rex_w, '\x83', orbyte(7<<3), mem_reg_plus_const(1), immediate(2, 'b'))
CMP_mi32 = insn(rex_w, '\x81', orbyte(7<<3), mem_reg_plus_const(1), immediate(2))
CMP_mi = select_8_or_32_bit_immed(CMP_mi8, CMP_mi32)
CMP_mr = insn(rex_w, '\x39', register(2, 8), mem_reg_plus_const(1))
- CMP_ji8 = insn(rex_w, '\x83', '\x3D', immediate(1), immediate(2, 'b'))
- CMP_ji32 = insn(rex_w, '\x81', '\x3D', immediate(1), immediate(2))
+ CMP_ji8 = insn(rex_w, '\x83', orbyte(7<<3), abs_,
+ immediate(1), immediate(2, 'b'))
+ CMP_ji32 = insn(rex_w, '\x81', orbyte(7<<3), abs_,
+ immediate(1), immediate(2))
CMP_ji = select_8_or_32_bit_immed(CMP_ji8, CMP_ji32)
- CMP_jr = insn(rex_w, '\x39', register(2, 8), '\x05', immediate(1))
+ CMP_jr = insn(rex_w, '\x39', register(2, 8), abs_, immediate(1))
CMP32_mi = insn(rex_nw, '\x81', orbyte(7<<3), mem_reg_plus_const(1), immediate(2))
@@ -508,7 +529,7 @@
LEA32_rb = insn(rex_w, '\x8D', register(1,8),stack_bp(2,force_32bits=True))
LEA_ra = insn(rex_w, '\x8D', register(1, 8), mem_reg_plus_scaled_reg_plus_const(2))
LEA_rm = insn(rex_w, '\x8D', register(1, 8), mem_reg_plus_const(2))
- LEA_rj = insn(rex_w, '\x8D', register(1, 8), '\x05', immediate(2))
+ LEA_rj = insn(rex_w, '\x8D', register(1, 8), abs_, immediate(2))
CALL_l = insn('\xE8', relative(1))
CALL_r = insn(rex_nw, '\xFF', register(1), chr(0xC0 | (2<<3)))
@@ -534,12 +555,15 @@
CDQ = insn(rex_nw, '\x99')
TEST8_mi = insn(rex_nw, '\xF6', orbyte(0<<3), mem_reg_plus_const(1), immediate(2, 'b'))
- TEST8_ji = insn(rex_nw, '\xF6', orbyte(0<<3), '\x05', immediate(1), immediate(2, 'b'))
+ TEST8_ji = insn(rex_nw, '\xF6', orbyte(0<<3), abs_, immediate(1), immediate(2, 'b'))
TEST_rr = insn(rex_w, '\x85', register(2,8), register(1), '\xC0')
# x87 instructions
FSTP_b = insn('\xDD', orbyte(3<<3), stack_bp(1))
+ # reserved as an illegal instruction
+ UD2 = insn('\x0F\x0B')
+
# ------------------------------ SSE2 ------------------------------
# Conversion
@@ -639,7 +663,7 @@
add_insn('s', stack_sp(modrm_argnum))
add_insn('m', mem_reg_plus_const(modrm_argnum))
add_insn('a', mem_reg_plus_scaled_reg_plus_const(modrm_argnum))
- add_insn('j', '\x05', immediate(modrm_argnum))
+ add_insn('j', abs_, immediate(modrm_argnum))
# Define a regular MOV, and a variant MOV32 that only uses the low 4 bytes of a
# register
@@ -680,7 +704,7 @@
#
assert insnname_template.count('*') == 1
add_insn('x', register(2), '\xC0')
- add_insn('j', '\x05', immediate(2))
+ add_insn('j', abs_, immediate(2))
define_pxmm_insn('PADDQ_x*', '\xD4')
define_pxmm_insn('PSUBQ_x*', '\xFB')
diff --git a/pypy/jit/metainterp/virtualref.py b/pypy/jit/metainterp/virtualref.py
--- a/pypy/jit/metainterp/virtualref.py
+++ b/pypy/jit/metainterp/virtualref.py
@@ -13,7 +13,6 @@
self.JIT_VIRTUAL_REF = lltype.GcStruct('JitVirtualRef',
('super', rclass.OBJECT),
('virtual_token', lltype.Signed),
- ('virtualref_index', lltype.Signed),
('forced', rclass.OBJECTPTR))
self.jit_virtual_ref_vtable = lltype.malloc(rclass.OBJECT_VTABLE,
zero=True, flavor='raw',
@@ -27,8 +26,6 @@
fielddescrof = self.cpu.fielddescrof
self.descr_virtual_token = fielddescrof(self.JIT_VIRTUAL_REF,
'virtual_token')
- self.descr_virtualref_index = fielddescrof(self.JIT_VIRTUAL_REF,
- 'virtualref_index')
self.descr_forced = fielddescrof(self.JIT_VIRTUAL_REF, 'forced')
#
# record the type JIT_VIRTUAL_REF explicitly in the rtyper, too
diff --git a/pypy/interpreter/executioncontext.py b/pypy/interpreter/executioncontext.py
--- a/pypy/interpreter/executioncontext.py
+++ b/pypy/interpreter/executioncontext.py
@@ -519,7 +519,7 @@
return
code = frame.pycode
if frame.instr_lb <= frame.last_instr < frame.instr_ub:
- if frame.last_instr <= frame.instr_prev:
+ if frame.last_instr < frame.instr_prev_plus_one:
# We jumped backwards in the same line.
executioncontext._trace(frame, 'line', self.space.w_None)
else:
@@ -557,5 +557,5 @@
frame.f_lineno = line
executioncontext._trace(frame, 'line', self.space.w_None)
- frame.instr_prev = frame.last_instr
+ frame.instr_prev_plus_one = frame.last_instr + 1
self.space.frame_trace_action.fire() # continue tracing
diff --git a/pypy/translator/backendopt/test/test_merge_if_blocks.py b/pypy/translator/backendopt/test/test_merge_if_blocks.py
--- a/pypy/translator/backendopt/test/test_merge_if_blocks.py
+++ b/pypy/translator/backendopt/test/test_merge_if_blocks.py
@@ -2,7 +2,7 @@
from pypy.translator.backendopt.merge_if_blocks import merge_if_blocks
from pypy.translator.backendopt.all import backend_optimizations
from pypy.translator.translator import TranslationContext, graphof as tgraphof
-from pypy.objspace.flow.model import flatten, Block
+from pypy.objspace.flow.model import Block
from pypy.translator.backendopt.removenoops import remove_same_as
from pypy.rpython.llinterp import LLInterpreter
from pypy.rlib.rarithmetic import r_uint, r_ulonglong, r_longlong, r_int
diff --git a/pypy/jit/metainterp/test/test_immutable.py b/pypy/jit/metainterp/test/test_immutable.py
--- a/pypy/jit/metainterp/test/test_immutable.py
+++ b/pypy/jit/metainterp/test/test_immutable.py
@@ -1,4 +1,4 @@
-from pypy.jit.metainterp.test.test_basic import LLJitMixin, OOJitMixin
+from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin
class ImmutableFieldsTests:
diff --git a/pypy/translator/test/test_simplify.py b/pypy/translator/test/test_simplify.py
--- a/pypy/translator/test/test_simplify.py
+++ b/pypy/translator/test/test_simplify.py
@@ -3,7 +3,7 @@
from pypy.translator.backendopt.all import backend_optimizations
from pypy.translator.simplify import (get_graph, transform_dead_op_vars,
desugar_isinstance)
-from pypy.objspace.flow.model import traverse, Block, Constant, summary
+from pypy.objspace.flow.model import Block, Constant, summary
from pypy import conftest
def translate(func, argtypes, backend_optimize=True):
@@ -156,36 +156,6 @@
assert graph.startblock.operations[-1].opname == 'direct_call'
-def test_remove_pointless_keepalive():
- from pypy.rlib import objectmodel
- class C:
- y = None
- z1 = None
- z2 = None
-
- def g():
- return C()
-
- def f(i):
- c = g()
- c.y
- if i:
- n = c.z1
- else:
- n = c.z2
- objectmodel.keepalive_until_here(c, n)
-
- graph, t = translate(f, [bool])
-
- #t.view()
-
- for block in graph.iterblocks():
- for op in block.operations:
- assert op.opname != 'getfield'
- if op.opname == 'keepalive':
- assert op.args[0] in graph.getargs()
-
-
def test_remove_identical_variables():
def g(code):
pc = 0
diff --git a/pypy/tool/jitlogparser/parser.py b/pypy/tool/jitlogparser/parser.py
--- a/pypy/tool/jitlogparser/parser.py
+++ b/pypy/tool/jitlogparser/parser.py
@@ -107,7 +107,8 @@
self.bytecode_no = int(bytecode_no)
self.operations = operations
self.storage = storage
- self.code = storage.disassemble_code(self.filename, self.startlineno)
+ self.code = storage.disassemble_code(self.filename, self.startlineno,
+ self.name)
def repr(self):
if self.filename is None:
diff --git a/lib_pypy/pypy_test/test_os_wait.py b/lib_pypy/pypy_test/test_os_wait.py
new file mode 100644
--- /dev/null
+++ b/lib_pypy/pypy_test/test_os_wait.py
@@ -0,0 +1,44 @@
+# Generates the resource cache
+from __future__ import absolute_import
+from lib_pypy.ctypes_config_cache import rebuild
+rebuild.rebuild_one('resource.ctc.py')
+
+import os
+
+from lib_pypy._pypy_wait import wait3, wait4
+
+if hasattr(os, 'wait3'):
+ def test_os_wait3():
+ exit_status = 0x33
+
+ if not hasattr(os, "fork"):
+ skip("Need fork() to test wait3()")
+
+ child = os.fork()
+ if child == 0: # in child
+ os._exit(exit_status)
+ else:
+ pid, status, rusage = wait3(0)
+ assert child == pid
+ assert os.WIFEXITED(status)
+ assert os.WEXITSTATUS(status) == exit_status
+ assert isinstance(rusage.ru_utime, float)
+ assert isinstance(rusage.ru_maxrss, int)
+
+if hasattr(os, 'wait4'):
+ def test_os_wait4():
+ exit_status = 0x33
+
+ if not hasattr(os, "fork"):
+ skip("Need fork() to test wait4()")
+
+ child = os.fork()
+ if child == 0: # in child
+ os._exit(exit_status)
+ else:
+ pid, status, rusage = wait4(child, 0)
+ assert child == pid
+ assert os.WIFEXITED(status)
+ assert os.WEXITSTATUS(status) == exit_status
+ assert isinstance(rusage.ru_utime, float)
+ assert isinstance(rusage.ru_maxrss, int)
diff --git a/pypy/jit/metainterp/test/test_memmgr.py b/pypy/jit/metainterp/test/test_memmgr.py
--- a/pypy/jit/metainterp/test/test_memmgr.py
+++ b/pypy/jit/metainterp/test/test_memmgr.py
@@ -12,7 +12,7 @@
import py
from pypy.jit.metainterp.memmgr import MemoryManager
-from pypy.jit.metainterp.test.test_basic import LLJitMixin
+from pypy.jit.metainterp.test.support import LLJitMixin
from pypy.rlib.jit import JitDriver, dont_look_inside
diff --git a/pypy/doc/config/confrest.py b/pypy/doc/config/confrest.py
--- a/pypy/doc/config/confrest.py
+++ b/pypy/doc/config/confrest.py
@@ -7,7 +7,6 @@
all_optiondescrs = [pypyoption.pypy_optiondescription,
translationoption.translation_optiondescription,
]
-
start_to_descr = dict([(descr._name, descr) for descr in all_optiondescrs])
class PyPyPage(PyPyPage):
@@ -29,7 +28,7 @@
Page = PyPyPage
def get_content(self, txtpath, encoding):
- if txtpath.basename == "commandline.txt":
+ if txtpath.basename == "commandline.rst":
result = []
for line in txtpath.read().splitlines():
if line.startswith('.. GENERATE:'):
diff --git a/pypy/jit/metainterp/test/test_float.py b/pypy/jit/metainterp/test/test_float.py
--- a/pypy/jit/metainterp/test/test_float.py
+++ b/pypy/jit/metainterp/test/test_float.py
@@ -1,5 +1,5 @@
import math
-from pypy.jit.metainterp.test.test_basic import LLJitMixin, OOJitMixin
+from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin
class FloatTests:
diff --git a/pypy/jit/metainterp/compile.py b/pypy/jit/metainterp/compile.py
--- a/pypy/jit/metainterp/compile.py
+++ b/pypy/jit/metainterp/compile.py
@@ -382,7 +382,7 @@
send_bridge_to_backend(metainterp.staticdata, self, inputargs,
new_loop.operations, new_loop.token)
- def copy_all_attrbutes_into(self, res):
+ def copy_all_attributes_into(self, res):
# XXX a bit ugly to have to list them all here
res.rd_snapshot = self.rd_snapshot
res.rd_frame_info_list = self.rd_frame_info_list
@@ -393,13 +393,13 @@
def _clone_if_mutable(self):
res = ResumeGuardDescr()
- self.copy_all_attrbutes_into(res)
+ self.copy_all_attributes_into(res)
return res
class ResumeAtPositionDescr(ResumeGuardDescr):
def _clone_if_mutable(self):
res = ResumeAtPositionDescr()
- self.copy_all_attrbutes_into(res)
+ self.copy_all_attributes_into(res)
return res
class ResumeGuardForcedDescr(ResumeGuardDescr):
@@ -473,7 +473,7 @@
def _clone_if_mutable(self):
res = ResumeGuardForcedDescr(self.metainterp_sd,
self.jitdriver_sd)
- self.copy_all_attrbutes_into(res)
+ self.copy_all_attributes_into(res)
return res
diff --git a/pypy/module/cpyext/test/test_arraymodule.py b/pypy/module/cpyext/test/test_arraymodule.py
--- a/pypy/module/cpyext/test/test_arraymodule.py
+++ b/pypy/module/cpyext/test/test_arraymodule.py
@@ -42,3 +42,13 @@
assert arr[1:].tolist() == [2,3,4]
assert arr[:2].tolist() == [1,2]
assert arr[1:3].tolist() == [2,3]
+
+ def test_buffer(self):
+ module = self.import_module(name='array')
+ arr = module.array('i', [1,2,3,4])
+ # XXX big-endian
+ assert str(buffer(arr)) == ('\x01\0\0\0'
+ '\x02\0\0\0'
+ '\x03\0\0\0'
+ '\x04\0\0\0')
+
diff --git a/pypy/rpython/lltypesystem/rdict.py b/pypy/rpython/lltypesystem/rdict.py
--- a/pypy/rpython/lltypesystem/rdict.py
+++ b/pypy/rpython/lltypesystem/rdict.py
@@ -4,13 +4,16 @@
from pypy.rpython.rdict import AbstractDictRepr, AbstractDictIteratorRepr,\
rtype_newdict
from pypy.rpython.lltypesystem import lltype, llmemory
-from pypy.rlib.rarithmetic import r_uint, intmask
+from pypy.rlib.rarithmetic import r_uint, intmask, LONG_BIT
from pypy.rpython.lltypesystem.lloperation import llop
from pypy.rlib.objectmodel import hlinvoke
from pypy.rpython import robject
-from pypy.rlib import objectmodel
+from pypy.rlib import objectmodel, jit
from pypy.rpython import rmodel
+HIGHEST_BIT = intmask(1 << (LONG_BIT - 1))
+MASK = intmask(HIGHEST_BIT - 1)
+
# ____________________________________________________________
#
# generic implementation of RPython dictionary, with parametric DICTKEY and
@@ -405,6 +408,10 @@
ENTRIES = lltype.typeOf(entries).TO
return ENTRIES.fasthashfn(entries[i].key)
+ at jit.dont_look_inside
+def ll_get_value(d, i):
+ return d.entries[i].value
+
def ll_keyhash_custom(d, key):
DICT = lltype.typeOf(d).TO
return hlinvoke(DICT.r_rdict_hashfn, d.fnkeyhash, key)
@@ -422,18 +429,21 @@
def ll_dict_getitem(d, key):
i = ll_dict_lookup(d, key, d.keyhash(key))
- entries = d.entries
- if entries.valid(i):
- return entries[i].value
- else:
- raise KeyError
-ll_dict_getitem.oopspec = 'dict.getitem(d, key)'
+ if not i & HIGHEST_BIT:
+ return ll_get_value(d, i)
+ else:
+ raise KeyError
def ll_dict_setitem(d, key, value):
hash = d.keyhash(key)
i = ll_dict_lookup(d, key, hash)
+ return _ll_dict_setitem_lookup_done(d, key, value, hash, i)
+
+ at jit.dont_look_inside
+def _ll_dict_setitem_lookup_done(d, key, value, hash, i):
+ valid = (i & HIGHEST_BIT) == 0
+ i = i & MASK
everused = d.entries.everused(i)
- valid = d.entries.valid(i)
# set up the new entry
ENTRY = lltype.typeOf(d.entries).TO.OF
entry = d.entries[i]
@@ -449,7 +459,6 @@
d.num_pristine_entries -= 1
if d.num_pristine_entries <= len(d.entries) / 3:
ll_dict_resize(d)
-ll_dict_setitem.oopspec = 'dict.setitem(d, key, value)'
def ll_dict_insertclean(d, key, value, hash):
# Internal routine used by ll_dict_resize() to insert an item which is
@@ -470,7 +479,7 @@
def ll_dict_delitem(d, key):
i = ll_dict_lookup(d, key, d.keyhash(key))
- if not d.entries.valid(i):
+ if i & HIGHEST_BIT:
raise KeyError
_ll_dict_del(d, i)
ll_dict_delitem.oopspec = 'dict.delitem(d, key)'
@@ -542,7 +551,7 @@
elif entries.everused(i):
freeslot = i
else:
- return i # pristine entry -- lookup failed
+ return i | HIGHEST_BIT # pristine entry -- lookup failed
# In the loop, a deleted entry (everused and not valid) is by far
# (factor of 100s) the least likely outcome, so test for that last.
@@ -557,7 +566,7 @@
if not entries.everused(i):
if freeslot == -1:
freeslot = i
- return freeslot
+ return freeslot | HIGHEST_BIT
elif entries.valid(i):
checkingkey = entries[i].key
if direct_compare and checkingkey == key:
@@ -711,22 +720,19 @@
def ll_get(dict, key, default):
i = ll_dict_lookup(dict, key, dict.keyhash(key))
- entries = dict.entries
- if entries.valid(i):
- return entries[i].value
- else:
+ if not i & HIGHEST_BIT:
+ return ll_get_value(dict, i)
+ else:
return default
-ll_get.oopspec = 'dict.get(dict, key, default)'
def ll_setdefault(dict, key, default):
- i = ll_dict_lookup(dict, key, dict.keyhash(key))
- entries = dict.entries
- if entries.valid(i):
- return entries[i].value
+ hash = dict.keyhash(key)
+ i = ll_dict_lookup(dict, key, hash)
+ if not i & HIGHEST_BIT:
+ return ll_get_value(dict, i)
else:
- ll_dict_setitem(dict, key, default)
+ _ll_dict_setitem_lookup_done(dict, key, default, hash, i)
return default
-ll_setdefault.oopspec = 'dict.setdefault(dict, key, default)'
def ll_copy(dict):
DICT = lltype.typeOf(dict).TO
@@ -768,7 +774,10 @@
while i < d2len:
if entries.valid(i):
entry = entries[i]
- ll_dict_setitem(dic1, entry.key, entry.value)
+ hash = entries.hash(i)
+ key = entry.key
+ j = ll_dict_lookup(dic1, key, hash)
+ _ll_dict_setitem_lookup_done(dic1, key, entry.value, hash, j)
i += 1
ll_update.oopspec = 'dict.update(dic1, dic2)'
@@ -833,8 +842,7 @@
def ll_contains(d, key):
i = ll_dict_lookup(d, key, d.keyhash(key))
- return d.entries.valid(i)
-ll_contains.oopspec = 'dict.contains(d, key)'
+ return not i & HIGHEST_BIT
POPITEMINDEX = lltype.Struct('PopItemIndex', ('nextindex', lltype.Signed))
global_popitem_index = lltype.malloc(POPITEMINDEX, zero=True, immortal=True)
diff --git a/pypy/rpython/lltypesystem/module/test/test_ll_math.py b/pypy/rpython/lltypesystem/module/test/test_ll_math.py
--- a/pypy/rpython/lltypesystem/module/test/test_ll_math.py
+++ b/pypy/rpython/lltypesystem/module/test/test_ll_math.py
@@ -11,6 +11,7 @@
nan = inf / inf
assert not ll_math.ll_math_isinf(0)
assert ll_math.ll_math_isinf(inf)
+ assert ll_math.ll_math_isinf(-inf)
assert not ll_math.ll_math_isinf(nan)
def test_isnan(self):
diff --git a/pypy/module/cpyext/stringobject.py b/pypy/module/cpyext/stringobject.py
--- a/pypy/module/cpyext/stringobject.py
+++ b/pypy/module/cpyext/stringobject.py
@@ -15,7 +15,7 @@
## The problem
## -----------
##
-## PyString_AsString() must returns a (non-movable) pointer to the underlying
+## PyString_AsString() must return a (non-movable) pointer to the underlying
## buffer, whereas pypy strings are movable. C code may temporarily store
## this address and use it, as long as it owns a reference to the PyObject.
## There is no "release" function to specify that the pointer is not needed
diff --git a/pypy/translator/c/src/ll_math.h b/pypy/translator/c/src/ll_math.h
--- a/pypy/translator/c/src/ll_math.h
+++ b/pypy/translator/c/src/ll_math.h
@@ -1,9 +1,6 @@
/* Definitions of some C99 math library functions, for those platforms
that don't implement these functions already. */
-int _pypy_math_isinf(double x);
-int _pypy_math_isnan(double x);
-
double _pypy_math_acosh(double x);
double _pypy_math_asinh(double x);
double _pypy_math_atanh(double x);
diff --git a/pypy/rpython/ootypesystem/rdict.py b/pypy/rpython/ootypesystem/rdict.py
--- a/pypy/rpython/ootypesystem/rdict.py
+++ b/pypy/rpython/ootypesystem/rdict.py
@@ -153,6 +153,13 @@
hop.exception_cannot_occur()
return self.send_message(hop, 'll_clear')
+ def rtype_method_popitem(self, hop):
+ v_dict, = hop.inputargs(self)
+ r_tuple = hop.r_result
+ cTUPLE = hop.inputconst(ootype.Void, r_tuple.lowleveltype)
+ hop.exception_is_here()
+ return hop.gendirectcall(ll_popitem, cTUPLE, v_dict)
+
def __get_func(self, interp, r_func, fn, TYPE):
if isinstance(r_func, MethodOfFrozenPBCRepr):
obj = r_func.r_im_self.convert_const(fn.im_self)
@@ -353,6 +360,16 @@
ll_dict_values = _make_ll_keys_values_items('values')
ll_dict_items = _make_ll_keys_values_items('items')
+def ll_popitem(ELEM, d):
+ it = d.ll_get_items_iterator()
+ if it.ll_go_next():
+ res = ootype.new(ELEM)
+ key = res.item0 = it.ll_current_key()
+ res.item1 = it.ll_current_value()
+ d.ll_remove(key)
+ return res
+ raise KeyError
+
# ____________________________________________________________
#
# Iteration.
diff --git a/pypy/translator/cli/opcodes.py b/pypy/translator/cli/opcodes.py
--- a/pypy/translator/cli/opcodes.py
+++ b/pypy/translator/cli/opcodes.py
@@ -71,6 +71,8 @@
'hint': [PushArg(0), StoreResult],
'direct_call': [Call],
'indirect_call': [IndirectCall],
+ 'int_between': [PushAllArgs, 'call bool [pypylib]pypy.runtime.Utils::IntBetween(int32, int32, int32)'],
+
'cast_ptr_to_weakadr': [PushAllArgs, 'newobj instance void class %s::.ctor(object)' % WEAKREF],
'gc__collect': 'call void class [mscorlib]System.GC::Collect()',
@@ -147,7 +149,10 @@
'cast_float_to_uint': 'conv.u4',
'cast_longlong_to_float': 'conv.r8',
'cast_float_to_longlong': 'conv.i8',
+ 'cast_ulonglong_to_float': 'conv.r8',
+ 'cast_float_to_ulonglong': 'conv.u8',
'cast_primitive': [PushAllArgs, CastPrimitive],
+ 'force_cast': [PushAllArgs, CastPrimitive],
'truncate_longlong_to_int': 'conv.i4',
}
@@ -266,6 +271,8 @@
'ullong_ge': _not('clt.un'),
'ullong_lshift': [PushAllArgs, 'conv.u4', 'shl'],
'ullong_rshift': [PushAllArgs, 'conv.i4', 'shr'],
+ 'ullong_and': 'and',
+ 'ullong_or': 'or',
'oois': 'ceq',
'ooisnot': _not('ceq'),
diff --git a/pypy/module/cpyext/test/test_typeobject.py b/pypy/module/cpyext/test/test_typeobject.py
--- a/pypy/module/cpyext/test/test_typeobject.py
+++ b/pypy/module/cpyext/test/test_typeobject.py
@@ -201,6 +201,23 @@
assert cmpr == 3
assert cmpr != 42
+ def test_richcompare(self):
+ module = self.import_module("comparisons")
+ cmpr = module.CmpType()
+
+ # should not crash
+ cmpr < 4
+ cmpr <= 4
+ cmpr > 4
+ cmpr >= 4
+
+ assert cmpr.__le__(4) is NotImplemented
+
+ def test_tpcompare(self):
+ module = self.import_module("comparisons")
+ cmpr = module.OldCmpType()
+ assert cmpr < cmpr
+
def test_hash(self):
module = self.import_module("comparisons")
cmpr = module.CmpType()
@@ -245,6 +262,11 @@
obj = foo.new()
assert module.read_tp_dict(obj) == foo.fooType.copy
+ def test_custom_allocation(self):
+ foo = self.import_module("foo")
+ obj = foo.newCustom()
+ assert type(obj) is foo.Custom
+ assert type(foo.Custom) is foo.MetaType
class TestTypes(BaseApiTest):
def test_type_attributes(self, space, api):
diff --git a/pypy/module/cpyext/test/test_pystate.py b/pypy/module/cpyext/test/test_pystate.py
--- a/pypy/module/cpyext/test/test_pystate.py
+++ b/pypy/module/cpyext/test/test_pystate.py
@@ -29,20 +29,14 @@
state = api.PyInterpreterState_Head()
assert nullptr(PyInterpreterState.TO) == api.PyInterpreterState_Next(state)
-def clear_threadstate(space):
- # XXX: this should collect the ThreadState memory
- del space.getexecutioncontext().cpyext_threadstate
-
class TestThreadState(BaseApiTest):
def test_thread_state_get(self, space, api):
ts = api.PyThreadState_Get()
assert ts != nullptr(PyThreadState.TO)
- clear_threadstate(space)
def test_thread_state_interp(self, space, api):
ts = api.PyThreadState_Get()
assert ts.c_interp == api.PyInterpreterState_Head()
- clear_threadstate(space)
def test_basic_threadstate_dance(self, space, api):
# Let extension modules call these functions,
@@ -54,5 +48,3 @@
api.PyEval_AcquireThread(tstate)
api.PyEval_ReleaseThread(tstate)
-
- clear_threadstate(space)
diff --git a/pypy/interpreter/eval.py b/pypy/interpreter/eval.py
--- a/pypy/interpreter/eval.py
+++ b/pypy/interpreter/eval.py
@@ -56,13 +56,10 @@
"""A frame is an environment supporting the execution of a code object.
Abstract base class."""
- def __init__(self, space, w_globals=None, numlocals=-1):
+ def __init__(self, space, w_globals=None):
self.space = space
self.w_globals = w_globals # wrapped dict of globals
self.w_locals = None # wrapped dict of locals
- if numlocals < 0: # compute the minimal size based on arguments
- numlocals = len(self.getcode().getvarnames())
- self.numlocals = numlocals
def run(self):
"Abstract method to override. Runs the frame"
@@ -96,6 +93,10 @@
where the order is according to self.getcode().signature()."""
raise TypeError, "abstract"
+ def getfastscopelength(self):
+ "Abstract. Get the expected number of locals."
+ raise TypeError, "abstract"
+
def fast2locals(self):
# Copy values from self.fastlocals_w to self.w_locals
if self.w_locals is None:
@@ -113,10 +114,11 @@
# Copy values from self.w_locals to self.fastlocals_w
assert self.w_locals is not None
varnames = self.getcode().getvarnames()
+ numlocals = self.getfastscopelength()
- new_fastlocals_w = [None]*self.numlocals
-
- for i in range(min(len(varnames), self.numlocals)):
+ new_fastlocals_w = [None] * numlocals
+
+ for i in range(min(len(varnames), numlocals)):
w_name = self.space.wrap(varnames[i])
try:
w_value = self.space.getitem(self.w_locals, w_name)
diff --git a/pypy/jit/codewriter/support.py b/pypy/jit/codewriter/support.py
--- a/pypy/jit/codewriter/support.py
+++ b/pypy/jit/codewriter/support.py
@@ -399,12 +399,7 @@
return ll_rdict.ll_newdict(DICT)
_ll_0_newdict.need_result_type = True
- _ll_2_dict_getitem = ll_rdict.ll_dict_getitem
- _ll_3_dict_setitem = ll_rdict.ll_dict_setitem
_ll_2_dict_delitem = ll_rdict.ll_dict_delitem
- _ll_3_dict_setdefault = ll_rdict.ll_setdefault
- _ll_2_dict_contains = ll_rdict.ll_contains
- _ll_3_dict_get = ll_rdict.ll_get
_ll_1_dict_copy = ll_rdict.ll_copy
_ll_1_dict_clear = ll_rdict.ll_clear
_ll_2_dict_update = ll_rdict.ll_update
diff --git a/pypy/rlib/_jit_vref.py b/pypy/rlib/_jit_vref.py
--- a/pypy/rlib/_jit_vref.py
+++ b/pypy/rlib/_jit_vref.py
@@ -8,6 +8,8 @@
from pypy.rpython.lltypesystem import lltype
from pypy.rpython.error import TyperError
+from pypy.rpython.ootypesystem import ootype
+
class SomeVRef(annmodel.SomeObject):
@@ -24,7 +26,10 @@
return self.s_instance
def rtyper_makerepr(self, rtyper):
- return vrefrepr
+ if rtyper.type_system.name == 'lltypesystem':
+ return vrefrepr
+ elif rtyper.type_system.name == 'ootypesystem':
+ return oovrefrepr
def rtyper_makekey(self):
return self.__class__,
@@ -54,4 +59,20 @@
" prebuilt virtual_ref")
return lltype.nullptr(OBJECTPTR.TO)
+from pypy.rpython.ootypesystem.rclass import OBJECT
+
+class OOVRefRepr(VRefRepr):
+ lowleveltype = OBJECT
+ def rtype_simple_call(self, hop):
+ [v] = hop.inputargs(self)
+ v = hop.genop('jit_force_virtual', [v], resulttype = OBJECT)
+ return hop.genop('oodowncast', [v], resulttype = hop.r_result)
+
+ def convert_const(self, value):
+ if value() is not None:
+ raise TypeError("only supports virtual_ref_None as a"
+ " prebuilt virtual_ref")
+ return ootype.ROOT._null
+
vrefrepr = VRefRepr()
+oovrefrepr = OOVRefRepr()
diff --git a/pypy/translator/cli/test/test_class.py b/pypy/translator/cli/test/test_class.py
--- a/pypy/translator/cli/test/test_class.py
+++ b/pypy/translator/cli/test/test_class.py
@@ -1,11 +1,8 @@
import py
from pypy.translator.cli.test.runtest import CliTest
-from pypy.translator.oosupport.test_template.class_ import BaseTestClass, BaseTestSpecialcase
+from pypy.translator.oosupport.test_template.class_ import BaseTestClass
# ====> ../../oosupport/test_template/class_.py
class TestCliClass(CliTest, BaseTestClass):
pass
-
-class TestCliSpecialCase(CliTest, BaseTestSpecialcase):
- pass
diff --git a/pypy/jit/metainterp/test/test_exception.py b/pypy/jit/metainterp/test/test_exception.py
--- a/pypy/jit/metainterp/test/test_exception.py
+++ b/pypy/jit/metainterp/test/test_exception.py
@@ -1,5 +1,5 @@
import py, sys
-from pypy.jit.metainterp.test.test_basic import LLJitMixin, OOJitMixin
+from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin
from pypy.rlib.jit import JitDriver, dont_look_inside
from pypy.rlib.rarithmetic import ovfcheck, LONG_BIT, intmask
from pypy.jit.codewriter.policy import StopAtXPolicy
diff --git a/pypy/jit/backend/x86/arch.py b/pypy/jit/backend/x86/arch.py
--- a/pypy/jit/backend/x86/arch.py
+++ b/pypy/jit/backend/x86/arch.py
@@ -1,17 +1,29 @@
# Constants that depend on whether we are on 32-bit or 64-bit
+# The frame size gives the standard fixed part at the start of
+# every assembler frame: the saved value of some registers,
+# one word for the force_index, and some extra space used only
+# during a malloc that needs to go via its slow path.
+
import sys
if sys.maxint == (2**31 - 1):
WORD = 4
- # ebp + ebx + esi + edi + force_index = 5 words
- FRAME_FIXED_SIZE = 5
+ # ebp + ebx + esi + edi + 4 extra words + force_index = 9 words
+ FRAME_FIXED_SIZE = 9
+ FORCE_INDEX_OFS = -8*WORD
+ MY_COPY_OF_REGS = -7*WORD
IS_X86_32 = True
IS_X86_64 = False
else:
WORD = 8
- # rbp + rbx + r12 + r13 + r14 + r15 + force_index = 7 words
- FRAME_FIXED_SIZE = 7
+ # rbp + rbx + r12 + r13 + r14 + r15 + 11 extra words + force_index = 18
+ FRAME_FIXED_SIZE = 18
+ FORCE_INDEX_OFS = -17*WORD
+ MY_COPY_OF_REGS = -16*WORD
IS_X86_32 = False
IS_X86_64 = True
-FORCE_INDEX_OFS = -(FRAME_FIXED_SIZE-1)*WORD
+# The extra space has room for almost all registers, apart from eax and edx
+# which are used in the malloc itself. They are:
+# ecx, ebx, esi, edi [32 and 64 bits]
+# r8, r9, r10, r12, r13, r14, r15 [64 bits only]
diff --git a/pypy/config/translationoption.py b/pypy/config/translationoption.py
--- a/pypy/config/translationoption.py
+++ b/pypy/config/translationoption.py
@@ -350,7 +350,11 @@
}
def final_check_config(config):
- pass
+ # XXX: this should be a real config option, but it is hard to refactor it;
+ # instead, we "just" patch it from here
+ from pypy.rlib import rfloat
+ if config.translation.type_system == 'ootype':
+ rfloat.USE_SHORT_FLOAT_REPR = False
def set_opt_level(config, level):
"""Apply optimization suggestions on the 'config'.
diff --git a/pypy/module/itertools/interp_itertools.py b/pypy/module/itertools/interp_itertools.py
--- a/pypy/module/itertools/interp_itertools.py
+++ b/pypy/module/itertools/interp_itertools.py
@@ -486,6 +486,7 @@
class W_IMap(Wrappable):
_error_name = "imap"
+ _immutable_fields_ = ["w_fun", "iterators_w"]
def __init__(self, space, w_fun, args_w):
self.space = space
diff --git a/pypy/rlib/rfloat.py b/pypy/rlib/rfloat.py
--- a/pypy/rlib/rfloat.py
+++ b/pypy/rlib/rfloat.py
@@ -4,6 +4,8 @@
from pypy.rpython.tool import rffi_platform
from pypy.translator.tool.cbuild import ExternalCompilationInfo
from pypy.rlib import objectmodel
+from pypy.rpython.extfunc import register_external
+from pypy.annotation.model import SomeString
USE_SHORT_FLOAT_REPR = True # XXX make it a translation option?
@@ -24,16 +26,28 @@
globals().update(rffi_platform.configure(CConfig))
def rstring_to_float(s):
+ return rstring_to_float_impl(s)
+
+def rstring_to_float_impl(s):
if USE_SHORT_FLOAT_REPR:
from pypy.rlib.rdtoa import strtod
return strtod(s)
-
sign, before_point, after_point, exponent = break_up_float(s)
-
if not before_point and not after_point:
raise ValueError
+ return parts_to_float(sign, before_point, after_point, exponent)
- return parts_to_float(sign, before_point, after_point, exponent)
+def oo_rstring_to_float(s):
+ from pypy.rpython.annlowlevel import oostr
+ from pypy.rpython.ootypesystem import ootype
+ lls = oostr(s)
+ return ootype.ooparse_float(lls)
+
+register_external(rstring_to_float, [SomeString(can_be_None=False)], float,
+ llimpl=rstring_to_float_impl,
+ ooimpl=oo_rstring_to_float,
+ sandboxsafe=True)
+
# float as string -> sign, beforept, afterpt, exponent
def break_up_float(s):
@@ -153,128 +167,132 @@
result = formatd(value, tp, precision, flags)
return result, special
-if USE_SHORT_FLOAT_REPR:
- def round_double(value, ndigits):
- # The basic idea is very simple: convert and round the double to
- # a decimal string using _Py_dg_dtoa, then convert that decimal
- # string back to a double with _Py_dg_strtod. There's one minor
- # difficulty: Python 2.x expects round to do
- # round-half-away-from-zero, while _Py_dg_dtoa does
- # round-half-to-even. So we need some way to detect and correct
- # the halfway cases.
+def round_double(value, ndigits):
+ if USE_SHORT_FLOAT_REPR:
+ return round_double_short_repr(value, ndigits)
+ else:
+ return round_double_fallback_repr(value, ndigits)
- # a halfway value has the form k * 0.5 * 10**-ndigits for some
- # odd integer k. Or in other words, a rational number x is
- # exactly halfway between two multiples of 10**-ndigits if its
- # 2-valuation is exactly -ndigits-1 and its 5-valuation is at
- # least -ndigits. For ndigits >= 0 the latter condition is
- # automatically satisfied for a binary float x, since any such
- # float has nonnegative 5-valuation. For 0 > ndigits >= -22, x
- # needs to be an integral multiple of 5**-ndigits; we can check
- # this using fmod. For -22 > ndigits, there are no halfway
- # cases: 5**23 takes 54 bits to represent exactly, so any odd
- # multiple of 0.5 * 10**n for n >= 23 takes at least 54 bits of
- # precision to represent exactly.
+def round_double_short_repr(value, ndigits):
+ # The basic idea is very simple: convert and round the double to
+ # a decimal string using _Py_dg_dtoa, then convert that decimal
+ # string back to a double with _Py_dg_strtod. There's one minor
+ # difficulty: Python 2.x expects round to do
+ # round-half-away-from-zero, while _Py_dg_dtoa does
+ # round-half-to-even. So we need some way to detect and correct
+ # the halfway cases.
- sign = copysign(1.0, value)
- value = abs(value)
+ # a halfway value has the form k * 0.5 * 10**-ndigits for some
+ # odd integer k. Or in other words, a rational number x is
+ # exactly halfway between two multiples of 10**-ndigits if its
+ # 2-valuation is exactly -ndigits-1 and its 5-valuation is at
+ # least -ndigits. For ndigits >= 0 the latter condition is
+ # automatically satisfied for a binary float x, since any such
+ # float has nonnegative 5-valuation. For 0 > ndigits >= -22, x
+ # needs to be an integral multiple of 5**-ndigits; we can check
+ # this using fmod. For -22 > ndigits, there are no halfway
+ # cases: 5**23 takes 54 bits to represent exactly, so any odd
+ # multiple of 0.5 * 10**n for n >= 23 takes at least 54 bits of
+ # precision to represent exactly.
- # find 2-valuation value
- m, expo = math.frexp(value)
- while m != math.floor(m):
- m *= 2.0
- expo -= 1
+ sign = copysign(1.0, value)
+ value = abs(value)
- # determine whether this is a halfway case.
- halfway_case = 0
- if expo == -ndigits - 1:
- if ndigits >= 0:
+ # find 2-valuation value
+ m, expo = math.frexp(value)
+ while m != math.floor(m):
+ m *= 2.0
+ expo -= 1
+
+ # determine whether this is a halfway case.
+ halfway_case = 0
+ if expo == -ndigits - 1:
+ if ndigits >= 0:
+ halfway_case = 1
+ elif ndigits >= -22:
+ # 22 is the largest k such that 5**k is exactly
+ # representable as a double
+ five_pow = 1.0
+ for i in range(-ndigits):
+ five_pow *= 5.0
+ if math.fmod(value, five_pow) == 0.0:
halfway_case = 1
- elif ndigits >= -22:
- # 22 is the largest k such that 5**k is exactly
- # representable as a double
- five_pow = 1.0
- for i in range(-ndigits):
- five_pow *= 5.0
- if math.fmod(value, five_pow) == 0.0:
- halfway_case = 1
- # round to a decimal string; use an extra place for halfway case
- strvalue = formatd(value, 'f', ndigits + halfway_case)
+ # round to a decimal string; use an extra place for halfway case
+ strvalue = formatd(value, 'f', ndigits + halfway_case)
- if halfway_case:
- buf = [c for c in strvalue]
- if ndigits >= 0:
- endpos = len(buf) - 1
- else:
- endpos = len(buf) + ndigits
- # Sanity checks: there should be exactly ndigits+1 places
- # following the decimal point, and the last digit in the
- # buffer should be a '5'
- if not objectmodel.we_are_translated():
- assert buf[endpos] == '5'
- if '.' in buf:
- assert endpos == len(buf) - 1
- assert buf.index('.') == len(buf) - ndigits - 2
+ if halfway_case:
+ buf = [c for c in strvalue]
+ if ndigits >= 0:
+ endpos = len(buf) - 1
+ else:
+ endpos = len(buf) + ndigits
+ # Sanity checks: there should be exactly ndigits+1 places
+ # following the decimal point, and the last digit in the
+ # buffer should be a '5'
+ if not objectmodel.we_are_translated():
+ assert buf[endpos] == '5'
+ if '.' in buf:
+ assert endpos == len(buf) - 1
+ assert buf.index('.') == len(buf) - ndigits - 2
- # increment and shift right at the same time
- i = endpos - 1
- carry = 1
- while i >= 0:
+ # increment and shift right at the same time
+ i = endpos - 1
+ carry = 1
+ while i >= 0:
+ digit = ord(buf[i])
+ if digit == ord('.'):
+ buf[i+1] = chr(digit)
+ i -= 1
digit = ord(buf[i])
- if digit == ord('.'):
- buf[i+1] = chr(digit)
- i -= 1
- digit = ord(buf[i])
- carry += digit - ord('0')
- buf[i+1] = chr(carry % 10 + ord('0'))
- carry /= 10
- i -= 1
- buf[0] = chr(carry + ord('0'))
- if ndigits < 0:
- buf.append('0')
+ carry += digit - ord('0')
+ buf[i+1] = chr(carry % 10 + ord('0'))
+ carry /= 10
+ i -= 1
+ buf[0] = chr(carry + ord('0'))
+ if ndigits < 0:
+ buf.append('0')
- strvalue = ''.join(buf)
+ strvalue = ''.join(buf)
- return sign * rstring_to_float(strvalue)
+ return sign * rstring_to_float(strvalue)
-else:
- # fallback version, to be used when correctly rounded
- # binary<->decimal conversions aren't available
- def round_double(value, ndigits):
- if ndigits >= 0:
- if ndigits > 22:
- # pow1 and pow2 are each safe from overflow, but
- # pow1*pow2 ~= pow(10.0, ndigits) might overflow
- pow1 = math.pow(10.0, ndigits - 22)
- pow2 = 1e22
- else:
- pow1 = math.pow(10.0, ndigits)
- pow2 = 1.0
+# fallback version, to be used when correctly rounded
+# binary<->decimal conversions aren't available
+def round_double_fallback_repr(value, ndigits):
+ if ndigits >= 0:
+ if ndigits > 22:
+ # pow1 and pow2 are each safe from overflow, but
+ # pow1*pow2 ~= pow(10.0, ndigits) might overflow
+ pow1 = math.pow(10.0, ndigits - 22)
+ pow2 = 1e22
+ else:
+ pow1 = math.pow(10.0, ndigits)
+ pow2 = 1.0
- y = (value * pow1) * pow2
- # if y overflows, then rounded value is exactly x
- if isinf(y):
- return value
+ y = (value * pow1) * pow2
+ # if y overflows, then rounded value is exactly x
+ if isinf(y):
+ return value
- else:
- pow1 = math.pow(10.0, -ndigits);
- pow2 = 1.0 # unused; for translation
- y = value / pow1
+ else:
+ pow1 = math.pow(10.0, -ndigits);
+ pow2 = 1.0 # unused; for translation
+ y = value / pow1
- if y >= 0.0:
- z = math.floor(y + 0.5)
- else:
- z = math.ceil(y - 0.5)
- if math.fabs(y-z) == 1.0: # obscure case, see the test
- z = y
+ if y >= 0.0:
+ z = math.floor(y + 0.5)
+ else:
+ z = math.ceil(y - 0.5)
+ if math.fabs(y-z) == 1.0: # obscure case, see the test
+ z = y
- if ndigits >= 0:
- z = (z / pow2) / pow1
- else:
- z *= pow1
- return z
+ if ndigits >= 0:
+ z = (z / pow2) / pow1
+ else:
+ z *= pow1
+ return z
INFINITY = 1e200 * 1e200
NAN = INFINITY / INFINITY
diff --git a/pypy/translator/cli/src/debug.cs b/pypy/translator/cli/src/debug.cs
--- a/pypy/translator/cli/src/debug.cs
+++ b/pypy/translator/cli/src/debug.cs
@@ -1,5 +1,6 @@
using System;
using System.IO;
+using System.Collections.Generic;
using System.Diagnostics;
// this code is modeled after translator/c/src/debug.h
@@ -21,7 +22,7 @@
static int have_debug_prints = -1;
static bool debug_ready = false;
static bool debug_profile = false;
- static string debug_prefix = null;
+ static string[] active_categories = null;
public static void close_file()
{
@@ -29,6 +30,14 @@
debug_file.Close();
}
+ public static bool startswithoneof(string category, string[] active_categories)
+ {
+ foreach(string cat in active_categories)
+ if (category.StartsWith(cat))
+ return true;
+ return false;
+ }
+
public static bool HAVE_DEBUG_PRINTS()
{
if ((have_debug_prints & 1) != 0) {
@@ -48,7 +57,8 @@
have_debug_prints <<= 1;
if (!debug_profile) {
/* non-profiling version */
- if (debug_prefix == null || !category.StartsWith(debug_prefix)) {
+ if (active_categories == null ||
+ !startswithoneof(category, active_categories)) {
/* wrong section name, or no PYPYLOG at all, skip it */
return;
}
@@ -83,7 +93,8 @@
}
else {
/* PYPYLOG=prefix:filename --- conditional logging */
- debug_prefix = filename.Substring(0, colon);
+ string debug_prefix = filename.Substring(0, colon);
+ active_categories = debug_prefix.Split(',');
filename = filename.Substring(colon+1);
}
if (filename != "-")
diff --git a/pypy/objspace/std/test/test_dictmultiobject.py b/pypy/objspace/std/test/test_dictmultiobject.py
--- a/pypy/objspace/std/test/test_dictmultiobject.py
+++ b/pypy/objspace/std/test/test_dictmultiobject.py
@@ -1,3 +1,4 @@
+import sys
from pypy.interpreter.error import OperationError
from pypy.objspace.std.dictmultiobject import \
W_DictMultiObject, setitem__DictMulti_ANY_ANY, getitem__DictMulti_ANY, \
@@ -151,6 +152,8 @@
class AppTest_DictObject:
+ def setup_class(cls):
+ cls.w_on_pypy = cls.space.wrap("__pypy__" in sys.builtin_module_names)
def test_equality(self):
d = {1:2}
@@ -259,7 +262,29 @@
d[33] = 99
assert d == dd
assert x == 99
-
+
+ def test_setdefault_fast(self):
+ class Key(object):
+ calls = 0
+ def __hash__(self):
+ self.calls += 1
+ return object.__hash__(self)
+
+ k = Key()
+ d = {}
+ d.setdefault(k, [])
+ if self.on_pypy:
+ assert k.calls == 1
+
+ d.setdefault(k, 1)
+ if self.on_pypy:
+ assert k.calls == 2
+
+ k = Key()
+ d.setdefault(k, 42)
+ if self.on_pypy:
+ assert k.calls == 1
+
def test_update(self):
d = {1:2, 3:4}
dd = d.copy()
@@ -704,13 +729,20 @@
class FakeString(str):
+ hash_count = 0
def unwrap(self, space):
self.unwrapped = True
return str(self)
+ def __hash__(self):
+ self.hash_count += 1
+ return str.__hash__(self)
+
# the minimal 'space' needed to use a W_DictMultiObject
class FakeSpace:
+ hash_count = 0
def hash_w(self, obj):
+ self.hash_count += 1
return hash(obj)
def unwrap(self, x):
return x
@@ -726,6 +758,8 @@
return []
DictObjectCls = W_DictMultiObject
def type(self, w_obj):
+ if isinstance(w_obj, FakeString):
+ return str
return type(w_obj)
w_str = str
def str_w(self, string):
@@ -890,6 +924,19 @@
impl.setitem(x, x)
assert impl.r_dict_content is not None
+ def test_setdefault_fast(self):
+ on_pypy = "__pypy__" in sys.builtin_module_names
+ impl = self.impl
+ key = FakeString(self.string)
+ x = impl.setdefault(key, 1)
+ assert x == 1
+ if on_pypy:
+ assert key.hash_count == 1
+ x = impl.setdefault(key, 2)
+ assert x == 1
+ if on_pypy:
+ assert key.hash_count == 2
+
class TestStrDictImplementation(BaseTestRDictImplementation):
ImplementionClass = StrDictImplementation
diff --git a/pypy/module/cpyext/test/test_pyerrors.py b/pypy/module/cpyext/test/test_pyerrors.py
--- a/pypy/module/cpyext/test/test_pyerrors.py
+++ b/pypy/module/cpyext/test/test_pyerrors.py
@@ -96,6 +96,10 @@
out, err = capfd.readouterr()
assert "Exception ValueError: 'message' in 'location' ignored" == err.strip()
+ def test_ExceptionInstance_Class(self, space, api):
+ instance = space.call_function(space.w_ValueError)
+ assert api.PyExceptionInstance_Class(instance) is space.w_ValueError
+
class AppTestFetch(AppTestCpythonExtensionBase):
def setup_class(cls):
AppTestCpythonExtensionBase.setup_class.im_func(cls)
diff --git a/pypy/rpython/rstr.py b/pypy/rpython/rstr.py
--- a/pypy/rpython/rstr.py
+++ b/pypy/rpython/rstr.py
@@ -221,14 +221,33 @@
def rtype_method_split(self, hop):
rstr = hop.args_r[0].repr
- v_str, v_chr = hop.inputargs(rstr.repr, rstr.char_repr)
+ if hop.nb_args == 3:
+ v_str, v_chr, v_max = hop.inputargs(rstr.repr, rstr.char_repr, Signed)
+ else:
+ v_str, v_chr = hop.inputargs(rstr.repr, rstr.char_repr)
+ v_max = hop.inputconst(Signed, -1)
try:
list_type = hop.r_result.lowleveltype.TO
except AttributeError:
list_type = hop.r_result.lowleveltype
cLIST = hop.inputconst(Void, list_type)
hop.exception_cannot_occur()
- return hop.gendirectcall(self.ll.ll_split_chr, cLIST, v_str, v_chr)
+ return hop.gendirectcall(self.ll.ll_split_chr, cLIST, v_str, v_chr, v_max)
+
+ def rtype_method_rsplit(self, hop):
+ rstr = hop.args_r[0].repr
+ if hop.nb_args == 3:
+ v_str, v_chr, v_max = hop.inputargs(rstr.repr, rstr.char_repr, Signed)
+ else:
+ v_str, v_chr = hop.inputargs(rstr.repr, rstr.char_repr)
+ v_max = hop.inputconst(Signed, -1)
+ try:
+ list_type = hop.r_result.lowleveltype.TO
+ except AttributeError:
+ list_type = hop.r_result.lowleveltype
+ cLIST = hop.inputconst(Void, list_type)
+ hop.exception_cannot_occur()
+ return hop.gendirectcall(self.ll.ll_rsplit_chr, cLIST, v_str, v_chr, v_max)
def rtype_method_replace(self, hop):
rstr = hop.args_r[0].repr
diff --git a/pypy/translator/backendopt/merge_if_blocks.py b/pypy/translator/backendopt/merge_if_blocks.py
--- a/pypy/translator/backendopt/merge_if_blocks.py
+++ b/pypy/translator/backendopt/merge_if_blocks.py
@@ -1,4 +1,4 @@
-from pypy.objspace.flow.model import Block, Constant, Variable, flatten
+from pypy.objspace.flow.model import Block, Constant, Variable
from pypy.objspace.flow.model import checkgraph, mkentrymap
from pypy.translator.backendopt.support import log
@@ -75,14 +75,19 @@
# False link
checkvar = [var for var in current.operations[-1].args
if isinstance(var, Variable)][0]
+ resvar = current.operations[-1].result
case = [var for var in current.operations[-1].args
if isinstance(var, Constant)][0]
- chain.append((current, case))
checkvars.append(checkvar)
falseexit = current.exits[0]
assert not falseexit.exitcase
trueexit = current.exits[1]
targetblock = falseexit.target
+ # if the result of the check is also passed through the link, we
+ # cannot construct the chain
+ if resvar in falseexit.args or resvar in trueexit.args:
+ break
+ chain.append((current, case))
if len(entrymap[targetblock]) != 1:
break
if checkvar not in falseexit.args:
diff --git a/pypy/jit/metainterp/test/test_virtualizable.py b/pypy/jit/metainterp/test/test_virtualizable.py
--- a/pypy/jit/metainterp/test/test_virtualizable.py
+++ b/pypy/jit/metainterp/test/test_virtualizable.py
@@ -6,7 +6,7 @@
from pypy.jit.codewriter import heaptracker
from pypy.rlib.jit import JitDriver, hint, dont_look_inside
from pypy.rlib.rarithmetic import intmask
-from pypy.jit.metainterp.test.test_basic import LLJitMixin, OOJitMixin
+from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin
from pypy.rpython.rclass import FieldListAccessor
from pypy.jit.metainterp.warmspot import get_stats, get_translator
from pypy.jit.metainterp import history
diff --git a/pypy/jit/metainterp/test/test_optimizeopt.py b/pypy/jit/metainterp/test/test_optimizeopt.py
--- a/pypy/jit/metainterp/test/test_optimizeopt.py
+++ b/pypy/jit/metainterp/test/test_optimizeopt.py
@@ -135,7 +135,7 @@
return type(self) is type(other) # xxx obscure
def clone_if_mutable(self):
res = Storage(self.metainterp_sd, self.original_greenkey)
- self.copy_all_attrbutes_into(res)
+ self.copy_all_attributes_into(res)
return res
def _sortboxes(boxes):
@@ -816,6 +816,52 @@
"""
self.optimize_loop(ops, expected, preamble)
+ def test_compare_with_itself(self):
+ ops = """
+ []
+ i0 = escape()
+ i1 = int_lt(i0, i0)
+ guard_false(i1) []
+ i2 = int_le(i0, i0)
+ guard_true(i2) []
+ i3 = int_eq(i0, i0)
+ guard_true(i3) []
+ i4 = int_ne(i0, i0)
+ guard_false(i4) []
+ i5 = int_gt(i0, i0)
+ guard_false(i5) []
+ i6 = int_ge(i0, i0)
+ guard_true(i6) []
+ jump()
+ """
+ expected = """
+ []
+ i0 = escape()
+ jump()
+ """
+ self.optimize_loop(ops, expected)
+
+ def test_compare_with_itself_uint(self):
+ py.test.skip("implement me")
+ ops = """
+ []
+ i0 = escape()
+ i7 = uint_lt(i0, i0)
+ guard_false(i7) []
+ i8 = uint_le(i0, i0)
+ guard_true(i8) []
+ i9 = uint_gt(i0, i0)
+ guard_false(i9) []
+ i10 = uint_ge(i0, i0)
+ guard_true(i10) []
+ jump()
+ """
+ expected = """
+ []
+ i0 = escape()
+ jump()
+ """
+ self.optimize_loop(ops, expected)
@@ -1791,7 +1837,7 @@
"""
self.optimize_loop(ops, ops)
- def test_duplicate_setfield_1(self):
+ def test_duplicate_setfield_0(self):
ops = """
[p1, i1, i2]
setfield_gc(p1, i1, descr=valuedescr)
@@ -1800,8 +1846,27 @@
"""
expected = """
[p1, i1, i2]
+ jump(p1, i1, i2)
+ """
+ # in this case, all setfields are removed, because we can prove
+ # that in the loop it will always have the same value
+ self.optimize_loop(ops, expected)
+
+ def test_duplicate_setfield_1(self):
+ ops = """
+ [p1]
+ i1 = escape()
+ i2 = escape()
+ setfield_gc(p1, i1, descr=valuedescr)
setfield_gc(p1, i2, descr=valuedescr)
- jump(p1, i1, i2)
+ jump(p1)
+ """
+ expected = """
+ [p1]
+ i1 = escape()
+ i2 = escape()
+ setfield_gc(p1, i2, descr=valuedescr)
+ jump(p1)
"""
self.optimize_loop(ops, expected)
@@ -1848,6 +1913,7 @@
setfield_gc(p1, i4, descr=nextdescr)
#
setfield_gc(p1, i2, descr=valuedescr)
+ escape()
jump(p1, i1, i2, p3)
"""
preamble = """
@@ -1860,6 +1926,7 @@
#
setfield_gc(p1, i2, descr=valuedescr)
setfield_gc(p1, i4, descr=nextdescr)
+ escape()
jump(p1, i1, i2, p3, i3)
"""
expected = """
@@ -1871,6 +1938,7 @@
#
setfield_gc(p1, i2, descr=valuedescr)
setfield_gc(p1, i4, descr=nextdescr)
+ escape()
jump(p1, i1, i2, p3, i3)
"""
self.optimize_loop(ops, expected, preamble)
@@ -1943,6 +2011,7 @@
guard_true(i3) []
i4 = int_neg(i2)
setfield_gc(p1, NULL, descr=nextdescr)
+ escape()
jump(p1, i2, i4)
"""
preamble = """
@@ -1950,12 +2019,14 @@
guard_true(i3) [p1]
i4 = int_neg(i2)
setfield_gc(p1, NULL, descr=nextdescr)
+ escape()
jump(p1, i2, i4)
"""
expected = """
[p1, i2, i4]
guard_true(i4) [p1]
setfield_gc(p1, NULL, descr=nextdescr)
+ escape()
jump(p1, i2, 1)
"""
self.optimize_loop(ops, expected, preamble)
@@ -1969,6 +2040,7 @@
guard_true(i3) []
i4 = int_neg(i2)
setfield_gc(p1, NULL, descr=nextdescr)
+ escape()
jump(p1, i2, i4)
"""
preamble = """
@@ -1976,12 +2048,14 @@
guard_true(i3) [i2, p1]
i4 = int_neg(i2)
setfield_gc(p1, NULL, descr=nextdescr)
+ escape()
jump(p1, i2, i4)
"""
expected = """
[p1, i2, i4]
guard_true(i4) [i2, p1]
setfield_gc(p1, NULL, descr=nextdescr)
+ escape()
jump(p1, i2, 1)
"""
self.optimize_loop(ops, expected)
@@ -2027,15 +2101,34 @@
guard_value(p1, ConstPtr(myptr)) []
setfield_gc(p1, i1, descr=valuedescr)
setfield_gc(ConstPtr(myptr), i2, descr=valuedescr)
+ escape()
jump(p1, i1, i2)
"""
expected = """
[i1, i2]
setfield_gc(ConstPtr(myptr), i2, descr=valuedescr)
+ escape()
jump(i1, i2)
"""
self.optimize_loop(ops, expected)
+ def test_dont_force_setfield_around_copystrcontent(self):
+ ops = """
+ [p0, i0, p1, i1, i2]
+ setfield_gc(p0, i1, descr=valuedescr)
+ copystrcontent(p0, i0, p1, i1, i2)
+ escape()
+ jump(p0, i0, p1, i1, i2)
+ """
+ expected = """
+ [p0, i0, p1, i1, i2]
+ copystrcontent(p0, i0, p1, i1, i2)
+ setfield_gc(p0, i1, descr=valuedescr)
+ escape()
+ jump(p0, i0, p1, i1, i2)
+ """
+ self.optimize_loop(ops, expected)
+
def test_duplicate_getarrayitem_1(self):
ops = """
[p1]
@@ -2356,6 +2449,33 @@
"""
self.optimize_loop(ops, expected, preamble)
+ def test_bug_5(self):
+ ops = """
+ [p0]
+ i0 = escape()
+ i2 = getfield_gc(p0, descr=valuedescr)
+ i4 = int_add(i2, 1)
+ setfield_gc(p0, i4, descr=valuedescr)
+ guard_true(i0) []
+ i6 = getfield_gc(p0, descr=valuedescr)
+ i8 = int_sub(i6, 1)
+ setfield_gc(p0, i8, descr=valuedescr)
+ escape()
+ jump(p0)
+ """
+ expected = """
+ [p0]
+ i0 = escape()
+ i2 = getfield_gc(p0, descr=valuedescr)
+ i4 = int_add(i2, 1)
+ setfield_gc(p0, i4, descr=valuedescr)
+ guard_true(i0) []
+ setfield_gc(p0, i2, descr=valuedescr)
+ escape()
+ jump(p0)
+ """
+ self.optimize_loop(ops, expected)
+
def test_invalid_loop_1(self):
ops = """
[p1]
@@ -2637,7 +2757,7 @@
"""
self.optimize_loop(ops, expected)
- def test_fold_partially_constant_ops(self):
+ def test_fold_partially_constant_add_sub(self):
ops = """
[i0]
i1 = int_sub(i0, 0)
@@ -2671,7 +2791,7 @@
"""
self.optimize_loop(ops, expected)
- def test_fold_partially_constant_ops_ovf(self):
+ def test_fold_partially_constant_add_sub_ovf(self):
ops = """
[i0]
i1 = int_sub_ovf(i0, 0)
@@ -2708,6 +2828,21 @@
"""
self.optimize_loop(ops, expected)
+ def test_fold_partially_constant_shift(self):
+ ops = """
+ [i0]
+ i1 = int_lshift(i0, 0)
+ i2 = int_rshift(i1, 0)
+ i3 = int_eq(i2, i0)
+ guard_true(i3) []
+ jump(i2)
+ """
+ expected = """
+ [i0]
+ jump(i0)
+ """
+ self.optimize_loop(ops, expected)
+
# ----------
class TestLLtype(OptimizeOptTest, LLtypeMixin):
@@ -2992,7 +3127,6 @@
i0 = force_token()
p2 = new_with_vtable(ConstClass(jit_virtual_ref_vtable))
setfield_gc(p2, i0, descr=virtualtokendescr)
- setfield_gc(p2, 5, descr=virtualrefindexdescr)
escape(p2)
setfield_gc(p2, p1, descr=virtualforceddescr)
setfield_gc(p2, -3, descr=virtualtokendescr)
@@ -3025,7 +3159,6 @@
#
p2 = new_with_vtable(ConstClass(jit_virtual_ref_vtable))
setfield_gc(p2, i3, descr=virtualtokendescr)
- setfield_gc(p2, 3, descr=virtualrefindexdescr)
setfield_gc(p0, p2, descr=nextdescr)
#
call_may_force(i1, descr=mayforcevirtdescr)
@@ -3065,7 +3198,6 @@
#
p2 = new_with_vtable(ConstClass(jit_virtual_ref_vtable))
setfield_gc(p2, i3, descr=virtualtokendescr)
- setfield_gc(p2, 2, descr=virtualrefindexdescr)
setfield_gc(p0, p2, descr=nextdescr)
#
call_may_force(i1, descr=mayforcevirtdescr)
@@ -3103,6 +3235,7 @@
guard_no_exception(descr=fdescr) [p2, p1]
virtual_ref_finish(p2, p1)
setfield_gc(p0, NULL, descr=refdescr)
+ escape()
jump(p0, i1)
"""
preamble = """
@@ -3111,6 +3244,7 @@
call(i1, descr=nonwritedescr)
guard_no_exception(descr=fdescr) [i3, i1, p0]
setfield_gc(p0, NULL, descr=refdescr)
+ escape()
jump(p0, i1)
"""
expected = """
@@ -3119,6 +3253,7 @@
call(i1, descr=nonwritedescr)
guard_no_exception(descr=fdescr2) [i3, i1, p0]
setfield_gc(p0, NULL, descr=refdescr)
+ escape()
jump(p0, i1)
"""
self.optimize_loop(ops, expected, preamble)
@@ -3129,7 +3264,7 @@
#self.loop.inputargs[0].value = self.nodeobjvalue
#self.check_expanded_fail_descr('''p2, p1
# p0.refdescr = p2
- # where p2 is a jit_virtual_ref_vtable, virtualtokendescr=i3, virtualrefindexdescr=2
+ # where p2 is a jit_virtual_ref_vtable, virtualtokendescr=i3
# where p1 is a node_vtable, nextdescr=p1b
# where p1b is a node_vtable, valuedescr=i1
# ''', rop.GUARD_NO_EXCEPTION)
@@ -3150,7 +3285,6 @@
i3 = force_token()
p2 = new_with_vtable(ConstClass(jit_virtual_ref_vtable))
setfield_gc(p2, i3, descr=virtualtokendescr)
- setfield_gc(p2, 7, descr=virtualrefindexdescr)
escape(p2)
p1 = new_with_vtable(ConstClass(node_vtable))
setfield_gc(p2, p1, descr=virtualforceddescr)
@@ -3176,7 +3310,6 @@
i3 = force_token()
p2 = new_with_vtable(ConstClass(jit_virtual_ref_vtable))
setfield_gc(p2, i3, descr=virtualtokendescr)
- setfield_gc(p2, 23, descr=virtualrefindexdescr)
escape(p2)
setfield_gc(p2, p1, descr=virtualforceddescr)
setfield_gc(p2, -3, descr=virtualtokendescr)
@@ -4842,6 +4975,58 @@
p2 = new_with_vtable(ConstClass(node_vtable))
setfield_gc(p2, i1, descr=nextdescr)
"""
+ py.test.skip("no test here")
+
+ def test_immutable_not(self):
+ ops = """
+ []
+ p0 = new_with_vtable(ConstClass(intobj_noimmut_vtable))
+ setfield_gc(p0, 42, descr=noimmut_intval)
+ escape(p0)
+ jump()
+ """
+ self.optimize_loop(ops, ops)
+
+ def test_immutable_variable(self):
+ ops = """
+ [i0]
+ p0 = new_with_vtable(ConstClass(intobj_immut_vtable))
+ setfield_gc(p0, i0, descr=immut_intval)
+ escape(p0)
+ jump(i0)
+ """
+ self.optimize_loop(ops, ops)
+
+ def test_immutable_incomplete(self):
+ ops = """
+ []
+ p0 = new_with_vtable(ConstClass(intobj_immut_vtable))
+ escape(p0)
+ jump()
+ """
+ self.optimize_loop(ops, ops)
+
+ def test_immutable_constantfold(self):
+ ops = """
+ []
+ p0 = new_with_vtable(ConstClass(intobj_immut_vtable))
+ setfield_gc(p0, 1242, descr=immut_intval)
+ escape(p0)
+ jump()
+ """
+ from pypy.rpython.lltypesystem import lltype, llmemory
+ class IntObj1242(object):
+ _TYPE = llmemory.GCREF.TO
+ def __eq__(self, other):
+ return other.container.intval == 1242
+ self.namespace['intobj1242'] = lltype._ptr(llmemory.GCREF,
+ IntObj1242())
+ expected = """
+ []
+ escape(ConstPtr(intobj1242))
+ jump()
+ """
+ self.optimize_loop(ops, expected)
# ----------
def optimize_strunicode_loop(self, ops, optops, preamble=None):
diff --git a/pypy/module/cpyext/eval.py b/pypy/module/cpyext/eval.py
--- a/pypy/module/cpyext/eval.py
+++ b/pypy/module/cpyext/eval.py
@@ -112,6 +112,7 @@
try:
while True:
count = fread(buf, 1, BUF_SIZE, fp)
+ count = rffi.cast(lltype.Signed, count)
source += rffi.charpsize2str(buf, count)
if count < BUF_SIZE:
if feof(fp):
diff --git a/pypy/rpython/test/test_rfloat.py b/pypy/rpython/test/test_rfloat.py
--- a/pypy/rpython/test/test_rfloat.py
+++ b/pypy/rpython/test/test_rfloat.py
@@ -156,6 +156,37 @@
return x
self.interpret(fn, [1.0, 2.0, 3.0])
+ def test_copysign(self):
+ import math
+ def fn(x, y):
+ return math.copysign(x, y)
+ assert self.interpret(fn, [42, -1]) == -42
+ assert self.interpret(fn, [42, -0.0]) == -42
+ assert self.interpret(fn, [42, 0.0]) == 42
+
+ def test_rstring_to_float(self):
+ from pypy.rlib.rfloat import rstring_to_float
+ def fn(i):
+ s = ['42.3', '123.4'][i]
+ return rstring_to_float(s)
+ assert self.interpret(fn, [0]) == 42.3
+
+ def test_isnan(self):
+ import math
+ def fn(x):
+ inf = x * x
+ nan = inf / inf
+ return math.isnan(nan)
+ assert self.interpret(fn, [1e200])
+
+ def test_isinf(self):
+ import math
+ def fn(x):
+ inf = x * x
+ return math.isinf(inf)
+ assert self.interpret(fn, [1e200])
+
+
class TestLLtype(BaseTestRfloat, LLRtypeMixin):
def test_hash(self):
diff --git a/pypy/jit/metainterp/optimizeopt/optimizer.py b/pypy/jit/metainterp/optimizeopt/optimizer.py
--- a/pypy/jit/metainterp/optimizeopt/optimizer.py
+++ b/pypy/jit/metainterp/optimizeopt/optimizer.py
@@ -514,12 +514,10 @@
break
else:
# all constant arguments: constant-fold away
- argboxes = [self.get_constant_box(op.getarg(i))
- for i in range(op.numargs())]
- resbox = execute_nonspec(self.cpu, None,
- op.getopnum(), argboxes, op.getdescr())
- # FIXME: Don't we need to check for an overflow here?
- self.make_constant(op.result, resbox.constbox())
+ resbox = self.constant_fold(op)
+ # note that INT_xxx_OVF is not done from here, and the
+ # overflows in the INT_xxx operations are ignored
+ self.make_constant(op.result, resbox)
return
# did we do the exact same operation already?
@@ -538,6 +536,13 @@
if nextop:
self.emit_operation(nextop)
+ def constant_fold(self, op):
+ argboxes = [self.get_constant_box(op.getarg(i))
+ for i in range(op.numargs())]
+ resbox = execute_nonspec(self.cpu, None,
+ op.getopnum(), argboxes, op.getdescr())
+ return resbox.constbox()
+
#def optimize_GUARD_NO_OVERFLOW(self, op):
# # otherwise the default optimizer will clear fields, which is unwanted
# # in this case
diff --git a/pypy/jit/metainterp/test/test_jitdriver.py b/pypy/jit/metainterp/test/test_jitdriver.py
--- a/pypy/jit/metainterp/test/test_jitdriver.py
+++ b/pypy/jit/metainterp/test/test_jitdriver.py
@@ -1,6 +1,6 @@
"""Tests for multiple JitDrivers."""
from pypy.rlib.jit import JitDriver, unroll_safe
-from pypy.jit.metainterp.test.test_basic import LLJitMixin, OOJitMixin
+from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin
from pypy.jit.metainterp.warmspot import get_stats
diff --git a/pypy/jit/metainterp/test/test_basic.py b/pypy/jit/metainterp/test/test_basic.py
deleted file mode 100644
--- a/pypy/jit/metainterp/test/test_basic.py
+++ /dev/null
@@ -1,2411 +0,0 @@
-import py
-import sys
-from pypy.rlib.jit import JitDriver, we_are_jitted, hint, dont_look_inside
-from pypy.rlib.jit import loop_invariant
-from pypy.rlib.jit import jit_debug, assert_green, AssertGreenFailed
-from pypy.rlib.jit import unroll_safe, current_trace_length
-from pypy.jit.metainterp.warmspot import ll_meta_interp, get_stats
-from pypy.jit.backend.llgraph import runner
-from pypy.jit.metainterp import pyjitpl, history
-from pypy.jit.metainterp.warmstate import set_future_value
-from pypy.jit.codewriter.policy import JitPolicy, StopAtXPolicy
-from pypy.jit.codewriter import longlong
-from pypy import conftest
-from pypy.rlib.rarithmetic import ovfcheck
-from pypy.jit.metainterp.typesystem import LLTypeHelper, OOTypeHelper
-from pypy.rpython.lltypesystem import lltype, llmemory
-from pypy.rpython.ootypesystem import ootype
-from pypy.jit.metainterp.optimizeopt import ALL_OPTS_DICT
-
-def _get_jitcodes(testself, CPUClass, func, values, type_system,
- supports_longlong=False, **kwds):
- from pypy.jit.codewriter import support, codewriter
-
- class FakeJitCell:
- __compiled_merge_points = []
- def get_compiled_merge_points(self):
- return self.__compiled_merge_points[:]
- def set_compiled_merge_points(self, lst):
- self.__compiled_merge_points = lst
-
- class FakeWarmRunnerState:
- def attach_unoptimized_bridge_from_interp(self, greenkey, newloop):
- pass
-
- def jit_cell_at_key(self, greenkey):
- assert greenkey == []
- return self._cell
- _cell = FakeJitCell()
-
- trace_limit = sys.maxint
- enable_opts = ALL_OPTS_DICT
-
- func._jit_unroll_safe_ = True
- rtyper = support.annotate(func, values, type_system=type_system)
- graphs = rtyper.annotator.translator.graphs
- result_kind = history.getkind(graphs[0].getreturnvar().concretetype)[0]
-
- class FakeJitDriverSD:
- num_green_args = 0
- portal_graph = graphs[0]
- virtualizable_info = None
- greenfield_info = None
- result_type = result_kind
- portal_runner_ptr = "???"
-
- stats = history.Stats()
- cpu = CPUClass(rtyper, stats, None, False)
- cw = codewriter.CodeWriter(cpu, [FakeJitDriverSD()])
- testself.cw = cw
- policy = JitPolicy()
- policy.set_supports_longlong(supports_longlong)
- cw.find_all_graphs(policy)
- #
- testself.warmrunnerstate = FakeWarmRunnerState()
- testself.warmrunnerstate.cpu = cpu
- FakeJitDriverSD.warmstate = testself.warmrunnerstate
- if hasattr(testself, 'finish_setup_for_interp_operations'):
- testself.finish_setup_for_interp_operations()
- #
- cw.make_jitcodes(verbose=True)
-
-def _run_with_blackhole(testself, args):
- from pypy.jit.metainterp.blackhole import BlackholeInterpBuilder
- cw = testself.cw
- blackholeinterpbuilder = BlackholeInterpBuilder(cw)
- blackholeinterp = blackholeinterpbuilder.acquire_interp()
- count_i = count_r = count_f = 0
- for value in args:
- T = lltype.typeOf(value)
- if T == lltype.Signed:
- blackholeinterp.setarg_i(count_i, value)
- count_i += 1
- elif T == llmemory.GCREF:
- blackholeinterp.setarg_r(count_r, value)
- count_r += 1
- elif T == lltype.Float:
- value = longlong.getfloatstorage(value)
- blackholeinterp.setarg_f(count_f, value)
- count_f += 1
- else:
- raise TypeError(T)
- [jitdriver_sd] = cw.callcontrol.jitdrivers_sd
- blackholeinterp.setposition(jitdriver_sd.mainjitcode, 0)
- blackholeinterp.run()
- return blackholeinterp._final_result_anytype()
-
-def _run_with_pyjitpl(testself, args):
-
- class DoneWithThisFrame(Exception):
- pass
-
- class DoneWithThisFrameRef(DoneWithThisFrame):
- def __init__(self, cpu, *args):
- DoneWithThisFrame.__init__(self, *args)
-
- cw = testself.cw
- opt = history.Options(listops=True)
- metainterp_sd = pyjitpl.MetaInterpStaticData(cw.cpu, opt)
- metainterp_sd.finish_setup(cw)
- [jitdriver_sd] = metainterp_sd.jitdrivers_sd
- metainterp = pyjitpl.MetaInterp(metainterp_sd, jitdriver_sd)
- metainterp_sd.DoneWithThisFrameInt = DoneWithThisFrame
- metainterp_sd.DoneWithThisFrameRef = DoneWithThisFrameRef
- metainterp_sd.DoneWithThisFrameFloat = DoneWithThisFrame
- testself.metainterp = metainterp
- try:
- metainterp.compile_and_run_once(jitdriver_sd, *args)
- except DoneWithThisFrame, e:
- #if conftest.option.view:
- # metainterp.stats.view()
- return e.args[0]
- else:
- raise Exception("FAILED")
-
-def _run_with_machine_code(testself, args):
- metainterp = testself.metainterp
- num_green_args = metainterp.jitdriver_sd.num_green_args
- loop_tokens = metainterp.get_compiled_merge_points(args[:num_green_args])
- if len(loop_tokens) != 1:
- return NotImplemented
- # a loop was successfully created by _run_with_pyjitpl(); call it
- cpu = metainterp.cpu
- for i in range(len(args) - num_green_args):
- x = args[num_green_args + i]
- typecode = history.getkind(lltype.typeOf(x))
- set_future_value(cpu, i, x, typecode)
- faildescr = cpu.execute_token(loop_tokens[0])
- assert faildescr.__class__.__name__.startswith('DoneWithThisFrameDescr')
- if metainterp.jitdriver_sd.result_type == history.INT:
- return cpu.get_latest_value_int(0)
- elif metainterp.jitdriver_sd.result_type == history.REF:
- return cpu.get_latest_value_ref(0)
- elif metainterp.jitdriver_sd.result_type == history.FLOAT:
- return cpu.get_latest_value_float(0)
- else:
- return None
-
-
-class JitMixin:
- basic = True
- def check_loops(self, expected=None, everywhere=False, **check):
- get_stats().check_loops(expected=expected, everywhere=everywhere,
- **check)
- def check_loop_count(self, count):
- """NB. This is a hack; use check_tree_loop_count() or
- check_enter_count() for the real thing.
- This counts as 1 every bridge in addition to every loop; and it does
- not count at all the entry bridges from interpreter, although they
- are TreeLoops as well."""
- assert get_stats().compiled_count == count
- def check_tree_loop_count(self, count):
- assert len(get_stats().loops) == count
- def check_loop_count_at_most(self, count):
- assert get_stats().compiled_count <= count
- def check_enter_count(self, count):
- assert get_stats().enter_count == count
- def check_enter_count_at_most(self, count):
- assert get_stats().enter_count <= count
- def check_jumps(self, maxcount):
- assert get_stats().exec_jumps <= maxcount
- def check_aborted_count(self, count):
- assert get_stats().aborted_count == count
- def check_aborted_count_at_least(self, count):
- assert get_stats().aborted_count >= count
-
- def meta_interp(self, *args, **kwds):
- kwds['CPUClass'] = self.CPUClass
- kwds['type_system'] = self.type_system
- if "backendopt" not in kwds:
- kwds["backendopt"] = False
- return ll_meta_interp(*args, **kwds)
-
- def interp_operations(self, f, args, **kwds):
- # get the JitCodes for the function f
- _get_jitcodes(self, self.CPUClass, f, args, self.type_system, **kwds)
- # try to run it with blackhole.py
- result1 = _run_with_blackhole(self, args)
- # try to run it with pyjitpl.py
- result2 = _run_with_pyjitpl(self, args)
- assert result1 == result2
- # try to run it by running the code compiled just before
- result3 = _run_with_machine_code(self, args)
- assert result1 == result3 or result3 == NotImplemented
- #
- if (longlong.supports_longlong and
- isinstance(result1, longlong.r_float_storage)):
- result1 = longlong.getrealfloat(result1)
- return result1
-
- def check_history(self, expected=None, **isns):
- # this can be used after calling meta_interp
- get_stats().check_history(expected, **isns)
-
- def check_operations_history(self, expected=None, **isns):
- # this can be used after interp_operations
- if expected is not None:
- expected = dict(expected)
- expected['jump'] = 1
- self.metainterp.staticdata.stats.check_history(expected, **isns)
-
-
-class LLJitMixin(JitMixin):
- type_system = 'lltype'
- CPUClass = runner.LLtypeCPU
-
- @staticmethod
- def Ptr(T):
- return lltype.Ptr(T)
-
- @staticmethod
- def GcStruct(name, *fields, **kwds):
- S = lltype.GcStruct(name, *fields, **kwds)
- return S
-
- malloc = staticmethod(lltype.malloc)
- nullptr = staticmethod(lltype.nullptr)
-
- @staticmethod
- def malloc_immortal(T):
- return lltype.malloc(T, immortal=True)
-
- def _get_NODE(self):
- NODE = lltype.GcForwardReference()
- NODE.become(lltype.GcStruct('NODE', ('value', lltype.Signed),
- ('next', lltype.Ptr(NODE))))
- return NODE
-
-class OOJitMixin(JitMixin):
- type_system = 'ootype'
- #CPUClass = runner.OOtypeCPU
-
- def setup_class(cls):
- py.test.skip("ootype tests skipped for now")
-
- @staticmethod
- def Ptr(T):
- return T
-
- @staticmethod
- def GcStruct(name, *fields, **kwds):
- if 'hints' in kwds:
- kwds['_hints'] = kwds['hints']
- del kwds['hints']
- I = ootype.Instance(name, ootype.ROOT, dict(fields), **kwds)
- return I
-
- malloc = staticmethod(ootype.new)
- nullptr = staticmethod(ootype.null)
-
- @staticmethod
- def malloc_immortal(T):
- return ootype.new(T)
-
- def _get_NODE(self):
- NODE = ootype.Instance('NODE', ootype.ROOT, {})
- NODE._add_fields({'value': ootype.Signed,
- 'next': NODE})
- return NODE
-
-
-class BasicTests:
-
- def test_basic(self):
- def f(x, y):
- return x + y
- res = self.interp_operations(f, [40, 2])
- assert res == 42
-
- def test_basic_inst(self):
- class A:
- pass
- def f(n):
- a = A()
- a.x = n
- return a.x
- res = self.interp_operations(f, [42])
- assert res == 42
-
- def test_uint_floordiv(self):
- from pypy.rlib.rarithmetic import r_uint
-
- def f(a, b):
- a = r_uint(a)
- b = r_uint(b)
- return a/b
-
- res = self.interp_operations(f, [-4, 3])
- assert res == long(r_uint(-4)) // 3
-
- def test_direct_call(self):
- def g(n):
- return n + 2
- def f(a, b):
- return g(a) + g(b)
- res = self.interp_operations(f, [8, 98])
- assert res == 110
-
- def test_direct_call_with_guard(self):
- def g(n):
- if n < 0:
- return 0
- return n + 2
- def f(a, b):
- return g(a) + g(b)
- res = self.interp_operations(f, [8, 98])
- assert res == 110
-
- def test_loop(self):
- myjitdriver = JitDriver(greens = [], reds = ['x', 'y', 'res'])
- def f(x, y):
- res = 0
- while y > 0:
- myjitdriver.can_enter_jit(x=x, y=y, res=res)
- myjitdriver.jit_merge_point(x=x, y=y, res=res)
- res += x
- y -= 1
- return res
- res = self.meta_interp(f, [6, 7])
- assert res == 42
- self.check_loop_count(1)
- self.check_loops({'guard_true': 1,
- 'int_add': 1, 'int_sub': 1, 'int_gt': 1,
- 'jump': 1})
- if self.basic:
- found = 0
- for op in get_stats().loops[0]._all_operations():
- if op.getopname() == 'guard_true':
- liveboxes = op.getfailargs()
- assert len(liveboxes) == 3
- for box in liveboxes:
- assert isinstance(box, history.BoxInt)
- found += 1
- assert found == 1
-
- def test_loop_invariant_mul1(self):
- myjitdriver = JitDriver(greens = [], reds = ['y', 'res', 'x'])
- def f(x, y):
- res = 0
- while y > 0:
- myjitdriver.can_enter_jit(x=x, y=y, res=res)
- myjitdriver.jit_merge_point(x=x, y=y, res=res)
- res += x * x
- y -= 1
- return res
- res = self.meta_interp(f, [6, 7])
- assert res == 252
- self.check_loop_count(1)
- self.check_loops({'guard_true': 1,
- 'int_add': 1, 'int_sub': 1, 'int_gt': 1,
- 'jump': 1})
-
- def test_loop_invariant_mul_ovf(self):
- myjitdriver = JitDriver(greens = [], reds = ['y', 'res', 'x'])
- def f(x, y):
- res = 0
- while y > 0:
- myjitdriver.can_enter_jit(x=x, y=y, res=res)
- myjitdriver.jit_merge_point(x=x, y=y, res=res)
- b = y * 2
- res += ovfcheck(x * x) + b
- y -= 1
- return res
- res = self.meta_interp(f, [6, 7])
- assert res == 308
- self.check_loop_count(1)
- self.check_loops({'guard_true': 1,
- 'int_add': 2, 'int_sub': 1, 'int_gt': 1,
- 'int_lshift': 1,
- 'jump': 1})
-
- def test_loop_invariant_mul_bridge1(self):
- myjitdriver = JitDriver(greens = [], reds = ['y', 'res', 'x'])
- def f(x, y):
- res = 0
- while y > 0:
- myjitdriver.can_enter_jit(x=x, y=y, res=res)
- myjitdriver.jit_merge_point(x=x, y=y, res=res)
- res += x * x
- if y<16:
- x += 1
- y -= 1
- return res
- res = self.meta_interp(f, [6, 32])
- assert res == 3427
- self.check_loop_count(3)
-
- def test_loop_invariant_mul_bridge_maintaining1(self):
- myjitdriver = JitDriver(greens = [], reds = ['y', 'res', 'x'])
- def f(x, y):
- res = 0
- while y > 0:
- myjitdriver.can_enter_jit(x=x, y=y, res=res)
- myjitdriver.jit_merge_point(x=x, y=y, res=res)
- res += x * x
- if y<16:
- res += 1
- y -= 1
- return res
- res = self.meta_interp(f, [6, 32])
- assert res == 1167
- self.check_loop_count(3)
- self.check_loops({'int_add': 3, 'int_lt': 2,
- 'int_sub': 2, 'guard_false': 1,
- 'jump': 2,
- 'int_gt': 1, 'guard_true': 2})
-
-
- def test_loop_invariant_mul_bridge_maintaining2(self):
- myjitdriver = JitDriver(greens = [], reds = ['y', 'res', 'x'])
- def f(x, y):
- res = 0
- while y > 0:
- myjitdriver.can_enter_jit(x=x, y=y, res=res)
- myjitdriver.jit_merge_point(x=x, y=y, res=res)
- z = x * x
- res += z
- if y<16:
- res += z
- y -= 1
- return res
- res = self.meta_interp(f, [6, 32])
- assert res == 1692
- self.check_loop_count(3)
- self.check_loops({'int_add': 3, 'int_lt': 2,
- 'int_sub': 2, 'guard_false': 1,
- 'jump': 2,
- 'int_gt': 1, 'guard_true': 2})
-
- def test_loop_invariant_mul_bridge_maintaining3(self):
- myjitdriver = JitDriver(greens = [], reds = ['y', 'res', 'x', 'm'])
- def f(x, y, m):
- res = 0
- while y > 0:
- myjitdriver.can_enter_jit(x=x, y=y, res=res, m=m)
- myjitdriver.jit_merge_point(x=x, y=y, res=res, m=m)
- z = x * x
- res += z
- if y<m:
- res += z
- y -= 1
- return res
- res = self.meta_interp(f, [6, 32, 16])
- assert res == 1692
- self.check_loop_count(3)
- self.check_loops({'int_add': 2, 'int_lt': 1,
- 'int_sub': 2, 'guard_false': 1,
- 'jump': 2, 'int_mul': 1,
- 'int_gt': 2, 'guard_true': 2})
-
- def test_loop_invariant_intbox(self):
- myjitdriver = JitDriver(greens = [], reds = ['y', 'res', 'x'])
- class I:
- __slots__ = 'intval'
- _immutable_ = True
- def __init__(self, intval):
- self.intval = intval
- def f(i, y):
- res = 0
- x = I(i)
- while y > 0:
- myjitdriver.can_enter_jit(x=x, y=y, res=res)
- myjitdriver.jit_merge_point(x=x, y=y, res=res)
- res += x.intval * x.intval
- y -= 1
- return res
- res = self.meta_interp(f, [6, 7])
- assert res == 252
- self.check_loop_count(1)
- self.check_loops({'guard_true': 1,
- 'int_add': 1, 'int_sub': 1, 'int_gt': 1,
- 'jump': 1})
-
- def test_loops_are_transient(self):
- import gc, weakref
- myjitdriver = JitDriver(greens = [], reds = ['x', 'y', 'res'])
- def f(x, y):
- res = 0
- while y > 0:
- myjitdriver.can_enter_jit(x=x, y=y, res=res)
- myjitdriver.jit_merge_point(x=x, y=y, res=res)
- res += x
- if y%2:
- res *= 2
- y -= 1
- return res
- wr_loops = []
- old_init = history.TreeLoop.__init__.im_func
- try:
- def track_init(self, name):
- old_init(self, name)
- wr_loops.append(weakref.ref(self))
- history.TreeLoop.__init__ = track_init
- res = self.meta_interp(f, [6, 15], no_stats=True)
- finally:
- history.TreeLoop.__init__ = old_init
-
- assert res == f(6, 15)
- gc.collect()
-
- #assert not [wr for wr in wr_loops if wr()]
- for loop in [wr for wr in wr_loops if wr()]:
- assert loop().name == 'short preamble'
-
- def test_string(self):
- def f(n):
- bytecode = 'adlfkj' + chr(n)
- if n < len(bytecode):
- return bytecode[n]
- else:
- return "?"
- res = self.interp_operations(f, [1])
- assert res == ord("d") # XXX should be "d"
- res = self.interp_operations(f, [6])
- assert res == 6
- res = self.interp_operations(f, [42])
- assert res == ord("?")
-
- def test_chr2str(self):
- def f(n):
- s = chr(n)
- return s[0]
- res = self.interp_operations(f, [3])
- assert res == 3
-
- def test_unicode(self):
- def f(n):
- bytecode = u'adlfkj' + unichr(n)
- if n < len(bytecode):
- return bytecode[n]
- else:
- return u"?"
- res = self.interp_operations(f, [1])
- assert res == ord(u"d") # XXX should be "d"
- res = self.interp_operations(f, [6])
- assert res == 6
- res = self.interp_operations(f, [42])
- assert res == ord(u"?")
-
- def test_residual_call(self):
- @dont_look_inside
- def externfn(x, y):
- return x * y
- def f(n):
- return externfn(n, n+1)
- res = self.interp_operations(f, [6])
- assert res == 42
- self.check_operations_history(int_add=1, int_mul=0, call=1, guard_no_exception=0)
-
- def test_residual_call_pure(self):
- def externfn(x, y):
- return x * y
- externfn._pure_function_ = True
- def f(n):
- n = hint(n, promote=True)
- return externfn(n, n+1)
- res = self.interp_operations(f, [6])
- assert res == 42
- # CALL_PURE is not recorded in the history if all-constant args
- self.check_operations_history(int_add=0, int_mul=0,
- call=0, call_pure=0)
-
- def test_residual_call_pure_1(self):
- def externfn(x, y):
- return x * y
- externfn._pure_function_ = True
- def f(n):
- return externfn(n, n+1)
- res = self.interp_operations(f, [6])
- assert res == 42
- # CALL_PURE is recorded in the history if not-all-constant args
- self.check_operations_history(int_add=1, int_mul=0,
- call=0, call_pure=1)
-
- def test_residual_call_pure_2(self):
- myjitdriver = JitDriver(greens = [], reds = ['n'])
- def externfn(x):
- return x - 1
- externfn._pure_function_ = True
- def f(n):
- while n > 0:
- myjitdriver.can_enter_jit(n=n)
- myjitdriver.jit_merge_point(n=n)
- n = externfn(n)
- return n
- res = self.meta_interp(f, [7])
- assert res == 0
- # CALL_PURE is recorded in the history, but turned into a CALL
- # by optimizeopt.py
- self.check_loops(int_sub=0, call=1, call_pure=0)
-
- def test_constfold_call_pure(self):
- myjitdriver = JitDriver(greens = ['m'], reds = ['n'])
- def externfn(x):
- return x - 3
- externfn._pure_function_ = True
- def f(n, m):
- while n > 0:
- myjitdriver.can_enter_jit(n=n, m=m)
- myjitdriver.jit_merge_point(n=n, m=m)
- n -= externfn(m)
- return n
- res = self.meta_interp(f, [21, 5])
- assert res == -1
- # the CALL_PURE is constant-folded away by optimizeopt.py
- self.check_loops(int_sub=1, call=0, call_pure=0)
-
- def test_constfold_call_pure_2(self):
- myjitdriver = JitDriver(greens = ['m'], reds = ['n'])
- def externfn(x):
- return x - 3
- externfn._pure_function_ = True
- class V:
- def __init__(self, value):
- self.value = value
- def f(n, m):
- while n > 0:
- myjitdriver.can_enter_jit(n=n, m=m)
- myjitdriver.jit_merge_point(n=n, m=m)
- v = V(m)
- n -= externfn(v.value)
- return n
- res = self.meta_interp(f, [21, 5])
- assert res == -1
- # the CALL_PURE is constant-folded away by optimizeopt.py
- self.check_loops(int_sub=1, call=0, call_pure=0)
-
- def test_pure_function_returning_object(self):
- myjitdriver = JitDriver(greens = ['m'], reds = ['n'])
- class V:
- def __init__(self, x):
- self.x = x
- v1 = V(1)
- v2 = V(2)
- def externfn(x):
- if x:
- return v1
- else:
- return v2
- externfn._pure_function_ = True
- def f(n, m):
- while n > 0:
- myjitdriver.can_enter_jit(n=n, m=m)
- myjitdriver.jit_merge_point(n=n, m=m)
- m = V(m).x
- n -= externfn(m).x + externfn(m + m - m).x
- return n
- res = self.meta_interp(f, [21, 5])
- assert res == -1
- # the CALL_PURE is constant-folded away by optimizeopt.py
- self.check_loops(int_sub=1, call=0, call_pure=0, getfield_gc=0)
-
- def test_constant_across_mp(self):
- myjitdriver = JitDriver(greens = [], reds = ['n'])
- class X(object):
- pass
- def f(n):
- while n > -100:
- myjitdriver.can_enter_jit(n=n)
- myjitdriver.jit_merge_point(n=n)
- x = X()
- x.arg = 5
- if n <= 0: break
- n -= x.arg
- x.arg = 6 # prevents 'x.arg' from being annotated as constant
- return n
- res = self.meta_interp(f, [31])
- assert res == -4
-
- def test_stopatxpolicy(self):
- myjitdriver = JitDriver(greens = [], reds = ['y'])
- def internfn(y):
- return y * 3
- def externfn(y):
- return y % 4
- def f(y):
- while y >= 0:
- myjitdriver.can_enter_jit(y=y)
- myjitdriver.jit_merge_point(y=y)
- if y & 7:
- f = internfn
- else:
- f = externfn
- f(y)
- y -= 1
- return 42
- policy = StopAtXPolicy(externfn)
- res = self.meta_interp(f, [31], policy=policy)
- assert res == 42
- self.check_loops(int_mul=1, int_mod=0)
-
- def test_we_are_jitted(self):
- myjitdriver = JitDriver(greens = [], reds = ['y'])
- def f(y):
- while y >= 0:
- myjitdriver.can_enter_jit(y=y)
- myjitdriver.jit_merge_point(y=y)
- if we_are_jitted():
- x = 1
- else:
- x = 10
- y -= x
- return y
- assert f(55) == -5
- res = self.meta_interp(f, [55])
- assert res == -1
-
- def test_confirm_enter_jit(self):
- def confirm_enter_jit(x, y):
- return x <= 5
- myjitdriver = JitDriver(greens = ['x'], reds = ['y'],
- confirm_enter_jit = confirm_enter_jit)
- def f(x, y):
- while y >= 0:
- myjitdriver.can_enter_jit(x=x, y=y)
- myjitdriver.jit_merge_point(x=x, y=y)
- y -= x
- return y
- #
- res = self.meta_interp(f, [10, 84])
- assert res == -6
- self.check_loop_count(0)
- #
- res = self.meta_interp(f, [3, 19])
- assert res == -2
- self.check_loop_count(1)
-
- def test_can_never_inline(self):
- def can_never_inline(x):
- return x > 50
- myjitdriver = JitDriver(greens = ['x'], reds = ['y'],
- can_never_inline = can_never_inline)
- @dont_look_inside
- def marker():
- pass
- def f(x, y):
- while y >= 0:
- myjitdriver.can_enter_jit(x=x, y=y)
- myjitdriver.jit_merge_point(x=x, y=y)
- x += 1
- if x == 4 or x == 61:
- marker()
- y -= x
- return y
- #
- res = self.meta_interp(f, [3, 6], repeat=7)
- assert res == 6 - 4 - 5
- self.check_history(call=0) # because the trace starts in the middle
- #
- res = self.meta_interp(f, [60, 84], repeat=7)
- assert res == 84 - 61 - 62
- self.check_history(call=1) # because the trace starts immediately
-
- def test_format(self):
- def f(n):
- return len("<%d>" % n)
- res = self.interp_operations(f, [421])
- assert res == 5
-
- def test_switch(self):
- def f(n):
- if n == -5: return 12
- elif n == 2: return 51
- elif n == 7: return 1212
- else: return 42
- res = self.interp_operations(f, [7])
- assert res == 1212
- res = self.interp_operations(f, [12311])
- assert res == 42
-
- def test_r_uint(self):
- from pypy.rlib.rarithmetic import r_uint
- myjitdriver = JitDriver(greens = [], reds = ['y'])
- def f(y):
- y = r_uint(y)
- while y > 0:
- myjitdriver.can_enter_jit(y=y)
- myjitdriver.jit_merge_point(y=y)
- y -= 1
- return y
- res = self.meta_interp(f, [10])
- assert res == 0
-
- def test_uint_operations(self):
- from pypy.rlib.rarithmetic import r_uint
- def f(n):
- return ((r_uint(n) - 123) >> 1) <= r_uint(456)
- res = self.interp_operations(f, [50])
- assert res == False
- self.check_operations_history(int_rshift=0, uint_rshift=1,
- int_le=0, uint_le=1,
- int_sub=1)
-
- def test_uint_condition(self):
- from pypy.rlib.rarithmetic import r_uint
- def f(n):
- if ((r_uint(n) - 123) >> 1) <= r_uint(456):
- return 24
- else:
- return 12
- res = self.interp_operations(f, [50])
- assert res == 12
- self.check_operations_history(int_rshift=0, uint_rshift=1,
- int_le=0, uint_le=1,
- int_sub=1)
-
- def test_int_between(self):
- #
- def check(arg1, arg2, arg3, expect_result, **expect_operations):
- from pypy.rpython.lltypesystem import lltype
- from pypy.rpython.lltypesystem.lloperation import llop
- loc = locals().copy()
- exec py.code.Source("""
- def f(n, m, p):
- arg1 = %(arg1)s
- arg2 = %(arg2)s
- arg3 = %(arg3)s
- return llop.int_between(lltype.Bool, arg1, arg2, arg3)
- """ % locals()).compile() in loc
- res = self.interp_operations(loc['f'], [5, 6, 7])
- assert res == expect_result
- self.check_operations_history(expect_operations)
- #
- check('n', 'm', 'p', True, int_sub=2, uint_lt=1)
- check('n', 'p', 'm', False, int_sub=2, uint_lt=1)
- #
- check('n', 'm', 6, False, int_sub=2, uint_lt=1)
- #
- check('n', 4, 'p', False, int_sub=2, uint_lt=1)
- check('n', 5, 'p', True, int_sub=2, uint_lt=1)
- check('n', 8, 'p', False, int_sub=2, uint_lt=1)
- #
- check('n', 6, 7, True, int_sub=2, uint_lt=1)
- #
- check(-2, 'n', 'p', True, int_sub=2, uint_lt=1)
- check(-2, 'm', 'p', True, int_sub=2, uint_lt=1)
- check(-2, 'p', 'm', False, int_sub=2, uint_lt=1)
- #check(0, 'n', 'p', True, uint_lt=1) xxx implement me
- #check(0, 'm', 'p', True, uint_lt=1)
- #check(0, 'p', 'm', False, uint_lt=1)
- #
- check(2, 'n', 6, True, int_sub=1, uint_lt=1)
- check(2, 'm', 6, False, int_sub=1, uint_lt=1)
- check(2, 'p', 6, False, int_sub=1, uint_lt=1)
- check(5, 'n', 6, True, int_eq=1) # 6 == 5+1
- check(5, 'm', 6, False, int_eq=1) # 6 == 5+1
- #
- check(2, 6, 'm', False, int_sub=1, uint_lt=1)
- check(2, 6, 'p', True, int_sub=1, uint_lt=1)
- #
- check(2, 40, 6, False)
- check(2, 40, 60, True)
-
- def test_getfield(self):
- class A:
- pass
- a1 = A()
- a1.foo = 5
- a2 = A()
- a2.foo = 8
- def f(x):
- if x > 5:
- a = a1
- else:
- a = a2
- return a.foo * x
- res = self.interp_operations(f, [42])
- assert res == 210
- self.check_operations_history(getfield_gc=1)
-
- def test_getfield_immutable(self):
- class A:
- _immutable_ = True
- a1 = A()
- a1.foo = 5
- a2 = A()
- a2.foo = 8
- def f(x):
- if x > 5:
- a = a1
- else:
- a = a2
- return a.foo * x
- res = self.interp_operations(f, [42])
- assert res == 210
- self.check_operations_history(getfield_gc=0)
-
- def test_setfield_bool(self):
- class A:
- def __init__(self):
- self.flag = True
- myjitdriver = JitDriver(greens = [], reds = ['n', 'obj'])
- def f(n):
- obj = A()
- res = False
- while n > 0:
- myjitdriver.can_enter_jit(n=n, obj=obj)
- myjitdriver.jit_merge_point(n=n, obj=obj)
- obj.flag = False
- n -= 1
- return res
- res = self.meta_interp(f, [7])
- assert type(res) == bool
- assert not res
-
- def test_switch_dict(self):
- def f(x):
- if x == 1: return 61
- elif x == 2: return 511
- elif x == 3: return -22
- elif x == 4: return 81
- elif x == 5: return 17
- elif x == 6: return 54
- elif x == 7: return 987
- elif x == 8: return -12
- elif x == 9: return 321
- return -1
- res = self.interp_operations(f, [5])
- assert res == 17
- res = self.interp_operations(f, [15])
- assert res == -1
-
- def test_int_add_ovf(self):
- def f(x, y):
- try:
- return ovfcheck(x + y)
- except OverflowError:
- return -42
- res = self.interp_operations(f, [-100, 2])
- assert res == -98
- res = self.interp_operations(f, [1, sys.maxint])
- assert res == -42
-
- def test_int_sub_ovf(self):
- def f(x, y):
- try:
- return ovfcheck(x - y)
- except OverflowError:
- return -42
- res = self.interp_operations(f, [-100, 2])
- assert res == -102
- res = self.interp_operations(f, [1, -sys.maxint])
- assert res == -42
-
- def test_int_mul_ovf(self):
- def f(x, y):
- try:
- return ovfcheck(x * y)
- except OverflowError:
- return -42
- res = self.interp_operations(f, [-100, 2])
- assert res == -200
- res = self.interp_operations(f, [-3, sys.maxint//2])
- assert res == -42
-
- def test_mod_ovf(self):
- myjitdriver = JitDriver(greens = [], reds = ['n', 'x', 'y'])
- def f(n, x, y):
- while n > 0:
- myjitdriver.can_enter_jit(x=x, y=y, n=n)
- myjitdriver.jit_merge_point(x=x, y=y, n=n)
- n -= ovfcheck(x % y)
- return n
- res = self.meta_interp(f, [20, 1, 2])
- assert res == 0
- self.check_loops(call=0)
-
- def test_abs(self):
- myjitdriver = JitDriver(greens = [], reds = ['i', 't'])
- def f(i):
- t = 0
- while i < 10:
- myjitdriver.can_enter_jit(i=i, t=t)
- myjitdriver.jit_merge_point(i=i, t=t)
- t += abs(i)
- i += 1
- return t
- res = self.meta_interp(f, [-5])
- assert res == 5+4+3+2+1+0+1+2+3+4+5+6+7+8+9
-
- def test_float(self):
- myjitdriver = JitDriver(greens = [], reds = ['x', 'y', 'res'])
- def f(x, y):
- x = float(x)
- y = float(y)
- res = 0.0
- while y > 0.0:
- myjitdriver.can_enter_jit(x=x, y=y, res=res)
- myjitdriver.jit_merge_point(x=x, y=y, res=res)
- res += x
- y -= 1.0
- return res
- res = self.meta_interp(f, [6, 7])
- assert res == 42.0
- self.check_loop_count(1)
- self.check_loops({'guard_true': 1,
- 'float_add': 1, 'float_sub': 1, 'float_gt': 1,
- 'jump': 1})
-
- def test_print(self):
- myjitdriver = JitDriver(greens = [], reds = ['n'])
- def f(n):
- while n > 0:
- myjitdriver.can_enter_jit(n=n)
- myjitdriver.jit_merge_point(n=n)
- print n
- n -= 1
- return n
- res = self.meta_interp(f, [7])
- assert res == 0
-
- def test_bridge_from_interpreter(self):
- mydriver = JitDriver(reds = ['n'], greens = [])
-
- def f(n):
- while n > 0:
- mydriver.can_enter_jit(n=n)
- mydriver.jit_merge_point(n=n)
- n -= 1
-
- self.meta_interp(f, [20], repeat=7)
- self.check_tree_loop_count(2) # the loop and the entry path
- # we get:
- # ENTER - compile the new loop and the entry bridge
- # ENTER - compile the leaving path
- self.check_enter_count(2)
-
- def test_bridge_from_interpreter_2(self):
- # one case for backend - computing of framesize on guard failure
- mydriver = JitDriver(reds = ['n'], greens = [])
- glob = [1]
-
- def f(n):
- while n > 0:
- mydriver.can_enter_jit(n=n)
- mydriver.jit_merge_point(n=n)
- if n == 17 and glob[0]:
- glob[0] = 0
- x = n + 1
- y = n + 2
- z = n + 3
- k = n + 4
- n -= 1
- n += x + y + z + k
- n -= x + y + z + k
- n -= 1
-
- self.meta_interp(f, [20], repeat=7)
-
- def test_bridge_from_interpreter_3(self):
- # one case for backend - computing of framesize on guard failure
- mydriver = JitDriver(reds = ['n', 'x', 'y', 'z', 'k'], greens = [])
- class Global:
- pass
- glob = Global()
-
- def f(n):
- glob.x = 1
- x = 0
- y = 0
- z = 0
- k = 0
- while n > 0:
- mydriver.can_enter_jit(n=n, x=x, y=y, z=z, k=k)
- mydriver.jit_merge_point(n=n, x=x, y=y, z=z, k=k)
- x += 10
- y += 3
- z -= 15
- k += 4
- if n == 17 and glob.x:
- glob.x = 0
- x += n + 1
- y += n + 2
- z += n + 3
- k += n + 4
- n -= 1
- n -= 1
- return x + 2*y + 3*z + 5*k + 13*n
-
- res = self.meta_interp(f, [20], repeat=7)
- assert res == f(20)
-
- def test_bridge_from_interpreter_4(self):
- jitdriver = JitDriver(reds = ['n', 'k'], greens = [])
-
- def f(n, k):
- while n > 0:
- jitdriver.can_enter_jit(n=n, k=k)
- jitdriver.jit_merge_point(n=n, k=k)
- if k:
- n -= 2
- else:
- n -= 1
- return n + k
-
- from pypy.rpython.test.test_llinterp import get_interpreter, clear_tcache
- from pypy.jit.metainterp.warmspot import WarmRunnerDesc
-
- interp, graph = get_interpreter(f, [0, 0], backendopt=False,
- inline_threshold=0, type_system=self.type_system)
- clear_tcache()
- translator = interp.typer.annotator.translator
- translator.config.translation.gc = "boehm"
- warmrunnerdesc = WarmRunnerDesc(translator,
- CPUClass=self.CPUClass)
- state = warmrunnerdesc.jitdrivers_sd[0].warmstate
- state.set_param_threshold(3) # for tests
- state.set_param_trace_eagerness(0) # for tests
- warmrunnerdesc.finish()
- for n, k in [(20, 0), (20, 1)]:
- interp.eval_graph(graph, [n, k])
-
- def test_bridge_leaving_interpreter_5(self):
- mydriver = JitDriver(reds = ['n', 'x'], greens = [])
- class Global:
- pass
- glob = Global()
-
- def f(n):
- x = 0
- glob.x = 1
- while n > 0:
- mydriver.can_enter_jit(n=n, x=x)
- mydriver.jit_merge_point(n=n, x=x)
- glob.x += 1
- x += 3
- n -= 1
- glob.x += 100
- return glob.x + x
- res = self.meta_interp(f, [20], repeat=7)
- assert res == f(20)
-
- def test_instantiate_classes(self):
- class Base: pass
- class A(Base): foo = 72
- class B(Base): foo = 8
- def f(n):
- if n > 5:
- cls = A
- else:
- cls = B
- return cls().foo
- res = self.interp_operations(f, [3])
- assert res == 8
- res = self.interp_operations(f, [13])
- assert res == 72
-
- def test_instantiate_does_not_call(self):
- mydriver = JitDriver(reds = ['n', 'x'], greens = [])
- class Base: pass
- class A(Base): foo = 72
- class B(Base): foo = 8
-
- def f(n):
- x = 0
- while n > 0:
- mydriver.can_enter_jit(n=n, x=x)
- mydriver.jit_merge_point(n=n, x=x)
- if n % 2 == 0:
- cls = A
- else:
- cls = B
- inst = cls()
- x += inst.foo
- n -= 1
- return x
- res = self.meta_interp(f, [20], enable_opts='')
- assert res == f(20)
- self.check_loops(call=0)
-
- def test_zerodivisionerror(self):
- # test the case of exception-raising operation that is not delegated
- # to the backend at all: ZeroDivisionError
- #
- def f(n):
- assert n >= 0
- try:
- return ovfcheck(5 % n)
- except ZeroDivisionError:
- return -666
- except OverflowError:
- return -777
- res = self.interp_operations(f, [0])
- assert res == -666
- #
- def f(n):
- assert n >= 0
- try:
- return ovfcheck(6 // n)
- except ZeroDivisionError:
- return -667
- except OverflowError:
- return -778
- res = self.interp_operations(f, [0])
- assert res == -667
-
- def test_div_overflow(self):
- import sys
- from pypy.rpython.lltypesystem.lloperation import llop
- myjitdriver = JitDriver(greens = [], reds = ['x', 'y', 'res'])
- def f(x, y):
- res = 0
- while y > 0:
- myjitdriver.can_enter_jit(x=x, y=y, res=res)
- myjitdriver.jit_merge_point(x=x, y=y, res=res)
- try:
- res += llop.int_floordiv_ovf(lltype.Signed,
- -sys.maxint-1, x)
- x += 5
- except OverflowError:
- res += 100
- y -= 1
- return res
- res = self.meta_interp(f, [-41, 16])
- assert res == ((-sys.maxint-1) // (-41) +
- (-sys.maxint-1) // (-36) +
- (-sys.maxint-1) // (-31) +
- (-sys.maxint-1) // (-26) +
- (-sys.maxint-1) // (-21) +
- (-sys.maxint-1) // (-16) +
- (-sys.maxint-1) // (-11) +
- (-sys.maxint-1) // (-6) +
- 100 * 8)
-
- def test_isinstance(self):
- class A:
- pass
- class B(A):
- pass
- def fn(n):
- if n:
- obj = A()
- else:
- obj = B()
- return isinstance(obj, B)
- res = self.interp_operations(fn, [0])
- assert res
- self.check_operations_history(guard_class=1)
- res = self.interp_operations(fn, [1])
- assert not res
-
- def test_isinstance_2(self):
- driver = JitDriver(greens = [], reds = ['n', 'sum', 'x'])
- class A:
- pass
- class B(A):
- pass
- class C(B):
- pass
-
- def main():
- return f(5, B()) * 10 + f(5, C()) + f(5, A()) * 100
-
- def f(n, x):
- sum = 0
- while n > 0:
- driver.can_enter_jit(x=x, n=n, sum=sum)
- driver.jit_merge_point(x=x, n=n, sum=sum)
- if isinstance(x, B):
- sum += 1
- n -= 1
- return sum
-
- res = self.meta_interp(main, [])
- assert res == 55
-
- def test_assert_isinstance(self):
- class A:
- pass
- class B(A):
- pass
- def fn(n):
- # this should only be called with n != 0
- if n:
- obj = B()
- obj.a = n
- else:
- obj = A()
- obj.a = 17
- assert isinstance(obj, B)
- return obj.a
- res = self.interp_operations(fn, [1])
- assert res == 1
- self.check_operations_history(guard_class=0)
- if self.type_system == 'ootype':
- self.check_operations_history(instanceof=0)
-
- def test_r_dict(self):
- from pypy.rlib.objectmodel import r_dict
- class FooError(Exception):
- pass
- def myeq(n, m):
- return n == m
- def myhash(n):
- if n < 0:
- raise FooError
- return -n
- def f(n):
- d = r_dict(myeq, myhash)
- for i in range(10):
- d[i] = i*i
- try:
- return d[n]
- except FooError:
- return 99
- res = self.interp_operations(f, [5])
- assert res == f(5)
-
- def test_free_object(self):
- import weakref
- from pypy.rlib import rgc
- from pypy.rpython.lltypesystem.lloperation import llop
- myjitdriver = JitDriver(greens = [], reds = ['n', 'x'])
- class X(object):
- pass
- def main(n, x):
- while n > 0:
- myjitdriver.can_enter_jit(n=n, x=x)
- myjitdriver.jit_merge_point(n=n, x=x)
- n -= x.foo
- def g(n):
- x = X()
- x.foo = 2
- main(n, x)
- x.foo = 5
- return weakref.ref(x)
- def f(n):
- r = g(n)
- rgc.collect(); rgc.collect(); rgc.collect()
- return r() is None
- #
- assert f(30) == 1
- res = self.meta_interp(f, [30], no_stats=True)
- assert res == 1
-
- def test_pass_around(self):
- myjitdriver = JitDriver(greens = [], reds = ['n', 'x'])
-
- def call():
- pass
-
- def f(n, x):
- while n > 0:
- myjitdriver.can_enter_jit(n=n, x=x)
- myjitdriver.jit_merge_point(n=n, x=x)
- if n % 2:
- call()
- if n == 8:
- return x
- x = 3
- else:
- x = 5
- n -= 1
- return 0
-
- self.meta_interp(f, [40, 0])
-
- def test_const_inputargs(self):
- myjitdriver = JitDriver(greens = ['m'], reds = ['n', 'x'])
- def f(n, x):
- m = 0x7FFFFFFF
- while n > 0:
- myjitdriver.can_enter_jit(m=m, n=n, x=x)
- myjitdriver.jit_merge_point(m=m, n=n, x=x)
- x = 42
- n -= 1
- m = m >> 1
- return x
-
- res = self.meta_interp(f, [50, 1], enable_opts='')
- assert res == 42
-
- def test_set_param(self):
- myjitdriver = JitDriver(greens = [], reds = ['n', 'x'])
- def g(n):
- x = 0
- while n > 0:
- myjitdriver.can_enter_jit(n=n, x=x)
- myjitdriver.jit_merge_point(n=n, x=x)
- n -= 1
- x += n
- return x
- def f(n, threshold):
- myjitdriver.set_param('threshold', threshold)
- return g(n)
-
- res = self.meta_interp(f, [10, 3])
- assert res == 9 + 8 + 7 + 6 + 5 + 4 + 3 + 2 + 1 + 0
- self.check_tree_loop_count(2)
-
- res = self.meta_interp(f, [10, 13])
- assert res == 9 + 8 + 7 + 6 + 5 + 4 + 3 + 2 + 1 + 0
- self.check_tree_loop_count(0)
-
- def test_dont_look_inside(self):
- @dont_look_inside
- def g(a, b):
- return a + b
- def f(a, b):
- return g(a, b)
- res = self.interp_operations(f, [3, 5])
- assert res == 8
- self.check_operations_history(int_add=0, call=1)
-
- def test_listcomp(self):
- myjitdriver = JitDriver(greens = [], reds = ['x', 'y', 'lst'])
- def f(x, y):
- lst = [0, 0, 0]
- while y > 0:
- myjitdriver.can_enter_jit(x=x, y=y, lst=lst)
- myjitdriver.jit_merge_point(x=x, y=y, lst=lst)
- lst = [i+x for i in lst if i >=0]
- y -= 1
- return lst[0]
- res = self.meta_interp(f, [6, 7], listcomp=True, backendopt=True, listops=True)
- # XXX: the loop looks inefficient
- assert res == 42
-
- def test_tuple_immutable(self):
- def new(a, b):
- return a, b
- def f(a, b):
- tup = new(a, b)
- return tup[1]
- res = self.interp_operations(f, [3, 5])
- assert res == 5
- self.check_operations_history(setfield_gc=2, getfield_gc_pure=1)
-
- def test_oosend_look_inside_only_one(self):
- class A:
- pass
- class B(A):
- def g(self):
- return 123
- class C(A):
- @dont_look_inside
- def g(self):
- return 456
- def f(n):
- if n > 3:
- x = B()
- else:
- x = C()
- return x.g() + x.g()
- res = self.interp_operations(f, [10])
- assert res == 123 * 2
- res = self.interp_operations(f, [-10])
- assert res == 456 * 2
-
- def test_residual_external_call(self):
- import math
- myjitdriver = JitDriver(greens = [], reds = ['y', 'x', 'res'])
- def f(x, y):
- x = float(x)
- res = 0.0
- while y > 0:
- myjitdriver.can_enter_jit(x=x, y=y, res=res)
- myjitdriver.jit_merge_point(x=x, y=y, res=res)
- # this is an external call that the default policy ignores
- rpart, ipart = math.modf(x)
- res += ipart
- y -= 1
- return res
- res = self.meta_interp(f, [6, 7])
- assert res == 42
- self.check_loop_count(1)
- self.check_loops(call=1)
-
- def test_merge_guardclass_guardvalue(self):
- from pypy.rlib.objectmodel import instantiate
- myjitdriver = JitDriver(greens = [], reds = ['x', 'l'])
-
- class A(object):
- def g(self, x):
- return x - 5
- class B(A):
- def g(self, y):
- return y - 3
-
- a1 = A()
- a2 = A()
- b = B()
- def f(x):
- l = [a1] * 100 + [a2] * 100 + [b] * 100
- while x > 0:
- myjitdriver.can_enter_jit(x=x, l=l)
- myjitdriver.jit_merge_point(x=x, l=l)
- a = l[x]
- x = a.g(x)
- hint(a, promote=True)
- return x
- res = self.meta_interp(f, [299], listops=True)
- assert res == f(299)
- self.check_loops(guard_class=0, guard_value=2)
- self.check_loops(guard_class=0, guard_value=5, everywhere=True)
-
- def test_merge_guardnonnull_guardclass(self):
- from pypy.rlib.objectmodel import instantiate
- myjitdriver = JitDriver(greens = [], reds = ['x', 'l'])
-
- class A(object):
- def g(self, x):
- return x - 3
- class B(A):
- def g(self, y):
- return y - 5
-
- a1 = A()
- b1 = B()
- def f(x):
- l = [None] * 100 + [b1] * 100 + [a1] * 100
- while x > 0:
- myjitdriver.can_enter_jit(x=x, l=l)
- myjitdriver.jit_merge_point(x=x, l=l)
- a = l[x]
- if a:
- x = a.g(x)
- else:
- x -= 7
- return x
- res = self.meta_interp(f, [299], listops=True)
- assert res == f(299)
- self.check_loops(guard_class=0, guard_nonnull=0,
- guard_nonnull_class=2, guard_isnull=0)
- self.check_loops(guard_class=0, guard_nonnull=0,
- guard_nonnull_class=4, guard_isnull=1,
- everywhere=True)
-
- def test_merge_guardnonnull_guardvalue(self):
- from pypy.rlib.objectmodel import instantiate
- myjitdriver = JitDriver(greens = [], reds = ['x', 'l'])
-
- class A(object):
- pass
- class B(A):
- pass
-
- a1 = A()
- b1 = B()
- def f(x):
- l = [b1] * 100 + [None] * 100 + [a1] * 100
- while x > 0:
- myjitdriver.can_enter_jit(x=x, l=l)
- myjitdriver.jit_merge_point(x=x, l=l)
- a = l[x]
- if a:
- x -= 5
- else:
- x -= 7
- hint(a, promote=True)
- return x
- res = self.meta_interp(f, [299], listops=True)
- assert res == f(299)
- self.check_loops(guard_class=0, guard_nonnull=0, guard_value=1,
- guard_nonnull_class=0, guard_isnull=1)
- self.check_loops(guard_class=0, guard_nonnull=0, guard_value=3,
- guard_nonnull_class=0, guard_isnull=2,
- everywhere=True)
-
- def test_merge_guardnonnull_guardvalue_2(self):
- from pypy.rlib.objectmodel import instantiate
- myjitdriver = JitDriver(greens = [], reds = ['x', 'l'])
-
- class A(object):
- pass
- class B(A):
- pass
-
- a1 = A()
- b1 = B()
- def f(x):
- l = [None] * 100 + [b1] * 100 + [a1] * 100
- while x > 0:
- myjitdriver.can_enter_jit(x=x, l=l)
- myjitdriver.jit_merge_point(x=x, l=l)
- a = l[x]
- if a:
- x -= 5
- else:
- x -= 7
- hint(a, promote=True)
- return x
- res = self.meta_interp(f, [299], listops=True)
- assert res == f(299)
- self.check_loops(guard_class=0, guard_nonnull=0, guard_value=2,
- guard_nonnull_class=0, guard_isnull=0)
- self.check_loops(guard_class=0, guard_nonnull=0, guard_value=4,
- guard_nonnull_class=0, guard_isnull=1,
- everywhere=True)
-
- def test_merge_guardnonnull_guardclass_guardvalue(self):
- from pypy.rlib.objectmodel import instantiate
- myjitdriver = JitDriver(greens = [], reds = ['x', 'l'])
-
- class A(object):
- def g(self, x):
- return x - 3
- class B(A):
- def g(self, y):
- return y - 5
-
- a1 = A()
- a2 = A()
- b1 = B()
- def f(x):
- l = [a2] * 100 + [None] * 100 + [b1] * 100 + [a1] * 100
- while x > 0:
- myjitdriver.can_enter_jit(x=x, l=l)
- myjitdriver.jit_merge_point(x=x, l=l)
- a = l[x]
- if a:
- x = a.g(x)
- else:
- x -= 7
- hint(a, promote=True)
- return x
- res = self.meta_interp(f, [399], listops=True)
- assert res == f(399)
- self.check_loops(guard_class=0, guard_nonnull=0, guard_value=2,
- guard_nonnull_class=0, guard_isnull=0)
- self.check_loops(guard_class=0, guard_nonnull=0, guard_value=5,
- guard_nonnull_class=0, guard_isnull=1,
- everywhere=True)
-
- def test_residual_call_doesnt_lose_info(self):
- myjitdriver = JitDriver(greens = [], reds = ['x', 'y', 'l'])
-
- class A(object):
- pass
-
- globall = [""]
- @dont_look_inside
- def g(x):
- globall[0] = str(x)
- return x
-
- def f(x):
- y = A()
- y.v = x
- l = [0]
- while y.v > 0:
- myjitdriver.can_enter_jit(x=x, y=y, l=l)
- myjitdriver.jit_merge_point(x=x, y=y, l=l)
- l[0] = y.v
- lc = l[0]
- y.v = g(y.v) - y.v/y.v + lc/l[0] - 1
- return y.v
- res = self.meta_interp(f, [20], listops=True)
- self.check_loops(getfield_gc=0, getarrayitem_gc=0)
- self.check_loops(getfield_gc=1, getarrayitem_gc=0, everywhere=True)
-
- def test_guard_isnull_nonnull(self):
- myjitdriver = JitDriver(greens = [], reds = ['x', 'res'])
- class A(object):
- pass
-
- @dont_look_inside
- def create(x):
- if x >= -40:
- return A()
- return None
-
- def f(x):
- res = 0
- while x > 0:
- myjitdriver.can_enter_jit(x=x, res=res)
- myjitdriver.jit_merge_point(x=x, res=res)
- obj = create(x-1)
- if obj is not None:
- res += 1
- obj2 = create(x-1000)
- if obj2 is None:
- res += 1
- x -= 1
- return res
- res = self.meta_interp(f, [21])
- assert res == 42
- self.check_loops(guard_nonnull=1, guard_isnull=1)
-
- def test_loop_invariant1(self):
- myjitdriver = JitDriver(greens = [], reds = ['x', 'res'])
- class A(object):
- pass
- a = A()
- a.current_a = A()
- a.current_a.x = 1
- @loop_invariant
- def f():
- return a.current_a
-
- def g(x):
- res = 0
- while x > 0:
- myjitdriver.can_enter_jit(x=x, res=res)
- myjitdriver.jit_merge_point(x=x, res=res)
- res += f().x
- res += f().x
- res += f().x
- x -= 1
- a.current_a = A()
- a.current_a.x = 2
- return res
- res = self.meta_interp(g, [21])
- assert res == 3 * 21
- self.check_loops(call=0)
- self.check_loops(call=1, everywhere=True)
-
- def test_bug_optimizeopt_mutates_ops(self):
- myjitdriver = JitDriver(greens = [], reds = ['x', 'res', 'const', 'a'])
- class A(object):
- pass
- class B(A):
- pass
-
- glob = A()
- glob.a = None
- def f(x):
- res = 0
- a = A()
- a.x = 0
- glob.a = A()
- const = 2
- while x > 0:
- myjitdriver.can_enter_jit(x=x, res=res, a=a, const=const)
- myjitdriver.jit_merge_point(x=x, res=res, a=a, const=const)
- if type(glob.a) is B:
- res += 1
- if a is None:
- a = A()
- a.x = x
- glob.a = B()
- const = 2
- else:
- const = hint(const, promote=True)
- x -= const
- res += a.x
- a = None
- glob.a = A()
- const = 1
- return res
- res = self.meta_interp(f, [21])
- assert res == f(21)
-
- def test_getitem_indexerror(self):
- lst = [10, 4, 9, 16]
- def f(n):
- try:
- return lst[n]
- except IndexError:
- return -2
- res = self.interp_operations(f, [2])
- assert res == 9
- res = self.interp_operations(f, [4])
- assert res == -2
- res = self.interp_operations(f, [-4])
- assert res == 10
- res = self.interp_operations(f, [-5])
- assert res == -2
-
- def test_guard_always_changing_value(self):
- myjitdriver = JitDriver(greens = [], reds = ['x'])
- class A:
- pass
- def f(x):
- while x > 0:
- myjitdriver.can_enter_jit(x=x)
- myjitdriver.jit_merge_point(x=x)
- a = A()
- hint(a, promote=True)
- x -= 1
- self.meta_interp(f, [50])
- self.check_loop_count(1)
- # this checks that the logic triggered by make_a_counter_per_value()
- # works and prevents generating tons of bridges
-
- def test_swap_values(self):
- def f(x, y):
- if x > 5:
- x, y = y, x
- return x - y
- res = self.interp_operations(f, [10, 2])
- assert res == -8
- res = self.interp_operations(f, [3, 2])
- assert res == 1
-
- def test_raw_malloc_and_access(self):
- from pypy.rpython.lltypesystem import rffi
-
- TP = rffi.CArray(lltype.Signed)
-
- def f(n):
- a = lltype.malloc(TP, n, flavor='raw')
- a[0] = n
- res = a[0]
- lltype.free(a, flavor='raw')
- return res
-
- res = self.interp_operations(f, [10])
- assert res == 10
-
- def test_raw_malloc_and_access_float(self):
- from pypy.rpython.lltypesystem import rffi
-
- TP = rffi.CArray(lltype.Float)
-
- def f(n, f):
- a = lltype.malloc(TP, n, flavor='raw')
- a[0] = f
- res = a[0]
- lltype.free(a, flavor='raw')
- return res
-
- res = self.interp_operations(f, [10, 3.5])
- assert res == 3.5
-
- def test_jit_debug(self):
- myjitdriver = JitDriver(greens = [], reds = ['x'])
- class A:
- pass
- def f(x):
- while x > 0:
- myjitdriver.can_enter_jit(x=x)
- myjitdriver.jit_merge_point(x=x)
- jit_debug("hi there:", x)
- jit_debug("foobar")
- x -= 1
- return x
- res = self.meta_interp(f, [8])
- assert res == 0
- self.check_loops(jit_debug=2)
-
- def test_assert_green(self):
- def f(x, promote):
- if promote:
- x = hint(x, promote=True)
- assert_green(x)
- return x
- res = self.interp_operations(f, [8, 1])
- assert res == 8
- py.test.raises(AssertGreenFailed, self.interp_operations, f, [8, 0])
-
- def test_multiple_specialied_versions1(self):
- myjitdriver = JitDriver(greens = [], reds = ['y', 'x', 'res'])
- class Base:
- def __init__(self, val):
- self.val = val
- class A(Base):
- def binop(self, other):
- return A(self.val + other.val)
- class B(Base):
- def binop(self, other):
- return B(self.val * other.val)
- def f(x, y):
- res = x
- while y > 0:
- myjitdriver.can_enter_jit(y=y, x=x, res=res)
- myjitdriver.jit_merge_point(y=y, x=x, res=res)
- res = res.binop(x)
- y -= 1
- return res
- def g(x, y):
- a1 = f(A(x), y)
- a2 = f(A(x), y)
- b1 = f(B(x), y)
- b2 = f(B(x), y)
- assert a1.val == a2.val
- assert b1.val == b2.val
- return a1.val + b1.val
- res = self.meta_interp(g, [6, 7])
- assert res == 6*8 + 6**8
- self.check_loop_count(5)
- self.check_loops({'guard_true': 2,
- 'int_add': 1, 'int_mul': 1, 'int_sub': 2,
- 'int_gt': 2, 'jump': 2})
-
- def test_multiple_specialied_versions_array(self):
- myjitdriver = JitDriver(greens = [], reds = ['idx', 'y', 'x', 'res',
- 'array'])
- class Base:
- def __init__(self, val):
- self.val = val
- class A(Base):
- def binop(self, other):
- return A(self.val + other.val)
- class B(Base):
- def binop(self, other):
- return B(self.val - other.val)
- def f(x, y):
- res = x
- array = [1, 2, 3]
- array[1] = 7
- idx = 0
- while y > 0:
- myjitdriver.can_enter_jit(idx=idx, y=y, x=x, res=res,
- array=array)
- myjitdriver.jit_merge_point(idx=idx, y=y, x=x, res=res,
- array=array)
- res = res.binop(x)
- res.val += array[idx] + array[1]
- if y < 7:
- idx = 2
- y -= 1
- return res
- def g(x, y):
- a1 = f(A(x), y)
- a2 = f(A(x), y)
- b1 = f(B(x), y)
- b2 = f(B(x), y)
- assert a1.val == a2.val
- assert b1.val == b2.val
- return a1.val + b1.val
- res = self.meta_interp(g, [6, 14])
- assert res == g(6, 14)
- self.check_loop_count(9)
- self.check_loops(getarrayitem_gc=6, everywhere=True)
-
- def test_multiple_specialied_versions_bridge(self):
- myjitdriver = JitDriver(greens = [], reds = ['y', 'x', 'z', 'res'])
- class Base:
- def __init__(self, val):
- self.val = val
- def getval(self):
- return self.val
- class A(Base):
- def binop(self, other):
- return A(self.getval() + other.getval())
- class B(Base):
- def binop(self, other):
- return B(self.getval() * other.getval())
- def f(x, y, z):
- res = x
- while y > 0:
- myjitdriver.can_enter_jit(y=y, x=x, z=z, res=res)
- myjitdriver.jit_merge_point(y=y, x=x, z=z, res=res)
- res = res.binop(x)
- y -= 1
- if y < 7:
- x = z
- return res
- def g(x, y):
- a1 = f(A(x), y, A(x))
- a2 = f(A(x), y, A(x))
- assert a1.val == a2.val
- b1 = f(B(x), y, B(x))
- b2 = f(B(x), y, B(x))
- assert b1.val == b2.val
- c1 = f(B(x), y, A(x))
- c2 = f(B(x), y, A(x))
- assert c1.val == c2.val
- d1 = f(A(x), y, B(x))
- d2 = f(A(x), y, B(x))
- assert d1.val == d2.val
- return a1.val + b1.val + c1.val + d1.val
- res = self.meta_interp(g, [3, 14])
- assert res == g(3, 14)
-
- def test_failing_inlined_guard(self):
- myjitdriver = JitDriver(greens = [], reds = ['y', 'x', 'z', 'res'])
- class Base:
- def __init__(self, val):
- self.val = val
- def getval(self):
- return self.val
- class A(Base):
- def binop(self, other):
- return A(self.getval() + other.getval())
- class B(Base):
- def binop(self, other):
- return B(self.getval() * other.getval())
- def f(x, y, z):
- res = x
- while y > 0:
- myjitdriver.can_enter_jit(y=y, x=x, z=z, res=res)
- myjitdriver.jit_merge_point(y=y, x=x, z=z, res=res)
- res = res.binop(x)
- y -= 1
- if y < 8:
- x = z
- return res
- def g(x, y):
- c1 = f(A(x), y, B(x))
- c2 = f(A(x), y, B(x))
- assert c1.val == c2.val
- return c1.val
- res = self.meta_interp(g, [3, 16])
- assert res == g(3, 16)
-
- def test_inlined_guard_in_short_preamble(self):
- myjitdriver = JitDriver(greens = [], reds = ['y', 'x', 'z', 'res'])
- class A:
- def __init__(self, val):
- self.val = val
- def getval(self):
- return self.val
- def binop(self, other):
- return A(self.getval() + other.getval())
- def f(x, y, z):
- res = x
- while y > 0:
- myjitdriver.can_enter_jit(y=y, x=x, z=z, res=res)
- myjitdriver.jit_merge_point(y=y, x=x, z=z, res=res)
- res = res.binop(x)
- y -= 1
- if y < 7:
- x = z
- return res
- def g(x, y):
- a1 = f(A(x), y, A(x))
- a2 = f(A(x), y, A(x))
- assert a1.val == a2.val
- return a1.val
- res = self.meta_interp(g, [3, 14])
- assert res == g(3, 14)
-
- def test_specialied_bridge(self):
- myjitdriver = JitDriver(greens = [], reds = ['y', 'x', 'res'])
- class A:
- def __init__(self, val):
- self.val = val
- def binop(self, other):
- return A(self.val + other.val)
- def f(x, y):
- res = A(0)
- while y > 0:
- myjitdriver.can_enter_jit(y=y, x=x, res=res)
- myjitdriver.jit_merge_point(y=y, x=x, res=res)
- res = res.binop(A(y))
- if y<7:
- res = x
- y -= 1
- return res
- def g(x, y):
- a1 = f(A(x), y)
- a2 = f(A(x), y)
- assert a1.val == a2.val
- return a1.val
- res = self.meta_interp(g, [6, 14])
- assert res == g(6, 14)
-
- def test_specialied_bridge_const(self):
- myjitdriver = JitDriver(greens = [], reds = ['y', 'const', 'x', 'res'])
- class A:
- def __init__(self, val):
- self.val = val
- def binop(self, other):
- return A(self.val + other.val)
- def f(x, y):
- res = A(0)
- const = 7
- while y > 0:
- myjitdriver.can_enter_jit(y=y, x=x, res=res, const=const)
- myjitdriver.jit_merge_point(y=y, x=x, res=res, const=const)
- const = hint(const, promote=True)
- res = res.binop(A(const))
- if y<7:
- res = x
- y -= 1
- return res
- def g(x, y):
- a1 = f(A(x), y)
- a2 = f(A(x), y)
- assert a1.val == a2.val
- return a1.val
- res = self.meta_interp(g, [6, 14])
- assert res == g(6, 14)
-
- def test_multiple_specialied_zigzag(self):
- myjitdriver = JitDriver(greens = [], reds = ['y', 'x', 'res'])
- class Base:
- def __init__(self, val):
- self.val = val
- class A(Base):
- def binop(self, other):
- return A(self.val + other.val)
- def switch(self):
- return B(self.val)
- class B(Base):
- def binop(self, other):
- return B(self.val * other.val)
- def switch(self):
- return A(self.val)
- def f(x, y):
- res = x
- while y > 0:
- myjitdriver.can_enter_jit(y=y, x=x, res=res)
- myjitdriver.jit_merge_point(y=y, x=x, res=res)
- if y % 4 == 0:
- res = res.switch()
- res = res.binop(x)
- y -= 1
- return res
- def g(x, y):
- a1 = f(A(x), y)
- a2 = f(A(x), y)
- b1 = f(B(x), y)
- b2 = f(B(x), y)
- assert a1.val == a2.val
- assert b1.val == b2.val
- return a1.val + b1.val
- res = self.meta_interp(g, [3, 23])
- assert res == 7068153
- self.check_loop_count(6)
- self.check_loops(guard_true=4, guard_class=0, int_add=2, int_mul=2,
- guard_false=2)
-
- def test_dont_trace_every_iteration(self):
- myjitdriver = JitDriver(greens = [], reds = ['a', 'b', 'i', 'sa'])
-
- def main(a, b):
- i = sa = 0
- #while i < 200:
- while i < 200:
- myjitdriver.can_enter_jit(a=a, b=b, i=i, sa=sa)
- myjitdriver.jit_merge_point(a=a, b=b, i=i, sa=sa)
- if a > 0: pass
- if b < 2: pass
- sa += a % b
- i += 1
- return sa
- def g():
- return main(10, 20) + main(-10, -20)
- res = self.meta_interp(g, [])
- assert res == g()
- self.check_enter_count(2)
-
- def test_current_trace_length(self):
- myjitdriver = JitDriver(greens = ['g'], reds = ['x'])
- @dont_look_inside
- def residual():
- print "hi there"
- @unroll_safe
- def loop(g):
- y = 0
- while y < g:
- residual()
- y += 1
- def f(x, g):
- n = 0
- while x > 0:
- myjitdriver.can_enter_jit(x=x, g=g)
- myjitdriver.jit_merge_point(x=x, g=g)
- loop(g)
- x -= 1
- n = current_trace_length()
- return n
- res = self.meta_interp(f, [5, 8])
- assert 14 < res < 42
- res = self.meta_interp(f, [5, 2])
- assert 4 < res < 14
-
- def test_compute_identity_hash(self):
- from pypy.rlib.objectmodel import compute_identity_hash
- class A(object):
- pass
- def f():
- a = A()
- return compute_identity_hash(a) == compute_identity_hash(a)
- res = self.interp_operations(f, [])
- assert res
- # a "did not crash" kind of test
-
- def test_compute_unique_id(self):
- from pypy.rlib.objectmodel import compute_unique_id
- class A(object):
- pass
- def f():
- a1 = A()
- a2 = A()
- return (compute_unique_id(a1) == compute_unique_id(a1) and
- compute_unique_id(a1) != compute_unique_id(a2))
- res = self.interp_operations(f, [])
- assert res
-
- def test_wrap_around_add(self):
- myjitdriver = JitDriver(greens = [], reds = ['x', 'n'])
- class A:
- pass
- def f(x):
- n = 0
- while x > 0:
- myjitdriver.can_enter_jit(x=x, n=n)
- myjitdriver.jit_merge_point(x=x, n=n)
- x += 1
- n += 1
- return n
- res = self.meta_interp(f, [sys.maxint-10])
- assert res == 11
- self.check_tree_loop_count(2)
-
- def test_wrap_around_mul(self):
- myjitdriver = JitDriver(greens = [], reds = ['x', 'n'])
- class A:
- pass
- def f(x):
- n = 0
- while x > 0:
- myjitdriver.can_enter_jit(x=x, n=n)
- myjitdriver.jit_merge_point(x=x, n=n)
- x *= 2
- n += 1
- return n
- res = self.meta_interp(f, [sys.maxint>>10])
- assert res == 11
- self.check_tree_loop_count(2)
-
- def test_wrap_around_sub(self):
- myjitdriver = JitDriver(greens = [], reds = ['x', 'n'])
- class A:
- pass
- def f(x):
- n = 0
- while x < 0:
- myjitdriver.can_enter_jit(x=x, n=n)
- myjitdriver.jit_merge_point(x=x, n=n)
- x -= 1
- n += 1
- return n
- res = self.meta_interp(f, [10-sys.maxint])
- assert res == 12
- self.check_tree_loop_count(2)
-
-
-
-class TestOOtype(BasicTests, OOJitMixin):
-
- def test_oohash(self):
- def f(n):
- s = ootype.oostring(n, -1)
- return s.ll_hash()
- res = self.interp_operations(f, [5])
- assert res == ootype.oostring(5, -1).ll_hash()
-
- def test_identityhash(self):
- A = ootype.Instance("A", ootype.ROOT)
- def f():
- obj1 = ootype.new(A)
- obj2 = ootype.new(A)
- return ootype.identityhash(obj1) == ootype.identityhash(obj2)
- assert not f()
- res = self.interp_operations(f, [])
- assert not res
-
- def test_oois(self):
- A = ootype.Instance("A", ootype.ROOT)
- def f(n):
- obj1 = ootype.new(A)
- if n:
- obj2 = obj1
- else:
- obj2 = ootype.new(A)
- return obj1 is obj2
- res = self.interp_operations(f, [0])
- assert not res
- res = self.interp_operations(f, [1])
- assert res
-
- def test_oostring_instance(self):
- A = ootype.Instance("A", ootype.ROOT)
- B = ootype.Instance("B", ootype.ROOT)
- def f(n):
- obj1 = ootype.new(A)
- obj2 = ootype.new(B)
- s1 = ootype.oostring(obj1, -1)
- s2 = ootype.oostring(obj2, -1)
- ch1 = s1.ll_stritem_nonneg(1)
- ch2 = s2.ll_stritem_nonneg(1)
- return ord(ch1) + ord(ch2)
- res = self.interp_operations(f, [0])
- assert res == ord('A') + ord('B')
-
- def test_subclassof(self):
- A = ootype.Instance("A", ootype.ROOT)
- B = ootype.Instance("B", A)
- clsA = ootype.runtimeClass(A)
- clsB = ootype.runtimeClass(B)
- myjitdriver = JitDriver(greens = [], reds = ['n', 'flag', 'res'])
-
- def getcls(flag):
- if flag:
- return clsA
- else:
- return clsB
-
- def f(flag, n):
- res = True
- while n > -100:
- myjitdriver.can_enter_jit(n=n, flag=flag, res=res)
- myjitdriver.jit_merge_point(n=n, flag=flag, res=res)
- cls = getcls(flag)
- n -= 1
- res = ootype.subclassof(cls, clsB)
- return res
-
- res = self.meta_interp(f, [1, 100],
- policy=StopAtXPolicy(getcls),
- enable_opts='')
- assert not res
-
- res = self.meta_interp(f, [0, 100],
- policy=StopAtXPolicy(getcls),
- enable_opts='')
- assert res
-
-class BaseLLtypeTests(BasicTests):
-
- def test_identityhash(self):
- A = lltype.GcStruct("A")
- def f():
- obj1 = lltype.malloc(A)
- obj2 = lltype.malloc(A)
- return lltype.identityhash(obj1) == lltype.identityhash(obj2)
- assert not f()
- res = self.interp_operations(f, [])
- assert not res
-
- def test_oops_on_nongc(self):
- from pypy.rpython.lltypesystem import lltype
-
- TP = lltype.Struct('x')
- def f(i1, i2):
- p1 = prebuilt[i1]
- p2 = prebuilt[i2]
- a = p1 is p2
- b = p1 is not p2
- c = bool(p1)
- d = not bool(p2)
- return 1000*a + 100*b + 10*c + d
- prebuilt = [lltype.malloc(TP, flavor='raw', immortal=True)] * 2
- expected = f(0, 1)
- assert self.interp_operations(f, [0, 1]) == expected
-
- def test_casts(self):
- py.test.skip("xxx fix or kill")
- if not self.basic:
- py.test.skip("test written in a style that "
- "means it's frontend only")
- from pypy.rpython.lltypesystem import lltype, llmemory, rffi
-
- TP = lltype.GcStruct('S1')
- def f(p):
- n = lltype.cast_ptr_to_int(p)
- return n
- x = lltype.malloc(TP)
- xref = lltype.cast_opaque_ptr(llmemory.GCREF, x)
- res = self.interp_operations(f, [xref])
- y = llmemory.cast_ptr_to_adr(x)
- y = llmemory.cast_adr_to_int(y)
- assert rffi.get_real_int(res) == rffi.get_real_int(y)
- #
- TP = lltype.Struct('S2')
- prebuilt = [lltype.malloc(TP, immortal=True),
- lltype.malloc(TP, immortal=True)]
- def f(x):
- p = prebuilt[x]
- n = lltype.cast_ptr_to_int(p)
- return n
- res = self.interp_operations(f, [1])
- y = llmemory.cast_ptr_to_adr(prebuilt[1])
- y = llmemory.cast_adr_to_int(y)
- assert rffi.get_real_int(res) == rffi.get_real_int(y)
-
- def test_collapsing_ptr_eq(self):
- S = lltype.GcStruct('S')
- p = lltype.malloc(S)
- driver = JitDriver(greens = [], reds = ['n', 'x'])
-
- def f(n, x):
- while n > 0:
- driver.can_enter_jit(n=n, x=x)
- driver.jit_merge_point(n=n, x=x)
- if x:
- n -= 1
- n -= 1
-
- def main():
- f(10, p)
- f(10, lltype.nullptr(S))
-
- self.meta_interp(main, [])
-
- def test_enable_opts(self):
- jitdriver = JitDriver(greens = [], reds = ['a'])
-
- class A(object):
- def __init__(self, i):
- self.i = i
-
- def f():
- a = A(0)
-
- while a.i < 10:
- jitdriver.jit_merge_point(a=a)
- jitdriver.can_enter_jit(a=a)
- a = A(a.i + 1)
-
- self.meta_interp(f, [])
- self.check_loops(new_with_vtable=0)
- self.meta_interp(f, [], enable_opts='')
- self.check_loops(new_with_vtable=1)
-
-class TestLLtype(BaseLLtypeTests, LLJitMixin):
- pass
diff --git a/pypy/jit/metainterp/optimizeopt/intbounds.py b/pypy/jit/metainterp/optimizeopt/intbounds.py
--- a/pypy/jit/metainterp/optimizeopt/intbounds.py
+++ b/pypy/jit/metainterp/optimizeopt/intbounds.py
@@ -205,7 +205,7 @@
v2 = self.getvalue(op.getarg(1))
if v1.intbound.known_lt(v2.intbound):
self.make_constant_int(op.result, 1)
- elif v1.intbound.known_ge(v2.intbound):
+ elif v1.intbound.known_ge(v2.intbound) or v1 is v2:
self.make_constant_int(op.result, 0)
else:
self.emit_operation(op)
@@ -215,7 +215,7 @@
v2 = self.getvalue(op.getarg(1))
if v1.intbound.known_gt(v2.intbound):
self.make_constant_int(op.result, 1)
- elif v1.intbound.known_le(v2.intbound):
+ elif v1.intbound.known_le(v2.intbound) or v1 is v2:
self.make_constant_int(op.result, 0)
else:
self.emit_operation(op)
@@ -223,7 +223,7 @@
def optimize_INT_LE(self, op):
v1 = self.getvalue(op.getarg(0))
v2 = self.getvalue(op.getarg(1))
- if v1.intbound.known_le(v2.intbound):
+ if v1.intbound.known_le(v2.intbound) or v1 is v2:
self.make_constant_int(op.result, 1)
elif v1.intbound.known_gt(v2.intbound):
self.make_constant_int(op.result, 0)
@@ -233,7 +233,7 @@
def optimize_INT_GE(self, op):
v1 = self.getvalue(op.getarg(0))
v2 = self.getvalue(op.getarg(1))
- if v1.intbound.known_ge(v2.intbound):
+ if v1.intbound.known_ge(v2.intbound) or v1 is v2:
self.make_constant_int(op.result, 1)
elif v1.intbound.known_lt(v2.intbound):
self.make_constant_int(op.result, 0)
diff --git a/pypy/objspace/flow/test/test_objspace.py b/pypy/objspace/flow/test/test_objspace.py
--- a/pypy/objspace/flow/test/test_objspace.py
+++ b/pypy/objspace/flow/test/test_objspace.py
@@ -1,8 +1,8 @@
from __future__ import with_statement
import new
import py
-from pypy.objspace.flow.model import Constant, Block, Link, Variable, traverse
-from pypy.objspace.flow.model import flatten, mkentrymap, c_last_exception
+from pypy.objspace.flow.model import Constant, Block, Link, Variable
+from pypy.objspace.flow.model import mkentrymap, c_last_exception
from pypy.interpreter.argument import Arguments
from pypy.translator.simplify import simplify_graph
from pypy.objspace.flow.objspace import FlowObjSpace, error
@@ -37,12 +37,10 @@
def all_operations(self, graph):
result = {}
- def visit(node):
- if isinstance(node, Block):
- for op in node.operations:
- result.setdefault(op.opname, 0)
- result[op.opname] += 1
- traverse(visit, graph)
+ for node in graph.iterblocks():
+ for op in node.operations:
+ result.setdefault(op.opname, 0)
+ result[op.opname] += 1
return result
@@ -246,12 +244,9 @@
x = self.codetest(self.implicitException)
simplify_graph(x)
self.show(x)
- def cannot_reach_exceptblock(link):
- if isinstance(link, Link):
- assert link.target is not x.exceptblock
- traverse(cannot_reach_exceptblock, x)
+ for link in x.iterlinks():
+ assert link.target is not x.exceptblock
-
def implicitAttributeError(x):
try:
x = getattr(x, "y")
@@ -263,10 +258,8 @@
x = self.codetest(self.implicitAttributeError)
simplify_graph(x)
self.show(x)
- def cannot_reach_exceptblock(link):
- if isinstance(link, Link):
- assert link.target is not x.exceptblock
- traverse(cannot_reach_exceptblock, x)
+ for link in x.iterlinks():
+ assert link.target is not x.exceptblock
#__________________________________________________________
def implicitException_int_and_id(x):
@@ -311,14 +304,12 @@
simplify_graph(x)
self.show(x)
found = {}
- def find_exceptions(link):
- if isinstance(link, Link):
+ for link in x.iterlinks():
if link.target is x.exceptblock:
if isinstance(link.args[0], Constant):
found[link.args[0].value] = True
else:
found[link.exitcase] = None
- traverse(find_exceptions, x)
assert found == {IndexError: True, KeyError: True, Exception: None}
def reraiseAnything(x):
@@ -332,12 +323,10 @@
simplify_graph(x)
self.show(x)
found = {}
- def find_exceptions(link):
- if isinstance(link, Link):
+ for link in x.iterlinks():
if link.target is x.exceptblock:
assert isinstance(link.args[0], Constant)
found[link.args[0].value] = True
- traverse(find_exceptions, x)
assert found == {ValueError: True, ZeroDivisionError: True, OverflowError: True}
def loop_in_bare_except_bug(lst):
@@ -521,11 +510,9 @@
def test_jump_target_specialization(self):
x = self.codetest(self.jump_target_specialization)
- def visitor(node):
- if isinstance(node, Block):
- for op in node.operations:
- assert op.opname != 'mul', "mul should have disappeared"
- traverse(visitor, x)
+ for block in x.iterblocks():
+ for op in block.operations:
+ assert op.opname != 'mul', "mul should have disappeared"
#__________________________________________________________
def highly_branching_example(a,b,c,d,e,f,g,h,i,j):
@@ -573,7 +560,8 @@
def test_highly_branching_example(self):
x = self.codetest(self.highly_branching_example)
- assert len(flatten(x)) < 60 # roughly 20 blocks + 30 links
+ # roughly 20 blocks + 30 links
+ assert len(list(x.iterblocks())) + len(list(x.iterlinks())) < 60
#__________________________________________________________
def test_unfrozen_user_class1(self):
@@ -589,11 +577,9 @@
graph = self.codetest(f)
results = []
- def visit(link):
- if isinstance(link, Link):
- if link.target == graph.returnblock:
- results.extend(link.args)
- traverse(visit, graph)
+ for link in graph.iterlinks():
+ if link.target == graph.returnblock:
+ results.extend(link.args)
assert len(results) == 2
def test_unfrozen_user_class2(self):
@@ -607,11 +593,9 @@
graph = self.codetest(f)
results = []
- def visit(link):
- if isinstance(link, Link):
- if link.target == graph.returnblock:
- results.extend(link.args)
- traverse(visit, graph)
+ for link in graph.iterlinks():
+ if link.target == graph.returnblock:
+ results.extend(link.args)
assert not isinstance(results[0], Constant)
def test_frozen_user_class1(self):
@@ -630,11 +614,9 @@
graph = self.codetest(f)
results = []
- def visit(link):
- if isinstance(link, Link):
- if link.target == graph.returnblock:
- results.extend(link.args)
- traverse(visit, graph)
+ for link in graph.iterlinks():
+ if link.target == graph.returnblock:
+ results.extend(link.args)
assert len(results) == 1
def test_frozen_user_class2(self):
@@ -650,11 +632,9 @@
graph = self.codetest(f)
results = []
- def visit(link):
- if isinstance(link, Link):
- if link.target == graph.returnblock:
- results.extend(link.args)
- traverse(visit, graph)
+ for link in graph.iterlinks():
+ if link.target == graph.returnblock:
+ results.extend(link.args)
assert results == [Constant(4)]
def test_const_star_call(self):
@@ -663,14 +643,9 @@
def f():
return g(1,*(2,3))
graph = self.codetest(f)
- call_args = []
- def visit(block):
- if isinstance(block, Block):
- for op in block.operations:
- if op.opname == "call_args":
- call_args.append(op)
- traverse(visit, graph)
- assert not call_args
+ for block in graph.iterblocks():
+ for op in block.operations:
+ assert not op.opname == "call_args"
def test_catch_importerror_1(self):
def f():
@@ -997,11 +972,9 @@
simplify_graph(x)
self.show(x)
excfound = []
- def check(link):
- if isinstance(link, Link):
- if link.target is x.exceptblock:
- excfound.append(link.exitcase)
- traverse(check, x)
+ for link in x.iterlinks():
+ if link.target is x.exceptblock:
+ excfound.append(link.exitcase)
assert len(excfound) == 2
excfound.sort()
expected = [Exception, AttributeError]
@@ -1019,11 +992,9 @@
simplify_graph(x)
self.show(x)
excfound = []
- def check(link):
- if isinstance(link, Link):
- if link.target is x.exceptblock:
- excfound.append(link.exitcase)
- traverse(check, x)
+ for link in x.iterlinks():
+ if link.target is x.exceptblock:
+ excfound.append(link.exitcase)
assert len(excfound) == 2
excfound.sort()
expected = [Exception, TypeError]
diff --git a/lib_pypy/pyrepl/readline.py b/lib_pypy/pyrepl/readline.py
--- a/lib_pypy/pyrepl/readline.py
+++ b/lib_pypy/pyrepl/readline.py
@@ -381,6 +381,9 @@
def _setup():
global _old_raw_input
+ if _old_raw_input is not None:
+ return # don't run _setup twice
+
try:
f_in = sys.stdin.fileno()
f_out = sys.stdout.fileno()
@@ -401,4 +404,5 @@
_old_raw_input = __builtin__.raw_input
__builtin__.raw_input = _wrapper.raw_input
+_old_raw_input = None
_setup()
diff --git a/pypy/jit/backend/x86/test/test_assembler.py b/pypy/jit/backend/x86/test/test_assembler.py
--- a/pypy/jit/backend/x86/test/test_assembler.py
+++ b/pypy/jit/backend/x86/test/test_assembler.py
@@ -140,7 +140,7 @@
xmmregisters = lltype.malloc(rffi.LONGP.TO, 16+ACTUAL_CPU.NUM_REGS+1,
flavor='raw', immortal=True)
registers = rffi.ptradd(xmmregisters, 16)
- stacklen = baseloc + 10
+ stacklen = baseloc + 30
stack = lltype.malloc(rffi.LONGP.TO, stacklen, flavor='raw',
immortal=True)
expected_ints = [0] * len(content)
diff --git a/pypy/translator/backendopt/test/test_malloc.py b/pypy/translator/backendopt/test/test_malloc.py
--- a/pypy/translator/backendopt/test/test_malloc.py
+++ b/pypy/translator/backendopt/test/test_malloc.py
@@ -3,7 +3,7 @@
from pypy.translator.backendopt.all import backend_optimizations
from pypy.translator.translator import TranslationContext, graphof
from pypy.translator import simplify
-from pypy.objspace.flow.model import checkgraph, flatten, Block, mkentrymap
+from pypy.objspace.flow.model import checkgraph, Block, mkentrymap
from pypy.rpython.llinterp import LLInterpreter
from pypy.rpython.lltypesystem import lltype, llmemory
from pypy.rpython.ootypesystem import ootype
@@ -22,8 +22,7 @@
remover = cls.MallocRemover()
checkgraph(graph)
count1 = count2 = 0
- for node in flatten(graph):
- if isinstance(node, Block):
+ for node in graph.iterblocks():
for op in node.operations:
if op.opname == cls.MallocRemover.MALLOC_OP:
S = op.args[0].value
@@ -47,7 +46,7 @@
auto_inline_graphs(t, t.graphs, inline)
if option.view:
t.view()
- # to detect missing keepalives and broken intermediate graphs,
+ # to detect broken intermediate graphs,
# we do the loop ourselves instead of calling remove_simple_mallocs()
while True:
progress = remover.remove_mallocs_once(graph)
@@ -158,18 +157,6 @@
type_system = 'lltype'
MallocRemover = LLTypeMallocRemover
- def test_with_keepalive(self):
- from pypy.rlib.objectmodel import keepalive_until_here
- def fn1(x, y):
- if x > 0:
- t = x+y, x-y
- else:
- t = x-y, x+y
- s, d = t
- keepalive_until_here(t)
- return s*d
- self.check(fn1, [int, int], [15, 10], 125)
-
def test_dont_remove_with__del__(self):
import os
delcalls = [0]
@@ -199,50 +186,6 @@
op = graph.startblock.exits[0].target.exits[1].target.operations[0]
assert op.opname == "malloc"
- def test_add_keepalives(self):
- class A:
- pass
- SMALL = lltype.Struct('SMALL', ('x', lltype.Signed))
- BIG = lltype.GcStruct('BIG', ('z', lltype.Signed), ('s', SMALL))
- def fn7(i):
- big = lltype.malloc(BIG)
- a = A()
- a.big = big
- a.small = big.s
- a.small.x = 0
- while i > 0:
- a.small.x += i
- i -= 1
- return a.small.x
- self.check(fn7, [int], [10], 55, must_be_removed=False)
-
- def test_getsubstruct(self):
- py.test.skip("fails because of the interior structure changes")
- SMALL = lltype.Struct('SMALL', ('x', lltype.Signed))
- BIG = lltype.GcStruct('BIG', ('z', lltype.Signed), ('s', SMALL))
-
- def fn(n1, n2):
- b = lltype.malloc(BIG)
- b.z = n1
- b.s.x = n2
- return b.z - b.s.x
-
- self.check(fn, [int, int], [100, 58], 42)
-
- def test_fixedsizearray(self):
- py.test.skip("fails because of the interior structure changes")
- A = lltype.FixedSizeArray(lltype.Signed, 3)
- S = lltype.GcStruct('S', ('a', A))
-
- def fn(n1, n2):
- s = lltype.malloc(S)
- a = s.a
- a[0] = n1
- a[2] = n2
- return a[0]-a[2]
-
- self.check(fn, [int, int], [100, 42], 58)
-
def test_wrapper_cannot_be_removed(self):
SMALL = lltype.OpaqueType('SMALL')
BIG = lltype.GcStruct('BIG', ('z', lltype.Signed), ('s', SMALL))
diff --git a/pypy/rlib/_rweakvaldict.py b/pypy/rlib/_rweakvaldict.py
--- a/pypy/rlib/_rweakvaldict.py
+++ b/pypy/rlib/_rweakvaldict.py
@@ -113,7 +113,7 @@
@jit.dont_look_inside
def ll_get(self, d, llkey):
hash = self.ll_keyhash(llkey)
- i = rdict.ll_dict_lookup(d, llkey, hash)
+ i = rdict.ll_dict_lookup(d, llkey, hash) & rdict.MASK
#llop.debug_print(lltype.Void, i, 'get')
valueref = d.entries[i].value
if valueref:
@@ -132,7 +132,7 @@
def ll_set_nonnull(self, d, llkey, llvalue):
hash = self.ll_keyhash(llkey)
valueref = weakref_create(llvalue) # GC effects here, before the rest
- i = rdict.ll_dict_lookup(d, llkey, hash)
+ i = rdict.ll_dict_lookup(d, llkey, hash) & rdict.MASK
everused = d.entries.everused(i)
d.entries[i].key = llkey
d.entries[i].value = valueref
@@ -146,7 +146,7 @@
@jit.dont_look_inside
def ll_set_null(self, d, llkey):
hash = self.ll_keyhash(llkey)
- i = rdict.ll_dict_lookup(d, llkey, hash)
+ i = rdict.ll_dict_lookup(d, llkey, hash) & rdict.MASK
if d.entries.everused(i):
# If the entry was ever used, clean up its key and value.
# We don't store a NULL value, but a dead weakref, because
diff --git a/pypy/translator/cli/test/test_list.py b/pypy/translator/cli/test/test_list.py
--- a/pypy/translator/cli/test/test_list.py
+++ b/pypy/translator/cli/test/test_list.py
@@ -7,7 +7,10 @@
def test_recursive(self):
py.test.skip("CLI doesn't support recursive lists")
- def test_getitem_exc(self):
+ def test_getitem_exc_1(self):
+ py.test.skip('fixme!')
+
+ def test_getitem_exc_2(self):
py.test.skip('fixme!')
def test_list_unsigned(self):
diff --git a/pypy/rpython/memory/gctransform/framework.py b/pypy/rpython/memory/gctransform/framework.py
--- a/pypy/rpython/memory/gctransform/framework.py
+++ b/pypy/rpython/memory/gctransform/framework.py
@@ -9,6 +9,7 @@
from pypy.rlib.rarithmetic import ovfcheck
from pypy.rlib import rstack, rgc
from pypy.rlib.debug import ll_assert
+from pypy.rlib.objectmodel import we_are_translated
from pypy.translator.backendopt import graphanalyze
from pypy.translator.backendopt.support import var_needsgc
from pypy.annotation import model as annmodel
@@ -152,8 +153,13 @@
# for regular translation: pick the GC from the config
GCClass, GC_PARAMS = choose_gc_from_config(translator.config)
+ self.root_stack_jit_hook = None
if hasattr(translator, '_jit2gc'):
self.layoutbuilder = translator._jit2gc['layoutbuilder']
+ try:
+ self.root_stack_jit_hook = translator._jit2gc['rootstackhook']
+ except KeyError:
+ pass
else:
self.layoutbuilder = TransformerLayoutBuilder(translator, GCClass)
self.layoutbuilder.transformer = self
@@ -501,6 +507,10 @@
s_gc = self.translator.annotator.bookkeeper.valueoftype(GCClass)
r_gc = self.translator.rtyper.getrepr(s_gc)
self.c_const_gc = rmodel.inputconst(r_gc, self.gcdata.gc)
+ s_gc_data = self.translator.annotator.bookkeeper.valueoftype(
+ gctypelayout.GCData)
+ r_gc_data = self.translator.rtyper.getrepr(s_gc_data)
+ self.c_const_gcdata = rmodel.inputconst(r_gc_data, self.gcdata)
self.malloc_zero_filled = GCClass.malloc_zero_filled
HDR = self.HDR = self.gcdata.gc.gcheaderbuilder.HDR
@@ -794,6 +804,15 @@
resulttype=llmemory.Address)
hop.genop('adr_add', [v_gc_adr, c_ofs], resultvar=op.result)
+ def gct_gc_adr_of_root_stack_top(self, hop):
+ op = hop.spaceop
+ ofs = llmemory.offsetof(self.c_const_gcdata.concretetype.TO,
+ 'inst_root_stack_top')
+ c_ofs = rmodel.inputconst(lltype.Signed, ofs)
+ v_gcdata_adr = hop.genop('cast_ptr_to_adr', [self.c_const_gcdata],
+ resulttype=llmemory.Address)
+ hop.genop('adr_add', [v_gcdata_adr, c_ofs], resultvar=op.result)
+
def gct_gc_x_swap_pool(self, hop):
op = hop.spaceop
[v_malloced] = op.args
@@ -1363,6 +1382,14 @@
return top
self.decr_stack = decr_stack
+ self.rootstackhook = gctransformer.root_stack_jit_hook
+ if self.rootstackhook is None:
+ def collect_stack_root(callback, gc, addr):
+ if gc.points_to_valid_gc_object(addr):
+ callback(gc, addr)
+ return sizeofaddr
+ self.rootstackhook = collect_stack_root
+
def push_stack(self, addr):
top = self.incr_stack(1)
top.address[0] = addr
@@ -1372,10 +1399,7 @@
return top.address[0]
def allocate_stack(self):
- result = llmemory.raw_malloc(self.rootstacksize)
- if result:
- llmemory.raw_memclear(result, self.rootstacksize)
- return result
+ return llmemory.raw_malloc(self.rootstacksize)
def setup_root_walker(self):
stackbase = self.allocate_stack()
@@ -1387,12 +1411,11 @@
def walk_stack_roots(self, collect_stack_root):
gcdata = self.gcdata
gc = self.gc
+ rootstackhook = self.rootstackhook
addr = gcdata.root_stack_base
end = gcdata.root_stack_top
while addr != end:
- if gc.points_to_valid_gc_object(addr):
- collect_stack_root(gc, addr)
- addr += sizeofaddr
+ addr += rootstackhook(collect_stack_root, gc, addr)
if self.collect_stacks_from_other_threads is not None:
self.collect_stacks_from_other_threads(collect_stack_root)
@@ -1499,12 +1522,11 @@
# collect all valid stacks from the dict (the entry
# corresponding to the current thread is not valid)
gc = self.gc
+ rootstackhook = self.rootstackhook
end = stacktop - sizeofaddr
addr = end.address[0]
while addr != end:
- if gc.points_to_valid_gc_object(addr):
- callback(gc, addr)
- addr += sizeofaddr
+ addr += rootstackhook(callback, gc, addr)
def collect_more_stacks(callback):
ll_assert(get_aid() == gcdata.active_thread,
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
@@ -19,7 +19,8 @@
from pypy.jit.backend.llsupport.descr import BaseCallDescr, BaseSizeDescr
from pypy.jit.backend.llsupport.regalloc import FrameManager, RegisterManager,\
TempBox
-from pypy.jit.backend.x86.arch import WORD, FRAME_FIXED_SIZE, IS_X86_32, IS_X86_64
+from pypy.jit.backend.x86.arch import WORD, FRAME_FIXED_SIZE
+from pypy.jit.backend.x86.arch import IS_X86_32, IS_X86_64, MY_COPY_OF_REGS
from pypy.rlib.rarithmetic import r_longlong, r_uint
class X86RegisterManager(RegisterManager):
@@ -34,6 +35,12 @@
esi: 2,
edi: 3,
}
+ REGLOC_TO_COPY_AREA_OFS = {
+ ecx: MY_COPY_OF_REGS + 0 * WORD,
+ ebx: MY_COPY_OF_REGS + 1 * WORD,
+ esi: MY_COPY_OF_REGS + 2 * WORD,
+ edi: MY_COPY_OF_REGS + 3 * WORD,
+ }
def call_result_location(self, v):
return eax
@@ -61,6 +68,19 @@
r14: 4,
r15: 5,
}
+ REGLOC_TO_COPY_AREA_OFS = {
+ ecx: MY_COPY_OF_REGS + 0 * WORD,
+ ebx: MY_COPY_OF_REGS + 1 * WORD,
+ esi: MY_COPY_OF_REGS + 2 * WORD,
+ edi: MY_COPY_OF_REGS + 3 * WORD,
+ r8: MY_COPY_OF_REGS + 4 * WORD,
+ r9: MY_COPY_OF_REGS + 5 * WORD,
+ r10: MY_COPY_OF_REGS + 6 * WORD,
+ r12: MY_COPY_OF_REGS + 7 * WORD,
+ r13: MY_COPY_OF_REGS + 8 * WORD,
+ r14: MY_COPY_OF_REGS + 9 * WORD,
+ r15: MY_COPY_OF_REGS + 10 * WORD,
+ }
class X86XMMRegisterManager(RegisterManager):
@@ -117,6 +137,16 @@
else:
return 1
+if WORD == 4:
+ gpr_reg_mgr_cls = X86RegisterManager
+ xmm_reg_mgr_cls = X86XMMRegisterManager
+elif WORD == 8:
+ gpr_reg_mgr_cls = X86_64_RegisterManager
+ xmm_reg_mgr_cls = X86_64_XMMRegisterManager
+else:
+ raise AssertionError("Word size should be 4 or 8")
+
+
class RegAlloc(object):
def __init__(self, assembler, translate_support_code=False):
@@ -135,16 +165,6 @@
# compute longevity of variables
longevity = self._compute_vars_longevity(inputargs, operations)
self.longevity = longevity
- # XXX
- if cpu.WORD == 4:
- gpr_reg_mgr_cls = X86RegisterManager
- xmm_reg_mgr_cls = X86XMMRegisterManager
- elif cpu.WORD == 8:
- gpr_reg_mgr_cls = X86_64_RegisterManager
- xmm_reg_mgr_cls = X86_64_XMMRegisterManager
- else:
- raise AssertionError("Word size should be 4 or 8")
-
self.rm = gpr_reg_mgr_cls(longevity,
frame_manager = self.fm,
assembler = self.assembler)
@@ -738,8 +758,12 @@
def _call(self, op, arglocs, force_store=[], guard_not_forced_op=None):
save_all_regs = guard_not_forced_op is not None
+ self.xrm.before_call(force_store, save_all_regs=save_all_regs)
+ if not save_all_regs:
+ gcrootmap = gc_ll_descr = self.assembler.cpu.gc_ll_descr.gcrootmap
+ if gcrootmap and gcrootmap.is_shadow_stack:
+ save_all_regs = 2
self.rm.before_call(force_store, save_all_regs=save_all_regs)
- self.xrm.before_call(force_store, save_all_regs=save_all_regs)
if op.result is not None:
if op.result.type == FLOAT:
resloc = self.xrm.after_call(op.result)
@@ -836,31 +860,53 @@
self.PerformDiscard(op, arglocs)
self.rm.possibly_free_vars_for_op(op)
- def _fastpath_malloc(self, op, descr):
+ def fastpath_malloc_fixedsize(self, op, descr):
assert isinstance(descr, BaseSizeDescr)
+ self._do_fastpath_malloc(op, descr.size, descr.tid)
+
+ def fastpath_malloc_varsize(self, op, arraydescr, num_elem):
+ assert isinstance(arraydescr, BaseArrayDescr)
+ ofs_length = arraydescr.get_ofs_length(self.translate_support_code)
+ basesize = arraydescr.get_base_size(self.translate_support_code)
+ itemsize = arraydescr.get_item_size(self.translate_support_code)
+ size = basesize + itemsize * num_elem
+ self._do_fastpath_malloc(op, size, arraydescr.tid)
+ self.assembler.set_new_array_length(eax, ofs_length, imm(num_elem))
+
+ def _do_fastpath_malloc(self, op, size, tid):
gc_ll_descr = self.assembler.cpu.gc_ll_descr
self.rm.force_allocate_reg(op.result, selected_reg=eax)
- # We need to force-allocate each of save_around_call_regs now.
- # The alternative would be to save and restore them around the
- # actual call to malloc(), in the rare case where we need to do
- # it; however, mark_gc_roots() would need to be adapted to know
- # where the variables end up being saved. Messy.
- for reg in self.rm.save_around_call_regs:
- if reg is not eax:
- tmp_box = TempBox()
- self.rm.force_allocate_reg(tmp_box, selected_reg=reg)
- self.rm.possibly_free_var(tmp_box)
- self.assembler.malloc_cond_fixedsize(
+ if gc_ll_descr.gcrootmap and gc_ll_descr.gcrootmap.is_shadow_stack:
+ # ---- shadowstack ----
+ # We need edx as a temporary, but otherwise don't save any more
+ # register. See comments in _build_malloc_slowpath().
+ tmp_box = TempBox()
+ self.rm.force_allocate_reg(tmp_box, selected_reg=edx)
+ self.rm.possibly_free_var(tmp_box)
+ else:
+ # ---- asmgcc ----
+ # We need to force-allocate each of save_around_call_regs now.
+ # The alternative would be to save and restore them around the
+ # actual call to malloc(), in the rare case where we need to do
+ # it; however, mark_gc_roots() would need to be adapted to know
+ # where the variables end up being saved. Messy.
+ for reg in self.rm.save_around_call_regs:
+ if reg is not eax:
+ tmp_box = TempBox()
+ self.rm.force_allocate_reg(tmp_box, selected_reg=reg)
+ self.rm.possibly_free_var(tmp_box)
+
+ self.assembler.malloc_cond(
gc_ll_descr.get_nursery_free_addr(),
gc_ll_descr.get_nursery_top_addr(),
- descr.size, descr.tid,
+ size, tid,
)
def consider_new(self, op):
gc_ll_descr = self.assembler.cpu.gc_ll_descr
if gc_ll_descr.can_inline_malloc(op.getdescr()):
- self._fastpath_malloc(op, op.getdescr())
+ self.fastpath_malloc_fixedsize(op, op.getdescr())
else:
args = gc_ll_descr.args_for_new(op.getdescr())
arglocs = [imm(x) for x in args]
@@ -870,7 +916,7 @@
classint = op.getarg(0).getint()
descrsize = heaptracker.vtable2descr(self.assembler.cpu, classint)
if self.assembler.cpu.gc_ll_descr.can_inline_malloc(descrsize):
- self._fastpath_malloc(op, descrsize)
+ self.fastpath_malloc_fixedsize(op, descrsize)
self.assembler.set_vtable(eax, imm(classint))
# result of fastpath malloc is in eax
else:
@@ -929,16 +975,25 @@
gc_ll_descr = self.assembler.cpu.gc_ll_descr
if gc_ll_descr.get_funcptr_for_newarray is not None:
# framework GC
- args = self.assembler.cpu.gc_ll_descr.args_for_new_array(op.getdescr())
+ box_num_elem = op.getarg(0)
+ if isinstance(box_num_elem, ConstInt):
+ num_elem = box_num_elem.value
+ if gc_ll_descr.can_inline_malloc_varsize(op.getdescr(),
+ num_elem):
+ self.fastpath_malloc_varsize(op, op.getdescr(), num_elem)
+ return
+ args = self.assembler.cpu.gc_ll_descr.args_for_new_array(
+ op.getdescr())
arglocs = [imm(x) for x in args]
- arglocs.append(self.loc(op.getarg(0)))
- return self._call(op, arglocs)
+ arglocs.append(self.loc(box_num_elem))
+ self._call(op, arglocs)
+ return
# boehm GC (XXX kill the following code at some point)
itemsize, basesize, ofs_length, _, _ = (
self._unpack_arraydescr(op.getdescr()))
scale_of_field = _get_scale(itemsize)
- return self._malloc_varsize(basesize, ofs_length, scale_of_field,
- op.getarg(0), op.result)
+ self._malloc_varsize(basesize, ofs_length, scale_of_field,
+ op.getarg(0), op.result)
def _unpack_arraydescr(self, arraydescr):
assert isinstance(arraydescr, BaseArrayDescr)
@@ -1132,7 +1187,7 @@
# call memcpy()
self.rm.before_call()
self.xrm.before_call()
- self.assembler._emit_call(imm(self.assembler.memcpy_addr),
+ self.assembler._emit_call(-1, imm(self.assembler.memcpy_addr),
[dstaddr_loc, srcaddr_loc, length_loc])
self.rm.possibly_free_var(length_box)
self.rm.possibly_free_var(dstaddr_box)
@@ -1200,18 +1255,24 @@
def consider_jit_debug(self, op):
pass
- def get_mark_gc_roots(self, gcrootmap):
+ def get_mark_gc_roots(self, gcrootmap, use_copy_area=False):
shape = gcrootmap.get_basic_shape(IS_X86_64)
for v, val in self.fm.frame_bindings.items():
if (isinstance(v, BoxPtr) and self.rm.stays_alive(v)):
assert isinstance(val, StackLoc)
- gcrootmap.add_ebp_offset(shape, get_ebp_ofs(val.position))
+ gcrootmap.add_frame_offset(shape, get_ebp_ofs(val.position))
for v, reg in self.rm.reg_bindings.items():
if reg is eax:
continue # ok to ignore this one
if (isinstance(v, BoxPtr) and self.rm.stays_alive(v)):
- assert reg in self.rm.REGLOC_TO_GCROOTMAP_REG_INDEX
- gcrootmap.add_callee_save_reg(shape, self.rm.REGLOC_TO_GCROOTMAP_REG_INDEX[reg])
+ if use_copy_area:
+ assert reg in self.rm.REGLOC_TO_COPY_AREA_OFS
+ area_offset = self.rm.REGLOC_TO_COPY_AREA_OFS[reg]
+ gcrootmap.add_frame_offset(shape, area_offset)
+ else:
+ assert reg in self.rm.REGLOC_TO_GCROOTMAP_REG_INDEX
+ gcrootmap.add_callee_save_reg(
+ shape, self.rm.REGLOC_TO_GCROOTMAP_REG_INDEX[reg])
return gcrootmap.compress_callshape(shape,
self.assembler.datablockwrapper)
diff --git a/pypy/module/cpyext/__init__.py b/pypy/module/cpyext/__init__.py
--- a/pypy/module/cpyext/__init__.py
+++ b/pypy/module/cpyext/__init__.py
@@ -46,6 +46,7 @@
import pypy.module.cpyext.complexobject
import pypy.module.cpyext.weakrefobject
import pypy.module.cpyext.funcobject
+import pypy.module.cpyext.frameobject
import pypy.module.cpyext.classobject
import pypy.module.cpyext.pypyintf
import pypy.module.cpyext.memoryobject
diff --git a/pypy/translator/backendopt/mallocprediction.py b/pypy/translator/backendopt/mallocprediction.py
--- a/pypy/translator/backendopt/mallocprediction.py
+++ b/pypy/translator/backendopt/mallocprediction.py
@@ -176,7 +176,6 @@
break
count += newcount
for graph in graphs:
- removenoops.remove_superfluous_keep_alive(graph)
removenoops.remove_duplicate_casts(graph, translator)
return count
diff --git a/pypy/jit/tl/pypyjit_child.py b/pypy/jit/tl/pypyjit_child.py
--- a/pypy/jit/tl/pypyjit_child.py
+++ b/pypy/jit/tl/pypyjit_child.py
@@ -2,7 +2,6 @@
from pypy.rpython.lltypesystem import lltype
from pypy.jit.metainterp import warmspot
from pypy.module.pypyjit.policy import PyPyJitPolicy
-from pypy.rlib.jit import OPTIMIZER_FULL, OPTIMIZER_NO_UNROLL
def run_child(glob, loc):
@@ -34,6 +33,5 @@
option.view = True
warmspot.jittify_and_run(interp, graph, [], policy=policy,
listops=True, CPUClass=CPUClass,
- backendopt=True, inline=True,
- optimizer=OPTIMIZER_FULL)
+ backendopt=True, inline=True)
diff --git a/pypy/translator/goal/translate.py b/pypy/translator/goal/translate.py
--- a/pypy/translator/goal/translate.py
+++ b/pypy/translator/goal/translate.py
@@ -285,6 +285,15 @@
elif drv.exe_name is None and '__name__' in targetspec_dic:
drv.exe_name = targetspec_dic['__name__'] + '-%(backend)s'
+ # Double check to ensure we are not overwriting the current interpreter
+ try:
+ exe_name = str(drv.compute_exe_name())
+ assert not os.path.samefile(exe_name, sys.executable), (
+ 'Output file %r is the currently running '
+ 'interpreter (use --output=...)'% exe_name)
+ except OSError:
+ pass
+
goals = translateconfig.goals
try:
drv.proceed(goals)
diff --git a/pypy/doc/config/objspace.extmodules.rst b/pypy/doc/config/objspace.extmodules.rst
new file mode 100644
--- /dev/null
+++ b/pypy/doc/config/objspace.extmodules.rst
@@ -0,0 +1,12 @@
+You can pass a comma-separated list of third-party builtin modules
+which should be translated along with the standard modules within
+``pypy.module``.
+
+The module names need to be fully qualified (i.e. have a ``.`` in them),
+be on the ``$PYTHONPATH`` and not conflict with any existing ones, e.g.
+``mypkg.somemod``.
+
+Once translated, the module will be accessible with a simple::
+
+ import somemod
+
diff --git a/pypy/jit/codewriter/test/test_regalloc.py b/pypy/jit/codewriter/test/test_regalloc.py
--- a/pypy/jit/codewriter/test/test_regalloc.py
+++ b/pypy/jit/codewriter/test/test_regalloc.py
@@ -9,7 +9,6 @@
from pypy.objspace.flow.model import c_last_exception
from pypy.rpython.lltypesystem import lltype, llmemory, rclass
from pypy.rlib.rarithmetic import ovfcheck
-from pypy.rlib.objectmodel import keepalive_until_here
class TestRegAlloc:
diff --git a/pypy/rpython/test/test_rdict.py b/pypy/rpython/test/test_rdict.py
--- a/pypy/rpython/test/test_rdict.py
+++ b/pypy/rpython/test/test_rdict.py
@@ -592,6 +592,26 @@
a.x = 5
self.interpret(fn, [])
+ def test_dict_popitem(self):
+ def func():
+ d = {}
+ d[5] = 2
+ d[6] = 3
+ k1, v1 = d.popitem()
+ assert len(d) == 1
+ k2, v2 = d.popitem()
+ try:
+ d.popitem()
+ except KeyError:
+ pass
+ else:
+ assert 0, "should have raised KeyError"
+ assert len(d) == 0
+ return k1*1000 + v1*100 + k2*10 + v2
+
+ res = self.interpret(func, [])
+ assert res in [5263, 6352]
+
class TestLLtype(BaseTestRdict, LLRtypeMixin):
def test_dict_but_not_with_char_keys(self):
@@ -696,26 +716,6 @@
# if it does not crash, we are fine. It crashes if you forget the hash field.
self.interpret(func, [])
- def test_dict_popitem(self):
- def func():
- d = {}
- d[5] = 2
- d[6] = 3
- k1, v1 = d.popitem()
- assert len(d) == 1
- k2, v2 = d.popitem()
- try:
- d.popitem()
- except KeyError:
- pass
- else:
- assert 0, "should have raised KeyError"
- assert len(d) == 0
- return k1*1000 + v1*100 + k2*10 + v2
-
- res = self.interpret(func, [])
- assert res in [5263, 6352]
-
# ____________________________________________________________
def test_opt_nullkeymarker(self):
diff --git a/pypy/rpython/lltypesystem/rffi.py b/pypy/rpython/lltypesystem/rffi.py
--- a/pypy/rpython/lltypesystem/rffi.py
+++ b/pypy/rpython/lltypesystem/rffi.py
@@ -305,6 +305,15 @@
stackcounter = StackCounter()
stackcounter._freeze_()
+def llexternal_use_eci(compilation_info):
+ """Return a dummy function that, if called in a RPython program,
+ adds the given ExternalCompilationInfo to it."""
+ eci = ExternalCompilationInfo(post_include_bits=['#define PYPY_NO_OP()'])
+ eci = eci.merge(compilation_info)
+ return llexternal('PYPY_NO_OP', [], lltype.Void,
+ compilation_info=eci, sandboxsafe=True, _nowrapper=True,
+ _callable=lambda: None)
+
# ____________________________________________________________
# Few helpers for keeping callback arguments alive
# this makes passing opaque objects possible (they don't even pass
@@ -737,6 +746,7 @@
def charpsize2str(cp, size):
l = [cp[i] for i in range(size)]
return emptystr.join(l)
+ charpsize2str._annenforceargs_ = [None, int]
return (str2charp, free_charp, charp2str,
get_nonmovingbuffer, free_nonmovingbuffer,
diff --git a/pypy/module/cpyext/include/Python.h b/pypy/module/cpyext/include/Python.h
--- a/pypy/module/cpyext/include/Python.h
+++ b/pypy/module/cpyext/include/Python.h
@@ -110,6 +110,8 @@
#include "intobject.h"
#include "listobject.h"
#include "unicodeobject.h"
+#include "compile.h"
+#include "frameobject.h"
#include "eval.h"
#include "pymem.h"
#include "pycobject.h"
diff --git a/pypy/translator/backendopt/removenoops.py b/pypy/translator/backendopt/removenoops.py
--- a/pypy/translator/backendopt/removenoops.py
+++ b/pypy/translator/backendopt/removenoops.py
@@ -108,15 +108,3 @@
for i, op in list(enumerate(block.operations))[::-1]:
if op.opname == "debug_assert":
del block.operations[i]
-
-def remove_superfluous_keep_alive(graph):
- for block in graph.iterblocks():
- used = {}
- for i, op in list(enumerate(block.operations))[::-1]:
- if op.opname == "keepalive":
- if op.args[0] in used:
- del block.operations[i]
- else:
- used[op.args[0]] = True
-
-
diff --git a/pypy/rpython/test/test_rbuiltin.py b/pypy/rpython/test/test_rbuiltin.py
--- a/pypy/rpython/test/test_rbuiltin.py
+++ b/pypy/rpython/test/test_rbuiltin.py
@@ -496,6 +496,13 @@
res = self.interpret(llf, [rffi.r_short(123)], policy=LowLevelAnnotatorPolicy())
assert res == 123
+ def test_force_cast(self):
+ def llfn(v):
+ return rffi.cast(rffi.SHORT, v)
+ res = self.interpret(llfn, [0x12345678])
+ assert res == 0x5678
+
+
class TestLLtype(BaseTestRbuiltin, LLRtypeMixin):
def test_isinstance_obj(self):
diff --git a/pypy/module/_io/interp_bufferedio.py b/pypy/module/_io/interp_bufferedio.py
--- a/pypy/module/_io/interp_bufferedio.py
+++ b/pypy/module/_io/interp_bufferedio.py
@@ -12,7 +12,6 @@
W_IOBase, DEFAULT_BUFFER_SIZE, convert_size,
check_readable_w, check_writable_w, check_seekable_w)
from pypy.module._io.interp_io import W_BlockingIOError
-from pypy.module.thread.os_lock import Lock
STATE_ZERO, STATE_OK, STATE_DETACHED = range(3)
@@ -121,7 +120,7 @@
## XXX cannot free a Lock?
## if self.lock:
## self.lock.free()
- self.lock = Lock(space)
+ self.lock = space.allocate_lock()
try:
self._raw_tell(space)
diff --git a/pypy/jit/backend/x86/test/test_gc_integration.py b/pypy/jit/backend/x86/test/test_gc_integration.py
--- a/pypy/jit/backend/x86/test/test_gc_integration.py
+++ b/pypy/jit/backend/x86/test/test_gc_integration.py
@@ -26,9 +26,10 @@
CPU = getcpuclass()
class MockGcRootMap(object):
+ is_shadow_stack = False
def get_basic_shape(self, is_64_bit):
return ['shape']
- def add_ebp_offset(self, shape, offset):
+ def add_frame_offset(self, shape, offset):
shape.append(offset)
def add_callee_save_reg(self, shape, reg_index):
index_to_name = { 1: 'ebx', 2: 'esi', 3: 'edi' }
@@ -44,7 +45,8 @@
get_funcptr_for_newarray = get_funcptr_for_new
get_funcptr_for_newstr = get_funcptr_for_new
get_funcptr_for_newunicode = get_funcptr_for_new
-
+ get_malloc_slowpath_addr = None
+
moving_gc = True
gcrootmap = MockGcRootMap()
@@ -166,26 +168,29 @@
class GCDescrFastpathMalloc(GcLLDescription):
gcrootmap = None
-
+ expected_malloc_slowpath_size = WORD*2
+
def __init__(self):
GcCache.__init__(self, False)
# create a nursery
NTP = rffi.CArray(lltype.Signed)
self.nursery = lltype.malloc(NTP, 16, flavor='raw')
- self.addrs = lltype.malloc(rffi.CArray(lltype.Signed), 2,
+ self.addrs = lltype.malloc(rffi.CArray(lltype.Signed), 3,
flavor='raw')
self.addrs[0] = rffi.cast(lltype.Signed, self.nursery)
- self.addrs[1] = self.addrs[0] + 64
- # 64 bytes
+ self.addrs[1] = self.addrs[0] + 16*WORD
+ self.addrs[2] = 0
+ # 16 WORDs
def malloc_slowpath(size):
- assert size == WORD*2
+ assert size == self.expected_malloc_slowpath_size
nadr = rffi.cast(lltype.Signed, self.nursery)
self.addrs[0] = nadr + size
+ self.addrs[2] += 1
return nadr
self.malloc_slowpath = malloc_slowpath
self.MALLOC_SLOWPATH = lltype.FuncType([lltype.Signed],
lltype.Signed)
- self._counter = 123
+ self._counter = 123000
def can_inline_malloc(self, descr):
return True
@@ -204,7 +209,7 @@
def get_nursery_top_addr(self):
return rffi.cast(lltype.Signed, self.addrs) + WORD
- def get_malloc_fixedsize_slowpath_addr(self):
+ def get_malloc_slowpath_addr(self):
fptr = llhelper(lltype.Ptr(self.MALLOC_SLOWPATH), self.malloc_slowpath)
return rffi.cast(lltype.Signed, fptr)
@@ -220,9 +225,11 @@
cpu.gc_ll_descr = GCDescrFastpathMalloc()
cpu.setup_once()
- NODE = lltype.Struct('node', ('tid', lltype.Signed),
- ('value', lltype.Signed))
- nodedescr = cpu.sizeof(NODE) # xxx hack: NODE is not a GcStruct
+ # hack: specify 'tid' explicitly, because this test is not running
+ # with the gc transformer
+ NODE = lltype.GcStruct('node', ('tid', lltype.Signed),
+ ('value', lltype.Signed))
+ nodedescr = cpu.sizeof(NODE)
valuedescr = cpu.fielddescrof(NODE, 'value')
self.cpu = cpu
@@ -254,6 +261,7 @@
assert gc_ll_descr.nursery[1] == 42
nurs_adr = rffi.cast(lltype.Signed, gc_ll_descr.nursery)
assert gc_ll_descr.addrs[0] == nurs_adr + (WORD*2)
+ assert gc_ll_descr.addrs[2] == 0 # slowpath never called
def test_malloc_slowpath(self):
ops = '''
@@ -274,6 +282,7 @@
gc_ll_descr = self.cpu.gc_ll_descr
nadr = rffi.cast(lltype.Signed, gc_ll_descr.nursery)
assert gc_ll_descr.addrs[0] == nadr + (WORD*2)
+ assert gc_ll_descr.addrs[2] == 1 # slowpath called once
def test_new_with_vtable(self):
ops = '''
@@ -289,3 +298,93 @@
assert gc_ll_descr.nursery[1] == self.vtable_int
nurs_adr = rffi.cast(lltype.Signed, gc_ll_descr.nursery)
assert gc_ll_descr.addrs[0] == nurs_adr + (WORD*3)
+ assert gc_ll_descr.addrs[2] == 0 # slowpath never called
+
+
+class Seen(Exception):
+ pass
+
+class GCDescrFastpathMallocVarsize(GCDescrFastpathMalloc):
+ def can_inline_malloc_varsize(self, arraydescr, num_elem):
+ return num_elem < 5
+ def get_funcptr_for_newarray(self):
+ return 52
+ def init_array_descr(self, A, descr):
+ descr.tid = self._counter
+ self._counter += 1
+ def args_for_new_array(self, descr):
+ raise Seen("args_for_new_array")
+
+class TestMallocVarsizeFastpath(BaseTestRegalloc):
+ def setup_method(self, method):
+ cpu = CPU(None, None)
+ cpu.vtable_offset = WORD
+ cpu.gc_ll_descr = GCDescrFastpathMallocVarsize()
+ cpu.setup_once()
+ self.cpu = cpu
+
+ ARRAY = lltype.GcArray(lltype.Signed)
+ arraydescr = cpu.arraydescrof(ARRAY)
+ self.arraydescr = arraydescr
+
+ self.namespace = locals().copy()
+
+ def test_malloc_varsize_fastpath(self):
+ # Hack. Running the GcLLDescr_framework without really having
+ # a complete GC means that we end up with both the tid and the
+ # length being at offset 0. In this case, so the length overwrites
+ # the tid. This is of course only the case in this test class.
+ ops = '''
+ []
+ p0 = new_array(4, descr=arraydescr)
+ setarrayitem_gc(p0, 0, 142, descr=arraydescr)
+ setarrayitem_gc(p0, 3, 143, descr=arraydescr)
+ finish(p0)
+ '''
+ self.interpret(ops, [])
+ # check the nursery
+ gc_ll_descr = self.cpu.gc_ll_descr
+ assert gc_ll_descr.nursery[0] == 4
+ assert gc_ll_descr.nursery[1] == 142
+ assert gc_ll_descr.nursery[4] == 143
+ nurs_adr = rffi.cast(lltype.Signed, gc_ll_descr.nursery)
+ assert gc_ll_descr.addrs[0] == nurs_adr + (WORD*5)
+ assert gc_ll_descr.addrs[2] == 0 # slowpath never called
+
+ def test_malloc_varsize_slowpath(self):
+ ops = '''
+ []
+ p0 = new_array(4, descr=arraydescr)
+ setarrayitem_gc(p0, 0, 420, descr=arraydescr)
+ setarrayitem_gc(p0, 3, 430, descr=arraydescr)
+ p1 = new_array(4, descr=arraydescr)
+ setarrayitem_gc(p1, 0, 421, descr=arraydescr)
+ setarrayitem_gc(p1, 3, 431, descr=arraydescr)
+ p2 = new_array(4, descr=arraydescr)
+ setarrayitem_gc(p2, 0, 422, descr=arraydescr)
+ setarrayitem_gc(p2, 3, 432, descr=arraydescr)
+ p3 = new_array(4, descr=arraydescr)
+ setarrayitem_gc(p3, 0, 423, descr=arraydescr)
+ setarrayitem_gc(p3, 3, 433, descr=arraydescr)
+ finish(p0, p1, p2, p3)
+ '''
+ gc_ll_descr = self.cpu.gc_ll_descr
+ gc_ll_descr.expected_malloc_slowpath_size = 5*WORD
+ self.interpret(ops, [])
+ assert gc_ll_descr.addrs[2] == 1 # slowpath called once
+
+ def test_malloc_varsize_too_big(self):
+ ops = '''
+ []
+ p0 = new_array(5, descr=arraydescr)
+ finish(p0)
+ '''
+ py.test.raises(Seen, self.interpret, ops, [])
+
+ def test_malloc_varsize_variable(self):
+ ops = '''
+ [i0]
+ p0 = new_array(i0, descr=arraydescr)
+ finish(p0)
+ '''
+ py.test.raises(Seen, self.interpret, ops, [])
diff --git a/pypy/translator/cli/src/ll_math.cs b/pypy/translator/cli/src/ll_math.cs
--- a/pypy/translator/cli/src/ll_math.cs
+++ b/pypy/translator/cli/src/ll_math.cs
@@ -224,5 +224,25 @@
{
return Math.Tanh(x);
}
+
+ static public bool ll_math_isnan(double x)
+ {
+ return double.IsNaN(x);
+ }
+
+ static public bool ll_math_isinf(double x)
+ {
+ return double.IsInfinity(x);
+ }
+
+ static public double ll_math_copysign(double x, double y)
+ {
+ if (x < 0.0)
+ x = -x;
+ if (y > 0.0 || (y == 0.0 && Math.Atan2(y, -1.0) > 0.0))
+ return x;
+ else
+ return -x;
+ }
}
}
diff --git a/pypy/interpreter/test/test_interpreter.py b/pypy/interpreter/test/test_interpreter.py
--- a/pypy/interpreter/test/test_interpreter.py
+++ b/pypy/interpreter/test/test_interpreter.py
@@ -283,9 +283,14 @@
sys.stdout = out = Out()
try:
raises(UnicodeError, "print unichr(0xa2)")
+ assert out.data == []
out.encoding = "cp424"
print unichr(0xa2)
assert out.data == [unichr(0xa2).encode("cp424"), "\n"]
+ del out.data[:]
+ del out.encoding
+ print u"foo\t", u"bar\n", u"trick", u"baz\n" # softspace handling
+ assert out.data == ["foo\t", "bar\n", "trick", " ", "baz\n", "\n"]
finally:
sys.stdout = save
diff --git a/pypy/module/imp/test/test_app.py b/pypy/module/imp/test/test_app.py
--- a/pypy/module/imp/test/test_app.py
+++ b/pypy/module/imp/test/test_app.py
@@ -1,3 +1,4 @@
+from __future__ import with_statement
MARKER = 42
class AppTestImpModule:
@@ -34,7 +35,8 @@
def test_load_dynamic(self):
raises(ImportError, self.imp.load_dynamic, 'foo', 'bar')
- raises(ImportError, self.imp.load_dynamic, 'foo', 'bar', 'baz.so')
+ raises(ImportError, self.imp.load_dynamic, 'foo', 'bar',
+ open(self.file_module))
def test_suffixes(self):
for suffix, mode, type in self.imp.get_suffixes():
diff --git a/pypy/translator/backendopt/support.py b/pypy/translator/backendopt/support.py
--- a/pypy/translator/backendopt/support.py
+++ b/pypy/translator/backendopt/support.py
@@ -39,74 +39,6 @@
# assume PyObjPtr
return True
-def needs_conservative_livevar_calculation(block):
- from pypy.rpython.lltypesystem import rclass
- vars = block.getvariables()
- assert len(block.exits) == 1
- exitingvars = block.exits[0].args
- for var in vars:
- TYPE = getattr(var, "concretetype", lltype.Ptr(lltype.PyObject))
- if isinstance(TYPE, lltype.Ptr) and not var_needsgc(var):
- if isinstance(TYPE.TO, lltype.FuncType):
- continue
- try:
- lltype.castable(TYPE, rclass.CLASSTYPE)
- except lltype.InvalidCast:
- if var in exitingvars:
- return True
- else:
- return False
-
-def generate_keepalive(vars, annotator=None):
- keepalive_ops = []
- for v in vars:
- if isinstance(v, Constant):
- continue
- if v.concretetype._is_atomic():
- continue
- v_keepalive = Variable()
- v_keepalive.concretetype = lltype.Void
- if annotator is not None:
- annotator.setbinding(v_keepalive, s_ImpossibleValue)
- keepalive_ops.append(SpaceOperation('keepalive', [v], v_keepalive))
- return keepalive_ops
-
-def split_block_with_keepalive(block, index_operation,
- keep_alive_op_args=True,
- annotator=None):
- splitlink = split_block(annotator, block, index_operation)
- afterblock = splitlink.target
- conservative_keepalives = needs_conservative_livevar_calculation(block)
- if conservative_keepalives:
- keep_alive_vars = [var for var in block.getvariables()
- if var_needsgc(var)]
- # XXX you could maybe remove more, if the variables are kept
- # alive by something else. but this is sometimes hard to know
- for i, var in enumerate(keep_alive_vars):
- try:
- index = splitlink.args.index(var)
- newvar = afterblock.inputargs[index]
- except ValueError:
- splitlink.args.append(var)
- newvar = copyvar(annotator, var)
- afterblock.inputargs.append(newvar)
- keep_alive_vars[i] = newvar
- elif keep_alive_op_args and afterblock.operations:
- keep_alive_vars = [var for var in afterblock.operations[0].args
- if isinstance(var, Variable) and var_needsgc(var)]
- if len(afterblock.operations) > 1 or afterblock.exitswitch != c_last_exception:
- afterblock.operations[1:1] = generate_keepalive(keep_alive_vars,
- annotator=annotator)
- keep_alive_vars = []
- else:
- keep_alive_vars = []
- pos = len(afterblock.operations)
- if afterblock.exitswitch == c_last_exception:
- pos -= 1 # insert the keepalives just before the last operation
- # in case of exception-catching
- afterblock.operations[pos:pos] = generate_keepalive(keep_alive_vars)
- return splitlink
-
def find_calls_from(translator, graph, memo=None):
if memo and graph in memo:
return memo[graph]
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
@@ -46,4 +46,5 @@
return PyBuffer_New(150);
"""),
])
- module.buffer_new()
+ b = module.buffer_new()
+ raises(AttributeError, getattr, b, 'x')
diff --git a/pypy/translator/jvm/metavm.py b/pypy/translator/jvm/metavm.py
--- a/pypy/translator/jvm/metavm.py
+++ b/pypy/translator/jvm/metavm.py
@@ -1,4 +1,5 @@
from pypy.rpython.ootypesystem import ootype
+from pypy.rpython.lltypesystem import rffi
from pypy.translator.oosupport.metavm import MicroInstruction
from pypy.translator.jvm.typesystem import JvmScalarType, JvmClassType
import pypy.translator.jvm.typesystem as jvm
@@ -94,14 +95,20 @@
(ootype.SignedLongLong, ootype.Signed): jvm.L2I,
(ootype.UnsignedLongLong, ootype.Unsigned): jvm.L2I,
(ootype.UnsignedLongLong, ootype.Signed): jvm.L2I,
+ (ootype.Signed, rffi.SHORT): jvm.I2S,
+ (ootype.Unsigned, ootype.SignedLongLong): jvm.PYPYUINTTOLONG,
(ootype.UnsignedLongLong, ootype.SignedLongLong): None,
(ootype.SignedLongLong, ootype.UnsignedLongLong): None,
+ (ootype.Signed, ootype.Unsigned): None,
+ (ootype.Unsigned, ootype.Signed): None,
}
class _CastPrimitive(MicroInstruction):
def render(self, generator, op):
FROM = op.args[0].concretetype
TO = op.result.concretetype
+ if TO == FROM:
+ return
opcode = CASTS[(FROM, TO)]
if opcode:
generator.emit(opcode)
diff --git a/pypy/module/imp/importing.py b/pypy/module/imp/importing.py
--- a/pypy/module/imp/importing.py
+++ b/pypy/module/imp/importing.py
@@ -32,6 +32,7 @@
else:
SO = ".so"
DEFAULT_SOABI = 'pypy-14'
+CHECK_FOR_PYW = sys.platform == 'win32'
@specialize.memo()
def get_so_extension(space):
@@ -58,6 +59,12 @@
if os.path.exists(pyfile) and case_ok(pyfile):
return PY_SOURCE, ".py", "U"
+ # on Windows, also check for a .pyw file
+ if CHECK_FOR_PYW:
+ pyfile = filepart + ".pyw"
+ if os.path.exists(pyfile) and case_ok(pyfile):
+ return PY_SOURCE, ".pyw", "U"
+
# The .py file does not exist. By default on PyPy, lonepycfiles
# is False: if a .py file does not exist, we don't even try to
# look for a lone .pyc file.
@@ -85,6 +92,9 @@
# XXX that's slow
def case_ok(filename):
index = filename.rfind(os.sep)
+ if os.altsep is not None:
+ index2 = filename.rfind(os.altsep)
+ index = max(index, index2)
if index < 0:
directory = os.curdir
else:
diff --git a/pypy/jit/backend/x86/test/test_rx86_64_auto_encoding.py b/pypy/jit/backend/x86/test/test_rx86_64_auto_encoding.py
--- a/pypy/jit/backend/x86/test/test_rx86_64_auto_encoding.py
+++ b/pypy/jit/backend/x86/test/test_rx86_64_auto_encoding.py
@@ -18,7 +18,6 @@
def should_skip_instruction(self, instrname, argmodes):
return (
super(TestRx86_64, self).should_skip_instruction(instrname, argmodes) or
- ('j' in argmodes) or
# Not testing FSTP on 64-bit for now
(instrname == 'FSTP')
)
diff --git a/pypy/objspace/flow/flowcontext.py b/pypy/objspace/flow/flowcontext.py
--- a/pypy/objspace/flow/flowcontext.py
+++ b/pypy/objspace/flow/flowcontext.py
@@ -311,8 +311,7 @@
# EggBlocks reuse the variables of their previous block,
# which is deemed not acceptable for simplicity of the operations
# that will be performed later on the flow graph.
- def fixegg(link):
- if isinstance(link, Link):
+ for link in list(self.graph.iterlinks()):
block = link.target
if isinstance(block, EggBlock):
if (not block.operations and len(block.exits) == 1 and
@@ -324,15 +323,14 @@
link.args = list(link2.args)
link.target = link2.target
assert link2.exitcase is None
- fixegg(link)
else:
mapping = {}
for a in block.inputargs:
mapping[a] = Variable(a)
block.renamevariables(mapping)
- elif isinstance(link, SpamBlock):
+ for block in self.graph.iterblocks():
+ if isinstance(link, SpamBlock):
del link.framestate # memory saver
- traverse(fixegg, self.graph)
def mergeblock(self, currentblock, currentstate):
next_instr = currentstate.next_instr
diff --git a/pypy/annotation/unaryop.py b/pypy/annotation/unaryop.py
--- a/pypy/annotation/unaryop.py
+++ b/pypy/annotation/unaryop.py
@@ -499,10 +499,14 @@
def getanyitem(str):
return str.basecharclass()
- def method_split(str, patt): # XXX
+ def method_split(str, patt, max=-1):
getbookkeeper().count("str_split", str, patt)
return getbookkeeper().newlist(str.basestringclass())
+ def method_rsplit(str, patt, max=-1):
+ getbookkeeper().count("str_rsplit", str, patt)
+ return getbookkeeper().newlist(str.basestringclass())
+
def method_replace(str, s1, s2):
return str.basestringclass()
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
@@ -722,31 +722,75 @@
newlen = len(s1.chars) - 1
return LLHelpers._ll_stringslice(s1, 0, newlen)
- def ll_split_chr(LIST, s, c):
+ def ll_split_chr(LIST, s, c, max):
chars = s.chars
strlen = len(chars)
count = 1
i = 0
+ if max == 0:
+ i = strlen
while i < strlen:
if chars[i] == c:
count += 1
+ if max >= 0 and count > max:
+ break
i += 1
res = LIST.ll_newlist(count)
items = res.ll_items()
i = 0
j = 0
resindex = 0
+ if max == 0:
+ j = strlen
while j < strlen:
if chars[j] == c:
item = items[resindex] = s.malloc(j - i)
item.copy_contents(s, item, i, 0, j - i)
resindex += 1
i = j + 1
+ if max >= 0 and resindex >= max:
+ j = strlen
+ break
j += 1
item = items[resindex] = s.malloc(j - i)
item.copy_contents(s, item, i, 0, j - i)
return res
+ def ll_rsplit_chr(LIST, s, c, max):
+ chars = s.chars
+ strlen = len(chars)
+ count = 1
+ i = 0
+ if max == 0:
+ i = strlen
+ while i < strlen:
+ if chars[i] == c:
+ count += 1
+ if max >= 0 and count > max:
+ break
+ i += 1
+ res = LIST.ll_newlist(count)
+ items = res.ll_items()
+ i = strlen
+ j = strlen
+ resindex = count - 1
+ assert resindex >= 0
+ if max == 0:
+ j = 0
+ while j > 0:
+ j -= 1
+ if chars[j] == c:
+ item = items[resindex] = s.malloc(i - j - 1)
+ item.copy_contents(s, item, j + 1, 0, i - j - 1)
+ resindex -= 1
+ i = j
+ if resindex == 0:
+ j = 0
+ break
+ item = items[resindex] = s.malloc(i - j)
+ item.copy_contents(s, item, j, 0, i - j)
+ return res
+
@purefunction
def ll_replace_chr_chr(s, c1, c2):
length = len(s.chars)
diff --git a/pypy/translator/backendopt/mallocv.py b/pypy/translator/backendopt/mallocv.py
--- a/pypy/translator/backendopt/mallocv.py
+++ b/pypy/translator/backendopt/mallocv.py
@@ -846,22 +846,6 @@
else:
return self.handle_default(op)
- def handle_op_keepalive(self, op):
- node = self.getnode(op.args[0])
- if isinstance(node, VirtualSpecNode):
- rtnodes, vtnodes = find_all_nodes([node])
- newops = []
- for rtnode in rtnodes:
- v = self.renamings[rtnode]
- if isinstance(v, Variable):
- T = v.concretetype
- if isinstance(T, lltype.Ptr) and T._needsgc():
- v0 = varoftype(lltype.Void)
- newops.append(SpaceOperation('keepalive', [v], v0))
- return newops
- else:
- return self.handle_default(op)
-
def handle_op_ptr_nonzero(self, op):
node = self.getnode(op.args[0])
if isinstance(node, VirtualSpecNode):
diff --git a/pypy/jit/backend/llsupport/descr.py b/pypy/jit/backend/llsupport/descr.py
--- a/pypy/jit/backend/llsupport/descr.py
+++ b/pypy/jit/backend/llsupport/descr.py
@@ -43,9 +43,14 @@
class SizeDescr(AbstractDescr):
size = 0 # help translation
+ is_immutable = False
- def __init__(self, size):
+ def __init__(self, size, count_fields_if_immut=-1):
self.size = size
+ self.count_fields_if_immut = count_fields_if_immut
+
+ def count_fields_if_immutable(self):
+ return self.count_fields_if_immut
def repr_of_descr(self):
return '<SizeDescr %s>' % self.size
@@ -62,15 +67,15 @@
return cache[STRUCT]
except KeyError:
size = symbolic.get_size(STRUCT, gccache.translate_support_code)
+ count_fields_if_immut = heaptracker.count_fields_if_immutable(STRUCT)
if heaptracker.has_gcstruct_a_vtable(STRUCT):
- sizedescr = SizeDescrWithVTable(size)
+ sizedescr = SizeDescrWithVTable(size, count_fields_if_immut)
else:
- sizedescr = SizeDescr(size)
+ sizedescr = SizeDescr(size, count_fields_if_immut)
gccache.init_size_descr(STRUCT, sizedescr)
cache[STRUCT] = sizedescr
return sizedescr
-
# ____________________________________________________________
# FieldDescrs
diff --git a/pypy/jit/backend/x86/regloc.py b/pypy/jit/backend/x86/regloc.py
--- a/pypy/jit/backend/x86/regloc.py
+++ b/pypy/jit/backend/x86/regloc.py
@@ -283,9 +283,15 @@
# These are the worst cases:
val2 = loc2.value_i()
code1 = loc1.location_code()
- if (code1 == 'j'
- or (code1 == 'm' and not rx86.fits_in_32bits(loc1.value_m()[1]))
- or (code1 == 'a' and not rx86.fits_in_32bits(loc1.value_a()[3]))):
+ if code1 == 'j':
+ checkvalue = loc1.value_j()
+ elif code1 == 'm':
+ checkvalue = loc1.value_m()[1]
+ elif code1 == 'a':
+ checkvalue = loc1.value_a()[3]
+ else:
+ checkvalue = 0
+ if not rx86.fits_in_32bits(checkvalue):
# INSN_ji, and both operands are 64-bit; or INSN_mi or INSN_ai
# and the constant offset in the address is 64-bit.
# Hopefully this doesn't happen too often
@@ -330,10 +336,10 @@
if code1 == possible_code1:
val1 = getattr(loc1, "value_" + possible_code1)()
# More faking out of certain operations for x86_64
- if self.WORD == 8 and possible_code1 == 'j':
+ if possible_code1 == 'j' and not rx86.fits_in_32bits(val1):
val1 = self._addr_as_reg_offset(val1)
invoke(self, "m" + possible_code2, val1, val2)
- elif self.WORD == 8 and possible_code2 == 'j':
+ elif possible_code2 == 'j' and not rx86.fits_in_32bits(val2):
val2 = self._addr_as_reg_offset(val2)
invoke(self, possible_code1 + "m", val1, val2)
elif possible_code1 == 'm' and not rx86.fits_in_32bits(val1[1]):
@@ -378,6 +384,10 @@
_rx86_getattr(self, name + "_l")(val)
self.add_pending_relocation()
else:
+ # xxx can we avoid "MOV r11, $val; JMP/CALL *r11"
+ # in case it would fit a 32-bit displacement?
+ # Hard, because we don't know yet where this insn
+ # will end up...
assert self.WORD == 8
self._load_scratch(val)
_rx86_getattr(self, name + "_r")(X86_64_SCRATCH_REG.value)
diff --git a/pypy/translator/backendopt/test/test_tailrecursion.py b/pypy/translator/backendopt/test/test_tailrecursion.py
--- a/pypy/translator/backendopt/test/test_tailrecursion.py
+++ b/pypy/translator/backendopt/test/test_tailrecursion.py
@@ -1,4 +1,4 @@
-from pypy.objspace.flow.model import traverse, Block, Link, Variable, Constant
+from pypy.objspace.flow.model import Block, Link, Variable, Constant
from pypy.translator.backendopt.tailrecursion import remove_tail_calls_to_self
from pypy.translator.translator import TranslationContext, graphof
from pypy.rpython.llinterp import LLInterpreter
diff --git a/pypy/module/cpyext/test/comparisons.c b/pypy/module/cpyext/test/comparisons.c
--- a/pypy/module/cpyext/test/comparisons.c
+++ b/pypy/module/cpyext/test/comparisons.c
@@ -69,12 +69,31 @@
};
+static int cmp_compare(PyObject *self, PyObject *other) {
+ return -1;
+}
+
+PyTypeObject OldCmpType = {
+ PyVarObject_HEAD_INIT(NULL, 0)
+ "comparisons.OldCmpType", /* tp_name */
+ sizeof(CmpObject), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ 0, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ (cmpfunc)cmp_compare, /* tp_compare */
+};
+
+
void initcomparisons(void)
{
PyObject *m, *d;
if (PyType_Ready(&CmpType) < 0)
return;
+ if (PyType_Ready(&OldCmpType) < 0)
+ return;
m = Py_InitModule("comparisons", NULL);
if (m == NULL)
return;
@@ -83,4 +102,6 @@
return;
if (PyDict_SetItemString(d, "CmpType", (PyObject *)&CmpType) < 0)
return;
+ if (PyDict_SetItemString(d, "OldCmpType", (PyObject *)&OldCmpType) < 0)
+ return;
}
diff --git a/pypy/module/signal/test/test_signal.py b/pypy/module/signal/test/test_signal.py
--- a/pypy/module/signal/test/test_signal.py
+++ b/pypy/module/signal/test/test_signal.py
@@ -262,6 +262,8 @@
signal(SIGALRM, SIG_DFL)
class AppTestItimer:
+ spaceconfig = dict(usemodules=['signal'])
+
def test_itimer_real(self):
import signal
diff --git a/pypy/translator/c/src/ll_math.c b/pypy/translator/c/src/ll_math.c
--- a/pypy/translator/c/src/ll_math.c
+++ b/pypy/translator/c/src/ll_math.c
@@ -22,18 +22,6 @@
#endif
#define PyPy_NAN (HUGE_VAL * 0.)
-int
-_pypy_math_isinf(double x)
-{
- return PyPy_IS_INFINITY(x);
-}
-
-int
-_pypy_math_isnan(double x)
-{
- return PyPy_IS_NAN(x);
-}
-
/* The following copyright notice applies to the original
implementations of acosh, asinh and atanh. */
diff --git a/pypy/module/pypyjit/test_pypy_c/model.py b/pypy/module/pypyjit/test_pypy_c/model.py
--- a/pypy/module/pypyjit/test_pypy_c/model.py
+++ b/pypy/module/pypyjit/test_pypy_c/model.py
@@ -250,7 +250,6 @@
# this is the ticker check generated in PyFrame.handle_operation_error
exc_ticker_check = """
ticker2 = getfield_raw(ticker_address, descr=<SignedFieldDescr pypysig_long_struct.c_value .*>)
- setfield_gc(_, _, descr=<GcPtrFieldDescr pypy.interpreter.pyframe.PyFrame.inst_w_f_trace .*>)
ticker_cond1 = int_lt(ticker2, 0)
guard_false(ticker_cond1, descr=...)
"""
@@ -260,13 +259,13 @@
@classmethod
def is_const(cls, v1):
return isinstance(v1, str) and v1.startswith('ConstClass(')
-
+
def match_var(self, v1, exp_v2):
assert v1 != '_'
if exp_v2 == '_':
return True
if self.is_const(v1) or self.is_const(exp_v2):
- return v1 == exp_v2
+ return v1[:-1].startswith(exp_v2[:-1])
if v1 not in self.alpha_map:
self.alpha_map[v1] = exp_v2
return self.alpha_map[v1] == exp_v2
@@ -285,9 +284,9 @@
self.match_var(op.res, exp_res)
self._assert(len(op.args) == len(exp_args), "wrong number of arguments")
for arg, exp_arg in zip(op.args, exp_args):
- self._assert(self.match_var(arg, exp_arg), "variable mismatch")
+ self._assert(self.match_var(arg, exp_arg), "variable mismatch: %r instead of %r" % (arg, exp_arg))
self.match_descr(op.descr, exp_descr)
-
+
def _next_op(self, iter_ops, assert_raises=False):
try:
diff --git a/pypy/module/thread/ll_thread.py b/pypy/module/thread/ll_thread.py
--- a/pypy/module/thread/ll_thread.py
+++ b/pypy/module/thread/ll_thread.py
@@ -1,10 +1,10 @@
-from pypy.rpython.lltypesystem import rffi
-from pypy.rpython.lltypesystem import lltype, llmemory
+from pypy.rpython.lltypesystem import rffi, lltype, llmemory
from pypy.rpython.tool import rffi_platform as platform
from pypy.translator.tool.cbuild import ExternalCompilationInfo
import py, os
from pypy.rpython.extregistry import ExtRegistryEntry
+from pypy.rlib import jit
from pypy.rlib.debug import ll_assert
from pypy.rlib.objectmodel import we_are_translated
from pypy.rpython.lltypesystem.lloperation import llop
@@ -79,6 +79,7 @@
# wrappers...
+ at jit.loop_invariant
def get_ident():
return rffi.cast(lltype.Signed, c_thread_get_ident())
@@ -113,6 +114,12 @@
def __del__(self):
free_ll_lock(self._lock)
+ def __enter__(self):
+ self.acquire(True)
+
+ def __exit__(self, *args):
+ self.release()
+
# ____________________________________________________________
#
# Stack size
diff --git a/pypy/jit/backend/llsupport/regalloc.py b/pypy/jit/backend/llsupport/regalloc.py
--- a/pypy/jit/backend/llsupport/regalloc.py
+++ b/pypy/jit/backend/llsupport/regalloc.py
@@ -1,5 +1,5 @@
-from pypy.jit.metainterp.history import Const, Box
+from pypy.jit.metainterp.history import Const, Box, REF
from pypy.rlib.objectmodel import we_are_translated
class TempBox(Box):
@@ -313,11 +313,12 @@
self.assembler.regalloc_mov(reg, to)
# otherwise it's clean
- def before_call(self, force_store=[], save_all_regs=False):
+ def before_call(self, force_store=[], save_all_regs=0):
""" Spill registers before a call, as described by
'self.save_around_call_regs'. Registers are not spilled if
they don't survive past the current operation, unless they
- are listed in 'force_store'.
+ are listed in 'force_store'. 'save_all_regs' can be 0 (default),
+ 1 (save all), or 2 (save default+PTRs).
"""
for v, reg in self.reg_bindings.items():
if v not in force_store and self.longevity[v][1] <= self.position:
@@ -325,9 +326,11 @@
del self.reg_bindings[v]
self.free_regs.append(reg)
continue
- if not save_all_regs and reg not in self.save_around_call_regs:
- # we don't have to
- continue
+ if save_all_regs != 1 and reg not in self.save_around_call_regs:
+ if save_all_regs == 0:
+ continue # we don't have to
+ if v.type != REF:
+ continue # only save GC pointers
self._sync_var(v)
del self.reg_bindings[v]
self.free_regs.append(reg)
diff --git a/pypy/module/pypyjit/test/test_pypy_c.py b/pypy/module/pypyjit/test/test_pypy_c.py
--- a/pypy/module/pypyjit/test/test_pypy_c.py
+++ b/pypy/module/pypyjit/test/test_pypy_c.py
@@ -3,6 +3,7 @@
import py
from py.test import skip
import sys, os, re
+import subprocess
class BytecodeTrace(list):
def get_opnames(self, prefix=""):
@@ -116,13 +117,12 @@
print >> f, "print 'OK :-)'"
f.close()
- if sys.platform.startswith('win'):
- py.test.skip("XXX this is not Windows-friendly")
print logfilepath
- child_stdout = os.popen('PYPYLOG=":%s" "%s" "%s"' % (
- logfilepath, self.pypy_c, filepath), 'r')
- result = child_stdout.read()
- child_stdout.close()
+ env = os.environ.copy()
+ env['PYPYLOG'] = ":%s" % (logfilepath,)
+ p = subprocess.Popen([self.pypy_c, str(filepath)],
+ env=env, stdout=subprocess.PIPE)
+ result, _ = p.communicate()
assert result
if result.strip().startswith('SKIP:'):
py.test.skip(result.strip())
@@ -1430,6 +1430,8 @@
res1 += dd(a, b, a1, b1)
res2 += dd(a, b, a2, b2)
res3 += dd(a, b, a3, b3)
+ # The purpose of this test is to check that we get
+ # the correct results, not really to count operations.
self.run_source('''
def main(a, b):
i = sa = 0
@@ -1437,11 +1439,10 @@
%s
i += 1
return sa
- ''' % code, 179, ([a1, b1], 2000 * res1),
- ([a2, b2], 2000 * res2),
- ([a3, b3], 2000 * res3),
- count_debug_merge_point=False)
-
+ ''' % code, sys.maxint, ([a1, b1], 2000 * res1),
+ ([a2, b2], 2000 * res2),
+ ([a3, b3], 2000 * res3))
+
def test_mod(self):
avalues = ('a', 'b', 7, -42, 8)
bvalues = ['b'] + range(-10, 0) + range(1,10)
@@ -1462,6 +1463,8 @@
res1 += dd(a, b, a1, b1)
res2 += dd(a, b, a2, b2)
res3 += dd(a, b, a3, b3)
+ # The purpose of this test is to check that we get
+ # the correct results, not really to count operations.
self.run_source('''
def main(a, b):
i = sa = 0
@@ -1471,11 +1474,10 @@
%s
i += 1
return sa
- ''' % code, 450, ([a1, b1], 2000 * res1),
- ([a2, b2], 2000 * res2),
- ([a3, b3], 2000 * res3),
- count_debug_merge_point=False)
-
+ ''' % code, sys.maxint, ([a1, b1], 2000 * res1),
+ ([a2, b2], 2000 * res2),
+ ([a3, b3], 2000 * res3))
+
def test_dont_trace_every_iteration(self):
self.run_source('''
def main(a, b):
diff --git a/pypy/jit/backend/llsupport/test/test_descr.py b/pypy/jit/backend/llsupport/test/test_descr.py
--- a/pypy/jit/backend/llsupport/test/test_descr.py
+++ b/pypy/jit/backend/llsupport/test/test_descr.py
@@ -18,12 +18,33 @@
descr_t = get_size_descr(c0, T)
assert descr_s.size == symbolic.get_size(S, False)
assert descr_t.size == symbolic.get_size(T, False)
+ assert descr_s.count_fields_if_immutable() == -1
+ assert descr_t.count_fields_if_immutable() == -1
assert descr_s == get_size_descr(c0, S)
assert descr_s != get_size_descr(c1, S)
#
descr_s = get_size_descr(c1, S)
assert isinstance(descr_s.size, Symbolic)
+ assert descr_s.count_fields_if_immutable() == -1
+def test_get_size_descr_immut():
+ S = lltype.GcStruct('S', hints={'immutable': True})
+ T = lltype.GcStruct('T', ('parent', S),
+ ('x', lltype.Char),
+ hints={'immutable': True})
+ U = lltype.GcStruct('U', ('parent', T),
+ ('u', lltype.Ptr(T)),
+ ('v', lltype.Signed),
+ hints={'immutable': True})
+ V = lltype.GcStruct('V', ('parent', U),
+ ('miss1', lltype.Void),
+ ('miss2', lltype.Void),
+ hints={'immutable': True})
+ for STRUCT, expected in [(S, 0), (T, 1), (U, 3), (V, 3)]:
+ for translated in [False, True]:
+ c0 = GcCache(translated)
+ descr_s = get_size_descr(c0, STRUCT)
+ assert descr_s.count_fields_if_immutable() == expected
def test_get_field_descr():
U = lltype.Struct('U')
diff --git a/pypy/rpython/test/test_rint.py b/pypy/rpython/test/test_rint.py
--- a/pypy/rpython/test/test_rint.py
+++ b/pypy/rpython/test/test_rint.py
@@ -4,7 +4,7 @@
from pypy.annotation import model as annmodel
from pypy.rpython.test import snippet
from pypy.rlib.rarithmetic import r_int, r_uint, r_longlong, r_ulonglong
-from pypy.rlib.rarithmetic import ovfcheck, r_int64, intmask
+from pypy.rlib.rarithmetic import ovfcheck, r_int64, intmask, int_between
from pypy.rlib import objectmodel
from pypy.rpython.test.tool import BaseRtypingTest, LLRtypeMixin, OORtypeMixin
@@ -215,6 +215,14 @@
assert res == f(inttype(0))
assert type(res) == inttype
+ def test_and_or(self):
+ inttypes = [int, r_uint, r_int64, r_ulonglong]
+ for inttype in inttypes:
+ def f(a, b, c):
+ return a&b|c
+ res = self.interpret(f, [inttype(0x1234), inttype(0x00FF), inttype(0x5600)])
+ assert res == f(0x1234, 0x00FF, 0x5600)
+
def test_neg_abs_ovf(self):
for op in (operator.neg, abs):
def f(x):
@@ -266,6 +274,8 @@
x = inttype(random.randint(-100000, 100000))
y = inttype(random.randint(-100000, 100000))
if not y: continue
+ if (i & 31) == 0:
+ x = (x//y) * y # case where x is exactly divisible by y
res = self.interpret(d, [x, y])
assert res == d(x, y)
@@ -276,6 +286,8 @@
x = inttype(random.randint(-100000, 100000))
y = inttype(random.randint(-100000, 100000))
if not y: continue
+ if (i & 31) == 0:
+ x = (x//y) * y # case where x is exactly divisible by y
res = self.interpret(m, [x, y])
assert res == m(x, y)
@@ -384,6 +396,18 @@
else:
assert res == 123456789012345678
+ def test_int_between(self):
+ def fn(a, b, c):
+ return int_between(a, b, c)
+ assert self.interpret(fn, [1, 1, 3])
+ assert self.interpret(fn, [1, 2, 3])
+ assert not self.interpret(fn, [1, 0, 2])
+ assert not self.interpret(fn, [1, 5, 2])
+ assert not self.interpret(fn, [1, 2, 2])
+ assert not self.interpret(fn, [1, 1, 1])
+
+
+
class TestLLtype(BaseTestRint, LLRtypeMixin):
pass
diff --git a/pypy/translator/jvm/src/pypy/PyPy.java b/pypy/translator/jvm/src/pypy/PyPy.java
--- a/pypy/translator/jvm/src/pypy/PyPy.java
+++ b/pypy/translator/jvm/src/pypy/PyPy.java
@@ -38,6 +38,10 @@
public final static int INT_MIN = Integer.MIN_VALUE;
public final static double ULONG_MAX = 18446744073709551616.0;
+ public static boolean int_between(int a, int b, int c) {
+ return a <= b && b < c;
+ }
+
/**
* Compares two unsigned integers (value1 and value2) and returns
* a value greater than, equal to, or less than zero if value 1 is
@@ -163,6 +167,13 @@
return ULONG_MAX + value;
}
}
+
+ public static long double_to_ulong(double value) {
+ if (value < 0)
+ return (long)(ULONG_MAX + value);
+ else
+ return (long)value;
+ }
public static int double_to_uint(double value) {
if (value <= Integer.MAX_VALUE)
@@ -746,11 +757,13 @@
return str.substring(start, end);
}
- public static Object[] ll_split_chr(String str, char c) {
+ public static Object[] ll_split_chr(String str, char c, int max) {
ArrayList list = new ArrayList();
int lastidx = 0, idx = 0;
while ((idx = str.indexOf(c, lastidx)) != -1)
{
+ if (max >= 0 && list.size() >= max)
+ break;
String sub = str.substring(lastidx, idx);
list.add(sub);
lastidx = idx+1;
@@ -759,6 +772,21 @@
return list.toArray(new String[list.size()]);
}
+ public static Object[] ll_rsplit_chr(String str, char c, int max) {
+ ArrayList list = new ArrayList();
+ int lastidx = str.length(), idx = 0;
+ while ((idx = str.lastIndexOf(c, lastidx - 1)) != -1)
+ {
+ if (max >= 0 && list.size() >= max)
+ break;
+ String sub = str.substring(idx + 1, lastidx);
+ list.add(0, sub);
+ lastidx = idx;
+ }
+ list.add(0, str.substring(0, lastidx));
+ return list.toArray(new String[list.size()]);
+ }
+
public static String ll_substring(String str, int start, int cnt) {
return str.substring(start,start+cnt);
}
@@ -1158,6 +1186,18 @@
return Math.tanh(x);
}
+ public double ll_math_copysign(double x, double y) {
+ return Math.copySign(x, y);
+ }
+
+ public boolean ll_math_isnan(double x) {
+ return Double.isNaN(x);
+ }
+
+ public boolean ll_math_isinf(double x) {
+ return Double.isInfinite(x);
+ }
+
private double check(double v) {
if (Double.isNaN(v))
interlink.throwValueError();
@@ -1170,9 +1210,42 @@
return Character.toLowerCase(c);
}
+ public int locale_tolower(int chr)
+ {
+ return Character.toLowerCase(chr);
+ }
+
+ public int locale_isupper(int chr)
+ {
+ return boolean2int(Character.isUpperCase(chr));
+ }
+
+ public int locale_islower(int chr)
+ {
+ return boolean2int(Character.isLowerCase(chr));
+ }
+
+ public int locale_isalpha(int chr)
+ {
+ return boolean2int(Character.isLetter(chr));
+ }
+
+ public int locale_isalnum(int chr)
+ {
+ return boolean2int(Character.isLetterOrDigit(chr));
+ }
+
+
// ----------------------------------------------------------------------
// Self Test
+ public static int boolean2int(boolean b)
+ {
+ if (b)
+ return 1;
+ return 0;
+ }
+
public static int __counter = 0, __failures = 0;
public static void ensure(boolean f) {
if (f) {
diff --git a/pypy/jit/backend/x86/support.py b/pypy/jit/backend/x86/support.py
--- a/pypy/jit/backend/x86/support.py
+++ b/pypy/jit/backend/x86/support.py
@@ -38,11 +38,7 @@
if sys.platform == 'win32':
ensure_sse2_floats = lambda : None
else:
- _sse2_eci = ExternalCompilationInfo(
+ ensure_sse2_floats = rffi.llexternal_use_eci(ExternalCompilationInfo(
compile_extra = ['-msse2', '-mfpmath=sse',
'-DPYPY_CPU_HAS_STANDARD_PRECISION'],
- separate_module_sources = ['void PYPY_NO_OP(void) {}'],
- )
- ensure_sse2_floats = rffi.llexternal('PYPY_NO_OP', [], lltype.Void,
- compilation_info=_sse2_eci,
- sandboxsafe=True)
+ ))
diff --git a/pypy/jit/metainterp/test/test_string.py b/pypy/jit/metainterp/test/test_string.py
--- a/pypy/jit/metainterp/test/test_string.py
+++ b/pypy/jit/metainterp/test/test_string.py
@@ -2,7 +2,7 @@
from pypy.rlib.jit import JitDriver, dont_look_inside, we_are_jitted
from pypy.jit.codewriter.policy import StopAtXPolicy
from pypy.rpython.ootypesystem import ootype
-from pypy.jit.metainterp.test.test_basic import LLJitMixin, OOJitMixin
+from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin
class StringTests:
diff --git a/pypy/translator/jvm/test/test_builtin.py b/pypy/translator/jvm/test/test_builtin.py
--- a/pypy/translator/jvm/test/test_builtin.py
+++ b/pypy/translator/jvm/test/test_builtin.py
@@ -37,6 +37,15 @@
def test_cast_primitive(self):
py.test.skip('fixme!')
+ def test_os_fstat(self):
+ import os, stat
+ def fn():
+ fd = os.open(__file__, os.O_RDONLY, 0)
+ st = os.fstat(fd)
+ os.close(fd)
+ return st.st_mode
+ res = self.interpret(fn, [])
+ assert stat.S_ISREG(res)
class TestJvmTime(JvmTest, BaseTestTime):
diff --git a/pypy/jit/codewriter/heaptracker.py b/pypy/jit/codewriter/heaptracker.py
--- a/pypy/jit/codewriter/heaptracker.py
+++ b/pypy/jit/codewriter/heaptracker.py
@@ -10,6 +10,30 @@
def int2adr(int):
return llmemory.cast_int_to_adr(int)
+def count_fields_if_immutable(STRUCT):
+ assert isinstance(STRUCT, lltype.GcStruct)
+ if STRUCT._hints.get('immutable', False):
+ try:
+ return _count_fields(STRUCT)
+ except ValueError:
+ pass
+ return -1
+
+def _count_fields(STRUCT):
+ if STRUCT == rclass.OBJECT:
+ return 0 # don't count 'typeptr'
+ result = 0
+ for fieldname, TYPE in STRUCT._flds.items():
+ if TYPE is lltype.Void:
+ pass # ignore Voids
+ elif not isinstance(TYPE, lltype.ContainerType):
+ result += 1
+ elif isinstance(TYPE, lltype.GcStruct):
+ result += _count_fields(TYPE)
+ else:
+ raise ValueError(TYPE)
+ return result
+
# ____________________________________________________________
def has_gcstruct_a_vtable(GCSTRUCT):
diff --git a/pypy/jit/metainterp/test/test_greenfield.py b/pypy/jit/metainterp/test/test_greenfield.py
--- a/pypy/jit/metainterp/test/test_greenfield.py
+++ b/pypy/jit/metainterp/test/test_greenfield.py
@@ -1,4 +1,4 @@
-from pypy.jit.metainterp.test.test_basic import LLJitMixin, OOJitMixin
+from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin
from pypy.rlib.jit import JitDriver
diff --git a/pypy/objspace/flow/model.py b/pypy/objspace/flow/model.py
--- a/pypy/objspace/flow/model.py
+++ b/pypy/objspace/flow/model.py
@@ -379,27 +379,6 @@
return result
-def traverse(visit, functiongraph):
- block = functiongraph.startblock
- visit(block)
- seen = identity_dict()
- seen[block] = True
- stack = list(block.exits[::-1])
- while stack:
- link = stack.pop()
- visit(link)
- block = link.target
- if block not in seen:
- visit(block)
- seen[block] = True
- stack += block.exits[::-1]
-
-
-def flatten(funcgraph):
- l = []
- traverse(l.append, funcgraph)
- return l
-
def flattenobj(*args):
for arg in args:
try:
@@ -497,6 +476,19 @@
assert block.operations == ()
assert block.exits == ()
+ def definevar(v, only_in_link=None):
+ assert isinstance(v, Variable)
+ assert v not in vars, "duplicate variable %r" % (v,)
+ assert v not in vars_previous_blocks, (
+ "variable %r used in more than one block" % (v,))
+ vars[v] = only_in_link
+
+ def usevar(v, in_link=None):
+ assert v in vars
+ if in_link is not None:
+ assert vars[v] is None or vars[v] is in_link
+
+
for block in graph.iterblocks():
assert bool(block.isstartblock) == (block is graph.startblock)
assert type(block.exits) is tuple, (
@@ -506,18 +498,6 @@
assert block in exitblocks
vars = {}
- def definevar(v, only_in_link=None):
- assert isinstance(v, Variable)
- assert v not in vars, "duplicate variable %r" % (v,)
- assert v not in vars_previous_blocks, (
- "variable %r used in more than one block" % (v,))
- vars[v] = only_in_link
-
- def usevar(v, in_link=None):
- assert v in vars
- if in_link is not None:
- assert vars[v] is None or vars[v] is in_link
-
for v in block.inputargs:
definevar(v)
diff --git a/.hgignore b/.hgignore
--- a/.hgignore
+++ b/.hgignore
@@ -17,7 +17,6 @@
^pypy/doc/.+\.html$
^pypy/doc/basicblock\.asc$
^pypy/doc/.+\.svninfo$
-^pypy/translator/c/src/dtoa.o$
^pypy/translator/c/src/libffi_msvc/.+\.obj$
^pypy/translator/c/src/libffi_msvc/.+\.dll$
^pypy/translator/c/src/libffi_msvc/.+\.lib$
@@ -64,4 +63,4 @@
^pypy/doc/image/parsing_example.+\.png$
^compiled
^.git/
-^release/
\ No newline at end of file
+^release/
diff --git a/pypy/config/pypyoption.py b/pypy/config/pypyoption.py
--- a/pypy/config/pypyoption.py
+++ b/pypy/config/pypyoption.py
@@ -13,7 +13,7 @@
and not p.basename.startswith('test')]
essential_modules = dict.fromkeys(
- ["exceptions", "_file", "sys", "__builtin__", "posix", "signal"]
+ ["exceptions", "_file", "sys", "__builtin__", "posix"]
)
default_modules = essential_modules.copy()
@@ -39,7 +39,7 @@
translation_modules = default_modules.copy()
translation_modules.update(dict.fromkeys(
["fcntl", "rctime", "select", "signal", "_rawffi", "zlib",
- "struct", "md5", "cStringIO", "array"]))
+ "struct", "_md5", "cStringIO", "array"]))
working_oo_modules = default_modules.copy()
working_oo_modules.update(dict.fromkeys(
@@ -159,6 +159,11 @@
cmdline="--allworkingmodules",
negation=True),
+ StrOption("extmodules",
+ "Comma-separated list of third-party builtin modules",
+ cmdline="--ext",
+ default=None),
+
BoolOption("translationmodules",
"use only those modules that are needed to run translate.py on pypy",
default=False,
@@ -352,8 +357,8 @@
config.objspace.std.suggest(optimized_list_getitem=True)
config.objspace.std.suggest(getattributeshortcut=True)
config.objspace.std.suggest(newshortcut=True)
- if not IS_64_BITS:
- config.objspace.std.suggest(withsmalllong=True)
+ #if not IS_64_BITS:
+ # config.objspace.std.suggest(withsmalllong=True)
# extra costly optimizations only go in level 3
if level == '3':
diff --git a/pypy/translator/stackless/transform.py b/pypy/translator/stackless/transform.py
--- a/pypy/translator/stackless/transform.py
+++ b/pypy/translator/stackless/transform.py
@@ -2,7 +2,7 @@
from pypy.rpython.lltypesystem.lloperation import LL_OPERATIONS
from pypy.rlib import rarithmetic
from pypy.rpython import rclass, rmodel
-from pypy.translator.backendopt import support
+from pypy.translator.unsimplify import split_block
from pypy.objspace.flow import model
from pypy.translator import unsimplify, simplify
from pypy.translator.unsimplify import varoftype
@@ -598,7 +598,7 @@
link = block.exits[0]
nextblock = None
else:
- link = support.split_block_with_keepalive(block, i+1)
+ link = split_block(None, block, i+1)
i = 0
nextblock = link.target
@@ -765,7 +765,7 @@
exitcases = dict.fromkeys([l.exitcase for l in block.exits])
nextblock = None
else:
- link = support.split_block_with_keepalive(block, i+1)
+ link = split_block(None, block, i+1)
nextblock = link.target
block.exitswitch = model.c_last_exception
link.llexitcase = None
diff --git a/pypy/module/posix/__init__.py b/pypy/module/posix/__init__.py
--- a/pypy/module/posix/__init__.py
+++ b/pypy/module/posix/__init__.py
@@ -5,6 +5,25 @@
import os, sys
exec 'import %s as posix' % os.name
+# this is the list of function which is *not* present in the posix module of
+# IronPython 2.6, and that we want to ignore for now
+lltype_only_defs = [
+ 'chown', 'chroot', 'closerange', 'confstr', 'confstr_names', 'ctermid', 'dup',
+ 'dup2', 'execv', 'execve', 'fchdir', 'fchmod', 'fchown', 'fdatasync', 'fork',
+ 'forkpty', 'fpathconf', 'fstatvfs', 'fsync', 'ftruncate', 'getegid', 'geteuid',
+ 'getgid', 'getgroups', 'getloadavg', 'getlogin', 'getpgid', 'getpgrp', 'getppid',
+ 'getsid', 'getuid', 'kill', 'killpg', 'lchown', 'link', 'lseek', 'major',
+ 'makedev', 'minor', 'mkfifo', 'mknod', 'nice', 'openpty', 'pathconf', 'pathconf_names',
+ 'pipe', 'readlink', 'setegid', 'seteuid', 'setgid', 'setgroups', 'setpgid', 'setpgrp',
+ 'setregid', 'setreuid', 'setsid', 'setuid', 'stat_float_times', 'statvfs',
+ 'statvfs_result', 'symlink', 'sysconf', 'sysconf_names', 'tcgetpgrp', 'tcsetpgrp',
+ 'ttyname', 'uname', 'wait', 'wait3', 'wait4'
+ ]
+
+# the Win32 urandom implementation isn't going to translate on JVM or CLI so
+# we have to remove it
+lltype_only_defs.append('urandom')
+
class Module(MixedModule):
"""This module provides access to operating system functionality that is
standardized by the C Standard and the POSIX standard (a thinly
@@ -31,6 +50,10 @@
if hasattr(os, 'wait'):
appleveldefs['wait'] = 'app_posix.wait'
+ if hasattr(os, 'wait3'):
+ appleveldefs['wait3'] = 'app_posix.wait3'
+ if hasattr(os, 'wait4'):
+ appleveldefs['wait4'] = 'app_posix.wait4'
interpleveldefs = {
'open' : 'interp_posix.open',
@@ -156,11 +179,12 @@
interpleveldefs[name] = 'interp_posix.' + name
def __init__(self, space, w_name):
+ # if it's an ootype translation, remove all the defs that are lltype
+ # only
backend = space.config.translation.backend
- # the Win32 urandom implementation isn't going to translate on JVM or CLI
- # so we have to remove it
- if 'urandom' in self.interpleveldefs and (backend == 'cli' or backend == 'jvm'):
- del self.interpleveldefs['urandom']
+ if backend == 'cli' or backend == 'jvm':
+ for name in lltype_only_defs:
+ self.interpleveldefs.pop(name, None)
MixedModule.__init__(self, space, w_name)
def startup(self, space):
diff --git a/pypy/jit/metainterp/test/test_list.py b/pypy/jit/metainterp/test/test_list.py
--- a/pypy/jit/metainterp/test/test_list.py
+++ b/pypy/jit/metainterp/test/test_list.py
@@ -1,6 +1,6 @@
import py
from pypy.rlib.jit import JitDriver
-from pypy.jit.metainterp.test.test_basic import LLJitMixin, OOJitMixin
+from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin
class ListTests:
diff --git a/pypy/objspace/std/mapdict.py b/pypy/objspace/std/mapdict.py
--- a/pypy/objspace/std/mapdict.py
+++ b/pypy/objspace/std/mapdict.py
@@ -641,6 +641,18 @@
else:
self._as_rdict().impl_fallback_setitem(w_key, w_value)
+ def impl_setdefault(self, w_key, w_default):
+ space = self.space
+ if space.is_w(space.type(w_key), space.w_str):
+ key = space.str_w(w_key)
+ w_result = self.impl_getitem_str(key)
+ if w_result is not None:
+ return w_result
+ self.impl_setitem_str(key, w_default)
+ return w_default
+ else:
+ return self._as_rdict().impl_fallback_setdefault(w_key, w_default)
+
def impl_delitem(self, w_key):
space = self.space
w_key_type = space.type(w_key)
diff --git a/pypy/rpython/extfunc.py b/pypy/rpython/extfunc.py
--- a/pypy/rpython/extfunc.py
+++ b/pypy/rpython/extfunc.py
@@ -249,6 +249,9 @@
llfakeimpl, oofakeimpl: optional; if provided, they are called by the llinterpreter
sandboxsafe: use True if the function performs no I/O (safe for --sandbox)
"""
+
+ if export_name is None:
+ export_name = function.__name__
class FunEntry(ExtFuncEntry):
_about_ = function
diff --git a/pypy/translator/goal/query.py b/pypy/translator/goal/query.py
--- a/pypy/translator/goal/query.py
+++ b/pypy/translator/goal/query.py
@@ -30,15 +30,13 @@
def polluted_qgen(translator):
"""list functions with still real SomeObject variables"""
annotator = translator.annotator
- def visit(block):
- if isinstance(block, flowmodel.Block):
- for v in block.getvariables():
- s = annotator.binding(v, None)
- if s and s.__class__ == annmodel.SomeObject and s.knowntype != type:
- raise Found
for g in translator.graphs:
try:
- flowmodel.traverse(visit, g)
+ for block in g.iterblocks():
+ for v in block.getvariables():
+ s = annotator.binding(v, None)
+ if s and s.__class__ == annmodel.SomeObject and s.knowntype != type:
+ raise Found
except Found:
line = "%s: %s" % (g, graph_sig(translator, g))
yield line
diff --git a/pypy/tool/jitlogparser/storage.py b/pypy/tool/jitlogparser/storage.py
--- a/pypy/tool/jitlogparser/storage.py
+++ b/pypy/tool/jitlogparser/storage.py
@@ -30,18 +30,18 @@
self.codes[fname] = res
return res
- def disassemble_code(self, fname, startlineno):
+ def disassemble_code(self, fname, startlineno, name):
try:
if py.path.local(fname).check(file=False):
return None # cannot find source file
except py.error.EACCES:
return None # cannot open the file
- key = (fname, startlineno)
+ key = (fname, startlineno, name)
try:
return self.disassembled_codes[key]
except KeyError:
codeobjs = self.load_code(fname)
- if startlineno not in codeobjs:
+ if (startlineno, name) not in codeobjs:
# cannot find the code obj at this line: this can happen for
# various reasons, e.g. because the .py files changed since
# the log was produced, or because the co_firstlineno
@@ -49,7 +49,7 @@
# produced by gateway.applevel(), such as the ones found in
# nanos.py)
return None
- code = codeobjs[startlineno]
+ code = codeobjs[(startlineno, name)]
res = dis(code)
self.disassembled_codes[key] = res
return res
diff --git a/pypy/jit/metainterp/test/test_longlong.py b/pypy/jit/metainterp/test/test_longlong.py
--- a/pypy/jit/metainterp/test/test_longlong.py
+++ b/pypy/jit/metainterp/test/test_longlong.py
@@ -1,6 +1,6 @@
import py, sys
from pypy.rlib.rarithmetic import r_longlong, r_ulonglong, r_uint, intmask
-from pypy.jit.metainterp.test.test_basic import LLJitMixin
+from pypy.jit.metainterp.test.support import LLJitMixin
class WrongResult(Exception):
pass
diff --git a/lib_pypy/_ctypes/builtin.py b/lib_pypy/_ctypes/builtin.py
--- a/lib_pypy/_ctypes/builtin.py
+++ b/lib_pypy/_ctypes/builtin.py
@@ -1,6 +1,9 @@
import _rawffi, sys
-import threading
+try:
+ from thread import _local as local
+except ImportError:
+ local = object # no threads
class ConvMode:
encoding = 'ascii'
@@ -28,7 +31,7 @@
arg = cobj._get_buffer_value()
return _rawffi.wcharp2rawunicode(arg, lgt)
-class ErrorObject(threading.local):
+class ErrorObject(local):
def __init__(self):
self.errno = 0
self.winerror = 0
diff --git a/pypy/module/cpyext/test/test_stringobject.py b/pypy/module/cpyext/test/test_stringobject.py
--- a/pypy/module/cpyext/test/test_stringobject.py
+++ b/pypy/module/cpyext/test/test_stringobject.py
@@ -194,8 +194,8 @@
c_buf = py_str.c_ob_type.c_tp_as_buffer
assert c_buf
py_obj = rffi.cast(PyObject, py_str)
- assert c_buf.c_bf_getsegcount(py_obj, lltype.nullptr(rffi.INTP.TO)) == 1
- ref = lltype.malloc(rffi.INTP.TO, 1, flavor='raw')
+ assert c_buf.c_bf_getsegcount(py_obj, lltype.nullptr(Py_ssize_tP.TO)) == 1
+ ref = lltype.malloc(Py_ssize_tP.TO, 1, flavor='raw')
assert c_buf.c_bf_getsegcount(py_obj, ref) == 1
assert ref[0] == 10
lltype.free(ref, flavor='raw')
diff --git a/pypy/rlib/objectmodel.py b/pypy/rlib/objectmodel.py
--- a/pypy/rlib/objectmodel.py
+++ b/pypy/rlib/objectmodel.py
@@ -255,7 +255,7 @@
x = ord(s[0]) << 7
i = 0
while i < length:
- x = (1000003*x) ^ ord(s[i])
+ x = intmask((1000003*x) ^ ord(s[i]))
i += 1
x ^= length
return intmask(x)
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
@@ -181,6 +181,7 @@
jIntegerClass = JvmClassType('java.lang.Integer')
jLongClass = JvmClassType('java.lang.Long')
+jShortClass = JvmClassType('java.lang.Short')
jDoubleClass = JvmClassType('java.lang.Double')
jByteClass = JvmClassType('java.lang.Byte')
jCharClass = JvmClassType('java.lang.Character')
@@ -239,6 +240,7 @@
jDouble = JvmScalarType('D', jDoubleClass, 'doubleValue')
jByte = JvmScalarType('B', jByteClass, 'byteValue')
jChar = JvmScalarType('C', jCharClass, 'charValue')
+jShort = JvmScalarType('S', jShortClass, 'shortValue')
class Generifier(object):
@@ -527,6 +529,7 @@
if desc == 'C': return self._o("i") # Characters
if desc == 'B': return self._o("i") # Bytes
if desc == 'Z': return self._o("i") # Boolean
+ if desc == 'S': return self._o("i") # Short
assert False, "Unknown argtype=%s" % repr(argtype)
raise NotImplementedError
@@ -625,6 +628,7 @@
NOP = Opcode('nop')
I2D = Opcode('i2d')
I2L = Opcode('i2l')
+I2S = Opcode('i2s')
D2I= Opcode('d2i')
#D2L= Opcode('d2l') #PAUL
L2I = Opcode('l2i')
@@ -891,6 +895,7 @@
SYSTEMIDENTITYHASH = Method.s(jSystem, 'identityHashCode', (jObject,), jInt)
SYSTEMGC = Method.s(jSystem, 'gc', (), jVoid)
INTTOSTRINGI = Method.s(jIntegerClass, 'toString', (jInt,), jString)
+SHORTTOSTRINGS = Method.s(jShortClass, 'toString', (jShort,), jString)
LONGTOSTRINGL = Method.s(jLongClass, 'toString', (jLong,), jString)
DOUBLETOSTRINGD = Method.s(jDoubleClass, 'toString', (jDouble,), jString)
CHARTOSTRINGC = Method.s(jCharClass, 'toString', (jChar,), jString)
@@ -922,15 +927,19 @@
CLASSISASSIGNABLEFROM = Method.v(jClass, 'isAssignableFrom', (jClass,), jBool)
STRINGBUILDERAPPEND = Method.v(jStringBuilder, 'append',
(jString,), jStringBuilder)
+PYPYINTBETWEEN = Method.s(jPyPy, 'int_between', (jInt,jInt,jInt), jBool)
PYPYUINTCMP = Method.s(jPyPy, 'uint_cmp', (jInt,jInt,), jInt)
PYPYULONGCMP = Method.s(jPyPy, 'ulong_cmp', (jLong,jLong), jInt)
PYPYUINTMOD = Method.v(jPyPy, 'uint_mod', (jInt, jInt), jInt)
PYPYUINTMUL = Method.v(jPyPy, 'uint_mul', (jInt, jInt), jInt)
PYPYUINTDIV = Method.v(jPyPy, 'uint_div', (jInt, jInt), jInt)
PYPYULONGMOD = Method.v(jPyPy, 'ulong_mod', (jLong, jLong), jLong)
+PYPYUINTTOLONG = Method.s(jPyPy, 'uint_to_long', (jInt,), jLong)
PYPYUINTTODOUBLE = Method.s(jPyPy, 'uint_to_double', (jInt,), jDouble)
PYPYDOUBLETOUINT = Method.s(jPyPy, 'double_to_uint', (jDouble,), jInt)
PYPYDOUBLETOLONG = Method.v(jPyPy, 'double_to_long', (jDouble,), jLong) #PAUL
+PYPYDOUBLETOULONG = Method.s(jPyPy, 'double_to_ulong', (jDouble,), jLong)
+PYPYULONGTODOUBLE = Method.s(jPyPy, 'ulong_to_double', (jLong,), jDouble)
PYPYLONGBITWISENEGATE = Method.v(jPyPy, 'long_bitwise_negate', (jLong,), jLong)
PYPYSTRTOINT = Method.v(jPyPy, 'str_to_int', (jString,), jInt)
PYPYSTRTOUINT = Method.v(jPyPy, 'str_to_uint', (jString,), jInt)
diff --git a/pypy/translator/backendopt/test/test_removenoops.py b/pypy/translator/backendopt/test/test_removenoops.py
--- a/pypy/translator/backendopt/test/test_removenoops.py
+++ b/pypy/translator/backendopt/test/test_removenoops.py
@@ -1,12 +1,12 @@
from pypy.translator.backendopt.removenoops import remove_same_as, \
- remove_unaryops, remove_duplicate_casts, remove_superfluous_keep_alive
+ remove_unaryops, remove_duplicate_casts
from pypy.translator.backendopt.inline import simple_inline_function
from pypy.translator.translator import TranslationContext, graphof
from pypy.rpython.memory.gctransform.test.test_transform import getops
from pypy.translator.test.snippet import simple_method
from pypy.translator.backendopt.all import backend_optimizations
from pypy.translator.backendopt.all import INLINE_THRESHOLD_FOR_TEST
-from pypy.objspace.flow.model import checkgraph, flatten, Block
+from pypy.objspace.flow.model import checkgraph, Block
from pypy.rpython.lltypesystem import lltype
from pypy.rpython.lltypesystem.lloperation import llop
from pypy.rpython.llinterp import LLInterpreter
@@ -115,20 +115,6 @@
result = interp.eval_graph(f_graph, [-2])
assert result == -1
-def test_remove_keepalive():
- S = lltype.GcStruct("s", ("f", lltype.Signed))
- def f():
- s1 = lltype.malloc(S)
- llop.keepalive(lltype.Void, s1)
- s2 = lltype.malloc(S)
- llop.keepalive(lltype.Void, s1)
- llop.keepalive(lltype.Void, s2)
- return lltype.cast_ptr_to_int(s1) + lltype.cast_ptr_to_int(s2)
- graph, t = get_graph(f, [])
- remove_superfluous_keep_alive(graph)
- ops = getops(graph)
- assert len(ops['keepalive']) == 2
-
def test_remove_duplicate_casts():
class A(object):
def __init__(self, x, y):
diff --git a/pypy/translator/simplify.py b/pypy/translator/simplify.py
--- a/pypy/translator/simplify.py
+++ b/pypy/translator/simplify.py
@@ -9,7 +9,7 @@
from pypy.objspace.flow import operation
from pypy.objspace.flow.model import (SpaceOperation, Variable, Constant, Block,
Link, c_last_exception, checkgraph,
- traverse, mkentrymap)
+ mkentrymap)
from pypy.rlib import rarithmetic
from pypy.translator import unsimplify
from pypy.translator.backendopt import ssa
@@ -76,23 +76,19 @@
def desugar_isinstance(graph):
"""Replace isinstance operation with a call to isinstance."""
constant_isinstance = Constant(isinstance)
- def visit(block):
- if not isinstance(block, Block):
- return
+ for block in graph.iterblocks():
for i in range(len(block.operations) - 1, -1, -1):
op = block.operations[i]
if op.opname == "isinstance":
args = [constant_isinstance, op.args[0], op.args[1]]
new_op = SpaceOperation("simple_call", args, op.result)
block.operations[i] = new_op
- traverse(visit, graph)
def eliminate_empty_blocks(graph):
"""Eliminate basic blocks that do not contain any operations.
When this happens, we need to replace the preceeding link with the
following link. Arguments of the links should be updated."""
- def visit(link):
- if isinstance(link, Link):
+ for link in list(graph.iterlinks()):
while not link.target.operations:
block1 = link.target
if block1.exitswitch is not None:
@@ -113,7 +109,6 @@
link.args = outputargs
link.target = exit.target
# the while loop above will simplify recursively the new link
- traverse(visit, graph)
def transform_ovfcheck(graph):
"""The special function calls ovfcheck and ovfcheck_lshift need to
@@ -174,11 +169,10 @@
def rename(v):
return renaming.get(v, v)
- def visit(block):
- if not (isinstance(block, Block)
- and block.exitswitch == clastexc
+ for block in graph.iterblocks():
+ if not (block.exitswitch == clastexc
and block.exits[-1].exitcase is Exception):
- return
+ continue
covered = [link.exitcase for link in block.exits[1:-1]]
seen = []
preserve = list(block.exits[:-1])
@@ -233,8 +227,6 @@
exits.append(link)
block.recloseblock(*(preserve + exits))
- traverse(visit, graph)
-
def transform_xxxitem(graph):
# xxx setitem too
for block in graph.iterblocks():
@@ -262,9 +254,9 @@
return True
return False
- def visit(block):
- if not (isinstance(block, Block) and block.exitswitch == clastexc):
- return
+ for block in list(graph.iterblocks()):
+ if block.exitswitch != clastexc:
+ continue
exits = []
seen = []
for link in block.exits:
@@ -283,8 +275,6 @@
seen.append(case)
block.recloseblock(*exits)
- traverse(visit, graph)
-
def join_blocks(graph):
"""Links can be deleted if they are the single exit of a block and
the single entry point of the next block. When this happens, we can
@@ -340,8 +330,7 @@
this is how implicit exceptions are removed (see _implicit_ in
flowcontext.py).
"""
- def visit(block):
- if isinstance(block, Block):
+ for block in list(graph.iterblocks()):
for i in range(len(block.exits)-1, -1, -1):
exit = block.exits[i]
if not (exit.target is graph.exceptblock and
@@ -361,7 +350,6 @@
lst = list(block.exits)
del lst[i]
block.recloseblock(*lst)
- traverse(visit, graph)
# _____________________________________________________________________
@@ -627,12 +615,11 @@
tgts.append((exit.exitcase, tgt))
return tgts
- def visit(block):
- if isinstance(block, Block) and block.operations and block.operations[-1].opname == 'is_true':
+ for block in graph.iterblocks():
+ if block.operations and block.operations[-1].opname == 'is_true':
tgts = has_is_true_exitpath(block)
if tgts:
candidates.append((block, tgts))
- traverse(visit, graph)
while candidates:
cand, tgts = candidates.pop()
diff --git a/pypy/translator/cli/metavm.py b/pypy/translator/cli/metavm.py
--- a/pypy/translator/cli/metavm.py
+++ b/pypy/translator/cli/metavm.py
@@ -270,23 +270,38 @@
generator.ilasm.call('void [pypylib]pypy.runtime.DebugPrint::DEBUG_PRINT(%s)' % signature)
+INT_SIZE = {
+ ootype.Bool: 1,
+ ootype.Char: 2,
+ ootype.UniChar: 2,
+ rffi.SHORT: 2,
+ ootype.Signed: 4,
+ ootype.Unsigned: 4,
+ ootype.SignedLongLong: 8,
+ ootype.UnsignedLongLong: 8
+ }
-OOTYPE_TO_MNEMONIC = {
- ootype.Bool: 'i1',
- ootype.Char: 'i2',
- ootype.UniChar: 'i2',
- rffi.SHORT: 'i2',
- ootype.Signed: 'i4',
- ootype.SignedLongLong: 'i8',
- ootype.Unsigned: 'u4',
- ootype.UnsignedLongLong: 'u8',
- ootype.Float: 'r8',
- }
+UNSIGNED_TYPES = [ootype.Char, ootype.UniChar, rffi.USHORT,
+ ootype.Unsigned, ootype.UnsignedLongLong]
+
+def ootype_to_mnemonic(FROM, TO, default=None):
+ if TO == ootype.Float:
+ return 'r8'
+ #
+ try:
+ size = str(INT_SIZE[TO])
+ except KeyError:
+ return default
+ if FROM in UNSIGNED_TYPES:
+ return 'u' + size
+ else:
+ return 'i' + size
class _CastPrimitive(MicroInstruction):
def render(self, generator, op):
+ FROM = op.args[0].concretetype
TO = op.result.concretetype
- mnemonic = OOTYPE_TO_MNEMONIC[TO]
+ mnemonic = ootype_to_mnemonic(FROM, TO)
generator.ilasm.opcode('conv.%s' % mnemonic)
Call = _Call()
diff --git a/pypy/module/cpyext/include/frameobject.h b/pypy/module/cpyext/include/frameobject.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/cpyext/include/frameobject.h
@@ -0,0 +1,17 @@
+#ifndef Py_FRAMEOBJECT_H
+#define Py_FRAMEOBJECT_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct {
+ PyObject_HEAD
+ PyCodeObject *f_code;
+ PyObject *f_globals;
+ int f_lineno;
+} PyFrameObject;
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* !Py_FRAMEOBJECT_H */
diff --git a/pypy/doc/config/generate.py b/pypy/doc/config/generate.py
--- a/pypy/doc/config/generate.py
+++ b/pypy/doc/config/generate.py
@@ -8,8 +8,8 @@
for descr in all_optiondescrs:
prefix = descr._name
c = config.Config(descr)
- thisdir.join(prefix + ".txt").ensure()
+ thisdir.join(prefix + ".rst").ensure()
for p in c.getpaths(include_groups=True):
- basename = prefix + "." + p + ".txt"
+ basename = prefix + "." + p + ".rst"
f = thisdir.join(basename)
f.ensure()
diff --git a/pypy/jit/metainterp/test/test_fficall.py b/pypy/jit/metainterp/test/test_fficall.py
--- a/pypy/jit/metainterp/test/test_fficall.py
+++ b/pypy/jit/metainterp/test/test_fficall.py
@@ -5,7 +5,7 @@
from pypy.rlib.libffi import ArgChain
from pypy.rlib.test.test_libffi import TestLibffiCall as _TestLibffiCall
from pypy.rpython.lltypesystem import lltype, rffi
-from pypy.jit.metainterp.test.test_basic import LLJitMixin
+from pypy.jit.metainterp.test.support import LLJitMixin
class TestFfiCall(LLJitMixin, _TestLibffiCall):
diff --git a/pypy/interpreter/pyopcode.py b/pypy/interpreter/pyopcode.py
--- a/pypy/interpreter/pyopcode.py
+++ b/pypy/interpreter/pyopcode.py
@@ -138,11 +138,13 @@
# raised after the exception handler block was popped.
try:
trace = self.w_f_trace
- self.w_f_trace = None
+ if trace is not None:
+ self.w_f_trace = None
try:
ec.bytecode_trace_after_exception(self)
finally:
- self.w_f_trace = trace
+ if trace is not None:
+ self.w_f_trace = trace
except OperationError, e:
operr = e
pytraceback.record_application_traceback(
@@ -1421,9 +1423,10 @@
# add a softspace unless we just printed a string which ends in a '\t'
# or '\n' -- or more generally any whitespace character but ' '
- if isinstance(x, str) and x and x[-1].isspace() and x[-1]!=' ':
- return
- # XXX add unicode handling
+ if isinstance(x, (str, unicode)) and x:
+ lastchar = x[-1]
+ if lastchar.isspace() and lastchar != ' ':
+ return
file_softspace(stream, True)
print_item_to._annspecialcase_ = "specialize:argtype(0)"
diff --git a/pypy/translator/goal/old_queries.py b/pypy/translator/goal/old_queries.py
--- a/pypy/translator/goal/old_queries.py
+++ b/pypy/translator/goal/old_queries.py
@@ -415,12 +415,10 @@
ops = 0
count = Counter()
def visit(block):
- if isinstance(block, flowmodel.Block):
+ for block in graph.iterblocks():
count.blocks += 1
count.ops += len(block.operations)
- elif isinstance(block, flowmodel.Link):
- count.links += 1
- flowmodel.traverse(visit, graph)
+ count.links = len(list(graph.iterlinks()))
return count.blocks, count.links, count.ops
# better used before backends opts
diff --git a/pypy/module/_multiprocessing/test/test_connection.py b/pypy/module/_multiprocessing/test/test_connection.py
--- a/pypy/module/_multiprocessing/test/test_connection.py
+++ b/pypy/module/_multiprocessing/test/test_connection.py
@@ -10,7 +10,7 @@
class AppTestBufferTooShort:
def setup_class(cls):
- space = gettestobjspace(usemodules=('_multiprocessing', 'thread'))
+ space = gettestobjspace(usemodules=('_multiprocessing', 'thread', 'signal'))
cls.space = space
if option.runappdirect:
@@ -88,7 +88,7 @@
class AppTestSocketConnection(BaseConnectionTest):
def setup_class(cls):
- space = gettestobjspace(usemodules=('_multiprocessing', 'thread'))
+ space = gettestobjspace(usemodules=('_multiprocessing', 'thread', 'signal'))
cls.space = space
cls.w_connections = space.newlist([])
diff --git a/pypy/module/thread/test/support.py b/pypy/module/thread/test/support.py
--- a/pypy/module/thread/test/support.py
+++ b/pypy/module/thread/test/support.py
@@ -32,7 +32,7 @@
class GenericTestThread:
def setup_class(cls):
- space = gettestobjspace(usemodules=('thread', 'time'))
+ space = gettestobjspace(usemodules=('thread', 'time', 'signal'))
cls.space = space
if option.runappdirect:
diff --git a/pypy/interpreter/nestedscope.py b/pypy/interpreter/nestedscope.py
--- a/pypy/interpreter/nestedscope.py
+++ b/pypy/interpreter/nestedscope.py
@@ -219,12 +219,14 @@
freevars = [self.space.interp_w(Cell, cell)
for cell in self.space.fixedview(w_freevarstuple)]
else:
- nfreevars = len(codeobj.co_freevars)
- freevars = [self.space.interp_w(Cell, self.popvalue())
- for i in range(nfreevars)]
- freevars.reverse()
- defaultarguments = [self.popvalue() for i in range(numdefaults)]
- defaultarguments.reverse()
+ n = len(codeobj.co_freevars)
+ freevars = [None] * n
+ while True:
+ n -= 1
+ if n < 0:
+ break
+ freevars[n] = self.space.interp_w(Cell, self.popvalue())
+ defaultarguments = self.popvalues(numdefaults)
fn = function.Function(self.space, codeobj, self.w_globals,
defaultarguments, freevars)
self.pushvalue(self.space.wrap(fn))
diff --git a/pypy/translator/cli/src/pypylib.cs b/pypy/translator/cli/src/pypylib.cs
--- a/pypy/translator/cli/src/pypylib.cs
+++ b/pypy/translator/cli/src/pypylib.cs
@@ -26,7 +26,10 @@
else {
string res = "";
foreach(char ch in x)
- res+= string.Format("\\x{0:X2}", (int)ch);
+ if (ch >= 32 && ch < 128)
+ res+= ch;
+ else
+ res+= string.Format("\\x{0:X2}", (int)ch);
return string.Format("'{0}'", res);
}
}
@@ -498,6 +501,11 @@
}
}
+ public static bool IntBetween(int a, int b, int c)
+ {
+ return a <= b && b < c;
+ }
+
public static bool Equal<T>(T t1, T t2)
{
if (t1 == null)
@@ -717,9 +725,31 @@
return s.Substring(start, count);
}
- public static string[] ll_split_chr(string s, char ch)
+ public static string[] ll_split_chr(string s, char ch, int max)
{
- return s.Split(ch);
+ if (max < 0)
+ return s.Split(ch);
+ else
+ return s.Split(new Char[] {ch}, max + 1);
+ }
+
+ public static string[] ll_rsplit_chr(string s, char ch, int max)
+ {
+ string[] splits = s.Split(ch);
+ if (max < 0 || splits.Length <= max + 1)
+ return splits;
+ else {
+ /* XXX not very efficient */
+ string first = splits[0];
+ // join the first (length - max - 1) items
+ int i;
+ for (i = 1; i < splits.Length - max; i++)
+ first += ch + splits[i];
+ splits[0] = first;
+ Array.Copy(splits, i, splits, 1, max);
+ Array.Resize(ref splits, max + 1);
+ return splits;
+ }
}
public static bool ll_contains(string s, char ch)
@@ -1123,10 +1153,36 @@
public class rffi
{
- public static int tolower(int chr)
- {
- return (int)Char.ToLower((char)chr);
- }
+ public static int tolower(int chr)
+ {
+ return (int)Char.ToLower((char)chr);
+ }
+
+ public static int locale_tolower(int chr)
+ {
+ return (int)Char.ToLower((char)chr);
+ }
+
+ public static int locale_isupper(int chr)
+ {
+ return Convert.ToInt32(Char.IsUpper((char)chr));
+ }
+
+ public static int locale_islower(int chr)
+ {
+ return Convert.ToInt32(Char.IsLower((char)chr));
+ }
+
+ public static int locale_isalpha(int chr)
+ {
+ return Convert.ToInt32(Char.IsLetter((char)chr));
+ }
+
+ public static int locale_isalnum(int chr)
+ {
+ return Convert.ToInt32(Char.IsLetterOrDigit((char)chr));
+ }
+
}
}
diff --git a/pypy/jit/backend/x86/test/test_basic.py b/pypy/jit/backend/x86/test/test_basic.py
--- a/pypy/jit/backend/x86/test/test_basic.py
+++ b/pypy/jit/backend/x86/test/test_basic.py
@@ -1,18 +1,18 @@
import py
from pypy.jit.backend.detect_cpu import getcpuclass
from pypy.jit.metainterp.warmspot import ll_meta_interp
-from pypy.jit.metainterp.test import test_basic
+from pypy.jit.metainterp.test import support, test_ajit
from pypy.jit.codewriter.policy import StopAtXPolicy
from pypy.rlib.jit import JitDriver
-class Jit386Mixin(test_basic.LLJitMixin):
+class Jit386Mixin(support.LLJitMixin):
type_system = 'lltype'
CPUClass = getcpuclass()
def check_jumps(self, maxcount):
pass
-class TestBasic(Jit386Mixin, test_basic.BaseLLtypeTests):
+class TestBasic(Jit386Mixin, test_ajit.BaseLLtypeTests):
# for the individual tests see
# ====> ../../../metainterp/test/test_basic.py
def test_bug(self):
diff --git a/pypy/module/thread/os_local.py b/pypy/module/thread/os_local.py
--- a/pypy/module/thread/os_local.py
+++ b/pypy/module/thread/os_local.py
@@ -12,7 +12,7 @@
def __init__(self, space, initargs):
self.initargs = initargs
ident = thread.get_ident()
- self.dicts = {ident: space.newdict()}
+ self.dicts = {ident: space.newdict(instance=True)}
def getdict(self, space):
ident = thread.get_ident()
@@ -51,10 +51,6 @@
__dict__ = GetSetProperty(descr_get_dict, cls=Local),
)
-def getlocaltype(space):
- return space.gettypeobject(Local.typedef)
-
-
def finish_thread(w_obj):
assert isinstance(w_obj, Local)
ident = thread.get_ident()
diff --git a/pypy/rpython/module/ll_os.py b/pypy/rpython/module/ll_os.py
--- a/pypy/rpython/module/ll_os.py
+++ b/pypy/rpython/module/ll_os.py
@@ -29,7 +29,7 @@
from pypy.rpython.lltypesystem.rstr import STR
from pypy.rpython.annlowlevel import llstr
from pypy.rlib import rgc
-from pypy.rlib.objectmodel import keepalive_until_here, specialize
+from pypy.rlib.objectmodel import specialize
def monkeypatch_rposix(posixfunc, unicodefunc, signature):
func_name = posixfunc.__name__
diff --git a/pypy/translator/jvm/src/pypy/StatResult.java b/pypy/translator/jvm/src/pypy/StatResult.java
--- a/pypy/translator/jvm/src/pypy/StatResult.java
+++ b/pypy/translator/jvm/src/pypy/StatResult.java
@@ -8,7 +8,7 @@
*
* <p>The actual stat() function is defined in PyPy.java.
*/
-class StatResult {
+public class StatResult {
public int item0, item3, item4, item5;
public long item1, item2, item6;
public double item7, item8, item9;
diff --git a/pypy/jit/metainterp/test/test_basic.py b/pypy/jit/metainterp/test/test_ajit.py
copy from pypy/jit/metainterp/test/test_basic.py
copy to pypy/jit/metainterp/test/test_ajit.py
--- a/pypy/jit/metainterp/test/test_basic.py
+++ b/pypy/jit/metainterp/test/test_ajit.py
@@ -4,269 +4,17 @@
from pypy.rlib.jit import loop_invariant
from pypy.rlib.jit import jit_debug, assert_green, AssertGreenFailed
from pypy.rlib.jit import unroll_safe, current_trace_length
-from pypy.jit.metainterp.warmspot import ll_meta_interp, get_stats
-from pypy.jit.backend.llgraph import runner
from pypy.jit.metainterp import pyjitpl, history
from pypy.jit.metainterp.warmstate import set_future_value
+from pypy.jit.metainterp.warmspot import get_stats
from pypy.jit.codewriter.policy import JitPolicy, StopAtXPolicy
-from pypy.jit.codewriter import longlong
from pypy import conftest
from pypy.rlib.rarithmetic import ovfcheck
from pypy.jit.metainterp.typesystem import LLTypeHelper, OOTypeHelper
from pypy.rpython.lltypesystem import lltype, llmemory
from pypy.rpython.ootypesystem import ootype
from pypy.jit.metainterp.optimizeopt import ALL_OPTS_DICT
-
-def _get_jitcodes(testself, CPUClass, func, values, type_system,
- supports_longlong=False, **kwds):
- from pypy.jit.codewriter import support, codewriter
-
- class FakeJitCell:
- __compiled_merge_points = []
- def get_compiled_merge_points(self):
- return self.__compiled_merge_points[:]
- def set_compiled_merge_points(self, lst):
- self.__compiled_merge_points = lst
-
- class FakeWarmRunnerState:
- def attach_unoptimized_bridge_from_interp(self, greenkey, newloop):
- pass
-
- def jit_cell_at_key(self, greenkey):
- assert greenkey == []
- return self._cell
- _cell = FakeJitCell()
-
- trace_limit = sys.maxint
- enable_opts = ALL_OPTS_DICT
-
- func._jit_unroll_safe_ = True
- rtyper = support.annotate(func, values, type_system=type_system)
- graphs = rtyper.annotator.translator.graphs
- result_kind = history.getkind(graphs[0].getreturnvar().concretetype)[0]
-
- class FakeJitDriverSD:
- num_green_args = 0
- portal_graph = graphs[0]
- virtualizable_info = None
- greenfield_info = None
- result_type = result_kind
- portal_runner_ptr = "???"
-
- stats = history.Stats()
- cpu = CPUClass(rtyper, stats, None, False)
- cw = codewriter.CodeWriter(cpu, [FakeJitDriverSD()])
- testself.cw = cw
- policy = JitPolicy()
- policy.set_supports_longlong(supports_longlong)
- cw.find_all_graphs(policy)
- #
- testself.warmrunnerstate = FakeWarmRunnerState()
- testself.warmrunnerstate.cpu = cpu
- FakeJitDriverSD.warmstate = testself.warmrunnerstate
- if hasattr(testself, 'finish_setup_for_interp_operations'):
- testself.finish_setup_for_interp_operations()
- #
- cw.make_jitcodes(verbose=True)
-
-def _run_with_blackhole(testself, args):
- from pypy.jit.metainterp.blackhole import BlackholeInterpBuilder
- cw = testself.cw
- blackholeinterpbuilder = BlackholeInterpBuilder(cw)
- blackholeinterp = blackholeinterpbuilder.acquire_interp()
- count_i = count_r = count_f = 0
- for value in args:
- T = lltype.typeOf(value)
- if T == lltype.Signed:
- blackholeinterp.setarg_i(count_i, value)
- count_i += 1
- elif T == llmemory.GCREF:
- blackholeinterp.setarg_r(count_r, value)
- count_r += 1
- elif T == lltype.Float:
- value = longlong.getfloatstorage(value)
- blackholeinterp.setarg_f(count_f, value)
- count_f += 1
- else:
- raise TypeError(T)
- [jitdriver_sd] = cw.callcontrol.jitdrivers_sd
- blackholeinterp.setposition(jitdriver_sd.mainjitcode, 0)
- blackholeinterp.run()
- return blackholeinterp._final_result_anytype()
-
-def _run_with_pyjitpl(testself, args):
-
- class DoneWithThisFrame(Exception):
- pass
-
- class DoneWithThisFrameRef(DoneWithThisFrame):
- def __init__(self, cpu, *args):
- DoneWithThisFrame.__init__(self, *args)
-
- cw = testself.cw
- opt = history.Options(listops=True)
- metainterp_sd = pyjitpl.MetaInterpStaticData(cw.cpu, opt)
- metainterp_sd.finish_setup(cw)
- [jitdriver_sd] = metainterp_sd.jitdrivers_sd
- metainterp = pyjitpl.MetaInterp(metainterp_sd, jitdriver_sd)
- metainterp_sd.DoneWithThisFrameInt = DoneWithThisFrame
- metainterp_sd.DoneWithThisFrameRef = DoneWithThisFrameRef
- metainterp_sd.DoneWithThisFrameFloat = DoneWithThisFrame
- testself.metainterp = metainterp
- try:
- metainterp.compile_and_run_once(jitdriver_sd, *args)
- except DoneWithThisFrame, e:
- #if conftest.option.view:
- # metainterp.stats.view()
- return e.args[0]
- else:
- raise Exception("FAILED")
-
-def _run_with_machine_code(testself, args):
- metainterp = testself.metainterp
- num_green_args = metainterp.jitdriver_sd.num_green_args
- loop_tokens = metainterp.get_compiled_merge_points(args[:num_green_args])
- if len(loop_tokens) != 1:
- return NotImplemented
- # a loop was successfully created by _run_with_pyjitpl(); call it
- cpu = metainterp.cpu
- for i in range(len(args) - num_green_args):
- x = args[num_green_args + i]
- typecode = history.getkind(lltype.typeOf(x))
- set_future_value(cpu, i, x, typecode)
- faildescr = cpu.execute_token(loop_tokens[0])
- assert faildescr.__class__.__name__.startswith('DoneWithThisFrameDescr')
- if metainterp.jitdriver_sd.result_type == history.INT:
- return cpu.get_latest_value_int(0)
- elif metainterp.jitdriver_sd.result_type == history.REF:
- return cpu.get_latest_value_ref(0)
- elif metainterp.jitdriver_sd.result_type == history.FLOAT:
- return cpu.get_latest_value_float(0)
- else:
- return None
-
-
-class JitMixin:
- basic = True
- def check_loops(self, expected=None, everywhere=False, **check):
- get_stats().check_loops(expected=expected, everywhere=everywhere,
- **check)
- def check_loop_count(self, count):
- """NB. This is a hack; use check_tree_loop_count() or
- check_enter_count() for the real thing.
- This counts as 1 every bridge in addition to every loop; and it does
- not count at all the entry bridges from interpreter, although they
- are TreeLoops as well."""
- assert get_stats().compiled_count == count
- def check_tree_loop_count(self, count):
- assert len(get_stats().loops) == count
- def check_loop_count_at_most(self, count):
- assert get_stats().compiled_count <= count
- def check_enter_count(self, count):
- assert get_stats().enter_count == count
- def check_enter_count_at_most(self, count):
- assert get_stats().enter_count <= count
- def check_jumps(self, maxcount):
- assert get_stats().exec_jumps <= maxcount
- def check_aborted_count(self, count):
- assert get_stats().aborted_count == count
- def check_aborted_count_at_least(self, count):
- assert get_stats().aborted_count >= count
-
- def meta_interp(self, *args, **kwds):
- kwds['CPUClass'] = self.CPUClass
- kwds['type_system'] = self.type_system
- if "backendopt" not in kwds:
- kwds["backendopt"] = False
- return ll_meta_interp(*args, **kwds)
-
- def interp_operations(self, f, args, **kwds):
- # get the JitCodes for the function f
- _get_jitcodes(self, self.CPUClass, f, args, self.type_system, **kwds)
- # try to run it with blackhole.py
- result1 = _run_with_blackhole(self, args)
- # try to run it with pyjitpl.py
- result2 = _run_with_pyjitpl(self, args)
- assert result1 == result2
- # try to run it by running the code compiled just before
- result3 = _run_with_machine_code(self, args)
- assert result1 == result3 or result3 == NotImplemented
- #
- if (longlong.supports_longlong and
- isinstance(result1, longlong.r_float_storage)):
- result1 = longlong.getrealfloat(result1)
- return result1
-
- def check_history(self, expected=None, **isns):
- # this can be used after calling meta_interp
- get_stats().check_history(expected, **isns)
-
- def check_operations_history(self, expected=None, **isns):
- # this can be used after interp_operations
- if expected is not None:
- expected = dict(expected)
- expected['jump'] = 1
- self.metainterp.staticdata.stats.check_history(expected, **isns)
-
-
-class LLJitMixin(JitMixin):
- type_system = 'lltype'
- CPUClass = runner.LLtypeCPU
-
- @staticmethod
- def Ptr(T):
- return lltype.Ptr(T)
-
- @staticmethod
- def GcStruct(name, *fields, **kwds):
- S = lltype.GcStruct(name, *fields, **kwds)
- return S
-
- malloc = staticmethod(lltype.malloc)
- nullptr = staticmethod(lltype.nullptr)
-
- @staticmethod
- def malloc_immortal(T):
- return lltype.malloc(T, immortal=True)
-
- def _get_NODE(self):
- NODE = lltype.GcForwardReference()
- NODE.become(lltype.GcStruct('NODE', ('value', lltype.Signed),
- ('next', lltype.Ptr(NODE))))
- return NODE
-
-class OOJitMixin(JitMixin):
- type_system = 'ootype'
- #CPUClass = runner.OOtypeCPU
-
- def setup_class(cls):
- py.test.skip("ootype tests skipped for now")
-
- @staticmethod
- def Ptr(T):
- return T
-
- @staticmethod
- def GcStruct(name, *fields, **kwds):
- if 'hints' in kwds:
- kwds['_hints'] = kwds['hints']
- del kwds['hints']
- I = ootype.Instance(name, ootype.ROOT, dict(fields), **kwds)
- return I
-
- malloc = staticmethod(ootype.new)
- nullptr = staticmethod(ootype.null)
-
- @staticmethod
- def malloc_immortal(T):
- return ootype.new(T)
-
- def _get_NODE(self):
- NODE = ootype.Instance('NODE', ootype.ROOT, {})
- NODE._add_fields({'value': ootype.Signed,
- 'next': NODE})
- return NODE
-
+from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin
class BasicTests:
diff --git a/pypy/translator/jvm/src/pypy/ll_os.java b/pypy/translator/jvm/src/pypy/ll_os.java
--- a/pypy/translator/jvm/src/pypy/ll_os.java
+++ b/pypy/translator/jvm/src/pypy/ll_os.java
@@ -14,10 +14,22 @@
abstract class FileWrapper
{
+ private final String name;
+
+ public FileWrapper(String name)
+ {
+ this.name = name;
+ }
+
public abstract void write(String buffer);
public abstract String read(int count);
public abstract void close();
public abstract RandomAccessFile getFile();
+
+ public String getName()
+ {
+ return this.name;
+ }
}
class PrintStreamWrapper extends FileWrapper
@@ -25,8 +37,9 @@
private final PrintStream stream;
private final ll_os os;
- public PrintStreamWrapper(PrintStream stream, ll_os os)
+ public PrintStreamWrapper(String name, PrintStream stream, ll_os os)
{
+ super(name);
this.stream = stream;
this.os = os;
}
@@ -58,8 +71,9 @@
private final InputStream stream;
private final ll_os os;
- public InputStreamWrapper(InputStream stream, ll_os os)
+ public InputStreamWrapper(String name, InputStream stream, ll_os os)
{
+ super(name);
this.stream = stream;
this.os = os;
}
@@ -102,11 +116,13 @@
private final boolean canWrite;
private final ll_os os;
- public RandomAccessFileWrapper(RandomAccessFile file,
+ public RandomAccessFileWrapper(String name,
+ RandomAccessFile file,
boolean canRead,
boolean canWrite,
ll_os os)
{
+ super(name);
this.file = file;
this.canRead = canRead;
this.canWrite = canWrite;
@@ -228,9 +244,9 @@
public ll_os(Interlink interlink) {
this.interlink = interlink;
- FileDescriptors.put(0, new InputStreamWrapper(System.in, this));
- FileDescriptors.put(1, new PrintStreamWrapper(System.out, this));
- FileDescriptors.put(2, new PrintStreamWrapper(System.err, this));
+ FileDescriptors.put(0, new InputStreamWrapper("<stdin>", System.in, this));
+ FileDescriptors.put(1, new PrintStreamWrapper("<stdout>", System.out, this));
+ FileDescriptors.put(2, new PrintStreamWrapper("<stderr>", System.err, this));
fdcount = 2;
}
@@ -339,7 +355,7 @@
// XXX: we ignore O_CREAT
RandomAccessFile file = open_file(name, javaMode, flags);
RandomAccessFileWrapper wrapper =
- new RandomAccessFileWrapper(file, canRead, canWrite, this);
+ new RandomAccessFileWrapper(name, file, canRead, canWrite, this);
fdcount++;
FileDescriptors.put(fdcount, wrapper);
@@ -418,6 +434,12 @@
return ll_os_stat(path); // XXX
}
+ public StatResult ll_os_fstat(int fd)
+ {
+ String name = getfd(fd).getName();
+ return ll_os_stat(name);
+ }
+
public String ll_os_strerror(int errno)
{
String msg = ErrorMessages.remove(errno);
diff --git a/pypy/rpython/memory/test/test_gc.py b/pypy/rpython/memory/test/test_gc.py
--- a/pypy/rpython/memory/test/test_gc.py
+++ b/pypy/rpython/memory/test/test_gc.py
@@ -8,7 +8,7 @@
from pypy.rpython.lltypesystem.rstr import STR
from pypy.rpython.lltypesystem.lloperation import llop
from pypy.rlib.objectmodel import we_are_translated
-from pypy.rlib.objectmodel import compute_unique_id, keepalive_until_here
+from pypy.rlib.objectmodel import compute_unique_id
from pypy.rlib import rgc
from pypy.rlib.rstring import StringBuilder
from pypy.rlib.rarithmetic import LONG_BIT
diff --git a/pypy/translator/backendopt/test/test_mallocprediction.py b/pypy/translator/backendopt/test/test_mallocprediction.py
--- a/pypy/translator/backendopt/test/test_mallocprediction.py
+++ b/pypy/translator/backendopt/test/test_mallocprediction.py
@@ -4,7 +4,7 @@
from pypy.translator.backendopt.all import backend_optimizations
from pypy.translator.translator import TranslationContext, graphof
from pypy.rpython.llinterp import LLInterpreter
-from pypy.objspace.flow.model import checkgraph, flatten, Block
+from pypy.objspace.flow.model import checkgraph, Block
from pypy.conftest import option
import sys
diff --git a/pypy/module/cpyext/test/foo.c b/pypy/module/cpyext/test/foo.c
--- a/pypy/module/cpyext/test/foo.c
+++ b/pypy/module/cpyext/test/foo.c
@@ -435,14 +435,6 @@
return (PyObject *)foop;
}
-/* List of functions exported by this module */
-
-static PyMethodDef foo_functions[] = {
- {"new", (PyCFunction)foo_new, METH_NOARGS, NULL},
- {NULL, NULL} /* Sentinel */
-};
-
-
static int initerrtype_init(PyObject *self, PyObject *args, PyObject *kwargs) {
PyErr_SetString(PyExc_ValueError, "init raised an error!");
return -1;
@@ -592,6 +584,41 @@
0 /*tp_weaklist*/
};
+/* A type with a custom allocator */
+static void custom_dealloc(PyObject *ob)
+{
+ free(ob);
+}
+
+static PyTypeObject CustomType;
+
+static PyObject *newCustom(PyObject *self, PyObject *args)
+{
+ PyObject *obj = calloc(1, sizeof(PyObject));
+ obj->ob_type = &CustomType;
+ _Py_NewReference(obj);
+ return obj;
+}
+
+static PyTypeObject CustomType = {
+ PyObject_HEAD_INIT(NULL)
+ 0,
+ "foo.Custom", /*tp_name*/
+ sizeof(PyObject), /*tp_size*/
+ 0, /*tp_itemsize*/
+ /* methods */
+ (destructor)custom_dealloc, /*tp_dealloc*/
+};
+
+
+/* List of functions exported by this module */
+
+static PyMethodDef foo_functions[] = {
+ {"new", (PyCFunction)foo_new, METH_NOARGS, NULL},
+ {"newCustom", (PyCFunction)newCustom, METH_NOARGS, NULL},
+ {NULL, NULL} /* Sentinel */
+};
+
/* Initialize this module. */
@@ -616,7 +643,10 @@
if (PyType_Ready(&InitErrType) < 0)
return;
if (PyType_Ready(&SimplePropertyType) < 0)
- return;
+ return;
+ CustomType.ob_type = &MetaType;
+ if (PyType_Ready(&CustomType) < 0)
+ return;
m = Py_InitModule("foo", foo_functions);
if (m == NULL)
return;
@@ -635,4 +665,6 @@
return;
if (PyDict_SetItemString(d, "Property", (PyObject *) &SimplePropertyType) < 0)
return;
+ if (PyDict_SetItemString(d, "Custom", (PyObject *) &CustomType) < 0)
+ return;
}
diff --git a/pypy/translator/backendopt/test/test_mallocv.py b/pypy/translator/backendopt/test/test_mallocv.py
--- a/pypy/translator/backendopt/test/test_mallocv.py
+++ b/pypy/translator/backendopt/test/test_mallocv.py
@@ -5,7 +5,7 @@
from pypy.translator.backendopt.all import backend_optimizations
from pypy.translator.translator import TranslationContext, graphof
from pypy.translator import simplify
-from pypy.objspace.flow.model import checkgraph, flatten, Block, mkentrymap
+from pypy.objspace.flow.model import checkgraph, Block, mkentrymap
from pypy.objspace.flow.model import summary
from pypy.rpython.llinterp import LLInterpreter, LLException
from pypy.rpython.lltypesystem import lltype, llmemory, lloperation
@@ -33,8 +33,7 @@
def check_malloc_removed(cls, graph, expected_mallocs, expected_calls):
count_mallocs = 0
count_calls = 0
- for node in flatten(graph):
- if isinstance(node, Block):
+ for node in graph.iterblocks():
for op in node.operations:
if op.opname == 'malloc':
count_mallocs += 1
@@ -54,7 +53,7 @@
if option.view:
t.view()
self.original_graph_count = len(t.graphs)
- # to detect missing keepalives and broken intermediate graphs,
+ # to detect broken intermediate graphs,
# we do the loop ourselves instead of calling remove_simple_mallocs()
maxiter = 100
mallocv = MallocVirtualizer(t.graphs, t.rtyper, verbose=True)
@@ -557,36 +556,6 @@
type_system = 'lltype'
#MallocRemover = LLTypeMallocRemover
- def test_with_keepalive(self):
- from pypy.rlib.objectmodel import keepalive_until_here
- def fn1(x, y):
- if x > 0:
- t = x+y, x-y
- else:
- t = x-y, x+y
- s, d = t
- keepalive_until_here(t)
- return s*d
- self.check(fn1, [int, int], [15, 10], 125)
-
- def test_add_keepalives(self):
- class A:
- pass
- SMALL = lltype.Struct('SMALL', ('x', lltype.Signed))
- BIG = lltype.GcStruct('BIG', ('z', lltype.Signed), ('s', SMALL))
- def fn7(i):
- big = lltype.malloc(BIG)
- a = A()
- a.big = big
- a.small = big.s
- a.small.x = 0
- while i > 0:
- a.small.x += i
- i -= 1
- return a.small.x
- self.check(fn7, [int], [10], 55,
- expected_mallocs=1) # no support for interior structs
-
def test_getsubstruct(self):
SMALL = lltype.Struct('SMALL', ('x', lltype.Signed))
BIG = lltype.GcStruct('BIG', ('z', lltype.Signed), ('s', SMALL))
@@ -770,39 +739,6 @@
return x.u1.b * x.u2.a
self.check(fn, [], [], DONT_CHECK_RESULT)
- def test_keep_all_keepalives(self):
- SIZE = llmemory.sizeof(lltype.Signed)
- PARRAY = lltype.Ptr(lltype.FixedSizeArray(lltype.Signed, 1))
- class A:
- def __init__(self):
- self.addr = llmemory.raw_malloc(SIZE)
- def __del__(self):
- llmemory.raw_free(self.addr)
- class B:
- pass
- def myfunc():
- b = B()
- b.keep = A()
- b.data = llmemory.cast_adr_to_ptr(b.keep.addr, PARRAY)
- b.data[0] = 42
- ptr = b.data
- # normally 'b' could go away as early as here, which would free
- # the memory held by the instance of A in b.keep...
- res = ptr[0]
- # ...so we explicitly keep 'b' alive until here
- objectmodel.keepalive_until_here(b)
- return res
- graph = self.check(myfunc, [], [], 42,
- expected_mallocs=1, # 'A' instance left
- expected_calls=1) # to A.__init__()
-
- # there is a getarrayitem near the end of the graph of myfunc.
- # However, the memory it accesses must still be protected by the
- # following keepalive, even after malloc removal
- entrymap = mkentrymap(graph)
- [link] = entrymap[graph.returnblock]
- assert link.prevblock.operations[-1].opname == 'keepalive'
-
def test_nested_struct(self):
S = lltype.GcStruct("S", ('x', lltype.Signed))
T = lltype.GcStruct("T", ('s', 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
@@ -576,20 +576,56 @@
res = self.interpret(f, [i, newlines])
assert res == f(i, newlines)
- def test_split(self):
+ def _make_split_test(self, split_fn):
const = self.const
def fn(i):
s = [const(''), const('0.1.2.4.8'), const('.1.2'), const('1.2.'), const('.1.2.4.')][i]
- l = s.split(const('.'))
+ l = getattr(s, split_fn)(const('.'))
sum = 0
for num in l:
- if len(num):
- sum += ord(num[0]) - ord(const('0')[0])
+ if len(num):
+ sum += ord(num[0]) - ord(const('0')[0])
return sum + len(l) * 100
+ return fn
+
+ def test_split(self):
+ fn = self._make_split_test('split')
for i in range(5):
res = self.interpret(fn, [i])
assert res == fn(i)
+ def test_rsplit(self):
+ fn = self._make_split_test('rsplit')
+ for i in range(5):
+ res = self.interpret(fn, [i])
+ assert res == fn(i)
+
+ def _make_split_limit_test(self, split_fn):
+ const = self.const
+ def fn(i, j):
+ s = [const(''), const('0.1.2.4.8'), const('.1.2'), const('1.2.'), const('.1.2.4.')][i]
+ l = getattr(s, split_fn)(const('.'), j)
+ sum = 0
+ for num in l:
+ if len(num):
+ sum += ord(num[0]) - ord(const('0')[0])
+ return sum + len(l) * 100
+ return fn
+
+ def test_split_limit(self):
+ fn = self._make_split_limit_test('split')
+ for i in range(5):
+ for j in range(4):
+ res = self.interpret(fn, [i, j])
+ assert res == fn(i, j)
+
+ def test_rsplit_limit(self):
+ fn = self._make_split_limit_test('rsplit')
+ for i in range(5):
+ for j in range(4):
+ res = self.interpret(fn, [i, j])
+ assert res == fn(i, j)
+
def test_contains(self):
const = self.const
constchar = self.constchar
diff --git a/pypy/jit/metainterp/test/test_loop_unroll.py b/pypy/jit/metainterp/test/test_loop_unroll.py
--- a/pypy/jit/metainterp/test/test_loop_unroll.py
+++ b/pypy/jit/metainterp/test/test_loop_unroll.py
@@ -1,7 +1,7 @@
import py
from pypy.rlib.jit import JitDriver
from pypy.jit.metainterp.test import test_loop
-from pypy.jit.metainterp.test.test_basic import LLJitMixin, OOJitMixin
+from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin
from pypy.jit.metainterp.optimizeopt import ALL_OPTS_NAMES
class LoopUnrollTest(test_loop.LoopTest):
diff --git a/pypy/rlib/test/test__jit_vref.py b/pypy/rlib/test/test__jit_vref.py
--- a/pypy/rlib/test/test__jit_vref.py
+++ b/pypy/rlib/test/test__jit_vref.py
@@ -6,8 +6,12 @@
from pypy.annotation.annrpython import RPythonAnnotator
from pypy.rpython.test.test_llinterp import interpret
from pypy.rpython.lltypesystem.rclass import OBJECTPTR
+from pypy.rpython.ootypesystem.rclass import OBJECT
from pypy.rpython.lltypesystem import lltype
+from pypy.rpython.test.tool import BaseRtypingTest, LLRtypeMixin, OORtypeMixin
+
+from pypy.rpython.ootypesystem import ootype
class X(object):
pass
@@ -79,37 +83,48 @@
assert s.s_instance.can_be_None
assert s.s_instance.classdef == a.bookkeeper.getuniqueclassdef(X)
-def test_rtype_1():
- def f():
- return virtual_ref(X())
- x = interpret(f, [])
- assert lltype.typeOf(x) == OBJECTPTR
+class BaseTestVRef(BaseRtypingTest):
+ def test_rtype_1(self):
+ def f():
+ return virtual_ref(X())
+ x = self.interpret(f, [])
+ assert lltype.typeOf(x) == self.OBJECTTYPE
-def test_rtype_2():
- def f():
- x1 = X()
- vref = virtual_ref(x1)
- x2 = vref()
- virtual_ref_finish(x2)
- return x2
- x = interpret(f, [])
- assert lltype.castable(OBJECTPTR, lltype.typeOf(x)) > 0
+ def test_rtype_2(self):
+ def f():
+ x1 = X()
+ vref = virtual_ref(x1)
+ x2 = vref()
+ virtual_ref_finish(x2)
+ return x2
+ x = self.interpret(f, [])
+ assert self.castable(self.OBJECTTYPE, x)
-def test_rtype_3():
- def f(n):
- if n > 0:
- return virtual_ref(Y())
- else:
- return non_virtual_ref(Z())
- x = interpret(f, [-5])
- assert lltype.typeOf(x) == OBJECTPTR
+ def test_rtype_3(self):
+ def f(n):
+ if n > 0:
+ return virtual_ref(Y())
+ else:
+ return non_virtual_ref(Z())
+ x = self.interpret(f, [-5])
+ assert lltype.typeOf(x) == self.OBJECTTYPE
-def test_rtype_4():
- def f(n):
- if n > 0:
- return virtual_ref(X())
- else:
- return vref_None
- x = interpret(f, [-5])
- assert lltype.typeOf(x) == OBJECTPTR
- assert not x
+ def test_rtype_4(self):
+ def f(n):
+ if n > 0:
+ return virtual_ref(X())
+ else:
+ return vref_None
+ x = self.interpret(f, [-5])
+ assert lltype.typeOf(x) == self.OBJECTTYPE
+ assert not x
+
+class TestLLtype(BaseTestVRef, LLRtypeMixin):
+ OBJECTTYPE = OBJECTPTR
+ def castable(self, TO, var):
+ return lltype.castable(TO, lltype.typeOf(var)) > 0
+
+class TestOOtype(BaseTestVRef, OORtypeMixin):
+ OBJECTTYPE = OBJECT
+ def castable(self, TO, var):
+ return ootype.isSubclass(lltype.typeOf(var), TO)
diff --git a/pypy/module/cpyext/object.py b/pypy/module/cpyext/object.py
--- a/pypy/module/cpyext/object.py
+++ b/pypy/module/cpyext/object.py
@@ -5,10 +5,9 @@
Py_GE, CONST_STRING, FILEP, fwrite)
from pypy.module.cpyext.pyobject import (
PyObject, PyObjectP, create_ref, from_ref, Py_IncRef, Py_DecRef,
- track_reference, get_typedescr, RefcountState)
+ track_reference, get_typedescr, _Py_NewReference, RefcountState)
from pypy.module.cpyext.typeobject import PyTypeObjectPtr
from pypy.module.cpyext.pyerrors import PyErr_NoMemory, PyErr_BadInternalCall
-from pypy.objspace.std.objectobject import W_ObjectObject
from pypy.objspace.std.typeobject import W_TypeObject
from pypy.interpreter.error import OperationError
import pypy.module.__builtin__.operation as operation
@@ -184,26 +183,17 @@
return 0
@cpython_api([PyObject, PyTypeObjectPtr], PyObject)
-def PyObject_Init(space, py_obj, type):
+def PyObject_Init(space, obj, type):
"""Initialize a newly-allocated object op with its type and initial
reference. Returns the initialized object. If type indicates that the
object participates in the cyclic garbage detector, it is added to the
detector's set of observed objects. Other fields of the object are not
affected."""
- if not py_obj:
+ if not obj:
PyErr_NoMemory(space)
- py_obj.c_ob_type = type
- py_obj.c_ob_refcnt = 1
- w_type = from_ref(space, rffi.cast(PyObject, type))
- assert isinstance(w_type, W_TypeObject)
- if w_type.is_cpytype():
- w_obj = space.allocate_instance(W_ObjectObject, w_type)
- track_reference(space, py_obj, w_obj)
- state = space.fromcache(RefcountState)
- state.set_lifeline(w_obj, py_obj)
- else:
- assert False, "Please add more cases in PyObject_Init"
- return py_obj
+ obj.c_ob_type = type
+ _Py_NewReference(space, obj)
+ return obj
@cpython_api([PyVarObject, PyTypeObjectPtr, Py_ssize_t], PyObject)
def PyObject_InitVar(space, py_obj, type, size):
@@ -255,6 +245,16 @@
expression cmp(o1, o2)."""
return space.int_w(space.cmp(w_o1, w_o2))
+ at cpython_api([PyObject, PyObject, rffi.INTP], rffi.INT_real, error=-1)
+def PyObject_Cmp(space, w_o1, w_o2, result):
+ """Compare the values of o1 and o2 using a routine provided by o1, if one
+ exists, otherwise with a routine provided by o2. The result of the
+ comparison is returned in result. Returns -1 on failure. This is the
+ equivalent of the Python statement result = cmp(o1, o2)."""
+ res = space.int_w(space.cmp(w_o1, w_o2))
+ result[0] = rffi.cast(rffi.INT, res)
+ return 0
+
@cpython_api([PyObject, PyObject, rffi.INT_real], PyObject)
def PyObject_RichCompare(space, w_o1, w_o2, opid_int):
"""Compare the values of o1 and o2 using the operation specified by opid,
@@ -395,7 +395,7 @@
raise OperationError(space.w_TypeError, space.wrap(
"expected a character buffer object"))
if generic_cpy_call(space, pb.c_bf_getsegcount,
- obj, lltype.nullptr(rffi.INTP.TO)) != 1:
+ obj, lltype.nullptr(Py_ssize_tP.TO)) != 1:
raise OperationError(space.w_TypeError, space.wrap(
"expected a single-segment buffer object"))
size = generic_cpy_call(space, pb.c_bf_getcharbuffer,
diff --git a/dotviewer/conftest.py b/dotviewer/conftest.py
--- a/dotviewer/conftest.py
+++ b/dotviewer/conftest.py
@@ -6,4 +6,6 @@
dest="pygame", default=False,
help="allow interactive tests using Pygame")
-option = py.test.config.option
+def pytest_configure(config):
+ global option
+ option = config.option
diff --git a/pypy/translator/gensupp.py b/pypy/translator/gensupp.py
--- a/pypy/translator/gensupp.py
+++ b/pypy/translator/gensupp.py
@@ -6,15 +6,13 @@
import sys
from pypy.objspace.flow.model import Block
-from pypy.objspace.flow.model import traverse
# ordering the blocks of a graph by source position
def ordered_blocks(graph):
# collect all blocks
allblocks = []
- def visit(block):
- if isinstance(block, Block):
+ for block in graph.iterblocks():
# first we order by offset in the code string
if block.operations:
ofs = block.operations[0].offset
@@ -26,7 +24,6 @@
else:
txt = "dummy"
allblocks.append((ofs, txt, block))
- traverse(visit, graph)
allblocks.sort()
#for ofs, txt, block in allblocks:
# print ofs, txt, block
diff --git a/pypy/translator/jvm/test/test_extreme.py b/pypy/translator/jvm/test/test_extreme.py
--- a/pypy/translator/jvm/test/test_extreme.py
+++ b/pypy/translator/jvm/test/test_extreme.py
@@ -1,5 +1,8 @@
+import py
from pypy.translator.jvm.test.runtest import JvmTest
from pypy.translator.oosupport.test_template.extreme import BaseTestExtreme
class TestExtreme(BaseTestExtreme, JvmTest):
- pass
+
+ def test_runtimeerror_due_to_stack_overflow(self):
+ py.test.skip('hotspot bug')
diff --git a/pypy/translator/c/gcc/trackgcroot.py b/pypy/translator/c/gcc/trackgcroot.py
--- a/pypy/translator/c/gcc/trackgcroot.py
+++ b/pypy/translator/c/gcc/trackgcroot.py
@@ -1645,8 +1645,9 @@
darwin64='')
print >> output, "%s:" % _globalname('pypy_asm_stackwalk')
- print >> output, """\
+ s = """\
/* See description in asmgcroot.py */
+ .cfi_startproc
movq\t%rdi, %rdx\t/* 1st argument, which is the callback */
movq\t%rsi, %rcx\t/* 2nd argument, which is gcrootanchor */
movq\t%rsp, %rax\t/* my frame top address */
@@ -1666,6 +1667,7 @@
pushq\t%rcx\t\t\t/* self->prev = gcrootanchor */
movq\t%rsp, 8(%rcx)\t/* gcrootanchor->next = self */
movq\t%rsp, 0(%rax)\t\t\t/* next->prev = self */
+ .cfi_def_cfa_offset 80\t/* 9 pushes + the retaddr = 80 bytes */
/* note: the Mac OS X 16 bytes aligment must be respected. */
call\t*%rdx\t\t/* invoke the callback */
@@ -1687,7 +1689,14 @@
/* the return value is the one of the 'call' above, */
/* because %rax (and possibly %rdx) are unmodified */
ret
+ .cfi_endproc
"""
+ if self.format == 'darwin64':
+ # obscure. gcc there seems not to support .cfi_...
+ # hack it out...
+ s = re.sub(r'([.]cfi_[^/\n]+)([/\n])',
+ r'/* \1 disabled on darwin */\2', s)
+ print >> output, s
_variant(elf64='.size pypy_asm_stackwalk, .-pypy_asm_stackwalk',
darwin64='')
else:
diff --git a/pypy/rpython/memory/gc/env.py b/pypy/rpython/memory/gc/env.py
--- a/pypy/rpython/memory/gc/env.py
+++ b/pypy/rpython/memory/gc/env.py
@@ -259,7 +259,7 @@
get_L2cache = globals().get('get_L2cache_' + sys.platform,
lambda: -1) # implement me for other platforms
-NURSERY_SIZE_UNKNOWN_CACHE = 1024*1024*1024
+NURSERY_SIZE_UNKNOWN_CACHE = 1024*1024
# arbitrary 1M. better than default of 131k for most cases
# in case it didn't work
diff --git a/pypy/rpython/lltypesystem/rlist.py b/pypy/rpython/lltypesystem/rlist.py
--- a/pypy/rpython/lltypesystem/rlist.py
+++ b/pypy/rpython/lltypesystem/rlist.py
@@ -16,7 +16,6 @@
from pypy.rlib.debug import ll_assert
from pypy.rlib.rarithmetic import ovfcheck
from pypy.rpython.lltypesystem import rffi
-from pypy.rlib.objectmodel import keepalive_until_here
from pypy.rpython.lltypesystem.lloperation import llop
from pypy.rlib import rgc
diff --git a/pypy/jit/tl/spli/test/test_jit.py b/pypy/jit/tl/spli/test/test_jit.py
--- a/pypy/jit/tl/spli/test/test_jit.py
+++ b/pypy/jit/tl/spli/test/test_jit.py
@@ -1,6 +1,6 @@
import py
-from pypy.jit.metainterp.test.test_basic import JitMixin
+from pypy.jit.metainterp.test.support import JitMixin
from pypy.jit.tl.spli import interpreter, objects, serializer
from pypy.jit.metainterp.typesystem import LLTypeHelper, OOTypeHelper
from pypy.jit.backend.llgraph import runner
diff --git a/pypy/jit/metainterp/test/test_virtual.py b/pypy/jit/metainterp/test/test_virtual.py
--- a/pypy/jit/metainterp/test/test_virtual.py
+++ b/pypy/jit/metainterp/test/test_virtual.py
@@ -2,7 +2,7 @@
from pypy.rlib.jit import JitDriver, hint
from pypy.rlib.objectmodel import compute_unique_id
from pypy.jit.codewriter.policy import StopAtXPolicy
-from pypy.jit.metainterp.test.test_basic import LLJitMixin, OOJitMixin
+from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin
from pypy.rpython.lltypesystem import lltype, rclass
from pypy.rpython.lltypesystem.lloperation import llop
from pypy.rpython.ootypesystem import ootype
diff --git a/pypy/module/thread/test/test_thread.py b/pypy/module/thread/test/test_thread.py
--- a/pypy/module/thread/test/test_thread.py
+++ b/pypy/module/thread/test/test_thread.py
@@ -214,3 +214,21 @@
assert res == 1024*1024
res = thread.stack_size(0)
assert res == 2*1024*1024
+
+ def test_interrupt_main(self):
+ import thread, time
+ import signal
+
+ def f():
+ time.sleep(0.5)
+ thread.interrupt_main()
+
+ def busy_wait():
+ for x in range(1000):
+ time.sleep(0.01)
+
+ # This is normally called by app_main.py
+ signal.signal(signal.SIGINT, signal.default_int_handler)
+
+ thread.start_new_thread(f, ())
+ raises(KeyboardInterrupt, busy_wait)
diff --git a/pypy/interpreter/function.py b/pypy/interpreter/function.py
--- a/pypy/interpreter/function.py
+++ b/pypy/interpreter/function.py
@@ -22,13 +22,21 @@
return func.code
class Defaults(object):
- _immutable_fields_ = ["items[*]"]
+ _immutable_fields_ = ["items[*]", "promote"]
- def __init__(self, items):
+ def __init__(self, items, promote=False):
self.items = items
+ self.promote = promote
def getitems(self):
- return jit.hint(self, promote=True).items
+ # an idea - we want to promote only items that we know won't change
+ # too often. this is the case for builtin functions and functions
+ # with known constant defaults. Otherwise we don't want to promote
+ # this so lambda a=a won't create a new trace each time it's
+ # encountered
+ if self.promote:
+ return jit.hint(self, promote=True).items
+ return self.items
def getitem(self, idx):
return self.getitems()[idx]
@@ -44,14 +52,15 @@
can_change_code = True
def __init__(self, space, code, w_globals=None, defs_w=[], closure=None,
- forcename=None):
+ forcename=None, promote_defs=False):
self.space = space
self.name = forcename or code.co_name
self.w_doc = None # lazily read from code.getdocstring()
self.code = code # Code instance
self.w_func_globals = w_globals # the globals dictionary
self.closure = closure # normally, list of Cell instances or None
- self.defs = Defaults(defs_w) # wrapper around list of w_default's
+ self.defs = Defaults(defs_w, promote=promote_defs)
+ # wrapper around list of w_default's
self.w_func_dict = None # filled out below if needed
self.w_module = None
@@ -620,7 +629,8 @@
def __init__(self, func):
assert isinstance(func, Function)
Function.__init__(self, func.space, func.code, func.w_func_globals,
- func.defs.getitems(), func.closure, func.name)
+ func.defs.getitems(), func.closure, func.name,
+ promote_defs=True)
self.w_doc = func.w_doc
self.w_func_dict = func.w_func_dict
self.w_module = func.w_module
diff --git a/pypy/module/cpyext/unicodeobject.py b/pypy/module/cpyext/unicodeobject.py
--- a/pypy/module/cpyext/unicodeobject.py
+++ b/pypy/module/cpyext/unicodeobject.py
@@ -7,15 +7,16 @@
bootstrap_function, PyObjectFields, cpython_struct, CONST_STRING,
CONST_WSTRING)
from pypy.module.cpyext.pyerrors import PyErr_BadArgument
-from pypy.module.cpyext.pyobject import PyObject, from_ref, make_typedescr
+from pypy.module.cpyext.pyobject import (
+ PyObject, PyObjectP, Py_DecRef, make_ref, from_ref, track_reference,
+ make_typedescr, get_typedescr)
from pypy.module.cpyext.stringobject import PyString_Check
from pypy.module.sys.interp_encoding import setdefaultencoding
from pypy.objspace.std import unicodeobject, unicodetype
from pypy.rlib import runicode
import sys
-## See comment in stringobject.py. PyUnicode_FromUnicode(NULL, size) is not
-## yet supported.
+## See comment in stringobject.py.
PyUnicodeObjectStruct = lltype.ForwardReference()
PyUnicodeObject = lltype.Ptr(PyUnicodeObjectStruct)
@@ -28,7 +29,8 @@
make_typedescr(space.w_unicode.instancetypedef,
basestruct=PyUnicodeObject.TO,
attach=unicode_attach,
- dealloc=unicode_dealloc)
+ dealloc=unicode_dealloc,
+ realize=unicode_realize)
# Buffer for the default encoding (used by PyUnicde_GetDefaultEncoding)
DEFAULT_ENCODING_SIZE = 100
@@ -39,12 +41,39 @@
Py_UNICODE = lltype.UniChar
+def new_empty_unicode(space, length):
+ """
+ Allocatse a PyUnicodeObject and its buffer, but without a corresponding
+ interpreter object. The buffer may be mutated, until unicode_realize() is
+ called.
+ """
+ typedescr = get_typedescr(space.w_unicode.instancetypedef)
+ py_obj = typedescr.allocate(space, space.w_unicode)
+ py_uni = rffi.cast(PyUnicodeObject, py_obj)
+
+ buflen = length + 1
+ py_uni.c_size = length
+ py_uni.c_buffer = lltype.malloc(rffi.CWCHARP.TO, buflen,
+ flavor='raw', zero=True)
+ return py_uni
+
def unicode_attach(space, py_obj, w_obj):
"Fills a newly allocated PyUnicodeObject with a unicode string"
py_unicode = rffi.cast(PyUnicodeObject, py_obj)
py_unicode.c_size = len(space.unicode_w(w_obj))
py_unicode.c_buffer = lltype.nullptr(rffi.CWCHARP.TO)
+def unicode_realize(space, py_obj):
+ """
+ Creates the unicode in the interpreter. The PyUnicodeObject buffer must not
+ be modified after this call.
+ """
+ py_uni = rffi.cast(PyUnicodeObject, py_obj)
+ s = rffi.wcharpsize2unicode(py_uni.c_buffer, py_uni.c_size)
+ w_obj = space.wrap(s)
+ track_reference(space, py_obj, w_obj)
+ return w_obj
+
@cpython_api([PyObject], lltype.Void, external=False)
def unicode_dealloc(space, py_obj):
py_unicode = rffi.cast(PyUnicodeObject, py_obj)
@@ -128,7 +157,9 @@
def PyUnicode_AsUnicode(space, ref):
"""Return a read-only pointer to the Unicode object's internal Py_UNICODE
buffer, NULL if unicode is not a Unicode object."""
- if not PyUnicode_Check(space, ref):
+ # Don't use PyUnicode_Check, it will realize the object :-(
+ w_type = from_ref(space, rffi.cast(PyObject, ref.c_ob_type))
+ if not space.is_true(space.issubtype(w_type, space.w_unicode)):
raise OperationError(space.w_TypeError,
space.wrap("expected unicode object"))
return PyUnicode_AS_UNICODE(space, ref)
@@ -237,10 +268,11 @@
object. If the buffer is not NULL, the return value might be a shared object.
Therefore, modification of the resulting Unicode object is only allowed when u
is NULL."""
- if not wchar_p:
- raise NotImplementedError
- s = rffi.wcharpsize2unicode(wchar_p, length)
- return space.wrap(s)
+ if wchar_p:
+ s = rffi.wcharpsize2unicode(wchar_p, length)
+ return make_ref(space, space.wrap(s))
+ else:
+ return rffi.cast(PyObject, new_empty_unicode(space, length))
@cpython_api([CONST_WSTRING, Py_ssize_t], PyObject)
def PyUnicode_FromWideChar(space, wchar_p, length):
@@ -330,6 +362,29 @@
w_str = space.wrap(rffi.charpsize2str(s, size))
return space.call_method(w_str, 'decode', space.wrap("utf-8"))
+ at cpython_api([PyObjectP, Py_ssize_t], rffi.INT_real, error=-1)
+def PyUnicode_Resize(space, ref, newsize):
+ # XXX always create a new string so far
+ py_uni = rffi.cast(PyUnicodeObject, ref[0])
+ if not py_uni.c_buffer:
+ raise OperationError(space.w_SystemError, space.wrap(
+ "PyUnicode_Resize called on already created string"))
+ try:
+ py_newuni = new_empty_unicode(space, newsize)
+ except MemoryError:
+ Py_DecRef(space, ref[0])
+ ref[0] = lltype.nullptr(PyObject.TO)
+ raise
+ to_cp = newsize
+ oldsize = py_uni.c_size
+ if oldsize < newsize:
+ to_cp = oldsize
+ for i in range(to_cp):
+ py_newuni.c_buffer[i] = py_uni.c_buffer[i]
+ Py_DecRef(space, ref[0])
+ ref[0] = rffi.cast(PyObject, py_newuni)
+ return 0
+
@cpython_api([PyObject], PyObject)
def PyUnicode_AsUTF8String(space, w_unicode):
"""Encode a Unicode object using UTF-8 and return the result as Python string
diff --git a/pypy/objspace/std/typeobject.py b/pypy/objspace/std/typeobject.py
--- a/pypy/objspace/std/typeobject.py
+++ b/pypy/objspace/std/typeobject.py
@@ -10,7 +10,7 @@
from pypy.rlib.objectmodel import we_are_translated
from pypy.rlib.objectmodel import current_object_addr_as_int, compute_hash
from pypy.rlib.jit import hint, purefunction_promote, we_are_jitted
-from pypy.rlib.jit import purefunction, dont_look_inside
+from pypy.rlib.jit import purefunction, dont_look_inside, unroll_safe
from pypy.rlib.rarithmetic import intmask, r_uint
# from compiler/misc.py
@@ -163,7 +163,7 @@
if (not we_are_jitted() or w_self.is_heaptype() or
w_self.space.config.objspace.std.mutable_builtintypes):
return w_self._version_tag
- # heap objects cannot get their version_tag changed
+ # prebuilt objects cannot get their version_tag changed
return w_self._pure_version_tag()
@purefunction_promote()
@@ -253,7 +253,7 @@
return w_value
return None
-
+ @unroll_safe
def _lookup(w_self, key):
space = w_self.space
for w_class in w_self.mro_w:
@@ -262,6 +262,7 @@
return w_value
return None
+ @unroll_safe
def _lookup_where(w_self, key):
# like lookup() but also returns the parent class in which the
# attribute was found
diff --git a/pypy/module/pypyjit/test_pypy_c/test_pypy_c_new.py b/pypy/module/pypyjit/test_pypy_c/test_pypy_c_new.py
--- a/pypy/module/pypyjit/test_pypy_c/test_pypy_c_new.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_pypy_c_new.py
@@ -487,6 +487,7 @@
""")
def test_range_iter(self):
+ py.test.skip("until we fix defaults")
def main(n):
def g(n):
return range(n)
@@ -539,7 +540,7 @@
i12 = int_sub_ovf(i3, 1)
guard_no_overflow(descr=<Guard5>)
--TICK--
- jump(p0, p1, p2, i12, p4, descr=<Loop0>)
+ jump(p0, p1, p2, i12, descr=<Loop0>)
""")
def test_exception_inside_loop_2(self):
@@ -585,7 +586,7 @@
--EXC-TICK--
i14 = int_add(i4, 1)
--TICK--
- jump(p0, p1, p2, p3, i14, i5, p6, descr=<Loop0>)
+ jump(p0, p1, p2, p3, i14, i5, descr=<Loop0>)
""")
def test_chain_of_guards(self):
@@ -685,13 +686,13 @@
assert log.result == 500
loop, = log.loops_by_id('import')
assert loop.match_by_id('import', """
- p14 = call(ConstClass(ll_split_chr__GcStruct_listLlT_rpy_stringPtr_Char), p8, 46, descr=<GcPtrCallDescr>)
+ p14 = call(ConstClass(ll_split_chr), p8, 46, -1, descr=<GcPtrCallDescr>)
guard_no_exception(descr=<Guard4>)
guard_nonnull(p14, descr=<Guard5>)
i15 = getfield_gc(p14, descr=<SignedFieldDescr list.length .*>)
i16 = int_is_true(i15)
guard_true(i16, descr=<Guard6>)
- p18 = call(ConstClass(ll_pop_default__dum_nocheckConst_listPtr), p14, descr=<GcPtrCallDescr>)
+ p18 = call(ConstClass(ll_pop_default), p14, descr=<GcPtrCallDescr>)
guard_no_exception(descr=<Guard7>)
i19 = getfield_gc(p14, descr=<SignedFieldDescr list.length .*>)
i20 = int_is_true(i19)
@@ -1009,10 +1010,11 @@
""")
def test_func_defaults(self):
+ py.test.skip("skipped until we fix defaults")
def main(n):
i = 1
while i < n:
- i += len(xrange(i)) / i
+ i += len(xrange(i+1)) - i
return i
log = self.run(main, [10000])
@@ -1023,17 +1025,49 @@
guard_true(i10, descr=<Guard3>)
# This can be improved if the JIT realized the lookup of i5 produces
# a constant and thus can be removed entirely
- i12 = int_sub(i5, 1)
- i13 = uint_floordiv(i12, i7)
+ i120 = int_add(i5, 1)
+ i140 = int_lt(0, i120)
+ guard_true(i140, descr=<Guard4>)
+ i13 = uint_floordiv(i5, i7)
i15 = int_add(i13, 1)
i17 = int_lt(i15, 0)
- guard_false(i17, descr=<Guard4>)
- i18 = int_floordiv(i15, i5)
- i19 = int_xor(i15, i5)
- i20 = int_mod(i15, i5)
- i21 = int_is_true(i20)
- i22 = int_add_ovf(i5, i18)
- guard_no_overflow(descr=<Guard5>)
+ guard_false(i17, descr=<Guard5>)
+ i20 = int_sub(i15, i5)
+ i21 = int_add_ovf(i5, i20)
+ guard_no_overflow(descr=<Guard6>)
--TICK--
- jump(p0, p1, p2, p3, p4, i22, i6, i7, p8, p9, descr=<Loop0>)
+ jump(p0, p1, p2, p3, p4, i21, i6, i7, p8, p9, descr=<Loop0>)
""")
+
+ def test_unpack_iterable_non_list_tuple(self):
+ def main(n):
+ import array
+
+ items = [array.array("i", [1])] * n
+ total = 0
+ for a, in items:
+ total += a
+ return total
+
+ log = self.run(main, [1000000])
+ assert log.result == 1000000
+ loop, = log.loops_by_filename(self.filepath)
+ assert loop.match("""
+ i16 = int_ge(i12, i13)
+ guard_false(i16, descr=<Guard3>)
+ p17 = getarrayitem_gc(p15, i12, descr=<GcPtrArrayDescr>)
+ i19 = int_add(i12, 1)
+ setfield_gc(p4, i19, descr=<SignedFieldDescr .*W_AbstractSeqIterObject.inst_index .*>)
+ guard_nonnull_class(p17, 146982464, descr=<Guard4>)
+ i21 = getfield_gc(p17, descr=<SignedFieldDescr .*W_ArrayTypei.inst_len .*>)
+ i23 = int_lt(0, i21)
+ guard_true(i23, descr=<Guard5>)
+ i24 = getfield_gc(p17, descr=<NonGcPtrFieldDescr .*W_ArrayTypei.inst_buffer .*>)
+ i25 = getarrayitem_raw(i24, 0, descr=<SignedArrayNoLengthDescr>)
+ i27 = int_lt(1, i21)
+ guard_false(i27, descr=<Guard6>)
+ i28 = int_add_ovf(i10, i25)
+ guard_no_overflow(descr=<Guard7>)
+ --TICK--
+ jump(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, i28, i25, i19, i13, p14, p15, descr=<Loop0>)
+ """)
diff --git a/pypy/objspace/flow/test/test_model.py b/pypy/objspace/flow/test/test_model.py
--- a/pypy/objspace/flow/test/test_model.py
+++ b/pypy/objspace/flow/test/test_model.py
@@ -71,19 +71,6 @@
pieces.headerblock.exits[1],
pieces.whileblock.exits[0]]
-def test_traverse():
- lst = []
- traverse(lst.append, graph)
- assert lst == [pieces.startblock,
- pieces.startblock.exits[0],
- pieces.headerblock,
- pieces.headerblock.exits[0],
- graph.returnblock,
- pieces.headerblock.exits[1],
- pieces.whileblock,
- pieces.whileblock.exits[0]]
- assert flatten(graph) == lst
-
def test_mkentrymap():
entrymap = mkentrymap(graph)
startlink = entrymap[graph.startblock][0]
diff --git a/pypy/jit/metainterp/test/test_virtualref.py b/pypy/jit/metainterp/test/test_virtualref.py
--- a/pypy/jit/metainterp/test/test_virtualref.py
+++ b/pypy/jit/metainterp/test/test_virtualref.py
@@ -3,7 +3,7 @@
from pypy.rlib.jit import JitDriver, dont_look_inside, vref_None
from pypy.rlib.jit import virtual_ref, virtual_ref_finish
from pypy.rlib.objectmodel import compute_unique_id
-from pypy.jit.metainterp.test.test_basic import LLJitMixin, OOJitMixin
+from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin
from pypy.jit.metainterp.resoperation import rop
from pypy.jit.metainterp.virtualref import VirtualRefInfo
diff --git a/pypy/jit/metainterp/test/test_blackhole.py b/pypy/jit/metainterp/test/test_blackhole.py
--- a/pypy/jit/metainterp/test/test_blackhole.py
+++ b/pypy/jit/metainterp/test/test_blackhole.py
@@ -1,6 +1,6 @@
import py
from pypy.rlib.jit import JitDriver
-from pypy.jit.metainterp.test.test_basic import LLJitMixin, OOJitMixin
+from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin
from pypy.jit.metainterp.blackhole import BlackholeInterpBuilder
from pypy.jit.metainterp.blackhole import BlackholeInterpreter
from pypy.jit.metainterp.blackhole import convert_and_run_from_pyjitpl
diff --git a/pypy/jit/metainterp/test/test_tlc.py b/pypy/jit/metainterp/test/test_tlc.py
--- a/pypy/jit/metainterp/test/test_tlc.py
+++ b/pypy/jit/metainterp/test/test_tlc.py
@@ -3,7 +3,7 @@
from pypy.jit.tl import tlc
-from pypy.jit.metainterp.test.test_basic import OOJitMixin, LLJitMixin
+from pypy.jit.metainterp.test.support import OOJitMixin, LLJitMixin
class TLCTests:
diff --git a/pypy/module/signal/interp_signal.py b/pypy/module/signal/interp_signal.py
--- a/pypy/module/signal/interp_signal.py
+++ b/pypy/module/signal/interp_signal.py
@@ -146,6 +146,15 @@
self.pending_signals[n] = None
self.reissue_signal_action.fire_after_thread_switch()
+ def set_interrupt(self):
+ "Simulates the effect of a SIGINT signal arriving"
+ n = cpy_signal.SIGINT
+ if self.reissue_signal_action is None:
+ self.report_signal(n)
+ else:
+ self.pending_signals[n] = None
+ self.reissue_signal_action.fire_after_thread_switch()
+
def report_signal(self, n):
try:
w_handler = self.handlers_w[n]
diff --git a/pypy/module/cpyext/test/test_cpyext.py b/pypy/module/cpyext/test/test_cpyext.py
--- a/pypy/module/cpyext/test/test_cpyext.py
+++ b/pypy/module/cpyext/test/test_cpyext.py
@@ -106,6 +106,11 @@
del obj
import gc; gc.collect()
+ try:
+ del space.getexecutioncontext().cpyext_threadstate
+ except AttributeError:
+ pass
+
for w_obj in state.non_heaptypes_w:
Py_DecRef(space, w_obj)
state.non_heaptypes_w[:] = []
@@ -385,6 +390,19 @@
assert module.__doc__ == "docstring"
assert module.return_cookie() == 3.14
+ def test_load_dynamic(self):
+ import sys
+ init = """
+ if (Py_IsInitialized())
+ Py_InitModule("foo", NULL);
+ """
+ foo = self.import_module(name='foo', init=init)
+ assert 'foo' in sys.modules
+ del sys.modules['foo']
+ import imp
+ foo2 = imp.load_dynamic('foo', foo.__file__)
+ assert 'foo' in sys.modules
+ assert foo.__dict__ == foo2.__dict__
def test_InitModule4_dotted(self):
"""
diff --git a/pypy/jit/metainterp/test/test_slist.py b/pypy/jit/metainterp/test/test_slist.py
--- a/pypy/jit/metainterp/test/test_slist.py
+++ b/pypy/jit/metainterp/test/test_slist.py
@@ -1,5 +1,5 @@
import py
-from pypy.jit.metainterp.test.test_basic import LLJitMixin, OOJitMixin
+from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin
from pypy.rlib.jit import JitDriver
class ListTests(object):
diff --git a/pypy/module/thread/os_lock.py b/pypy/module/thread/os_lock.py
--- a/pypy/module/thread/os_lock.py
+++ b/pypy/module/thread/os_lock.py
@@ -113,7 +113,4 @@
def allocate_lock(space):
"""Create a new lock object. (allocate() is an obsolete synonym.)
See LockType.__doc__ for information about locks."""
- return space.wrap(Lock(space))
-
-def getlocktype(space):
- return space.gettypeobject(Lock.typedef)
+ return space.wrap(Lock(space))
\ No newline at end of file
diff --git a/pypy/module/cpyext/import_.py b/pypy/module/cpyext/import_.py
--- a/pypy/module/cpyext/import_.py
+++ b/pypy/module/cpyext/import_.py
@@ -1,8 +1,10 @@
from pypy.interpreter import module
from pypy.module.cpyext.api import (
generic_cpy_call, cpython_api, PyObject, CONST_STRING)
+from pypy.module.cpyext.pyobject import borrow_from
from pypy.rpython.lltypesystem import rffi
from pypy.interpreter.error import OperationError
+from pypy.interpreter.module import Module
@cpython_api([PyObject], PyObject)
def PyImport_Import(space, w_name):
@@ -45,3 +47,29 @@
space.warn('PyImport_ImportModuleNoBlock() is not non-blocking',
space.w_RuntimeWarning)
return PyImport_Import(space, space.wrap(rffi.charp2str(name)))
+
+ at cpython_api([PyObject], PyObject)
+def PyImport_ReloadModule(space, w_mod):
+ from pypy.module.imp.importing import reload
+ return reload(space, w_mod)
+
+ at cpython_api([CONST_STRING], PyObject)
+def PyImport_AddModule(space, name):
+ """Return the module object corresponding to a module name. The name
+ argument may be of the form package.module. First check the modules
+ dictionary if there's one there, and if not, create a new one and insert
+ it in the modules dictionary. Return NULL with an exception set on
+ failure.
+
+ This function does not load or import the module; if the module wasn't
+ already loaded, you will get an empty module object. Use
+ PyImport_ImportModule() or one of its variants to import a module.
+ Package structures implied by a dotted name for name are not created if
+ not already present."""
+ from pypy.module.imp.importing import check_sys_modules_w
+ modulename = rffi.charp2str(name)
+ w_mod = check_sys_modules_w(space, modulename)
+ if not w_mod or space.is_w(w_mod, space.w_None):
+ w_mod = Module(space, space.wrap(modulename))
+ return borrow_from(None, w_mod)
+
diff --git a/pypy/translator/exceptiontransform.py b/pypy/translator/exceptiontransform.py
--- a/pypy/translator/exceptiontransform.py
+++ b/pypy/translator/exceptiontransform.py
@@ -229,7 +229,6 @@
n_need_exc_matching_blocks += need_exc_matching
n_gen_exc_checks += gen_exc_checks
cleanup_graph(graph)
- removenoops.remove_superfluous_keep_alive(graph)
return n_need_exc_matching_blocks, n_gen_exc_checks
def replace_stack_unwind(self, block):
diff --git a/pypy/jit/metainterp/test/test_dlist.py b/pypy/jit/metainterp/test/test_dlist.py
deleted file mode 100644
--- a/pypy/jit/metainterp/test/test_dlist.py
+++ /dev/null
@@ -1,165 +0,0 @@
-
-import py
-from pypy.rlib.jit import JitDriver
-from pypy.jit.metainterp.test.test_basic import LLJitMixin, OOJitMixin
-py.test.skip("Disabled")
-
-class ListTests:
- def test_basic(self):
- myjitdriver = JitDriver(greens = [], reds = ['n', 'l'])
- def f(n):
- l = [0]
- while n > 0:
- myjitdriver.can_enter_jit(n=n, l=l)
- myjitdriver.jit_merge_point(n=n, l=l)
- x = l[0]
- l[0] = x + 1
- n -= 1
- return l[0]
-
- res = self.meta_interp(f, [10], listops=True)
- assert res == f(10)
- self.check_loops(getarrayitem_gc=0, setarrayitem_gc=1)
-# XXX fix codewriter
-# guard_exception=0,
-# guard_no_exception=1)
-
- def test_list_escapes(self):
- myjitdriver = JitDriver(greens = [], reds = ['n', 'l'])
- def f(n):
- l = [0] * (n + 1)
- while n > 0:
- myjitdriver.can_enter_jit(n=n, l=l)
- myjitdriver.jit_merge_point(n=n, l=l)
- x = l[0]
- l[0] = x + 1
- l[n] = n
- n -= 1
- return l[3]
-
- res = self.meta_interp(f, [10], listops=True)
- assert res == f(10)
- self.check_loops(setarrayitem_gc=2, getarrayitem_gc=0)
-
- def test_list_escapes_but_getitem_goes(self):
- myjitdriver = JitDriver(greens = [], reds = ['n', 'l'])
- def f(n):
- l = [0] * (n + 1)
- while n > 0:
- myjitdriver.can_enter_jit(n=n, l=l)
- myjitdriver.jit_merge_point(n=n, l=l)
- x = l[0]
- l[0] = x + 1
- l[n] = n
- x = l[2]
- y = l[1] + l[2]
- l[1] = x + y
- n -= 1
- return l[3]
-
- res = self.meta_interp(f, [10], listops=True)
- assert res == f(10)
- self.check_loops(setarrayitem_gc=3, getarrayitem_gc=0)
-
- def test_list_of_ptrs(self):
- myjitdriver = JitDriver(greens = [], reds = ['n', 'l'])
- class A(object):
- def __init__(self, x):
- self.x = x
-
- def f(n):
- l = [A(3)]
- while n > 0:
- myjitdriver.can_enter_jit(n=n, l=l)
- myjitdriver.jit_merge_point(n=n, l=l)
- x = l[0].x + 1
- l[0] = A(x)
- n -= 1
- return l[0].x
-
- res = self.meta_interp(f, [10], listops=True)
- assert res == f(10)
- self.check_loops(setarrayitem_gc=1, getarrayitem_gc=0,
- new_with_vtable=1) # A should escape
-
- def test_list_checklength(self):
- myjitdriver = JitDriver(greens = [], reds = ['n', 'l'])
-
- def f(n, a):
- l = [0] * a
- while n > 0:
- myjitdriver.can_enter_jit(n=n, l=l)
- myjitdriver.jit_merge_point(n=n, l=l)
- if len(l) < 3:
- return 42
- l[0] = n
- n -= 1
- return l[0]
-
- res = self.meta_interp(f, [10, 13], listops=True)
- assert res == f(10, 13)
- self.check_loops(setarrayitem_gc=1, arraylen_gc=1)
-
- def test_list_checklength_run(self):
- myjitdriver = JitDriver(greens = [], reds = ['n', 'l'])
-
- def f(n, a):
- l = [0] * a
- while n > 0:
- myjitdriver.can_enter_jit(n=n, l=l)
- myjitdriver.jit_merge_point(n=n, l=l)
- if len(l) > n:
- return 42
- l[0] = n
- n -= 1
- return l[0]
-
- res = self.meta_interp(f, [50, 13], listops=True)
- assert res == 42
- self.check_loops(setarrayitem_gc=1, arraylen_gc=1)
-
- def test_checklength_cannot_go_away(self):
- myjitdriver = JitDriver(greens = [], reds = ['n', 'l'])
-
- def f(n):
- l = [0] * n
- while n > 0:
- myjitdriver.can_enter_jit(n=n, l=l)
- myjitdriver.jit_merge_point(n=n, l=l)
- if len(l) < 3:
- return len(l)
- l = [0] * n
- n -= 1
- return 0
-
- res = self.meta_interp(f, [10], listops=True)
- assert res == 2
- self.check_loops(arraylen_gc=1)
-
- def test_list_indexerror(self):
- # this is an example where IndexError is raised before
- # even getting to the JIT
- py.test.skip("I suspect bug somewhere outside of the JIT")
- myjitdriver = JitDriver(greens = [], reds = ['n', 'l'])
- def f(n):
- l = [0]
- while n > 0:
- myjitdriver.can_enter_jit(n=n, l=l)
- myjitdriver.jit_merge_point(n=n, l=l)
- l[n] = n
- n -= 1
- return l[3]
-
- def g(n):
- try:
- f(n)
- return 0
- except IndexError:
- return 42
-
- res = self.meta_interp(g, [10])
- assert res == 42
- self.check_loops(setitem=2)
-
-class TestLLtype(ListTests, LLJitMixin):
- pass
diff --git a/pypy/jit/metainterp/optimizeopt/virtualize.py b/pypy/jit/metainterp/optimizeopt/virtualize.py
--- a/pypy/jit/metainterp/optimizeopt/virtualize.py
+++ b/pypy/jit/metainterp/optimizeopt/virtualize.py
@@ -4,6 +4,8 @@
from pypy.jit.metainterp.optimizeutil import descrlist_dict
from pypy.rlib.objectmodel import we_are_translated
from pypy.jit.metainterp.optimizeopt import optimizer
+from pypy.jit.metainterp.executor import execute
+from pypy.jit.codewriter.heaptracker import vtable2descr
class AbstractVirtualValue(optimizer.OptValue):
@@ -72,28 +74,53 @@
assert isinstance(fieldvalue, optimizer.OptValue)
self._fields[ofs] = fieldvalue
+ def _get_descr(self):
+ raise NotImplementedError
+
+ def _is_immutable_and_filled_with_constants(self):
+ count = self._get_descr().count_fields_if_immutable()
+ if count != len(self._fields): # always the case if count == -1
+ return False
+ for value in self._fields.itervalues():
+ subbox = value.force_box()
+ if not isinstance(subbox, Const):
+ return False
+ return True
+
def _really_force(self):
- assert self.source_op is not None
+ op = self.source_op
+ assert op is not None
# ^^^ This case should not occur any more (see test_bug_3).
#
if not we_are_translated():
- self.source_op.name = 'FORCE ' + self.source_op.name
- newoperations = self.optimizer.newoperations
- newoperations.append(self.source_op)
- self.box = box = self.source_op.result
- #
- iteritems = self._fields.iteritems()
- if not we_are_translated(): #random order is fine, except for tests
- iteritems = list(iteritems)
- iteritems.sort(key = lambda (x,y): x.sort_key())
- for ofs, value in iteritems:
- if value.is_null():
- continue
- subbox = value.force_box()
- op = ResOperation(rop.SETFIELD_GC, [box, subbox], None,
- descr=ofs)
+ op.name = 'FORCE ' + self.source_op.name
+
+ if self._is_immutable_and_filled_with_constants():
+ box = self.optimizer.constant_fold(op)
+ self.make_constant(box)
+ for ofs, value in self._fields.iteritems():
+ subbox = value.force_box()
+ assert isinstance(subbox, Const)
+ execute(self.optimizer.cpu, None, rop.SETFIELD_GC,
+ ofs, box, subbox)
+ # keep self._fields, because it's all immutable anyway
+ else:
+ newoperations = self.optimizer.newoperations
newoperations.append(op)
- self._fields = None
+ self.box = box = op.result
+ #
+ iteritems = self._fields.iteritems()
+ if not we_are_translated(): #random order is fine, except for tests
+ iteritems = list(iteritems)
+ iteritems.sort(key = lambda (x,y): x.sort_key())
+ for ofs, value in iteritems:
+ if value.is_null():
+ continue
+ subbox = value.force_box()
+ op = ResOperation(rop.SETFIELD_GC, [box, subbox], None,
+ descr=ofs)
+ newoperations.append(op)
+ self._fields = None
def _get_field_descr_list(self):
_cached_sorted_fields = self._cached_sorted_fields
@@ -168,6 +195,9 @@
fielddescrs = self._get_field_descr_list()
return modifier.make_virtual(self.known_class, fielddescrs)
+ def _get_descr(self):
+ return vtable2descr(self.optimizer.cpu, self.known_class.getint())
+
def __repr__(self):
cls_name = self.known_class.value.adr.ptr._obj._TYPE._name
if self._fields is None:
@@ -185,6 +215,9 @@
fielddescrs = self._get_field_descr_list()
return modifier.make_vstruct(self.structdescr, fielddescrs)
+ def _get_descr(self):
+ return self.structdescr
+
class VArrayValue(AbstractVirtualValue):
def __init__(self, optimizer, arraydescr, size, keybox, source_op=None):
@@ -286,7 +319,6 @@
vrefinfo = self.optimizer.metainterp_sd.virtualref_info
c_cls = vrefinfo.jit_virtual_ref_const_class
descr_virtual_token = vrefinfo.descr_virtual_token
- descr_virtualref_index = vrefinfo.descr_virtualref_index
#
# Replace the VIRTUAL_REF operation with a virtual structure of type
# 'jit_virtual_ref'. The jit_virtual_ref structure may be forced soon,
@@ -296,7 +328,6 @@
tokenbox = BoxInt()
self.emit_operation(ResOperation(rop.FORCE_TOKEN, [], tokenbox))
vrefvalue.setfield(descr_virtual_token, self.getvalue(tokenbox))
- vrefvalue.setfield(descr_virtualref_index, self.getvalue(indexbox))
def optimize_VIRTUAL_REF_FINISH(self, op):
# Set the 'forced' field of the virtual_ref.
diff --git a/pypy/jit/backend/x86/test/test_rx86.py b/pypy/jit/backend/x86/test/test_rx86.py
--- a/pypy/jit/backend/x86/test/test_rx86.py
+++ b/pypy/jit/backend/x86/test/test_rx86.py
@@ -206,3 +206,8 @@
s = CodeBuilder64()
s.MOV_rm(edx, (edi, -1))
assert s.getvalue() == '\x48\x8B\x57\xFF'
+
+def test_movsd_xj_64():
+ s = CodeBuilder64()
+ s.MOVSD_xj(xmm2, 0x01234567)
+ assert s.getvalue() == '\xF2\x0F\x10\x14\x25\x67\x45\x23\x01'
diff --git a/pypy/module/cpyext/stubs.py b/pypy/module/cpyext/stubs.py
--- a/pypy/module/cpyext/stubs.py
+++ b/pypy/module/cpyext/stubs.py
@@ -351,14 +351,6 @@
"""Return the number of free variables in co."""
raise NotImplementedError
- at cpython_api([rffi.INT_real, rffi.INT_real, rffi.INT_real, rffi.INT_real, PyObject, PyObject, PyObject, PyObject, PyObject, PyObject, PyObject, PyObject, rffi.INT_real, PyObject], PyCodeObject)
-def PyCode_New(space, argcount, nlocals, stacksize, flags, code, consts, names, varnames, freevars, cellvars, filename, name, firstlineno, lnotab):
- """Return a new code object. If you need a dummy code object to
- create a frame, use PyCode_NewEmpty() instead. Calling
- PyCode_New() directly can bind you to a precise Python
- version since the definition of the bytecode changes often."""
- raise NotImplementedError
-
@cpython_api([PyObject], rffi.INT_real, error=-1)
def PyCodec_Register(space, search_function):
"""Register a new codec search function.
@@ -745,13 +737,6 @@
described there."""
raise NotImplementedError
- at cpython_api([], lltype.Void)
-def PyErr_SetInterrupt(space):
- """This function simulates the effect of a SIGINT signal arriving --- the
- next time PyErr_CheckSignals() is called, KeyboardInterrupt will be raised.
- It may be called without holding the interpreter lock."""
- raise NotImplementedError
-
@cpython_api([rffi.INT_real], rffi.INT_real, error=CANNOT_FAIL)
def PySignal_SetWakeupFd(space, fd):
"""This utility function specifies a file descriptor to which a '\0' byte will
@@ -1123,20 +1108,6 @@
with an exception set on failure (the module still exists in this case)."""
raise NotImplementedError
- at cpython_api([rffi.CCHARP], PyObject)
-def PyImport_AddModule(space, name):
- """Return the module object corresponding to a module name. The name argument
- may be of the form package.module. First check the modules dictionary if
- there's one there, and if not, create a new one and insert it in the modules
- dictionary. Return NULL with an exception set on failure.
-
- This function does not load or import the module; if the module wasn't already
- loaded, you will get an empty module object. Use PyImport_ImportModule()
- or one of its variants to import a module. Package structures implied by a
- dotted name for name are not created if not already present."""
- borrow_from()
- raise NotImplementedError
-
@cpython_api([rffi.CCHARP, PyObject], PyObject)
def PyImport_ExecCodeModule(space, name, co):
"""Given a module name (possibly of the form package.module) and a code
@@ -1972,14 +1943,6 @@
"""
raise NotImplementedError
- at cpython_api([PyObject, PyObject, rffi.INTP], rffi.INT_real, error=-1)
-def PyObject_Cmp(space, o1, o2, result):
- """Compare the values of o1 and o2 using a routine provided by o1, if one
- exists, otherwise with a routine provided by o2. The result of the
- comparison is returned in result. Returns -1 on failure. This is the
- equivalent of the Python statement result = cmp(o1, o2)."""
- raise NotImplementedError
-
@cpython_api([PyObject], PyObject)
def PyObject_Bytes(space, o):
"""Compute a bytes representation of object o. In 2.x, this is just a alias
diff --git a/pypy/rlib/_rweakkeydict.py b/pypy/rlib/_rweakkeydict.py
--- a/pypy/rlib/_rweakkeydict.py
+++ b/pypy/rlib/_rweakkeydict.py
@@ -123,7 +123,7 @@
@jit.dont_look_inside
def ll_get(d, llkey):
hash = compute_identity_hash(llkey)
- i = rdict.ll_dict_lookup(d, llkey, hash)
+ i = rdict.ll_dict_lookup(d, llkey, hash) & rdict.MASK
#llop.debug_print(lltype.Void, i, 'get', hex(hash),
# ll_debugrepr(d.entries[i].key),
# ll_debugrepr(d.entries[i].value))
@@ -143,7 +143,7 @@
def ll_set_nonnull(d, llkey, llvalue):
hash = compute_identity_hash(llkey)
keyref = weakref_create(llkey) # GC effects here, before the rest
- i = rdict.ll_dict_lookup(d, llkey, hash)
+ i = rdict.ll_dict_lookup(d, llkey, hash) & rdict.MASK
everused = d.entries.everused(i)
d.entries[i].key = keyref
d.entries[i].value = llvalue
@@ -160,7 +160,7 @@
@jit.dont_look_inside
def ll_set_null(d, llkey):
hash = compute_identity_hash(llkey)
- i = rdict.ll_dict_lookup(d, llkey, hash)
+ i = rdict.ll_dict_lookup(d, llkey, hash) & rdict.MASK
if d.entries.everused(i):
# If the entry was ever used, clean up its key and value.
# We don't store a NULL value, but a dead weakref, because
diff --git a/pypy/module/_io/test/test_bufferedio.py b/pypy/module/_io/test/test_bufferedio.py
--- a/pypy/module/_io/test/test_bufferedio.py
+++ b/pypy/module/_io/test/test_bufferedio.py
@@ -191,6 +191,10 @@
f = _io.BufferedReader(raw)
assert repr(f) == '<_io.BufferedReader name=%r>' % (self.tmpfile,)
+class AppTestBufferedReaderWithThreads(AppTestBufferedReader):
+ spaceconfig = dict(usemodules=['_io', 'thread'])
+
+
class AppTestBufferedWriter:
def setup_class(cls):
cls.space = gettestobjspace(usemodules=['_io'])
diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py
--- a/pypy/module/cpyext/api.py
+++ b/pypy/module/cpyext/api.py
@@ -400,21 +400,9 @@
# So we need a forward and backward mapping in our State instance
PyObjectStruct = lltype.ForwardReference()
PyObject = lltype.Ptr(PyObjectStruct)
-PyBufferProcs = lltype.ForwardReference()
PyObjectFields = (("ob_refcnt", lltype.Signed), ("ob_type", PyTypeObjectPtr))
-def F(ARGS, RESULT=lltype.Signed):
- return lltype.Ptr(lltype.FuncType(ARGS, RESULT))
-PyBufferProcsFields = (
- ("bf_getreadbuffer", F([PyObject, lltype.Signed, rffi.VOIDPP])),
- ("bf_getwritebuffer", F([PyObject, lltype.Signed, rffi.VOIDPP])),
- ("bf_getsegcount", F([PyObject, rffi.INTP])),
- ("bf_getcharbuffer", F([PyObject, lltype.Signed, rffi.CCHARPP])),
-# we don't support new buffer interface for now
- ("bf_getbuffer", rffi.VOIDP),
- ("bf_releasebuffer", rffi.VOIDP))
PyVarObjectFields = PyObjectFields + (("ob_size", Py_ssize_t), )
cpython_struct('PyObject', PyObjectFields, PyObjectStruct)
-cpython_struct('PyBufferProcs', PyBufferProcsFields, PyBufferProcs)
PyVarObjectStruct = cpython_struct("PyVarObject", PyVarObjectFields)
PyVarObject = lltype.Ptr(PyVarObjectStruct)
@@ -539,7 +527,8 @@
elif is_PyObject(callable.api_func.restype):
if result is None:
- retval = make_ref(space, None)
+ retval = rffi.cast(callable.api_func.restype,
+ make_ref(space, None))
elif isinstance(result, Reference):
retval = result.get_ref(space)
elif not rffi._isllptr(result):
diff --git a/pypy/translator/jvm/test/test_list.py b/pypy/translator/jvm/test/test_list.py
--- a/pypy/translator/jvm/test/test_list.py
+++ b/pypy/translator/jvm/test/test_list.py
@@ -6,7 +6,10 @@
def test_recursive(self):
py.test.skip("JVM doesn't support recursive lists")
- def test_getitem_exc(self):
+ def test_getitem_exc_1(self):
+ py.test.skip('fixme!')
+
+ def test_getitem_exc_2(self):
py.test.skip('fixme!')
def test_r_short_list(self):
diff --git a/pypy/module/cpyext/typeobject.py b/pypy/module/cpyext/typeobject.py
--- a/pypy/module/cpyext/typeobject.py
+++ b/pypy/module/cpyext/typeobject.py
@@ -3,14 +3,14 @@
from pypy.rpython.lltypesystem import rffi, lltype
from pypy.rpython.annlowlevel import llhelper
-from pypy.interpreter.baseobjspace import DescrMismatch
+from pypy.interpreter.baseobjspace import W_Root, DescrMismatch
from pypy.objspace.std.typeobject import W_TypeObject
from pypy.interpreter.typedef import GetSetProperty
from pypy.module.cpyext.api import (
- cpython_api, cpython_struct, bootstrap_function, Py_ssize_t,
+ cpython_api, cpython_struct, bootstrap_function, Py_ssize_t, Py_ssize_tP,
generic_cpy_call, Py_TPFLAGS_READY, Py_TPFLAGS_READYING,
Py_TPFLAGS_HEAPTYPE, METH_VARARGS, METH_KEYWORDS, CANNOT_FAIL,
- PyBufferProcs, build_type_checkers)
+ build_type_checkers)
from pypy.module.cpyext.pyobject import (
PyObject, make_ref, create_ref, from_ref, get_typedescr, make_typedescr,
track_reference, RefcountState, borrow_from)
@@ -24,7 +24,7 @@
from pypy.module.cpyext.structmember import PyMember_GetOne, PyMember_SetOne
from pypy.module.cpyext.typeobjectdefs import (
PyTypeObjectPtr, PyTypeObject, PyGetSetDef, PyMemberDef, newfunc,
- PyNumberMethods, PySequenceMethods)
+ PyNumberMethods, PySequenceMethods, PyBufferProcs)
from pypy.module.cpyext.slotdefs import (
slotdefs_for_tp_slots, slotdefs_for_wrappers, get_slot_tp_function)
from pypy.interpreter.error import OperationError
@@ -287,11 +287,17 @@
W_TypeObject.__init__(self, space, extension_name,
bases_w or [space.w_object], dict_w)
- self.flag_cpytype = True
+ if not space.is_true(space.issubtype(self, space.w_type)):
+ self.flag_cpytype = True
self.flag_heaptype = False
@bootstrap_function
def init_typeobject(space):
+ # Probably a hack
+ space.model.typeorder[W_PyCTypeObject] = [(W_PyCTypeObject, None),
+ (W_TypeObject, None),
+ (W_Root, None)]
+
make_typedescr(space.w_type.instancetypedef,
basestruct=PyTypeObject,
attach=type_attach,
@@ -355,14 +361,14 @@
# hopefully this does not clash with the memory model assumed in
# extension modules
- at cpython_api([PyObject, rffi.INTP], lltype.Signed, external=False,
+ at cpython_api([PyObject, Py_ssize_tP], lltype.Signed, external=False,
error=CANNOT_FAIL)
def str_segcount(space, w_obj, ref):
if ref:
- ref[0] = rffi.cast(rffi.INT, space.len_w(w_obj))
+ ref[0] = space.len_w(w_obj)
return 1
- at cpython_api([PyObject, lltype.Signed, rffi.VOIDPP], lltype.Signed,
+ at cpython_api([PyObject, Py_ssize_t, rffi.VOIDPP], lltype.Signed,
external=False, error=-1)
def str_getreadbuffer(space, w_str, segment, ref):
from pypy.module.cpyext.stringobject import PyString_AsString
@@ -375,7 +381,7 @@
Py_DecRef(space, pyref)
return space.len_w(w_str)
- at cpython_api([PyObject, lltype.Signed, rffi.CCHARPP], lltype.Signed,
+ at cpython_api([PyObject, Py_ssize_t, rffi.CCHARPP], lltype.Signed,
external=False, error=-1)
def str_getcharbuffer(space, w_str, segment, ref):
from pypy.module.cpyext.stringobject import PyString_AsString
@@ -472,14 +478,19 @@
def PyType_Ready(space, pto):
if pto.c_tp_flags & Py_TPFLAGS_READY:
return 0
+ type_realize(space, rffi.cast(PyObject, pto))
+ return 0
+
+def type_realize(space, py_obj):
+ pto = rffi.cast(PyTypeObjectPtr, py_obj)
assert pto.c_tp_flags & Py_TPFLAGS_READYING == 0
pto.c_tp_flags |= Py_TPFLAGS_READYING
try:
- type_realize(space, rffi.cast(PyObject, pto))
- pto.c_tp_flags |= Py_TPFLAGS_READY
+ w_obj = _type_realize(space, py_obj)
finally:
pto.c_tp_flags &= ~Py_TPFLAGS_READYING
- return 0
+ pto.c_tp_flags |= Py_TPFLAGS_READY
+ return w_obj
def solid_base(space, w_type):
typedef = w_type.instancetypedef
@@ -535,7 +546,7 @@
finally:
Py_DecRef(space, base_pyo)
-def type_realize(space, py_obj):
+def _type_realize(space, py_obj):
"""
Creates an interpreter type from a PyTypeObject structure.
"""
@@ -554,7 +565,9 @@
finish_type_1(space, py_type)
- w_obj = space.allocate_instance(W_PyCTypeObject, space.w_type)
+ w_metatype = from_ref(space, rffi.cast(PyObject, py_type.c_ob_type))
+
+ w_obj = space.allocate_instance(W_PyCTypeObject, w_metatype)
track_reference(space, py_obj, w_obj)
w_obj.__init__(space, py_type)
w_obj.ready()
diff --git a/pypy/objspace/std/test/test_listobject.py b/pypy/objspace/std/test/test_listobject.py
--- a/pypy/objspace/std/test/test_listobject.py
+++ b/pypy/objspace/std/test/test_listobject.py
@@ -347,8 +347,9 @@
assert list('') == []
assert list('abc') == ['a', 'b', 'c']
assert list((1, 2)) == [1, 2]
- l = []
+ l = [1]
assert list(l) is not l
+ assert list(l) == l
assert list(range(10)) == range(10)
def test_explicit_new_init(self):
diff --git a/pypy/jit/tl/pypyjit_demo.py b/pypy/jit/tl/pypyjit_demo.py
--- a/pypy/jit/tl/pypyjit_demo.py
+++ b/pypy/jit/tl/pypyjit_demo.py
@@ -1,19 +1,16 @@
try:
- import pypyjit
- pypyjit.set_param(threshold=3, inlining=True)
+ def main(n):
+ def g(n):
+ return range(n)
+ s = 0
+ for i in range(n): # ID: for
+ tmp = g(n)
+ s += tmp[i] # ID: getitem
+ a = 0
+ return s
+ main(10)
- def sqrt(y, n=10000):
- x = y / 2
- while n > 0:
- #assert y > 0 and x > 0
- if y > 0 and x > 0: pass
- n -= 1
- x = (x + y/x) / 2
- return x
-
- print sqrt(1234, 4)
-
except Exception, e:
print "Exception: ", type(e)
print e
diff --git a/pypy/objspace/std/dictmultiobject.py b/pypy/objspace/std/dictmultiobject.py
--- a/pypy/objspace/std/dictmultiobject.py
+++ b/pypy/objspace/std/dictmultiobject.py
@@ -108,6 +108,11 @@
#return w_value or None
return None
+ def impl_setdefault(self, w_key, w_default):
+ # here the dict is always empty
+ self._as_rdict().impl_fallback_setitem(w_key, w_default)
+ return w_default
+
def impl_setitem(self, w_key, w_value):
self._as_rdict().impl_fallback_setitem(w_key, w_value)
@@ -181,6 +186,9 @@
# _________________________________________________________________
# fallback implementation methods
+ def impl_fallback_setdefault(self, w_key, w_default):
+ return self.r_dict_content.setdefault(w_key, w_default)
+
def impl_fallback_setitem(self, w_key, w_value):
self.r_dict_content[w_key] = w_value
@@ -227,6 +235,7 @@
("length", 0),
("setitem_str", 2),
("setitem", 2),
+ ("setdefault", 2),
("delitem", 1),
("iter", 0),
("items", 0),
@@ -317,6 +326,14 @@
def impl_setitem_str(self, key, w_value):
self.content[key] = w_value
+ def impl_setdefault(self, w_key, w_default):
+ space = self.space
+ if space.is_w(space.type(w_key), space.w_str):
+ return self.content.setdefault(space.str_w(w_key), w_default)
+ else:
+ return self._as_rdict().impl_fallback_setdefault(w_key, w_default)
+
+
def impl_delitem(self, w_key):
space = self.space
w_key_type = space.type(w_key)
@@ -787,13 +804,7 @@
return w_default
def dict_setdefault__DictMulti_ANY_ANY(space, w_dict, w_key, w_default):
- # XXX should be more efficient, with only one dict lookup
- w_value = w_dict.getitem(w_key)
- if w_value is not None:
- return w_value
- else:
- w_dict.setitem(w_key, w_default)
- return w_default
+ return w_dict.setdefault(w_key, w_default)
def dict_pop__DictMulti_ANY(space, w_dict, w_key, defaults_w):
len_defaults = len(defaults_w)
diff --git a/pypy/translator/backendopt/test/test_inline.py b/pypy/translator/backendopt/test/test_inline.py
--- a/pypy/translator/backendopt/test/test_inline.py
+++ b/pypy/translator/backendopt/test/test_inline.py
@@ -1,7 +1,7 @@
# XXX clean up these tests to use more uniform helpers
import py
import os
-from pypy.objspace.flow.model import traverse, Block, Link, Variable, Constant
+from pypy.objspace.flow.model import Block, Link, Variable, Constant
from pypy.objspace.flow.model import last_exception, checkgraph
from pypy.translator.backendopt import canraise
from pypy.translator.backendopt.inline import simple_inline_function, CannotInline
@@ -20,29 +20,27 @@
from pypy.translator.backendopt import removenoops
from pypy.objspace.flow.model import summary
-def no_missing_concretetype(node):
- if isinstance(node, Block):
- for v in node.inputargs:
- assert hasattr(v, 'concretetype')
- for op in node.operations:
- for v in op.args:
- assert hasattr(v, 'concretetype')
- assert hasattr(op.result, 'concretetype')
- if isinstance(node, Link):
- if node.exitcase is not None:
- assert hasattr(node, 'llexitcase')
- for v in node.args:
- assert hasattr(v, 'concretetype')
- if isinstance(node.last_exception, (Variable, Constant)):
- assert hasattr(node.last_exception, 'concretetype')
- if isinstance(node.last_exc_value, (Variable, Constant)):
- assert hasattr(node.last_exc_value, 'concretetype')
-
def sanity_check(t):
# look for missing '.concretetype'
for graph in t.graphs:
checkgraph(graph)
- traverse(no_missing_concretetype, graph)
+ for node in graph.iterblocks():
+ for v in node.inputargs:
+ assert hasattr(v, 'concretetype')
+ for op in node.operations:
+ for v in op.args:
+ assert hasattr(v, 'concretetype')
+ assert hasattr(op.result, 'concretetype')
+ for node in graph.iterlinks():
+ if node.exitcase is not None:
+ assert hasattr(node, 'llexitcase')
+ for v in node.args:
+ assert hasattr(v, 'concretetype')
+ if isinstance(node.last_exception, (Variable, Constant)):
+ assert hasattr(node.last_exception, 'concretetype')
+ if isinstance(node.last_exc_value, (Variable, Constant)):
+ assert hasattr(node.last_exc_value, 'concretetype')
+
class CustomError1(Exception):
def __init__(self):
diff --git a/pypy/jit/metainterp/test/test_optimizebasic.py b/pypy/jit/metainterp/test/test_optimizebasic.py
--- a/pypy/jit/metainterp/test/test_optimizebasic.py
+++ b/pypy/jit/metainterp/test/test_optimizebasic.py
@@ -253,7 +253,7 @@
loop.call_pure_results = args_dict()
if call_pure_results is not None:
for k, v in call_pure_results.items():
- loop.call_pure_results[list(k)] = v
+ loop.call_pure_results[list(k)] = v
metainterp_sd = FakeMetaInterpStaticData(self.cpu)
if hasattr(self, 'vrefinfo'):
metainterp_sd.virtualref_info = self.vrefinfo
@@ -2886,7 +2886,7 @@
# the result of the call, recorded as the first arg), or turned into
# a regular CALL.
arg_consts = [ConstInt(i) for i in (123456, 4, 5, 6)]
- call_pure_results = {tuple(arg_consts): ConstInt(42)}
+ call_pure_results = {tuple(arg_consts): ConstInt(42)}
ops = '''
[i0, i1, i2]
escape(i1)
@@ -2931,7 +2931,6 @@
i0 = force_token()
p2 = new_with_vtable(ConstClass(jit_virtual_ref_vtable))
setfield_gc(p2, i0, descr=virtualtokendescr)
- setfield_gc(p2, 5, descr=virtualrefindexdescr)
escape(p2)
setfield_gc(p2, p1, descr=virtualforceddescr)
setfield_gc(p2, -3, descr=virtualtokendescr)
@@ -2964,7 +2963,6 @@
#
p2 = new_with_vtable(ConstClass(jit_virtual_ref_vtable))
setfield_gc(p2, i3, descr=virtualtokendescr)
- setfield_gc(p2, 3, descr=virtualrefindexdescr)
setfield_gc(p0, p2, descr=nextdescr)
#
call_may_force(i1, descr=mayforcevirtdescr)
@@ -3005,7 +3003,6 @@
#
p2 = new_with_vtable(ConstClass(jit_virtual_ref_vtable))
setfield_gc(p2, i3, descr=virtualtokendescr)
- setfield_gc(p2, 2, descr=virtualrefindexdescr)
setfield_gc(p0, p2, descr=nextdescr)
#
call_may_force(i1, descr=mayforcevirtdescr)
@@ -3062,7 +3059,7 @@
self.loop.inputargs[0].value = self.nodeobjvalue
self.check_expanded_fail_descr('''p2, p1
p0.refdescr = p2
- where p2 is a jit_virtual_ref_vtable, virtualtokendescr=i3, virtualrefindexdescr=2
+ where p2 is a jit_virtual_ref_vtable, virtualtokendescr=i3
where p1 is a node_vtable, nextdescr=p1b
where p1b is a node_vtable, valuedescr=i1
''', rop.GUARD_NO_EXCEPTION)
@@ -3084,7 +3081,6 @@
i3 = force_token()
p2 = new_with_vtable(ConstClass(jit_virtual_ref_vtable))
setfield_gc(p2, i3, descr=virtualtokendescr)
- setfield_gc(p2, 7, descr=virtualrefindexdescr)
escape(p2)
p1 = new_with_vtable(ConstClass(node_vtable))
setfield_gc(p2, p1, descr=virtualforceddescr)
@@ -3111,7 +3107,6 @@
i3 = force_token()
p2 = new_with_vtable(ConstClass(jit_virtual_ref_vtable))
setfield_gc(p2, i3, descr=virtualtokendescr)
- setfield_gc(p2, 23, descr=virtualrefindexdescr)
escape(p2)
setfield_gc(p2, p1, descr=virtualforceddescr)
setfield_gc(p2, -3, descr=virtualtokendescr)
@@ -3360,7 +3355,7 @@
i1 = int_lt(i0, 4)
guard_true(i1) []
i1p = int_gt(i0, -4)
- guard_true(i1p) []
+ guard_true(i1p) []
i2 = int_sub(i0, 10)
i3 = int_lt(i2, -5)
guard_true(i3) []
@@ -3371,7 +3366,7 @@
i1 = int_lt(i0, 4)
guard_true(i1) []
i1p = int_gt(i0, -4)
- guard_true(i1p) []
+ guard_true(i1p) []
i2 = int_sub(i0, 10)
jump(i0)
"""
diff --git a/pypy/rpython/rint.py b/pypy/rpython/rint.py
--- a/pypy/rpython/rint.py
+++ b/pypy/rpython/rint.py
@@ -212,52 +212,48 @@
# cpython, and rpython, assumed that integer division truncates
# towards -infinity. however, in C99 and most (all?) other
# backends, integer division truncates towards 0. so assuming
- # that, we can generate scary code that applies the necessary
+ # that, we call a helper function that applies the necessary
# correction in the right cases.
- # paper and pencil are encouraged for this :)
-
- from pypy.rpython.rbool import bool_repr
- assert isinstance(repr.lowleveltype, Number)
- c_zero = inputconst(repr.lowleveltype, repr.lowleveltype._default)
op = func.split('_', 1)[0]
if op == 'floordiv':
- # return (x/y) - (((x^y)<0)&((x%y)!=0));
- v_xor = hop.genop(prefix + 'xor', vlist,
- resulttype=repr)
- v_xor_le = hop.genop(prefix + 'lt', [v_xor, c_zero],
- resulttype=Bool)
- v_xor_le = hop.llops.convertvar(v_xor_le, bool_repr, repr)
- v_mod = hop.genop(prefix + 'mod', vlist,
- resulttype=repr)
- v_mod_ne = hop.genop(prefix + 'ne', [v_mod, c_zero],
- resulttype=Bool)
- v_mod_ne = hop.llops.convertvar(v_mod_ne, bool_repr, repr)
- v_corr = hop.genop(prefix + 'and', [v_xor_le, v_mod_ne],
- resulttype=repr)
- v_res = hop.genop(prefix + 'sub', [v_res, v_corr],
- resulttype=repr)
+ llfunc = globals()['ll_correct_' + prefix + 'floordiv']
+ v_res = hop.gendirectcall(llfunc, vlist[0], vlist[1], v_res)
elif op == 'mod':
- # return r + y*(((x^y)<0)&(r!=0));
- v_xor = hop.genop(prefix + 'xor', vlist,
- resulttype=repr)
- v_xor_le = hop.genop(prefix + 'lt', [v_xor, c_zero],
- resulttype=Bool)
- v_xor_le = hop.llops.convertvar(v_xor_le, bool_repr, repr)
- v_mod_ne = hop.genop(prefix + 'ne', [v_res, c_zero],
- resulttype=Bool)
- v_mod_ne = hop.llops.convertvar(v_mod_ne, bool_repr, repr)
- v_corr1 = hop.genop(prefix + 'and', [v_xor_le, v_mod_ne],
- resulttype=repr)
- v_corr = hop.genop(prefix + 'mul', [v_corr1, vlist[1]],
- resulttype=repr)
- v_res = hop.genop(prefix + 'add', [v_res, v_corr],
- resulttype=repr)
+ llfunc = globals()['ll_correct_' + prefix + 'mod']
+ v_res = hop.gendirectcall(llfunc, vlist[1], v_res)
+
v_res = hop.llops.convertvar(v_res, repr, r_result)
return v_res
+INT_BITS_1 = r_int.BITS - 1
+LLONG_BITS_1 = r_longlong.BITS - 1
+
+def ll_correct_int_floordiv(x, y, r):
+ p = r * y
+ if y < 0: u = p - x
+ else: u = x - p
+ return r + (u >> INT_BITS_1)
+
+def ll_correct_llong_floordiv(x, y, r):
+ p = r * y
+ if y < 0: u = p - x
+ else: u = x - p
+ return r + (u >> LLONG_BITS_1)
+
+def ll_correct_int_mod(y, r):
+ if y < 0: u = -r
+ else: u = r
+ return r + (y & (u >> INT_BITS_1))
+
+def ll_correct_llong_mod(y, r):
+ if y < 0: u = -r
+ else: u = r
+ return r + (y & (u >> LLONG_BITS_1))
+
+
#Helper functions for comparisons
def _rtype_compare_template(hop, func):
diff --git a/pypy/tool/jitlogparser/module_finder.py b/pypy/tool/jitlogparser/module_finder.py
--- a/pypy/tool/jitlogparser/module_finder.py
+++ b/pypy/tool/jitlogparser/module_finder.py
@@ -6,7 +6,7 @@
more = [code]
while more:
next = more.pop()
- res[next.co_firstlineno] = next
+ res[(next.co_firstlineno, next.co_name)] = next
more += [co for co in next.co_consts
if isinstance(co, types.CodeType)]
return res
diff --git a/pypy/module/imp/__init__.py b/pypy/module/imp/__init__.py
--- a/pypy/module/imp/__init__.py
+++ b/pypy/module/imp/__init__.py
@@ -19,6 +19,7 @@
'load_module': 'interp_imp.load_module',
'load_source': 'interp_imp.load_source',
'load_compiled': 'interp_imp.load_compiled',
+ 'load_dynamic': 'interp_imp.load_dynamic',
'_run_compiled_module': 'interp_imp._run_compiled_module', # pypy
'_getimporter': 'importing._getimporter', # pypy
#'run_module': 'interp_imp.run_module',
@@ -36,7 +37,6 @@
}
appleveldefs = {
- 'load_dynamic': 'app_imp.load_dynamic',
}
def __init__(self, space, *args):
diff --git a/pypy/translator/oosupport/test_template/builtin.py b/pypy/translator/oosupport/test_template/builtin.py
--- a/pypy/translator/oosupport/test_template/builtin.py
+++ b/pypy/translator/oosupport/test_template/builtin.py
@@ -227,6 +227,17 @@
assert res == ord('a')
+ def test_rlocale(self):
+ from pypy.rlib.rlocale import isupper, islower, isalpha, isalnum, tolower
+ def fn():
+ assert isupper(ord("A"))
+ assert islower(ord("a"))
+ assert not isalpha(ord(" "))
+ assert isalnum(ord("1"))
+ assert tolower(ord("A")) == ord("a")
+ self.interpret(fn, [])
+
+
class BaseTestTime(llBaseTestTime):
def test_time_clock(self):
diff --git a/pypy/jit/metainterp/test/support.py b/pypy/jit/metainterp/test/support.py
new file mode 100644
--- /dev/null
+++ b/pypy/jit/metainterp/test/support.py
@@ -0,0 +1,261 @@
+
+import py, sys
+from pypy.rpython.lltypesystem import lltype, llmemory
+from pypy.rpython.ootypesystem import ootype
+from pypy.jit.backend.llgraph import runner
+from pypy.jit.metainterp.warmspot import ll_meta_interp, get_stats
+from pypy.jit.metainterp.optimizeopt import ALL_OPTS_DICT
+from pypy.jit.metainterp import pyjitpl, history
+from pypy.jit.metainterp.warmstate import set_future_value
+from pypy.jit.codewriter.policy import JitPolicy
+from pypy.jit.codewriter import longlong
+
+def _get_jitcodes(testself, CPUClass, func, values, type_system,
+ supports_longlong=False, **kwds):
+ from pypy.jit.codewriter import support, codewriter
+
+ class FakeJitCell:
+ __compiled_merge_points = []
+ def get_compiled_merge_points(self):
+ return self.__compiled_merge_points[:]
+ def set_compiled_merge_points(self, lst):
+ self.__compiled_merge_points = lst
+
+ class FakeWarmRunnerState:
+ def attach_unoptimized_bridge_from_interp(self, greenkey, newloop):
+ pass
+
+ def jit_cell_at_key(self, greenkey):
+ assert greenkey == []
+ return self._cell
+ _cell = FakeJitCell()
+
+ trace_limit = sys.maxint
+ enable_opts = ALL_OPTS_DICT
+
+ func._jit_unroll_safe_ = True
+ rtyper = support.annotate(func, values, type_system=type_system)
+ graphs = rtyper.annotator.translator.graphs
+ result_kind = history.getkind(graphs[0].getreturnvar().concretetype)[0]
+
+ class FakeJitDriverSD:
+ num_green_args = 0
+ portal_graph = graphs[0]
+ virtualizable_info = None
+ greenfield_info = None
+ result_type = result_kind
+ portal_runner_ptr = "???"
+
+ stats = history.Stats()
+ cpu = CPUClass(rtyper, stats, None, False)
+ cw = codewriter.CodeWriter(cpu, [FakeJitDriverSD()])
+ testself.cw = cw
+ policy = JitPolicy()
+ policy.set_supports_longlong(supports_longlong)
+ cw.find_all_graphs(policy)
+ #
+ testself.warmrunnerstate = FakeWarmRunnerState()
+ testself.warmrunnerstate.cpu = cpu
+ FakeJitDriverSD.warmstate = testself.warmrunnerstate
+ if hasattr(testself, 'finish_setup_for_interp_operations'):
+ testself.finish_setup_for_interp_operations()
+ #
+ cw.make_jitcodes(verbose=True)
+
+def _run_with_blackhole(testself, args):
+ from pypy.jit.metainterp.blackhole import BlackholeInterpBuilder
+ cw = testself.cw
+ blackholeinterpbuilder = BlackholeInterpBuilder(cw)
+ blackholeinterp = blackholeinterpbuilder.acquire_interp()
+ count_i = count_r = count_f = 0
+ for value in args:
+ T = lltype.typeOf(value)
+ if T == lltype.Signed:
+ blackholeinterp.setarg_i(count_i, value)
+ count_i += 1
+ elif T == llmemory.GCREF:
+ blackholeinterp.setarg_r(count_r, value)
+ count_r += 1
+ elif T == lltype.Float:
+ value = longlong.getfloatstorage(value)
+ blackholeinterp.setarg_f(count_f, value)
+ count_f += 1
+ else:
+ raise TypeError(T)
+ [jitdriver_sd] = cw.callcontrol.jitdrivers_sd
+ blackholeinterp.setposition(jitdriver_sd.mainjitcode, 0)
+ blackholeinterp.run()
+ return blackholeinterp._final_result_anytype()
+
+def _run_with_pyjitpl(testself, args):
+
+ class DoneWithThisFrame(Exception):
+ pass
+
+ class DoneWithThisFrameRef(DoneWithThisFrame):
+ def __init__(self, cpu, *args):
+ DoneWithThisFrame.__init__(self, *args)
+
+ cw = testself.cw
+ opt = history.Options(listops=True)
+ metainterp_sd = pyjitpl.MetaInterpStaticData(cw.cpu, opt)
+ metainterp_sd.finish_setup(cw)
+ [jitdriver_sd] = metainterp_sd.jitdrivers_sd
+ metainterp = pyjitpl.MetaInterp(metainterp_sd, jitdriver_sd)
+ metainterp_sd.DoneWithThisFrameInt = DoneWithThisFrame
+ metainterp_sd.DoneWithThisFrameRef = DoneWithThisFrameRef
+ metainterp_sd.DoneWithThisFrameFloat = DoneWithThisFrame
+ testself.metainterp = metainterp
+ try:
+ metainterp.compile_and_run_once(jitdriver_sd, *args)
+ except DoneWithThisFrame, e:
+ #if conftest.option.view:
+ # metainterp.stats.view()
+ return e.args[0]
+ else:
+ raise Exception("FAILED")
+
+def _run_with_machine_code(testself, args):
+ metainterp = testself.metainterp
+ num_green_args = metainterp.jitdriver_sd.num_green_args
+ loop_tokens = metainterp.get_compiled_merge_points(args[:num_green_args])
+ if len(loop_tokens) != 1:
+ return NotImplemented
+ # a loop was successfully created by _run_with_pyjitpl(); call it
+ cpu = metainterp.cpu
+ for i in range(len(args) - num_green_args):
+ x = args[num_green_args + i]
+ typecode = history.getkind(lltype.typeOf(x))
+ set_future_value(cpu, i, x, typecode)
+ faildescr = cpu.execute_token(loop_tokens[0])
+ assert faildescr.__class__.__name__.startswith('DoneWithThisFrameDescr')
+ if metainterp.jitdriver_sd.result_type == history.INT:
+ return cpu.get_latest_value_int(0)
+ elif metainterp.jitdriver_sd.result_type == history.REF:
+ return cpu.get_latest_value_ref(0)
+ elif metainterp.jitdriver_sd.result_type == history.FLOAT:
+ return cpu.get_latest_value_float(0)
+ else:
+ return None
+
+
+class JitMixin:
+ basic = True
+ def check_loops(self, expected=None, everywhere=False, **check):
+ get_stats().check_loops(expected=expected, everywhere=everywhere,
+ **check)
+ def check_loop_count(self, count):
+ """NB. This is a hack; use check_tree_loop_count() or
+ check_enter_count() for the real thing.
+ This counts as 1 every bridge in addition to every loop; and it does
+ not count at all the entry bridges from interpreter, although they
+ are TreeLoops as well."""
+ assert get_stats().compiled_count == count
+ def check_tree_loop_count(self, count):
+ assert len(get_stats().loops) == count
+ def check_loop_count_at_most(self, count):
+ assert get_stats().compiled_count <= count
+ def check_enter_count(self, count):
+ assert get_stats().enter_count == count
+ def check_enter_count_at_most(self, count):
+ assert get_stats().enter_count <= count
+ def check_jumps(self, maxcount):
+ assert get_stats().exec_jumps <= maxcount
+ def check_aborted_count(self, count):
+ assert get_stats().aborted_count == count
+ def check_aborted_count_at_least(self, count):
+ assert get_stats().aborted_count >= count
+
+ def meta_interp(self, *args, **kwds):
+ kwds['CPUClass'] = self.CPUClass
+ kwds['type_system'] = self.type_system
+ if "backendopt" not in kwds:
+ kwds["backendopt"] = False
+ return ll_meta_interp(*args, **kwds)
+
+ def interp_operations(self, f, args, **kwds):
+ # get the JitCodes for the function f
+ _get_jitcodes(self, self.CPUClass, f, args, self.type_system, **kwds)
+ # try to run it with blackhole.py
+ result1 = _run_with_blackhole(self, args)
+ # try to run it with pyjitpl.py
+ result2 = _run_with_pyjitpl(self, args)
+ assert result1 == result2
+ # try to run it by running the code compiled just before
+ result3 = _run_with_machine_code(self, args)
+ assert result1 == result3 or result3 == NotImplemented
+ #
+ if (longlong.supports_longlong and
+ isinstance(result1, longlong.r_float_storage)):
+ result1 = longlong.getrealfloat(result1)
+ return result1
+
+ def check_history(self, expected=None, **isns):
+ # this can be used after calling meta_interp
+ get_stats().check_history(expected, **isns)
+
+ def check_operations_history(self, expected=None, **isns):
+ # this can be used after interp_operations
+ if expected is not None:
+ expected = dict(expected)
+ expected['jump'] = 1
+ self.metainterp.staticdata.stats.check_history(expected, **isns)
+
+
+class LLJitMixin(JitMixin):
+ type_system = 'lltype'
+ CPUClass = runner.LLtypeCPU
+
+ @staticmethod
+ def Ptr(T):
+ return lltype.Ptr(T)
+
+ @staticmethod
+ def GcStruct(name, *fields, **kwds):
+ S = lltype.GcStruct(name, *fields, **kwds)
+ return S
+
+ malloc = staticmethod(lltype.malloc)
+ nullptr = staticmethod(lltype.nullptr)
+
+ @staticmethod
+ def malloc_immortal(T):
+ return lltype.malloc(T, immortal=True)
+
+ def _get_NODE(self):
+ NODE = lltype.GcForwardReference()
+ NODE.become(lltype.GcStruct('NODE', ('value', lltype.Signed),
+ ('next', lltype.Ptr(NODE))))
+ return NODE
+
+class OOJitMixin(JitMixin):
+ type_system = 'ootype'
+ #CPUClass = runner.OOtypeCPU
+
+ def setup_class(cls):
+ py.test.skip("ootype tests skipped for now")
+
+ @staticmethod
+ def Ptr(T):
+ return T
+
+ @staticmethod
+ def GcStruct(name, *fields, **kwds):
+ if 'hints' in kwds:
+ kwds['_hints'] = kwds['hints']
+ del kwds['hints']
+ I = ootype.Instance(name, ootype.ROOT, dict(fields), **kwds)
+ return I
+
+ malloc = staticmethod(ootype.new)
+ nullptr = staticmethod(ootype.null)
+
+ @staticmethod
+ def malloc_immortal(T):
+ return ootype.new(T)
+
+ def _get_NODE(self):
+ NODE = ootype.Instance('NODE', ootype.ROOT, {})
+ NODE._add_fields({'value': ootype.Signed,
+ 'next': NODE})
+ return NODE
diff --git a/pypy/module/_winreg/interp_winreg.py b/pypy/module/_winreg/interp_winreg.py
--- a/pypy/module/_winreg/interp_winreg.py
+++ b/pypy/module/_winreg/interp_winreg.py
@@ -261,7 +261,8 @@
if ret != 0:
raiseWindowsError(space, ret, 'RegQueryValue')
- return space.wrap(rffi.charp2strn(buf, bufsize_p[0] - 1))
+ length = intmask(bufsize_p[0] - 1)
+ return space.wrap(rffi.charp2strn(buf, length))
def convert_to_regdata(space, w_value, typ):
buf = None
@@ -445,9 +446,10 @@
continue
if ret != 0:
raiseWindowsError(space, ret, 'RegQueryValueEx')
+ length = intmask(retDataSize[0])
return space.newtuple([
convert_from_regdata(space, databuf,
- retDataSize[0], retType[0]),
+ length, retType[0]),
space.wrap(retType[0]),
])
@@ -595,11 +597,11 @@
if ret != 0:
raiseWindowsError(space, ret, 'RegEnumValue')
+ length = intmask(retDataSize[0])
return space.newtuple([
space.wrap(rffi.charp2str(valuebuf)),
convert_from_regdata(space, databuf,
- retDataSize[0],
- retType[0]),
+ length, retType[0]),
space.wrap(retType[0]),
])
diff --git a/pypy/jit/backend/cli/test/test_basic.py b/pypy/jit/backend/cli/test/test_basic.py
--- a/pypy/jit/backend/cli/test/test_basic.py
+++ b/pypy/jit/backend/cli/test/test_basic.py
@@ -1,14 +1,14 @@
import py
from pypy.jit.backend.cli.runner import CliCPU
-from pypy.jit.metainterp.test import test_basic
+from pypy.jit.metainterp.test import support, test_ajit
-class CliJitMixin(test_basic.OOJitMixin):
+class CliJitMixin(suport.OOJitMixin):
CPUClass = CliCPU
def setup_class(cls):
from pypy.translator.cli.support import PythonNet
PythonNet.System # possibly raises Skip
-class TestBasic(CliJitMixin, test_basic.TestOOtype):
+class TestBasic(CliJitMixin, test_ajit.TestOOtype):
# for the individual tests see
# ====> ../../../metainterp/test/test_basic.py
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
@@ -106,6 +106,10 @@
'debug_catch_exception': Ignore,
'debug_reraise_traceback': Ignore,
'debug_print_traceback': Ignore,
+ 'debug_start': Ignore,
+ 'debug_stop': Ignore,
+ 'debug_print': Ignore,
+ 'keepalive': Ignore,
# __________ numeric operations __________
@@ -144,6 +148,7 @@
'int_xor_ovf': jvm.IXOR,
'int_floordiv_ovf_zer': jvm.IFLOORDIVZEROVF,
'int_mod_ovf_zer': _check_zer(jvm.IREMOVF),
+ 'int_between': jvm.PYPYINTBETWEEN,
'uint_invert': 'bitwise_negate',
@@ -185,8 +190,8 @@
'llong_mod_zer': _check_zer(jvm.LREM),
'llong_and': jvm.LAND,
'llong_or': jvm.LOR,
- 'llong_lshift': [PushAllArgs, jvm.L2I, jvm.LSHL, StoreResult],
- 'llong_rshift': [PushAllArgs, jvm.L2I, jvm.LSHR, StoreResult],
+ 'llong_lshift': [PushAllArgs, jvm.LSHL, StoreResult],
+ 'llong_rshift': [PushAllArgs, jvm.LSHR, StoreResult],
'llong_xor': jvm.LXOR,
'llong_floordiv_ovf': jvm.LFLOORDIVOVF,
'llong_floordiv_ovf_zer': jvm.LFLOORDIVZEROVF,
@@ -202,9 +207,11 @@
'ullong_truediv': None, # TODO
'ullong_floordiv': jvm.LDIV, # valid?
'ullong_mod': jvm.PYPYULONGMOD,
- 'ullong_lshift': [PushAllArgs, jvm.L2I, jvm.LSHL, StoreResult],
- 'ullong_rshift': [PushAllArgs, jvm.L2I, jvm.LUSHR, StoreResult],
+ 'ullong_lshift': [PushAllArgs, jvm.LSHL, StoreResult],
+ 'ullong_rshift': [PushAllArgs, jvm.LUSHR, StoreResult],
'ullong_mod_zer': jvm.PYPYULONGMOD,
+ 'ullong_or': jvm.LOR,
+ 'ullong_and': jvm.LAND,
# when casting from bool we want that every truth value is casted
# to 1: we can't simply DoNothing, because the CLI stack could
@@ -227,5 +234,8 @@
'cast_float_to_uint': jvm.PYPYDOUBLETOUINT,
'truncate_longlong_to_int': jvm.L2I,
'cast_longlong_to_float': jvm.L2D,
+ 'cast_float_to_ulonglong': jvm.PYPYDOUBLETOULONG,
+ 'cast_ulonglong_to_float': jvm.PYPYULONGTODOUBLE,
'cast_primitive': [PushAllArgs, CastPrimitive, StoreResult],
+ 'force_cast': [PushAllArgs, CastPrimitive, StoreResult],
})
diff --git a/pypy/jit/metainterp/test/test_tl.py b/pypy/jit/metainterp/test/test_tl.py
--- a/pypy/jit/metainterp/test/test_tl.py
+++ b/pypy/jit/metainterp/test/test_tl.py
@@ -1,6 +1,6 @@
import py
from pypy.jit.codewriter.policy import StopAtXPolicy
-from pypy.jit.metainterp.test.test_basic import OOJitMixin, LLJitMixin
+from pypy.jit.metainterp.test.support import OOJitMixin, LLJitMixin
class ToyLanguageTests:
diff --git a/pypy/interpreter/pyframe.py b/pypy/interpreter/pyframe.py
--- a/pypy/interpreter/pyframe.py
+++ b/pypy/interpreter/pyframe.py
@@ -46,15 +46,15 @@
w_f_trace = None
# For tracing
instr_lb = 0
- instr_ub = -1
- instr_prev = -1
+ instr_ub = 0
+ instr_prev_plus_one = 0
is_being_profiled = False
def __init__(self, space, code, w_globals, closure):
self = hint(self, access_directly=True, fresh_virtualizable=True)
assert isinstance(code, pycode.PyCode)
self.pycode = code
- eval.Frame.__init__(self, space, w_globals, code.co_nlocals)
+ eval.Frame.__init__(self, space, w_globals)
self.valuestack_w = [None] * code.co_stacksize
self.valuestackdepth = 0
self.lastblock = None
@@ -63,7 +63,7 @@
# regular functions always have CO_OPTIMIZED and CO_NEWLOCALS.
# class bodies only have CO_NEWLOCALS.
self.initialize_frame_scopes(closure, code)
- self.fastlocals_w = [None]*self.numlocals
+ self.fastlocals_w = [None] * code.co_nlocals
make_sure_not_resized(self.fastlocals_w)
self.f_lineno = code.co_firstlineno
@@ -335,7 +335,7 @@
w(self.instr_lb), #do we need these three (that are for tracing)
w(self.instr_ub),
- w(self.instr_prev),
+ w(self.instr_prev_plus_one),
w_cells,
]
@@ -349,7 +349,7 @@
args_w = space.unpackiterable(w_args)
w_f_back, w_builtin, w_pycode, w_valuestack, w_blockstack, w_exc_value, w_tb,\
w_globals, w_last_instr, w_finished, w_f_lineno, w_fastlocals, w_f_locals, \
- w_f_trace, w_instr_lb, w_instr_ub, w_instr_prev, w_cells = args_w
+ w_f_trace, w_instr_lb, w_instr_ub, w_instr_prev_plus_one, w_cells = args_w
new_frame = self
pycode = space.interp_w(PyCode, w_pycode)
@@ -397,7 +397,7 @@
new_frame.instr_lb = space.int_w(w_instr_lb) #the three for tracing
new_frame.instr_ub = space.int_w(w_instr_ub)
- new_frame.instr_prev = space.int_w(w_instr_prev)
+ new_frame.instr_prev_plus_one = space.int_w(w_instr_prev_plus_one)
self._setcellvars(cellvars)
# XXX what if the frame is in another thread??
@@ -430,7 +430,10 @@
"""Initialize cellvars from self.fastlocals_w
This is overridden in nestedscope.py"""
pass
-
+
+ def getfastscopelength(self):
+ return self.pycode.co_nlocals
+
def getclosure(self):
return None
diff --git a/pypy/jit/backend/llgraph/runner.py b/pypy/jit/backend/llgraph/runner.py
--- a/pypy/jit/backend/llgraph/runner.py
+++ b/pypy/jit/backend/llgraph/runner.py
@@ -25,12 +25,13 @@
class Descr(history.AbstractDescr):
def __init__(self, ofs, typeinfo, extrainfo=None, name=None,
- arg_types=None):
+ arg_types=None, count_fields_if_immut=-1):
self.ofs = ofs
self.typeinfo = typeinfo
self.extrainfo = extrainfo
self.name = name
self.arg_types = arg_types
+ self.count_fields_if_immut = count_fields_if_immut
def get_arg_types(self):
return self.arg_types
@@ -63,6 +64,9 @@
def as_vtable_size_descr(self):
return self
+ def count_fields_if_immutable(self):
+ return self.count_fields_if_immut
+
def __lt__(self, other):
raise TypeError("cannot use comparison on Descrs")
def __le__(self, other):
@@ -109,12 +113,14 @@
return False
def getdescr(self, ofs, typeinfo='?', extrainfo=None, name=None,
- arg_types=None):
- key = (ofs, typeinfo, extrainfo, name, arg_types)
+ arg_types=None, count_fields_if_immut=-1):
+ key = (ofs, typeinfo, extrainfo, name, arg_types,
+ count_fields_if_immut)
try:
return self._descrs[key]
except KeyError:
- descr = Descr(ofs, typeinfo, extrainfo, name, arg_types)
+ descr = Descr(ofs, typeinfo, extrainfo, name, arg_types,
+ count_fields_if_immut)
self._descrs[key] = descr
return descr
@@ -284,7 +290,8 @@
def sizeof(self, S):
assert not isinstance(S, lltype.Ptr)
- return self.getdescr(symbolic.get_size(S))
+ count = heaptracker.count_fields_if_immutable(S)
+ return self.getdescr(symbolic.get_size(S), count_fields_if_immut=count)
class LLtypeCPU(BaseCPU):
diff --git a/pypy/module/cpyext/typeobjectdefs.py b/pypy/module/cpyext/typeobjectdefs.py
--- a/pypy/module/cpyext/typeobjectdefs.py
+++ b/pypy/module/cpyext/typeobjectdefs.py
@@ -1,9 +1,8 @@
from pypy.rpython.lltypesystem import rffi, lltype
from pypy.rpython.lltypesystem.lltype import Ptr, FuncType, Void
-from pypy.module.cpyext.api import cpython_struct, \
- PyVarObjectFields, Py_ssize_t, Py_TPFLAGS_READYING, \
- Py_TPFLAGS_READY, Py_TPFLAGS_HEAPTYPE, \
- PyTypeObject, PyTypeObjectPtr, PyBufferProcs, FILEP
+from pypy.module.cpyext.api import (cpython_struct, Py_ssize_t, Py_ssize_tP,
+ PyVarObjectFields, PyTypeObject, PyTypeObjectPtr, FILEP,
+ Py_TPFLAGS_READYING, Py_TPFLAGS_READY, Py_TPFLAGS_HEAPTYPE)
from pypy.module.cpyext.pyobject import PyObject, make_ref, from_ref
from pypy.module.cpyext.modsupport import PyMethodDef
@@ -55,6 +54,14 @@
wrapperfunc = P(FT([PyO, PyO, rffi.VOIDP], PyO))
wrapperfunc_kwds = P(FT([PyO, PyO, rffi.VOIDP, PyO], PyO))
+readbufferproc = P(FT([PyO, Py_ssize_t, rffi.VOIDPP], Py_ssize_t))
+writebufferproc = P(FT([PyO, Py_ssize_t, rffi.VOIDPP], Py_ssize_t))
+segcountproc = P(FT([PyO, Py_ssize_tP], Py_ssize_t))
+charbufferproc = P(FT([PyO, Py_ssize_t, rffi.CCHARPP], Py_ssize_t))
+## We don't support new buffer interface for now
+getbufferproc = rffi.VOIDP
+releasebufferproc = rffi.VOIDP
+
PyGetSetDef = cpython_struct("PyGetSetDef", (
("name", rffi.CCHARP),
@@ -127,7 +134,6 @@
("mp_ass_subscript", objobjargproc),
))
-"""
PyBufferProcs = cpython_struct("PyBufferProcs", (
("bf_getreadbuffer", readbufferproc),
("bf_getwritebuffer", writebufferproc),
@@ -136,7 +142,6 @@
("bf_getbuffer", getbufferproc),
("bf_releasebuffer", releasebufferproc),
))
-"""
PyMemberDef = cpython_struct("PyMemberDef", (
("name", rffi.CCHARP),
diff --git a/pypy/module/posix/app_posix.py b/pypy/module/posix/app_posix.py
--- a/pypy/module/posix/app_posix.py
+++ b/pypy/module/posix/app_posix.py
@@ -190,14 +190,30 @@
def wait():
""" wait() -> (pid, status)
-
+
Wait for completion of a child process.
"""
return posix.waitpid(-1, 0)
+ def wait3(options):
+ """ wait3(options) -> (pid, status, rusage)
+
+ Wait for completion of a child process and provides resource usage informations
+ """
+ from _pypy_wait import wait3
+ return wait3(options)
+
+ def wait4(pid, options):
+ """ wait4(pid, options) -> (pid, status, rusage)
+
+ Wait for completion of the child process "pid" and provides resource usage informations
+ """
+ from _pypy_wait import wait4
+ return wait4(pid, options)
+
else:
# Windows implementations
-
+
# Supply os.popen() based on subprocess
def popen(cmd, mode="r", bufsize=-1):
"""popen(command [, mode='r' [, bufsize]]) -> pipe
@@ -285,7 +301,7 @@
raise TypeError("invalid cmd type (%s, expected string)" %
(type(cmd),))
return cmd
-
+
# A proxy for a file whose close waits for the process
class _wrap_close(object):
def __init__(self, stream, proc):
diff --git a/pypy/jit/metainterp/optimizeopt/heap.py b/pypy/jit/metainterp/optimizeopt/heap.py
--- a/pypy/jit/metainterp/optimizeopt/heap.py
+++ b/pypy/jit/metainterp/optimizeopt/heap.py
@@ -3,8 +3,102 @@
from pypy.jit.metainterp.resoperation import rop, ResOperation
from pypy.rlib.objectmodel import we_are_translated
from pypy.jit.metainterp.jitexc import JitException
+from pypy.jit.metainterp.optimizeopt.optimizer import Optimization
-from pypy.jit.metainterp.optimizeopt.optimizer import Optimization
+
+class CachedField(object):
+ def __init__(self):
+ # Cache information for a field descr. It can be in one
+ # of two states:
+ #
+ # 1. 'cached_fields' is a dict mapping OptValues of structs
+ # to OptValues of fields. All fields on-heap are
+ # synchronized with the values stored in the cache.
+ #
+ # 2. we just did one setfield, which is delayed (and thus
+ # not synchronized). 'lazy_setfield' is the delayed
+ # ResOperation. In this state, 'cached_fields' contains
+ # out-of-date information. More precisely, the field
+ # value pending in the ResOperation is *not* visible in
+ # 'cached_fields'.
+ #
+ self._cached_fields = {}
+ self._lazy_setfield = None
+ self._lazy_setfield_registered = False
+
+ def do_setfield(self, optheap, op):
+ # Update the state with the SETFIELD_GC operation 'op'.
+ structvalue = optheap.getvalue(op.getarg(0))
+ fieldvalue = optheap.getvalue(op.getarg(1))
+ if self.possible_aliasing(optheap, structvalue):
+ self.force_lazy_setfield(optheap)
+ assert not self.possible_aliasing(optheap, structvalue)
+ cached_fieldvalue = self._cached_fields.get(structvalue, None)
+ if cached_fieldvalue is not fieldvalue:
+ # common case: store the 'op' as lazy_setfield, and register
+ # myself in the optheap's _lazy_setfields list
+ self._lazy_setfield = op
+ if not self._lazy_setfield_registered:
+ optheap._lazy_setfields.append(self)
+ self._lazy_setfield_registered = True
+ else:
+ # this is the case where the pending setfield ends up
+ # storing precisely the value that is already there,
+ # as proved by 'cached_fields'. In this case, we don't
+ # need any _lazy_setfield: the heap value is already right.
+ # Note that this may reset to None a non-None lazy_setfield,
+ # cancelling its previous effects with no side effect.
+ self._lazy_setfield = None
+
+ def possible_aliasing(self, optheap, structvalue):
+ # If lazy_setfield is set and contains a setfield on a different
+ # structvalue, then we are annoyed, because it may point to either
+ # the same or a different structure at runtime.
+ return (self._lazy_setfield is not None
+ and (optheap.getvalue(self._lazy_setfield.getarg(0))
+ is not structvalue))
+
+ def getfield_from_cache(self, optheap, structvalue):
+ # Returns the up-to-date field's value, or None if not cached.
+ if self.possible_aliasing(optheap, structvalue):
+ self.force_lazy_setfield(optheap)
+ if self._lazy_setfield is not None:
+ op = self._lazy_setfield
+ assert optheap.getvalue(op.getarg(0)) is structvalue
+ return optheap.getvalue(op.getarg(1))
+ else:
+ return self._cached_fields.get(structvalue, None)
+
+ def remember_field_value(self, structvalue, fieldvalue):
+ assert self._lazy_setfield is None
+ self._cached_fields[structvalue] = fieldvalue
+
+ def force_lazy_setfield(self, optheap):
+ op = self._lazy_setfield
+ if op is not None:
+ # This is the way _lazy_setfield is usually reset to None.
+ # Now we clear _cached_fields, because actually doing the
+ # setfield might impact any of the stored result (because of
+ # possible aliasing).
+ self._cached_fields.clear()
+ self._lazy_setfield = None
+ optheap.next_optimization.propagate_forward(op)
+ # Once it is done, we can put at least one piece of information
+ # back in the cache: the value of this particular structure's
+ # field.
+ structvalue = optheap.getvalue(op.getarg(0))
+ fieldvalue = optheap.getvalue(op.getarg(1))
+ self.remember_field_value(structvalue, fieldvalue)
+
+ def get_reconstructed(self, optimizer, valuemap):
+ assert self._lazy_setfield is None
+ cf = CachedField()
+ for structvalue, fieldvalue in self._cached_fields.iteritems():
+ structvalue2 = structvalue.get_reconstructed(optimizer, valuemap)
+ fieldvalue2 = fieldvalue .get_reconstructed(optimizer, valuemap)
+ cf._cached_fields[structvalue2] = fieldvalue2
+ return cf
+
class CachedArrayItems(object):
def __init__(self):
@@ -20,40 +114,23 @@
"""Cache repeated heap accesses"""
def __init__(self):
- # cached fields: {descr: {OptValue_instance: OptValue_fieldvalue}}
+ # cached fields: {descr: CachedField}
self.cached_fields = {}
- self.known_heap_fields = {}
+ self._lazy_setfields = []
# cached array items: {descr: CachedArrayItems}
self.cached_arrayitems = {}
- # lazily written setfields (at most one per descr): {descr: op}
- self.lazy_setfields = {}
- self.lazy_setfields_descrs = [] # keys (at least) of previous dict
def reconstruct_for_next_iteration(self, optimizer, valuemap):
new = OptHeap()
if True:
self.force_all_lazy_setfields()
- assert not self.lazy_setfields_descrs
- assert not self.lazy_setfields
else:
- new.lazy_setfields_descrs = self.lazy_setfields_descrs
- new.lazy_setfields = self.lazy_setfields
+ assert 0 # was: new.lazy_setfields = self.lazy_setfields
for descr, d in self.cached_fields.items():
- newd = {}
- new.cached_fields[descr] = newd
- for value, fieldvalue in d.items():
- newd[value.get_reconstructed(optimizer, valuemap)] = \
- fieldvalue.get_reconstructed(optimizer, valuemap)
-
- for descr, d in self.known_heap_fields.items():
- newd = {}
- new.known_heap_fields[descr] = newd
- for value, fieldvalue in d.items():
- newd[value.get_reconstructed(optimizer, valuemap)] = \
- fieldvalue.get_reconstructed(optimizer, valuemap)
-
+ new.cached_fields[descr] = d.get_reconstructed(optimizer, valuemap)
+
new.cached_arrayitems = {}
for descr, d in self.cached_arrayitems.items():
newd = {}
@@ -74,30 +151,16 @@
return new
def clean_caches(self):
+ del self._lazy_setfields[:]
self.cached_fields.clear()
- self.known_heap_fields.clear()
self.cached_arrayitems.clear()
- def cache_field_value(self, descr, value, fieldvalue, write=False):
- if write:
- # when seeing a setfield, we have to clear the cache for the same
- # field on any other structure, just in case they are aliasing
- # each other
- d = self.cached_fields[descr] = {}
- else:
- d = self.cached_fields.setdefault(descr, {})
- d[value] = fieldvalue
-
- def read_cached_field(self, descr, value):
- # XXX self.cached_fields and self.lazy_setfields should probably
- # be merged somehow
- d = self.cached_fields.get(descr, None)
- if d is None:
- op = self.lazy_setfields.get(descr, None)
- if op is None:
- return None
- return self.getvalue(op.getarg(1))
- return d.get(value, None)
+ def field_cache(self, descr):
+ try:
+ cf = self.cached_fields[descr]
+ except KeyError:
+ cf = self.cached_fields[descr] = CachedField()
+ return cf
def cache_arrayitem_value(self, descr, value, indexvalue, fieldvalue, write=False):
d = self.cached_arrayitems.get(descr, None)
@@ -157,11 +220,15 @@
self.optimizer.pendingfields = self.force_lazy_setfields_for_guard()
return
opnum = op.getopnum()
- if (opnum == rop.SETFIELD_GC or
- opnum == rop.SETFIELD_RAW or
- opnum == rop.SETARRAYITEM_GC or
- opnum == rop.SETARRAYITEM_RAW or
- opnum == rop.DEBUG_MERGE_POINT):
+ if (opnum == rop.SETFIELD_GC or # handled specially
+ opnum == rop.SETFIELD_RAW or # no effect on GC struct/array
+ opnum == rop.SETARRAYITEM_GC or # handled specially
+ opnum == rop.SETARRAYITEM_RAW or # no effect on GC struct
+ opnum == rop.STRSETITEM or # no effect on GC struct/array
+ opnum == rop.UNICODESETITEM or # no effect on GC struct/array
+ opnum == rop.DEBUG_MERGE_POINT or # no effect whatsoever
+ opnum == rop.COPYSTRCONTENT or # no effect on GC struct/array
+ opnum == rop.COPYUNICODECONTENT): # no effect on GC struct/array
return
assert opnum != rop.CALL_PURE
if (opnum == rop.CALL or
@@ -179,8 +246,8 @@
for fielddescr in effectinfo.write_descrs_fields:
self.force_lazy_setfield(fielddescr)
try:
- del self.cached_fields[fielddescr]
- del self.known_heap_fields[fielddescr]
+ cf = self.cached_fields[fielddescr]
+ cf._cached_fields.clear()
except KeyError:
pass
for arraydescr in effectinfo.write_descrs_arrays:
@@ -194,10 +261,7 @@
# ^^^ we only need to force this field; the other fields
# of virtualref_info and virtualizable_info are not gcptrs.
return
- self.force_all_lazy_setfields()
- elif op.is_final() or (not we_are_translated() and
- op.getopnum() < 0): # escape() operations
- self.force_all_lazy_setfields()
+ self.force_all_lazy_setfields()
self.clean_caches()
@@ -205,58 +269,54 @@
assert value.is_constant()
newvalue = self.getvalue(value.box)
if value is not newvalue:
- for d in self.cached_fields.values():
- if value in d:
- d[newvalue] = d[value]
- # FIXME: Update the other caches too?
-
-
- def force_lazy_setfield(self, descr, before_guard=False):
+ for cf in self.cached_fields.itervalues():
+ if value in cf._cached_fields:
+ cf._cached_fields[newvalue] = cf._cached_fields[value]
+
+ def force_lazy_setfield(self, descr):
try:
- op = self.lazy_setfields[descr]
+ cf = self.cached_fields[descr]
except KeyError:
return
- del self.lazy_setfields[descr]
- value = self.getvalue(op.getarg(0))
- fieldvalue = self.getvalue(op.getarg(1))
- try:
- heapvalue = self.known_heap_fields[op.getdescr()][value]
- if fieldvalue is heapvalue:
- return
- except KeyError:
- pass
- self.next_optimization.propagate_forward(op)
+ cf.force_lazy_setfield(self)
+ def fixup_guard_situation(self):
# hackish: reverse the order of the last two operations if it makes
# sense to avoid a situation like "int_eq/setfield_gc/guard_true",
# which the backend (at least the x86 backend) does not handle well.
newoperations = self.optimizer.newoperations
- if before_guard and len(newoperations) >= 2:
- lastop = newoperations[-1]
- prevop = newoperations[-2]
- # - is_comparison() for cases like "int_eq/setfield_gc/guard_true"
- # - CALL_MAY_FORCE: "call_may_force/setfield_gc/guard_not_forced"
- # - is_ovf(): "int_add_ovf/setfield_gc/guard_no_overflow"
- opnum = prevop.getopnum()
- lastop_args = lastop.getarglist()
- if ((prevop.is_comparison() or opnum == rop.CALL_MAY_FORCE
- or prevop.is_ovf())
- and prevop.result not in lastop_args):
- newoperations[-2] = lastop
- newoperations[-1] = prevop
+ if len(newoperations) < 2:
+ return
+ lastop = newoperations[-1]
+ if (lastop.getopnum() != rop.SETFIELD_GC and
+ lastop.getopnum() != rop.SETARRAYITEM_GC):
+ return
+ # - is_comparison() for cases like "int_eq/setfield_gc/guard_true"
+ # - CALL_MAY_FORCE: "call_may_force/setfield_gc/guard_not_forced"
+ # - is_ovf(): "int_add_ovf/setfield_gc/guard_no_overflow"
+ prevop = newoperations[-2]
+ opnum = prevop.getopnum()
+ if not (prevop.is_comparison() or opnum == rop.CALL_MAY_FORCE
+ or prevop.is_ovf()):
+ return
+ if prevop.result in lastop.getarglist():
+ return
+ newoperations[-2] = lastop
+ newoperations[-1] = prevop
def force_all_lazy_setfields(self):
- if len(self.lazy_setfields_descrs) > 0:
- for descr in self.lazy_setfields_descrs:
- self.force_lazy_setfield(descr)
- del self.lazy_setfields_descrs[:]
+ for cf in self._lazy_setfields:
+ if not we_are_translated():
+ assert cf in self.cached_fields.values()
+ cf.force_lazy_setfield(self)
def force_lazy_setfields_for_guard(self):
pendingfields = []
- for descr in self.lazy_setfields_descrs:
- try:
- op = self.lazy_setfields[descr]
- except KeyError:
+ for cf in self._lazy_setfields:
+ if not we_are_translated():
+ assert cf in self.cached_fields.values()
+ op = cf._lazy_setfield
+ if op is None:
continue
# the only really interesting case that we need to handle in the
# guards' resume data is that of a virtual object that is stored
@@ -266,41 +326,27 @@
fieldvalue = self.getvalue(op.getarg(1))
if fieldvalue.is_virtual():
# this is the case that we leave to resume.py
- pendingfields.append((descr, value.box,
+ pendingfields.append((op.getdescr(), value.box,
fieldvalue.get_key_box()))
else:
- self.force_lazy_setfield(descr, before_guard=True)
+ cf.force_lazy_setfield(self)
+ self.fixup_guard_situation()
return pendingfields
- def force_lazy_setfield_if_necessary(self, op, value, write=False):
- try:
- op1 = self.lazy_setfields[op.getdescr()]
- except KeyError:
- if write:
- self.lazy_setfields_descrs.append(op.getdescr())
- else:
- if self.getvalue(op1.getarg(0)) is not value:
- self.force_lazy_setfield(op.getdescr())
-
def optimize_GETFIELD_GC(self, op):
- value = self.getvalue(op.getarg(0))
- self.force_lazy_setfield_if_necessary(op, value)
- # check if the field was read from another getfield_gc just before
- # or has been written to recently
- fieldvalue = self.read_cached_field(op.getdescr(), value)
+ structvalue = self.getvalue(op.getarg(0))
+ cf = self.field_cache(op.getdescr())
+ fieldvalue = cf.getfield_from_cache(self, structvalue)
if fieldvalue is not None:
self.make_equal_to(op.result, fieldvalue)
return
# default case: produce the operation
- value.ensure_nonnull()
+ structvalue.ensure_nonnull()
###self.optimizer.optimize_default(op)
self.emit_operation(op)
# then remember the result of reading the field
fieldvalue = self.getvalue(op.result)
- self.cache_field_value(op.getdescr(), value, fieldvalue)
- # keep track of what's on the heap
- d = self.known_heap_fields.setdefault(op.getdescr(), {})
- d[value] = fieldvalue
+ cf.remember_field_value(structvalue, fieldvalue)
def optimize_SETFIELD_GC(self, op):
if self.has_pure_result(rop.GETFIELD_GC_PURE, [op.getarg(0)],
@@ -309,14 +355,8 @@
(op.getdescr().repr_of_descr()))
raise BogusPureField
#
- value = self.getvalue(op.getarg(0))
- fieldvalue = self.getvalue(op.getarg(1))
- cached_fieldvalue = self.read_cached_field(op.getdescr(), value)
- if fieldvalue is not cached_fieldvalue:
- self.force_lazy_setfield_if_necessary(op, value, write=True)
- self.lazy_setfields[op.getdescr()] = op
- # remember the result of future reads of the field
- self.cache_field_value(op.getdescr(), value, fieldvalue, write=True)
+ cf = self.field_cache(op.getdescr())
+ cf.do_setfield(self, op)
def optimize_GETARRAYITEM_GC(self, op):
value = self.getvalue(op.getarg(0))
diff --git a/pypy/module/cpyext/funcobject.py b/pypy/module/cpyext/funcobject.py
--- a/pypy/module/cpyext/funcobject.py
+++ b/pypy/module/cpyext/funcobject.py
@@ -14,6 +14,10 @@
(("func_name", PyObject),)
cpython_struct("PyFunctionObject", PyFunctionObjectFields, PyFunctionObjectStruct)
+PyCodeObjectStruct = lltype.ForwardReference()
+PyCodeObject = lltype.Ptr(PyCodeObjectStruct)
+cpython_struct("PyCodeObject", PyObjectFields, PyCodeObjectStruct)
+
@bootstrap_function
def init_functionobject(space):
make_typedescr(Function.typedef,
@@ -65,7 +69,36 @@
assert isinstance(w_method, Method)
return borrow_from(w_method, w_method.w_class)
- at cpython_api([CONST_STRING, CONST_STRING, rffi.INT_real], PyObject)
+def unwrap_list_of_strings(space, w_list):
+ return [space.str_w(w_item) for w_item in space.fixedview(w_list)]
+
+ at cpython_api([rffi.INT_real, rffi.INT_real, rffi.INT_real, rffi.INT_real,
+ PyObject, PyObject, PyObject, PyObject, PyObject, PyObject,
+ PyObject, PyObject, rffi.INT_real, PyObject], PyCodeObject)
+def PyCode_New(space, argcount, nlocals, stacksize, flags,
+ w_code, w_consts, w_names, w_varnames, w_freevars, w_cellvars,
+ w_filename, w_funcname, firstlineno, w_lnotab):
+ """Return a new code object. If you need a dummy code object to
+ create a frame, use PyCode_NewEmpty() instead. Calling
+ PyCode_New() directly can bind you to a precise Python
+ version since the definition of the bytecode changes often."""
+ return space.wrap(PyCode(space,
+ argcount=rffi.cast(lltype.Signed, argcount),
+ nlocals=rffi.cast(lltype.Signed, nlocals),
+ stacksize=rffi.cast(lltype.Signed, stacksize),
+ flags=rffi.cast(lltype.Signed, flags),
+ code=space.str_w(w_code),
+ consts=space.fixedview(w_consts),
+ names=unwrap_list_of_strings(space, w_names),
+ varnames=unwrap_list_of_strings(space, w_varnames),
+ filename=space.str_w(w_filename),
+ name=space.str_w(w_funcname),
+ firstlineno=rffi.cast(lltype.Signed, firstlineno),
+ lnotab=space.str_w(w_lnotab),
+ freevars=unwrap_list_of_strings(space, w_freevars),
+ cellvars=unwrap_list_of_strings(space, w_cellvars)))
+
+ at cpython_api([CONST_STRING, CONST_STRING, rffi.INT_real], PyCodeObject)
def PyCode_NewEmpty(space, filename, funcname, firstlineno):
"""Creates a new empty code object with the specified source location."""
return space.wrap(PyCode(space,
diff --git a/pypy/translator/c/src/dtoa.c b/pypy/translator/c/src/dtoa.c
--- a/pypy/translator/c/src/dtoa.c
+++ b/pypy/translator/c/src/dtoa.c
@@ -116,7 +116,6 @@
/* Begin PYPY hacks */
/* #include "Python.h" */
-#define DOUBLE_IS_LITTLE_ENDIAN_IEEE754
#define HAVE_UINT32_T
#define HAVE_INT32_T
#define HAVE_UINT64_T
diff --git a/pypy/module/imp/interp_imp.py b/pypy/module/imp/interp_imp.py
--- a/pypy/module/imp/interp_imp.py
+++ b/pypy/module/imp/interp_imp.py
@@ -126,8 +126,16 @@
_run_compiled_module(space, w_modulename, filename, w_file, w_mod)
return w_mod
+ at unwrap_spec(filename=str)
+def load_dynamic(space, w_modulename, filename, w_file=None):
+ if not space.config.objspace.usemodules.cpyext:
+ raise OperationError(space.w_ImportError, space.wrap(
+ "Not implemented"))
+ importing.load_c_extension(space, filename, space.str_w(w_modulename))
+ return importing.check_sys_modules(space, w_modulename)
+
def new_module(space, w_name):
- return space.wrap(Module(space, w_name))
+ return space.wrap(Module(space, w_name, add_package=False))
def init_builtin(space, w_name):
name = space.str_w(w_name)
diff --git a/pypy/module/pyexpat/interp_pyexpat.py b/pypy/module/pyexpat/interp_pyexpat.py
--- a/pypy/module/pyexpat/interp_pyexpat.py
+++ b/pypy/module/pyexpat/interp_pyexpat.py
@@ -253,8 +253,10 @@
except OperationError, e:
parser._exc_info = e
XML_StopParser(parser.itself, XML_FALSE)
- return 0
- return 1
+ result = 0
+ else:
+ result = 1
+ return rffi.cast(rffi.INT, result)
callback_type = lltype.Ptr(lltype.FuncType(
[rffi.VOIDP, rffi.CCHARP, XML_Encoding_Ptr], rffi.INT))
XML_SetUnknownEncodingHandler = expat_external(
diff --git a/pypy/rpython/lltypesystem/module/ll_math.py b/pypy/rpython/lltypesystem/module/ll_math.py
--- a/pypy/rpython/lltypesystem/module/ll_math.py
+++ b/pypy/rpython/lltypesystem/module/ll_math.py
@@ -6,7 +6,7 @@
from pypy.rpython.lltypesystem import lltype, rffi
from pypy.tool.sourcetools import func_with_new_name
from pypy.tool.autopath import pypydir
-from pypy.rlib import rposix
+from pypy.rlib import jit, rposix
from pypy.translator.tool.cbuild import ExternalCompilationInfo
from pypy.rlib.rfloat import isinf, isnan, INFINITY, NAN
@@ -20,8 +20,7 @@
separate_module_files=[cdir.join('src', 'll_math.c')],
export_symbols=['_pypy_math_acosh', '_pypy_math_asinh',
'_pypy_math_atanh',
- '_pypy_math_expm1', '_pypy_math_log1p',
- '_pypy_math_isinf', '_pypy_math_isnan'],
+ '_pypy_math_expm1', '_pypy_math_log1p'],
)
math_prefix = '_pypy_math_'
else:
@@ -57,8 +56,6 @@
math_fmod = llexternal('fmod', [rffi.DOUBLE, rffi.DOUBLE], rffi.DOUBLE)
math_hypot = llexternal(underscore + 'hypot',
[rffi.DOUBLE, rffi.DOUBLE], rffi.DOUBLE)
-math_isinf = math_llexternal('isinf', [rffi.DOUBLE], rffi.INT)
-math_isnan = math_llexternal('isnan', [rffi.DOUBLE], rffi.INT)
# ____________________________________________________________
#
@@ -91,13 +88,13 @@
#
# Custom implementations
-
def ll_math_isnan(y):
- return bool(math_isnan(y))
-
+ # By not calling into the extenal function the JIT can inline this. Floats
+ # are awesome.
+ return y != y
def ll_math_isinf(y):
- return bool(math_isinf(y))
+ return y != 0 and y * .5 == y
ll_math_copysign = math_copysign
diff --git a/pypy/module/thread/os_thread.py b/pypy/module/thread/os_thread.py
--- a/pypy/module/thread/os_thread.py
+++ b/pypy/module/thread/os_thread.py
@@ -248,3 +248,8 @@
"""This is synonymous to ``raise SystemExit''. It will cause the current
thread to exit silently unless the exception is caught."""
raise OperationError(space.w_SystemExit, space.w_None)
+
+def interrupt_main(space):
+ """Raise a KeyboardInterrupt in the main thread.
+A subthread can use this function to interrupt the main thread."""
+ space.check_signal_action.set_interrupt()
diff --git a/pypy/module/imp/app_imp.py b/pypy/module/imp/app_imp.py
deleted file mode 100644
--- a/pypy/module/imp/app_imp.py
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-def load_dynamic(name, pathname, file=None):
- """Always raises ah ImportError on pypy"""
- raise ImportError('Not implemented')
diff --git a/pypy/interpreter/gateway.py b/pypy/interpreter/gateway.py
--- a/pypy/interpreter/gateway.py
+++ b/pypy/interpreter/gateway.py
@@ -1126,7 +1126,7 @@
"""
if not isinstance(source, str):
source = py.std.inspect.getsource(source).lstrip()
- while source.startswith('@py.test.mark.'):
+ while source.startswith(('@py.test.mark.', '@pytest.mark.')):
# these decorators are known to return the same function
# object, we may ignore them
assert '\n' in source
diff --git a/pypy/module/cpyext/longobject.py b/pypy/module/cpyext/longobject.py
--- a/pypy/module/cpyext/longobject.py
+++ b/pypy/module/cpyext/longobject.py
@@ -5,6 +5,7 @@
from pypy.interpreter.error import OperationError
from pypy.module.cpyext.intobject import PyInt_AsUnsignedLongMask
from pypy.rlib.rbigint import rbigint
+from pypy.rlib.rarithmetic import intmask
PyLong_Check, PyLong_CheckExact = build_type_checkers("Long")
@@ -178,9 +179,9 @@
assert isinstance(w_long, W_LongObject)
return w_long.num.sign
- at cpython_api([CONST_STRING, rffi.SIZE_T, rffi.INT_real, rffi.INT_real], PyObject)
+UCHARP = rffi.CArrayPtr(rffi.UCHAR)
+ at cpython_api([UCHARP, rffi.SIZE_T, rffi.INT_real, rffi.INT_real], PyObject)
def _PyLong_FromByteArray(space, bytes, n, little_endian, signed):
- s = rffi.charpsize2str(bytes, n)
little_endian = rffi.cast(lltype.Signed, little_endian)
signed = rffi.cast(lltype.Signed, signed)
@@ -189,9 +190,9 @@
for i in range(0, n):
if little_endian:
- c = ord(s[i])
+ c = intmask(bytes[i])
else:
- c = ord(s[n - i - 1])
+ c = intmask(bytes[n - i - 1])
if i == 0 and signed and c & 0x80:
negative = True
if negative:
diff --git a/pypy/jit/tl/tla/test_tla.py b/pypy/jit/tl/tla/test_tla.py
--- a/pypy/jit/tl/tla/test_tla.py
+++ b/pypy/jit/tl/tla/test_tla.py
@@ -155,7 +155,7 @@
# ____________________________________________________________
-from pypy.jit.metainterp.test.test_basic import LLJitMixin
+from pypy.jit.metainterp.test.support import LLJitMixin
class TestLLtype(LLJitMixin):
def test_loop(self):
diff --git a/pypy/interpreter/test/test_extmodules.py b/pypy/interpreter/test/test_extmodules.py
new file mode 100644
--- /dev/null
+++ b/pypy/interpreter/test/test_extmodules.py
@@ -0,0 +1,68 @@
+import sys
+import pytest
+
+from pypy.config.pypyoption import get_pypy_config
+from pypy.objspace.std import StdObjSpace
+from pypy.tool.udir import udir
+
+mod_init = """
+from pypy.interpreter.mixedmodule import MixedModule
+
+import time
+
+class Module(MixedModule):
+
+ appleveldefs = {}
+
+ interpleveldefs = {
+ 'clock' : 'interp_time.clock',
+ 'time' : 'interp_time.time_',
+ 'sleep' : 'interp_time.sleep',
+ }
+"""
+
+mod_interp = """
+import time
+
+from pypy.interpreter.gateway import unwrap_spec
+
+def clock(space):
+ return space.wrap(time.clock())
+
+def time_(space):
+ return space.wrap(time.time())
+
+ at unwrap_spec(seconds=float)
+def sleep(space, seconds):
+ time.sleep(seconds)
+"""
+
+old_sys_path = []
+
+def init_extmodule_code():
+ pkg = udir.join("testext")
+ pkg.ensure(dir=True)
+ pkg.join("__init__.py").write("# package")
+ mod = pkg.join("extmod")
+ mod.ensure(dir=True)
+ mod.join("__init__.py").write(mod_init)
+ mod.join("interp_time.py").write(mod_interp)
+
+class AppTestExtModules(object):
+ def setup_class(cls):
+ init_extmodule_code()
+ conf = get_pypy_config()
+ conf.objspace.extmodules = 'testext.extmod'
+ old_sys_path[:] = sys.path[:]
+ sys.path.insert(0, str(udir))
+ space = StdObjSpace(conf)
+ cls.space = space
+
+ def teardown_class(cls):
+ sys.path[:] = old_sys_path
+
+ @pytest.mark.skipif("config.option.runappdirect")
+ def test_import(self):
+ import extmod
+ assert extmod.__file__.endswith('extmod')
+ assert type(extmod.time()) is float
diff --git a/pypy/tool/jitlogparser/test/test_parser.py b/pypy/tool/jitlogparser/test/test_parser.py
--- a/pypy/tool/jitlogparser/test/test_parser.py
+++ b/pypy/tool/jitlogparser/test/test_parser.py
@@ -114,11 +114,11 @@
fname = str(py.path.local(__file__).join('..', 'x.py'))
ops = parse('''
[i0, i1]
- debug_merge_point("<code object f, file '%(fname)s', line 5> #9 LOAD_FAST", 0)
- debug_merge_point("<code object f, file '%(fname)s', line 5> #12 LOAD_CONST", 0)
- debug_merge_point("<code object f, file '%(fname)s', line 5> #22 LOAD_CONST", 0)
- debug_merge_point("<code object f, file '%(fname)s', line 5> #28 LOAD_CONST", 0)
- debug_merge_point("<code object f, file '%(fname)s', line 5> #6 SETUP_LOOP", 0)
+ debug_merge_point("<code object g, file '%(fname)s', line 5> #9 LOAD_FAST", 0)
+ debug_merge_point("<code object g, file '%(fname)s', line 5> #12 LOAD_CONST", 0)
+ debug_merge_point("<code object g, file '%(fname)s', line 5> #22 LOAD_CONST", 0)
+ debug_merge_point("<code object g, file '%(fname)s', line 5> #28 LOAD_CONST", 0)
+ debug_merge_point("<code object g, file '%(fname)s', line 5> #6 SETUP_LOOP", 0)
''' % locals())
res = Function.from_operations(ops.operations, LoopStorage())
assert res.linerange == (7, 9)
diff --git a/pypy/tool/pytest/appsupport.py b/pypy/tool/pytest/appsupport.py
--- a/pypy/tool/pytest/appsupport.py
+++ b/pypy/tool/pytest/appsupport.py
@@ -196,7 +196,7 @@
class _ExceptionInfo(object):
def __init__(self):
import sys
- self.type, self.value, _ = sys.exc_info()
+ self.type, self.value, self.traceback = sys.exc_info()
return _ExceptionInfo
""")
diff --git a/pypy/module/cpyext/frameobject.py b/pypy/module/cpyext/frameobject.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cpyext/frameobject.py
@@ -0,0 +1,82 @@
+from pypy.rpython.lltypesystem import rffi, lltype
+from pypy.module.cpyext.api import (
+ cpython_api, bootstrap_function, PyObjectFields, cpython_struct)
+from pypy.module.cpyext.pyobject import (
+ PyObject, Py_DecRef, make_ref, from_ref, track_reference,
+ make_typedescr, get_typedescr)
+from pypy.module.cpyext.state import State
+from pypy.module.cpyext.pystate import PyThreadState
+from pypy.module.cpyext.funcobject import PyCodeObject
+from pypy.interpreter.pyframe import PyFrame
+from pypy.interpreter.pycode import PyCode
+
+PyFrameObjectStruct = lltype.ForwardReference()
+PyFrameObject = lltype.Ptr(PyFrameObjectStruct)
+PyFrameObjectFields = (PyObjectFields +
+ (("f_code", PyCodeObject),
+ ("f_globals", PyObject),
+ ("f_lineno", rffi.INT),
+ ))
+cpython_struct("PyFrameObject", PyFrameObjectFields, PyFrameObjectStruct)
+
+ at bootstrap_function
+def init_frameobject(space):
+ make_typedescr(PyFrame.typedef,
+ basestruct=PyFrameObject.TO,
+ attach=frame_attach,
+ dealloc=frame_dealloc,
+ realize=frame_realize)
+
+def frame_attach(space, py_obj, w_obj):
+ "Fills a newly allocated PyFrameObject with a frame object"
+ frame = space.interp_w(PyFrame, w_obj)
+ py_frame = rffi.cast(PyFrameObject, py_obj)
+ py_frame.c_f_code = rffi.cast(PyCodeObject, make_ref(space, frame.pycode))
+ py_frame.c_f_globals = make_ref(space, frame.w_globals)
+ rffi.setintfield(py_frame, 'c_f_lineno', frame.f_lineno)
+
+ at cpython_api([PyObject], lltype.Void, external=False)
+def frame_dealloc(space, py_obj):
+ py_frame = rffi.cast(PyFrameObject, py_obj)
+ py_code = rffi.cast(PyObject, py_frame.c_f_code)
+ Py_DecRef(space, py_code)
+ Py_DecRef(space, py_frame.c_f_globals)
+ from pypy.module.cpyext.object import PyObject_dealloc
+ PyObject_dealloc(space, py_obj)
+
+def frame_realize(space, py_obj):
+ """
+ Creates the frame in the interpreter. The PyFrameObject structure must not
+ be modified after this call.
+ """
+ py_frame = rffi.cast(PyFrameObject, py_obj)
+ py_code = rffi.cast(PyObject, py_frame.c_f_code)
+ w_code = from_ref(space, py_code)
+ code = space.interp_w(PyCode, w_code)
+ w_globals = from_ref(space, py_frame.c_f_globals)
+
+ frame = PyFrame(space, code, w_globals, closure=None)
+ frame.f_lineno = py_frame.c_f_lineno
+ w_obj = space.wrap(frame)
+ track_reference(space, py_obj, w_obj)
+ return w_obj
+
+ at cpython_api([PyThreadState, PyCodeObject, PyObject, PyObject], PyFrameObject)
+def PyFrame_New(space, tstate, w_code, w_globals, w_locals):
+ typedescr = get_typedescr(PyFrame.typedef)
+ py_obj = typedescr.allocate(space, space.gettypeobject(PyFrame.typedef))
+ py_frame = rffi.cast(PyFrameObject, py_obj)
+ space.interp_w(PyCode, w_code) # sanity check
+ py_frame.c_f_code = rffi.cast(PyCodeObject, make_ref(space, w_code))
+ py_frame.c_f_globals = make_ref(space, w_globals)
+ return py_frame
+
+ at cpython_api([PyFrameObject], rffi.INT_real, error=-1)
+def PyTraceBack_Here(space, w_frame):
+ from pypy.interpreter.pytraceback import record_application_traceback
+ state = space.fromcache(State)
+ if state.operror is None:
+ return -1
+ frame = space.interp_w(PyFrame, w_frame)
+ record_application_traceback(space, state.operror, frame, 0)
+ return 0
diff --git a/pypy/jit/backend/x86/runner.py b/pypy/jit/backend/x86/runner.py
--- a/pypy/jit/backend/x86/runner.py
+++ b/pypy/jit/backend/x86/runner.py
@@ -19,6 +19,8 @@
def __init__(self, rtyper, stats, opts=None, translate_support_code=False,
gcdescr=None):
+ if gcdescr is not None:
+ gcdescr.force_index_ofs = FORCE_INDEX_OFS
AbstractLLCPU.__init__(self, rtyper, stats, opts,
translate_support_code, gcdescr)
@@ -127,7 +129,7 @@
fail_index = rffi.cast(TP, addr_of_force_index)[0]
assert fail_index >= 0, "already forced!"
faildescr = self.get_fail_descr_from_number(fail_index)
- rffi.cast(TP, addr_of_force_index)[0] = -1
+ rffi.cast(TP, addr_of_force_index)[0] = ~fail_index
frb = self.assembler._find_failure_recovery_bytecode(faildescr)
bytecode = rffi.cast(rffi.UCHARP, frb)
# start of "no gc operation!" block
@@ -147,7 +149,6 @@
WORD = 4
NUM_REGS = 8
CALLEE_SAVE_REGISTERS = [regloc.ebx, regloc.esi, regloc.edi]
- FRAME_FIXED_SIZE = len(CALLEE_SAVE_REGISTERS) + 2
supports_longlong = True
@@ -163,7 +164,6 @@
WORD = 8
NUM_REGS = 16
CALLEE_SAVE_REGISTERS = [regloc.ebx, regloc.r12, regloc.r13, regloc.r14, regloc.r15]
- FRAME_FIXED_SIZE = len(CALLEE_SAVE_REGISTERS) + 2
def __init__(self, *args, **kwargs):
assert sys.maxint == (2**63 - 1)
diff --git a/pypy/jit/metainterp/test/test_compile.py b/pypy/jit/metainterp/test/test_compile.py
--- a/pypy/jit/metainterp/test/test_compile.py
+++ b/pypy/jit/metainterp/test/test_compile.py
@@ -86,6 +86,8 @@
metainterp.history = History()
metainterp.history.operations = loop.operations[:]
metainterp.history.inputargs = loop.inputargs[:]
+ cpu._all_size_descrs_with_vtable = (
+ LLtypeMixin.cpu._all_size_descrs_with_vtable)
#
loop_tokens = []
loop_token = compile_new_loop(metainterp, loop_tokens, [], 0, None)
diff --git a/pypy/jit/metainterp/test/test_recursive.py b/pypy/jit/metainterp/test/test_recursive.py
--- a/pypy/jit/metainterp/test/test_recursive.py
+++ b/pypy/jit/metainterp/test/test_recursive.py
@@ -3,7 +3,7 @@
from pypy.rlib.jit import unroll_safe, dont_look_inside
from pypy.rlib.objectmodel import we_are_translated
from pypy.rlib.debug import fatalerror
-from pypy.jit.metainterp.test.test_basic import LLJitMixin, OOJitMixin
+from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin
from pypy.jit.codewriter.policy import StopAtXPolicy
from pypy.rpython.annlowlevel import hlstr
from pypy.jit.metainterp.warmspot import get_stats
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
@@ -490,7 +490,9 @@
# ^^^ returns an address of nursery free pointer, for later modifications
'gc_adr_of_nursery_top' : LLOp(),
# ^^^ returns an address of pointer, since it can change at runtime
-
+ 'gc_adr_of_root_stack_top': LLOp(),
+ # ^^^ returns the address of gcdata.root_stack_top (for shadowstack only)
+
# experimental operations in support of thread cloning, only
# implemented by the Mark&Sweep GC
'gc_x_swap_pool': LLOp(canraise=(MemoryError,), canunwindgc=True),
diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py
--- a/pypy/interpreter/baseobjspace.py
+++ b/pypy/interpreter/baseobjspace.py
@@ -365,7 +365,11 @@
def setbuiltinmodule(self, importname):
"""NOT_RPYTHON. load a lazy pypy/module and put it into sys.modules"""
- fullname = "pypy.module.%s" % importname
+ if '.' in importname:
+ fullname = importname
+ importname = fullname.rsplit('.', 1)[1]
+ else:
+ fullname = "pypy.module.%s" % importname
Module = __import__(fullname,
None, None, ["Module"]).Module
@@ -428,6 +432,11 @@
if value and name not in modules:
modules.append(name)
+ if self.config.objspace.extmodules:
+ for name in self.config.objspace.extmodules.split(','):
+ if name not in modules:
+ modules.append(name)
+
# a bit of custom logic: time2 or 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:
@@ -745,7 +754,12 @@
"""Unpack an iterable object into a real (interpreter-level) list.
Raise an OperationError(w_ValueError) if the length is wrong."""
w_iterator = self.iter(w_iterable)
- items = []
+ # If we know the expected length we can preallocate.
+ if expected_length == -1:
+ items = []
+ else:
+ items = [None] * expected_length
+ idx = 0
while True:
try:
w_item = self.next(w_iterator)
@@ -753,19 +767,22 @@
if not e.match(self, self.w_StopIteration):
raise
break # done
- if expected_length != -1 and len(items) == expected_length:
+ if expected_length != -1 and idx == expected_length:
raise OperationError(self.w_ValueError,
self.wrap("too many values to unpack"))
- items.append(w_item)
- if expected_length != -1 and len(items) < expected_length:
- i = len(items)
- if i == 1:
+ if expected_length == -1:
+ items.append(w_item)
+ else:
+ items[idx] = w_item
+ idx += 1
+ if expected_length != -1 and idx < expected_length:
+ if idx == 1:
plural = ""
else:
plural = "s"
raise OperationError(self.w_ValueError,
self.wrap("need more than %d value%s to unpack" %
- (i, plural)))
+ (idx, plural)))
return items
unpackiterable_unroll = jit.unroll_safe(func_with_new_name(unpackiterable,
@@ -1333,6 +1350,11 @@
pass
def _freeze_(self):
return True
+ def __enter__(self):
+ pass
+ def __exit__(self, *args):
+ pass
+
dummy_lock = DummyLock()
## Table describing the regular part of the interface of object spaces,
diff --git a/pypy/translator/cli/ilgenerator.py b/pypy/translator/cli/ilgenerator.py
--- a/pypy/translator/cli/ilgenerator.py
+++ b/pypy/translator/cli/ilgenerator.py
@@ -443,8 +443,8 @@
self.ilasm.opcode('newarr', clitype.itemtype.typename())
def _array_suffix(self, ARRAY, erase_unsigned=False):
- from pypy.translator.cli.metavm import OOTYPE_TO_MNEMONIC
- suffix = OOTYPE_TO_MNEMONIC.get(ARRAY.ITEM, 'ref')
+ from pypy.translator.cli.metavm import ootype_to_mnemonic
+ suffix = ootype_to_mnemonic(ARRAY.ITEM, ARRAY.ITEM, 'ref')
if erase_unsigned:
suffix = suffix.replace('u', 'i')
return suffix
diff --git a/pypy/module/cpyext/include/code.h b/pypy/module/cpyext/include/code.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/cpyext/include/code.h
@@ -0,0 +1,12 @@
+#ifndef Py_CODE_H
+#define Py_CODE_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef PyObject PyCodeObject;
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* !Py_CODE_H */
diff --git a/pypy/translator/backendopt/ssa.py b/pypy/translator/backendopt/ssa.py
--- a/pypy/translator/backendopt/ssa.py
+++ b/pypy/translator/backendopt/ssa.py
@@ -1,4 +1,4 @@
-from pypy.objspace.flow.model import Variable, mkentrymap, flatten, Block
+from pypy.objspace.flow.model import Variable, mkentrymap, Block
from pypy.tool.algo.unionfind import UnionFind
class DataFlowFamilyBuilder:
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
@@ -211,8 +211,11 @@
def ll_stringslice_minusone(s):
return s.ll_substring(0, s.ll_strlen()-1)
- def ll_split_chr(RESULT, s, c):
- return RESULT.ll_convert_from_array(s.ll_split_chr(c))
+ def ll_split_chr(RESULT, s, c, max):
+ return RESULT.ll_convert_from_array(s.ll_split_chr(c, max))
+
+ def ll_rsplit_chr(RESULT, s, c, max):
+ return RESULT.ll_convert_from_array(s.ll_rsplit_chr(c, max))
def ll_int(s, base):
if not 2 <= base <= 36:
diff --git a/lib_pypy/pyrepl/reader.py b/lib_pypy/pyrepl/reader.py
--- a/lib_pypy/pyrepl/reader.py
+++ b/lib_pypy/pyrepl/reader.py
@@ -274,8 +274,12 @@
screeninfo.append((0, []))
self.lxy = p, ln
prompt = self.get_prompt(ln, ll >= p >= 0)
+ while '\n' in prompt:
+ pre_prompt, _, prompt = prompt.partition('\n')
+ screen.append(pre_prompt)
+ screeninfo.append((0, []))
p -= ll + 1
- lp = len(prompt)
+ prompt, lp = self.process_prompt(prompt)
l, l2 = disp_str(line)
wrapcount = (len(l) + lp) / w
if wrapcount == 0:
@@ -297,6 +301,31 @@
screeninfo.append((0, []))
return screen
+ def process_prompt(self, prompt):
+ """ Process the prompt.
+
+ This means calculate the length of the prompt. The character \x01
+ and \x02 are used to bracket ANSI control sequences and need to be
+ excluded from the length calculation. So also a copy of the prompt
+ is returned with these control characters removed. """
+
+ out_prompt = ''
+ l = len(prompt)
+ pos = 0
+ while True:
+ s = prompt.find('\x01', pos)
+ if s == -1:
+ break
+ e = prompt.find('\x02', s)
+ if e == -1:
+ break
+ # Found start and end brackets, subtract from string length
+ l = l - (e-s+1)
+ out_prompt += prompt[pos:s] + prompt[s+1:e]
+ pos = e+1
+ out_prompt += prompt[pos:]
+ return out_prompt, l
+
def bow(self, p=None):
"""Return the 0-based index of the word break preceding p most
immediately.
diff --git a/pypy/translator/unsimplify.py b/pypy/translator/unsimplify.py
--- a/pypy/translator/unsimplify.py
+++ b/pypy/translator/unsimplify.py
@@ -54,8 +54,7 @@
def split_block(annotator, block, index, _forcelink=None):
"""return a link where prevblock is the block leading up but excluding the
index'th operation and target is a new block with the neccessary variables
- passed on. NOTE: if you call this after rtyping, you WILL need to worry
- about keepalives, you may use backendopt.support.split_block_with_keepalive.
+ passed on.
"""
assert 0 <= index <= len(block.operations)
if block.exitswitch == c_last_exception:
@@ -115,46 +114,6 @@
# in the second block!
return split_block(annotator, block, 0, _forcelink=block.inputargs)
-def remove_direct_loops(annotator, graph):
- """This is useful for code generators: it ensures that no link has
- common input and output variables, which could occur if a block's exit
- points back directly to the same block. It allows code generators to be
- simpler because they don't have to worry about overwriting input
- variables when generating a sequence of assignments."""
- def visit(link):
- if isinstance(link, Link) and link.prevblock is link.target:
- insert_empty_block(annotator, link)
- traverse(visit, graph)
-
-def remove_double_links(annotator, graph):
- """This can be useful for code generators: it ensures that no block has
- more than one incoming links from one and the same other block. It allows
- argument passing along links to be implemented with phi nodes since the
- value of an argument can be determined by looking from which block the
- control passed. """
- def visit(block):
- if isinstance(block, Block):
- double_links = []
- seen = {}
- for link in block.exits:
- if link.target in seen:
- double_links.append(link)
- seen[link.target] = True
- for link in double_links:
- insert_empty_block(annotator, link)
- traverse(visit, graph)
-
-def no_links_to_startblock(graph):
- """Ensure no links to start block."""
- links_to_start_block = False
- for block in graph.iterblocks():
- for link in block.exits:
- if link.target == graph.startblock:
- links_to_start_block = True
- break
- if links_to_start_block:
- insert_empty_startblock(None, graph)
-
def call_initial_function(translator, initial_func, annhelper=None):
"""Before the program starts, call 'initial_func()'."""
from pypy.annotation import model as annmodel
diff --git a/pypy/module/cpyext/test/test_unicodeobject.py b/pypy/module/cpyext/test/test_unicodeobject.py
--- a/pypy/module/cpyext/test/test_unicodeobject.py
+++ b/pypy/module/cpyext/test/test_unicodeobject.py
@@ -1,9 +1,81 @@
# encoding: iso-8859-15
from pypy.module.cpyext.test.test_api import BaseApiTest
-from pypy.module.cpyext.unicodeobject import Py_UNICODE
+from pypy.module.cpyext.test.test_cpyext import AppTestCpythonExtensionBase
+from pypy.module.cpyext.unicodeobject import (
+ Py_UNICODE, PyUnicodeObject, new_empty_unicode)
+from pypy.module.cpyext.api import PyObjectP, PyObject
+from pypy.module.cpyext.pyobject import Py_DecRef
from pypy.rpython.lltypesystem import rffi, lltype
import sys, py
+class AppTestUnicodeObject(AppTestCpythonExtensionBase):
+ def test_unicodeobject(self):
+ module = self.import_extension('foo', [
+ ("get_hello1", "METH_NOARGS",
+ """
+ return PyUnicode_FromStringAndSize(
+ "Hello world<should not be included>", 11);
+ """),
+ ("test_GetSize", "METH_NOARGS",
+ """
+ PyObject* s = PyUnicode_FromString("Hello world");
+ int result = 0;
+
+ if(PyUnicode_GetSize(s) == 11) {
+ result = 1;
+ }
+ if(s->ob_type->tp_basicsize != sizeof(void*)*4)
+ result = 0;
+ Py_DECREF(s);
+ return PyBool_FromLong(result);
+ """),
+ ("test_GetSize_exception", "METH_NOARGS",
+ """
+ PyObject* f = PyFloat_FromDouble(1.0);
+ Py_ssize_t size = PyUnicode_GetSize(f);
+
+ Py_DECREF(f);
+ return NULL;
+ """),
+ ("test_is_unicode", "METH_VARARGS",
+ """
+ return PyBool_FromLong(PyUnicode_Check(PyTuple_GetItem(args, 0)));
+ """)])
+ assert module.get_hello1() == u'Hello world'
+ assert module.test_GetSize()
+ raises(TypeError, module.test_GetSize_exception)
+
+ assert module.test_is_unicode(u"")
+ assert not module.test_is_unicode(())
+
+ def test_unicode_buffer_init(self):
+ module = self.import_extension('foo', [
+ ("getunicode", "METH_NOARGS",
+ """
+ PyObject *s, *t;
+ Py_UNICODE* c;
+ Py_ssize_t len;
+
+ s = PyUnicode_FromUnicode(NULL, 4);
+ if (s == NULL)
+ return NULL;
+ t = PyUnicode_FromUnicode(NULL, 3);
+ if (t == NULL)
+ return NULL;
+ Py_DECREF(t);
+ c = PyUnicode_AsUnicode(s);
+ c[0] = 'a';
+ c[1] = 0xe9;
+ c[3] = 'c';
+ return s;
+ """),
+ ])
+ s = module.getunicode()
+ assert len(s) == 4
+ assert s == u'a�\x00c'
+
+
+
class TestUnicode(BaseApiTest):
def test_unicodeobject(self, space, api):
assert api.PyUnicode_GET_SIZE(space.wrap(u'sp�m')) == 4
@@ -77,6 +149,28 @@
assert space.unwrap(w_res) == u'sp�'
rffi.free_charp(s)
+ def test_unicode_resize(self, space, api):
+ py_uni = new_empty_unicode(space, 10)
+ ar = lltype.malloc(PyObjectP.TO, 1, flavor='raw')
+ py_uni.c_buffer[0] = u'a'
+ py_uni.c_buffer[1] = u'b'
+ py_uni.c_buffer[2] = u'c'
+ ar[0] = rffi.cast(PyObject, py_uni)
+ api.PyUnicode_Resize(ar, 3)
+ py_uni = rffi.cast(PyUnicodeObject, ar[0])
+ assert py_uni.c_size == 3
+ assert py_uni.c_buffer[1] == u'b'
+ assert py_uni.c_buffer[3] == u'\x00'
+ # the same for growing
+ ar[0] = rffi.cast(PyObject, py_uni)
+ api.PyUnicode_Resize(ar, 10)
+ py_uni = rffi.cast(PyUnicodeObject, ar[0])
+ assert py_uni.c_size == 10
+ assert py_uni.c_buffer[1] == 'b'
+ assert py_uni.c_buffer[10] == '\x00'
+ Py_DecRef(space, ar[0])
+ lltype.free(ar, flavor='raw')
+
def test_AsUTF8String(self, space, api):
w_u = space.wrap(u'sp�m')
w_res = api.PyUnicode_AsUTF8String(w_u)
@@ -235,13 +329,13 @@
x_chunk = api.PyUnicode_AS_UNICODE(w_x)
api.Py_UNICODE_COPY(target_chunk, x_chunk, 4)
- w_y = api.PyUnicode_FromUnicode(target_chunk, 4)
+ w_y = space.wrap(rffi.wcharpsize2unicode(target_chunk, 4))
assert space.eq_w(w_y, space.wrap(u"abcd"))
size = api.PyUnicode_GET_SIZE(w_x)
api.Py_UNICODE_COPY(target_chunk, x_chunk, size)
- w_y = api.PyUnicode_FromUnicode(target_chunk, size)
+ w_y = space.wrap(rffi.wcharpsize2unicode(target_chunk, size))
assert space.eq_w(w_y, w_x)
diff --git a/pypy/objspace/std/listobject.py b/pypy/objspace/std/listobject.py
--- a/pypy/objspace/std/listobject.py
+++ b/pypy/objspace/std/listobject.py
@@ -36,29 +36,35 @@
init_defaults = Defaults([None])
def init__List(space, w_list, __args__):
+ from pypy.objspace.std.tupleobject import W_TupleObject
# this is on the silly side
w_iterable, = __args__.parse_obj(
None, 'list', init_signature, init_defaults)
- #
- # this is the old version of the loop at the end of this function:
- #
- # w_list.wrappeditems = space.unpackiterable(w_iterable)
- #
- # This is commented out to avoid assigning a new RPython list to
- # 'wrappeditems', which defeats the W_FastSeqIterObject optimization.
- #
items_w = w_list.wrappeditems
del items_w[:]
if w_iterable is not None:
- w_iterator = space.iter(w_iterable)
- while True:
- try:
- w_item = space.next(w_iterator)
- except OperationError, e:
- if not e.match(space, space.w_StopIteration):
- raise
- break # done
- items_w.append(w_item)
+ # unfortunately this is duplicating space.unpackiterable to avoid
+ # assigning a new RPython list to 'wrappeditems', which defeats the
+ # W_FastSeqIterObject optimization.
+ if isinstance(w_iterable, W_ListObject):
+ items_w.extend(w_iterable.wrappeditems)
+ elif isinstance(w_iterable, W_TupleObject):
+ items_w.extend(w_iterable.wrappeditems)
+ else:
+ _init_from_iterable(space, items_w, w_iterable)
+
+def _init_from_iterable(space, items_w, w_iterable):
+ # in its own function to make the JIT look into init__List
+ # XXX this would need a JIT driver somehow?
+ w_iterator = space.iter(w_iterable)
+ while True:
+ try:
+ w_item = space.next(w_iterator)
+ except OperationError, e:
+ if not e.match(space, space.w_StopIteration):
+ raise
+ break # done
+ items_w.append(w_item)
def len__List(space, w_list):
result = len(w_list.wrappeditems)
diff --git a/pypy/module/cpyext/include/compile.h b/pypy/module/cpyext/include/compile.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/cpyext/include/compile.h
@@ -0,0 +1,13 @@
+#ifndef Py_COMPILE_H
+#define Py_COMPILE_H
+
+#include "code.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* !Py_COMPILE_H */
diff --git a/pypy/jit/metainterp/test/test_warmspot.py b/pypy/jit/metainterp/test/test_warmspot.py
--- a/pypy/jit/metainterp/test/test_warmspot.py
+++ b/pypy/jit/metainterp/test/test_warmspot.py
@@ -6,7 +6,7 @@
from pypy.jit.backend.llgraph import runner
from pypy.jit.metainterp.history import BoxInt
-from pypy.jit.metainterp.test.test_basic import LLJitMixin, OOJitMixin
+from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin
from pypy.jit.metainterp.optimizeopt import ALL_OPTS_NAMES
diff --git a/pypy/doc/conf.py b/pypy/doc/conf.py
--- a/pypy/doc/conf.py
+++ b/pypy/doc/conf.py
@@ -45,9 +45,9 @@
# built documents.
#
# The short X.Y version.
-version = '1.4.1'
+version = '1.5'
# The full version, including alpha/beta/rc tags.
-release = '1.4.1'
+release = '1.5-alpha'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
diff --git a/pypy/translator/backendopt/test/test_ssa.py b/pypy/translator/backendopt/test/test_ssa.py
--- a/pypy/translator/backendopt/test/test_ssa.py
+++ b/pypy/translator/backendopt/test/test_ssa.py
@@ -1,6 +1,6 @@
from pypy.translator.backendopt.ssa import *
from pypy.translator.translator import TranslationContext
-from pypy.objspace.flow.model import flatten, Block, Link, Variable, Constant
+from pypy.objspace.flow.model import Block, Link, Variable, Constant
from pypy.objspace.flow.model import SpaceOperation
diff --git a/pypy/module/cpyext/test/test_api.py b/pypy/module/cpyext/test/test_api.py
--- a/pypy/module/cpyext/test/test_api.py
+++ b/pypy/module/cpyext/test/test_api.py
@@ -61,6 +61,12 @@
except OperationError, e:
print e.errorstr(self.space)
raise
+
+ try:
+ del self.space.getexecutioncontext().cpyext_threadstate
+ except AttributeError:
+ pass
+
if self.check_and_print_leaks():
assert False, "Test leaks or loses object(s)."
diff --git a/pypy/jit/backend/model.py b/pypy/jit/backend/model.py
--- a/pypy/jit/backend/model.py
+++ b/pypy/jit/backend/model.py
@@ -23,18 +23,22 @@
self.fail_descr_list = []
self.fail_descr_free_list = []
+ def reserve_some_free_fail_descr_number(self):
+ lst = self.fail_descr_list
+ if len(self.fail_descr_free_list) > 0:
+ n = self.fail_descr_free_list.pop()
+ assert lst[n] is None
+ else:
+ n = len(lst)
+ lst.append(None)
+ return n
+
def get_fail_descr_number(self, descr):
assert isinstance(descr, history.AbstractFailDescr)
n = descr.index
if n < 0:
- lst = self.fail_descr_list
- if len(self.fail_descr_free_list) > 0:
- n = self.fail_descr_free_list.pop()
- assert lst[n] is None
- lst[n] = descr
- else:
- n = len(lst)
- lst.append(descr)
+ n = self.reserve_some_free_fail_descr_number()
+ self.fail_descr_list[n] = descr
descr.index = n
return n
@@ -294,6 +298,13 @@
def record_faildescr_index(self, n):
self.faildescr_indices.append(n)
+ def reserve_and_record_some_faildescr_index(self):
+ # like record_faildescr_index(), but invent and return a new,
+ # unused faildescr index
+ n = self.cpu.reserve_some_free_fail_descr_number()
+ self.record_faildescr_index(n)
+ return n
+
def compiling_a_bridge(self):
self.cpu.total_compiled_bridges += 1
self.bridges_count += 1
diff --git a/pypy/translator/backendopt/inline.py b/pypy/translator/backendopt/inline.py
--- a/pypy/translator/backendopt/inline.py
+++ b/pypy/translator/backendopt/inline.py
@@ -5,7 +5,7 @@
from pypy.objspace.flow.model import Variable, Constant, Block, Link
from pypy.objspace.flow.model import SpaceOperation, c_last_exception
from pypy.objspace.flow.model import FunctionGraph
-from pypy.objspace.flow.model import traverse, mkentrymap, checkgraph
+from pypy.objspace.flow.model import mkentrymap, checkgraph
from pypy.annotation import model as annmodel
from pypy.rpython.lltypesystem.lltype import Bool, Signed, typeOf, Void, Ptr
from pypy.rpython.lltypesystem.lltype import normalizeptr
@@ -13,7 +13,7 @@
from pypy.rpython import rmodel
from pypy.tool.algo import sparsemat
from pypy.translator.backendopt import removenoops
-from pypy.translator.backendopt.support import log, split_block_with_keepalive
+from pypy.translator.backendopt.support import log
from pypy.translator.unsimplify import split_block
from pypy.translator.backendopt.support import find_backedges, find_loop_blocks
from pypy.translator.backendopt.canraise import RaiseAnalyzer
@@ -280,13 +280,6 @@
self.varmap[var] = copyvar(None, var)
return self.varmap[var]
- def generate_keepalive(self, *args):
- from pypy.translator.backendopt.support import generate_keepalive
- if self.translator.rtyper.type_system.name == 'lltypesystem':
- return generate_keepalive(*args)
- else:
- return []
-
def passon_vars(self, cache_key):
if cache_key in self._passon_vars:
return self._passon_vars[cache_key]
@@ -397,7 +390,6 @@
for exceptionlink in afterblock.exits[1:]:
if exc_match(vtable, exceptionlink.llexitcase):
passon_vars = self.passon_vars(link.prevblock)
- copiedblock.operations += self.generate_keepalive(passon_vars)
copiedlink.target = exceptionlink.target
linkargs = self.find_args_in_exceptional_case(
exceptionlink, link.prevblock, var_etype, var_evalue, afterblock, passon_vars)
@@ -445,7 +437,6 @@
del blocks[-1].exits[0].llexitcase
linkargs = copiedexceptblock.inputargs
copiedexceptblock.recloseblock(Link(linkargs, blocks[0]))
- copiedexceptblock.operations += self.generate_keepalive(linkargs)
def do_inline(self, block, index_operation):
splitlink = split_block(None, block, index_operation)
@@ -457,11 +448,8 @@
# this copy is created with the method passon_vars
self.original_passon_vars = [arg for arg in block.exits[0].args
if isinstance(arg, Variable)]
- n = 0
- while afterblock.operations[n].opname == 'keepalive':
- n += 1
- assert afterblock.operations[n].opname == self.op.opname
- self.op = afterblock.operations.pop(n)
+ assert afterblock.operations[0].opname == self.op.opname
+ self.op = afterblock.operations.pop(0)
#vars that need to be passed through the blocks of the inlined function
linktoinlined = splitlink
copiedstartblock = self.copy_block(self.graph_to_inline.startblock)
@@ -551,7 +539,6 @@
OP_WEIGHTS = {'same_as': 0,
'cast_pointer': 0,
- 'keepalive': 0,
'malloc': 2,
'yield_current_frame_to_caller': sys.maxint, # XXX bit extreme
'resume_point': sys.maxint, # XXX bit extreme
@@ -784,5 +771,4 @@
call_count_pred=call_count_pred)
log.inlining('inlined %d callsites.'% (count,))
for graph in graphs:
- removenoops.remove_superfluous_keep_alive(graph)
removenoops.remove_duplicate_casts(graph, translator)
diff --git a/pypy/module/cpyext/test/test_import.py b/pypy/module/cpyext/test/test_import.py
--- a/pypy/module/cpyext/test/test_import.py
+++ b/pypy/module/cpyext/test/test_import.py
@@ -1,5 +1,6 @@
from pypy.module.cpyext.test.test_api import BaseApiTest
from pypy.module.cpyext.test.test_cpyext import AppTestCpythonExtensionBase
+from pypy.rpython.lltypesystem import rffi, lltype
class TestImport(BaseApiTest):
def test_import(self, space, api):
@@ -7,6 +8,22 @@
assert pdb
assert space.getattr(pdb, space.wrap("pm"))
+ def test_addmodule(self, space, api):
+ with rffi.scoped_str2charp("sys") as modname:
+ w_sys = api.PyImport_AddModule(modname)
+ assert w_sys is space.sys
+
+ with rffi.scoped_str2charp("foobar") as modname:
+ w_foobar = api.PyImport_AddModule(modname)
+ assert space.str_w(space.getattr(w_foobar,
+ space.wrap('__name__'))) == 'foobar'
+
+ def test_reload(self, space, api):
+ pdb = api.PyImport_Import(space.wrap("pdb"))
+ space.delattr(pdb, space.wrap("set_trace"))
+ pdb = api.PyImport_ReloadModule(pdb)
+ assert space.getattr(pdb, space.wrap("set_trace"))
+
class AppTestImportLogic(AppTestCpythonExtensionBase):
def test_import_logic(self):
skip("leak?")
diff --git a/pypy/module/cpyext/test/test_frameobject.py b/pypy/module/cpyext/test/test_frameobject.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cpyext/test/test_frameobject.py
@@ -0,0 +1,66 @@
+from pypy.module.cpyext.test.test_cpyext import AppTestCpythonExtensionBase
+
+class AppTestFrameObject(AppTestCpythonExtensionBase):
+
+ def test_forge_frame(self):
+ module = self.import_extension('foo', [
+ ("raise_exception", "METH_NOARGS",
+ """
+ PyObject *py_srcfile = PyString_FromString("filename");
+ PyObject *py_funcname = PyString_FromString("funcname");
+ PyObject *py_globals = PyDict_New();
+ PyObject *empty_string = PyString_FromString("");
+ PyObject *empty_tuple = PyTuple_New(0);
+ PyCodeObject *py_code;
+ PyFrameObject *py_frame;
+
+ py_code = PyCode_New(
+ 0, /*int argcount,*/
+ #if PY_MAJOR_VERSION >= 3
+ 0, /*int kwonlyargcount,*/
+ #endif
+ 0, /*int nlocals,*/
+ 0, /*int stacksize,*/
+ 0, /*int flags,*/
+ empty_string, /*PyObject *code,*/
+ empty_tuple, /*PyObject *consts,*/
+ empty_tuple, /*PyObject *names,*/
+ empty_tuple, /*PyObject *varnames,*/
+ empty_tuple, /*PyObject *freevars,*/
+ empty_tuple, /*PyObject *cellvars,*/
+ py_srcfile, /*PyObject *filename,*/
+ py_funcname, /*PyObject *name,*/
+ 42, /*int firstlineno,*/
+ empty_string /*PyObject *lnotab*/
+ );
+
+ if (!py_code) goto bad;
+ py_frame = PyFrame_New(
+ PyThreadState_Get(), /*PyThreadState *tstate,*/
+ py_code, /*PyCodeObject *code,*/
+ py_globals, /*PyObject *globals,*/
+ 0 /*PyObject *locals*/
+ );
+ if (!py_frame) goto bad;
+ py_frame->f_lineno = 48; /* Does not work with CPython */
+ PyErr_SetString(PyExc_ValueError, "error message");
+ PyTraceBack_Here(py_frame);
+ bad:
+ Py_XDECREF(py_srcfile);
+ Py_XDECREF(py_funcname);
+ Py_XDECREF(empty_string);
+ Py_XDECREF(empty_tuple);
+ Py_XDECREF(py_globals);
+ Py_XDECREF(py_code);
+ Py_XDECREF(py_frame);
+ return NULL;
+ """),
+ ])
+ exc = raises(ValueError, module.raise_exception)
+ frame = exc.traceback.tb_frame
+ assert frame.f_code.co_filename == "filename"
+ assert frame.f_code.co_name == "funcname"
+
+ # Cython does not work on CPython as well...
+ assert exc.traceback.tb_lineno == 42 # should be 48
+ assert frame.f_lineno == 42
diff --git a/pypy/module/cpyext/slotdefs.py b/pypy/module/cpyext/slotdefs.py
--- a/pypy/module/cpyext/slotdefs.py
+++ b/pypy/module/cpyext/slotdefs.py
@@ -1,16 +1,20 @@
+from __future__ import with_statement
+
import re
from pypy.rpython.lltypesystem import rffi, lltype
-from pypy.module.cpyext.api import generic_cpy_call, cpython_api, PyObject
+from pypy.module.cpyext.api import (
+ cpython_api, generic_cpy_call, PyObject, Py_ssize_t)
from pypy.module.cpyext.typeobjectdefs import (
unaryfunc, wrapperfunc, ternaryfunc, PyTypeObjectPtr, binaryfunc,
- getattrfunc, setattrofunc, lenfunc, ssizeargfunc, ssizessizeargfunc,
- ssizeobjargproc, iternextfunc, initproc, richcmpfunc, hashfunc,
- descrgetfunc, descrsetfunc, objobjproc)
+ getattrfunc, getattrofunc, setattrofunc, lenfunc, ssizeargfunc,
+ ssizessizeargfunc, ssizeobjargproc, iternextfunc, initproc, richcmpfunc,
+ cmpfunc, hashfunc, descrgetfunc, descrsetfunc, objobjproc, readbufferproc)
from pypy.module.cpyext.pyobject import from_ref
from pypy.module.cpyext.pyerrors import PyErr_Occurred
from pypy.module.cpyext.state import State
from pypy.interpreter.error import OperationError, operationerrfmt
+from pypy.interpreter.buffer import Buffer as W_Buffer
from pypy.interpreter.argument import Arguments
from pypy.rlib.unroll import unrolling_iterable
from pypy.rlib.objectmodel import specialize
@@ -65,6 +69,12 @@
finally:
rffi.free_charp(name_ptr)
+def wrap_getattro(space, w_self, w_args, func):
+ func_target = rffi.cast(getattrofunc, func)
+ check_num_args(space, w_args, 1)
+ args_w = space.fixedview(w_args)
+ return generic_cpy_call(space, func_target, w_self, args_w[0])
+
def wrap_setattr(space, w_self, w_args, func):
func_target = rffi.cast(setattrofunc, func)
check_num_args(space, w_args, 2)
@@ -187,18 +197,59 @@
check_num_args(space, w_args, 0)
return space.wrap(generic_cpy_call(space, func_target, w_self))
+class CPyBuffer(W_Buffer):
+ # Similar to Py_buffer
+
+ def __init__(self, ptr, size, w_obj):
+ self.ptr = ptr
+ self.size = size
+ self.w_obj = w_obj # kept alive
+
+ def getlength(self):
+ return self.size
+
+ def getitem(self, index):
+ return self.ptr[index]
+
+def wrap_getreadbuffer(space, w_self, w_args, func):
+ func_target = rffi.cast(readbufferproc, func)
+ with lltype.scoped_alloc(rffi.VOIDPP.TO, 1) as ptr:
+ index = rffi.cast(Py_ssize_t, 0)
+ size = generic_cpy_call(space, func_target, w_self, index, ptr)
+ if size < 0:
+ space.fromcache(State).check_and_raise_exception(always=True)
+ return space.wrap(CPyBuffer(ptr[0], size, w_self))
+
def get_richcmp_func(OP_CONST):
def inner(space, w_self, w_args, func):
func_target = rffi.cast(richcmpfunc, func)
check_num_args(space, w_args, 1)
- args_w = space.fixedview(w_args)
- other_w = args_w[0]
+ w_other, = space.fixedview(w_args)
return generic_cpy_call(space, func_target,
- w_self, other_w, rffi.cast(rffi.INT_real, OP_CONST))
+ w_self, w_other, rffi.cast(rffi.INT_real, OP_CONST))
return inner
richcmp_eq = get_richcmp_func(Py_EQ)
richcmp_ne = get_richcmp_func(Py_NE)
+richcmp_lt = get_richcmp_func(Py_LT)
+richcmp_le = get_richcmp_func(Py_LE)
+richcmp_gt = get_richcmp_func(Py_GT)
+richcmp_ge = get_richcmp_func(Py_GE)
+
+def wrap_cmpfunc(space, w_self, w_args, func):
+ func_target = rffi.cast(cmpfunc, func)
+ check_num_args(space, w_args, 1)
+ w_other, = space.fixedview(w_args)
+
+ if not space.is_true(space.issubtype(space.type(w_self),
+ space.type(w_other))):
+ raise OperationError(space.w_TypeError, space.wrap(
+ "%s.__cmp__(x,y) requires y to be a '%s', not a '%s'" %
+ (space.type(w_self).getname(space),
+ space.type(w_self).getname(space),
+ space.type(w_other).getname(space))))
+
+ return space.wrap(generic_cpy_call(space, func_target, w_self, w_other))
@cpython_api([PyTypeObjectPtr, PyObject, PyObject], PyObject, external=False)
def slot_tp_new(space, type, w_args, w_kwds):
@@ -289,7 +340,12 @@
# irregular interface, because of tp_getattr/tp_getattro confusion
if NAME == "__getattr__":
- wrapper = wrap_getattr
+ if SLOT == "tp_getattro":
+ wrapper = wrap_getattro
+ elif SLOT == "tp_getattr":
+ wrapper = wrap_getattr
+ else:
+ assert False
function = globals().get(FUNCTION, None)
assert FLAGS == 0 or FLAGS == PyWrapperFlag_KEYWORDS
@@ -455,7 +511,7 @@
"oct(x)"),
UNSLOT("__hex__", nb_hex, slot_nb_hex, wrap_unaryfunc,
"hex(x)"),
- NBSLOT("__index__", nb_index, slot_nb_index, wrap_unaryfunc,
+ NBSLOT("__index__", nb_index, slot_nb_index, wrap_unaryfunc,
"x[y:z] <==> x[y.__index__():z.__index__()]"),
IBSLOT("__iadd__", nb_inplace_add, slot_nb_inplace_add,
wrap_binaryfunc, "+"),
@@ -560,12 +616,19 @@
for regex, repl in slotdef_replacements:
slotdefs_str = re.sub(regex, repl, slotdefs_str)
+slotdefs = eval(slotdefs_str)
+# PyPy addition
+slotdefs += (
+ TPSLOT("__buffer__", "tp_as_buffer.c_bf_getreadbuffer", None, "wrap_getreadbuffer", ""),
+)
+
slotdefs_for_tp_slots = unrolling_iterable(
[(x.method_name, x.slot_name, x.slot_names, x.slot_func)
- for x in eval(slotdefs_str)])
+ for x in slotdefs])
+
slotdefs_for_wrappers = unrolling_iterable(
[(x.method_name, x.slot_names, x.wrapper_func, x.wrapper_func_kwds, x.doc)
- for x in eval(slotdefs_str)])
+ for x in slotdefs])
if __name__ == "__main__":
print slotdefs_str
diff --git a/pypy/rpython/ootypesystem/ootype.py b/pypy/rpython/ootypesystem/ootype.py
--- a/pypy/rpython/ootypesystem/ootype.py
+++ b/pypy/rpython/ootypesystem/ootype.py
@@ -443,7 +443,8 @@
"ll_upper": Meth([], self.SELFTYPE_T),
"ll_lower": Meth([], self.SELFTYPE_T),
"ll_substring": Meth([Signed, Signed], self.SELFTYPE_T), # ll_substring(start, count)
- "ll_split_chr": Meth([self.CHAR], Array(self.SELFTYPE_T)), # XXX this is not pure!
+ "ll_split_chr": Meth([self.CHAR, Signed], Array(self.SELFTYPE_T)), # XXX this is not pure!
+ "ll_rsplit_chr": Meth([self.CHAR, Signed], Array(self.SELFTYPE_T)), # XXX this is not pure!
"ll_contains": Meth([self.CHAR], Bool),
"ll_replace_chr_chr": Meth([self.CHAR, self.CHAR], self.SELFTYPE_T),
})
@@ -1480,9 +1481,16 @@
# NOT_RPYTHON
return self.make_string(self._str[start:start+count])
- def ll_split_chr(self, ch):
+ def ll_split_chr(self, ch, max):
# NOT_RPYTHON
- l = [self.make_string(s) for s in self._str.split(ch)]
+ l = [self.make_string(s) for s in self._str.split(ch, max)]
+ res = _array(Array(self._TYPE), len(l))
+ res._array[:] = l
+ return res
+
+ def ll_rsplit_chr(self, ch, max):
+ # NOT_RPYTHON
+ l = [self.make_string(s) for s in self._str.rsplit(ch, max)]
res = _array(Array(self._TYPE), len(l))
res._array[:] = l
return res
diff --git a/pypy/jit/metainterp/optimizeopt/rewrite.py b/pypy/jit/metainterp/optimizeopt/rewrite.py
--- a/pypy/jit/metainterp/optimizeopt/rewrite.py
+++ b/pypy/jit/metainterp/optimizeopt/rewrite.py
@@ -154,6 +154,24 @@
self.emit_operation(op)
+ def optimize_INT_LSHIFT(self, op):
+ v1 = self.getvalue(op.getarg(0))
+ v2 = self.getvalue(op.getarg(1))
+
+ if v2.is_constant() and v2.box.getint() == 0:
+ self.make_equal_to(op.result, v1)
+ else:
+ self.emit_operation(op)
+
+ def optimize_INT_RSHIFT(self, op):
+ v1 = self.getvalue(op.getarg(0))
+ v2 = self.getvalue(op.getarg(1))
+
+ if v2.is_constant() and v2.box.getint() == 0:
+ self.make_equal_to(op.result, v1)
+ else:
+ self.emit_operation(op)
+
def optimize_CALL_PURE(self, op):
arg_consts = []
for i in range(op.numargs()):
diff --git a/pypy/objspace/std/fake.py b/pypy/objspace/std/fake.py
--- a/pypy/objspace/std/fake.py
+++ b/pypy/objspace/std/fake.py
@@ -151,9 +151,9 @@
class CPythonFakeFrame(eval.Frame):
- def __init__(self, space, code, w_globals=None, numlocals=-1):
+ def __init__(self, space, code, w_globals=None):
self.fakecode = code
- eval.Frame.__init__(self, space, w_globals, numlocals)
+ eval.Frame.__init__(self, space, w_globals)
def getcode(self):
return self.fakecode
diff --git a/pypy/jit/tl/pypyjit.py b/pypy/jit/tl/pypyjit.py
--- a/pypy/jit/tl/pypyjit.py
+++ b/pypy/jit/tl/pypyjit.py
@@ -101,7 +101,7 @@
# first annotate, rtype, and backendoptimize PyPy
try:
- interp, graph = get_interpreter(entry_point, [], backendopt=True,
+ interp, graph = get_interpreter(entry_point, [], backendopt=False,
config=config,
type_system=config.translation.type_system,
policy=PyPyAnnotatorPolicy(space))
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
@@ -8,9 +8,8 @@
from pypy.rpython.lltypesystem.lloperation import llop
from pypy.rpython.annlowlevel import llhelper
from pypy.jit.backend.model import CompiledLoopToken
-from pypy.jit.backend.x86.regalloc import (RegAlloc, X86RegisterManager,
- X86XMMRegisterManager, get_ebp_ofs,
- _get_scale)
+from pypy.jit.backend.x86.regalloc import (RegAlloc, get_ebp_ofs,
+ _get_scale, gpr_reg_mgr_cls)
from pypy.jit.backend.x86.arch import (FRAME_FIXED_SIZE, FORCE_INDEX_OFS, WORD,
IS_X86_32, IS_X86_64)
@@ -78,8 +77,8 @@
self.loop_run_counters = []
self.float_const_neg_addr = 0
self.float_const_abs_addr = 0
- self.malloc_fixedsize_slowpath1 = 0
- self.malloc_fixedsize_slowpath2 = 0
+ self.malloc_slowpath1 = 0
+ self.malloc_slowpath2 = 0
self.memcpy_addr = 0
self.setup_failure_recovery()
self._debug = False
@@ -124,8 +123,8 @@
self._build_failure_recovery(True, withfloats=True)
support.ensure_sse2_floats()
self._build_float_constants()
- if hasattr(gc_ll_descr, 'get_malloc_fixedsize_slowpath_addr'):
- self._build_malloc_fixedsize_slowpath()
+ if gc_ll_descr.get_malloc_slowpath_addr is not None:
+ self._build_malloc_slowpath()
self._build_stack_check_slowpath()
debug_start('jit-backend-counts')
self.set_debug(have_debug_prints())
@@ -133,6 +132,7 @@
def setup(self, looptoken):
assert self.memcpy_addr != 0, "setup_once() not called?"
+ self.current_clt = looptoken.compiled_loop_token
self.pending_guard_tokens = []
self.mc = codebuf.MachineCodeBlockWrapper()
if self.datablockwrapper is None:
@@ -145,6 +145,7 @@
self.mc = None
self.looppos = -1
self.currently_compiling_loop = None
+ self.current_clt = None
def finish_once(self):
if self._debug:
@@ -170,26 +171,47 @@
self.float_const_neg_addr = float_constants
self.float_const_abs_addr = float_constants + 16
- def _build_malloc_fixedsize_slowpath(self):
+ def _build_malloc_slowpath(self):
+ # With asmgcc, we need two helpers, so that we can write two CALL
+ # instructions in assembler, with a mark_gc_roots in between.
+ # With shadowstack, this is not needed, so we produce a single helper.
+ gcrootmap = self.cpu.gc_ll_descr.gcrootmap
+ #
# ---------- first helper for the slow path of malloc ----------
mc = codebuf.MachineCodeBlockWrapper()
if self.cpu.supports_floats: # save the XMM registers in
for i in range(self.cpu.NUM_REGS):# the *caller* frame, from esp+8
mc.MOVSD_sx((WORD*2)+8*i, i)
mc.SUB_rr(edx.value, eax.value) # compute the size we want
- if IS_X86_32:
- mc.MOV_sr(WORD, edx.value) # save it as the new argument
- elif IS_X86_64:
- # rdi can be clobbered: its content was forced to the stack
- # by _fastpath_malloc(), like all other save_around_call_regs.
- mc.MOV_rr(edi.value, edx.value)
-
- addr = self.cpu.gc_ll_descr.get_malloc_fixedsize_slowpath_addr()
- mc.JMP(imm(addr)) # tail call to the real malloc
- rawstart = mc.materialize(self.cpu.asmmemmgr, [])
- self.malloc_fixedsize_slowpath1 = rawstart
- # ---------- second helper for the slow path of malloc ----------
- mc = codebuf.MachineCodeBlockWrapper()
+ addr = self.cpu.gc_ll_descr.get_malloc_slowpath_addr()
+ #
+ if gcrootmap is not None and gcrootmap.is_shadow_stack:
+ # ---- shadowstack ----
+ for reg, ofs in gpr_reg_mgr_cls.REGLOC_TO_COPY_AREA_OFS.items():
+ mc.MOV_br(ofs, reg.value)
+ mc.SUB_ri(esp.value, 16 - WORD) # stack alignment of 16 bytes
+ if IS_X86_32:
+ mc.MOV_sr(0, edx.value) # push argument
+ elif IS_X86_64:
+ mc.MOV_rr(edi.value, edx.value)
+ mc.CALL(imm(addr))
+ mc.ADD_ri(esp.value, 16 - WORD)
+ for reg, ofs in gpr_reg_mgr_cls.REGLOC_TO_COPY_AREA_OFS.items():
+ mc.MOV_rb(reg.value, ofs)
+ else:
+ # ---- asmgcc ----
+ if IS_X86_32:
+ mc.MOV_sr(WORD, edx.value) # save it as the new argument
+ elif IS_X86_64:
+ # rdi can be clobbered: its content was forced to the stack
+ # by _fastpath_malloc(), like all other save_around_call_regs.
+ mc.MOV_rr(edi.value, edx.value)
+ mc.JMP(imm(addr)) # tail call to the real malloc
+ rawstart = mc.materialize(self.cpu.asmmemmgr, [])
+ self.malloc_slowpath1 = rawstart
+ # ---------- second helper for the slow path of malloc ----------
+ mc = codebuf.MachineCodeBlockWrapper()
+ #
if self.cpu.supports_floats: # restore the XMM registers
for i in range(self.cpu.NUM_REGS):# from where they were saved
mc.MOVSD_xs(i, (WORD*2)+8*i)
@@ -197,21 +219,28 @@
mc.MOV(edx, heap(nursery_free_adr)) # load this in EDX
mc.RET()
rawstart = mc.materialize(self.cpu.asmmemmgr, [])
- self.malloc_fixedsize_slowpath2 = rawstart
+ self.malloc_slowpath2 = rawstart
def _build_stack_check_slowpath(self):
- from pypy.rlib import rstack
_, _, slowpathaddr = self.cpu.insert_stack_check()
if slowpathaddr == 0 or self.cpu.exit_frame_with_exception_v < 0:
return # no stack check (for tests, or non-translated)
#
+ # make a "function" that is called immediately at the start of
+ # an assembler function. In particular, the stack looks like:
+ #
+ # | ... | <-- aligned to a multiple of 16
+ # | retaddr of caller |
+ # | my own retaddr | <-- esp
+ # +---------------------+
+ #
mc = codebuf.MachineCodeBlockWrapper()
- mc.PUSH_r(ebp.value)
- mc.MOV_rr(ebp.value, esp.value)
#
+ stack_size = WORD
if IS_X86_64:
# on the x86_64, we have to save all the registers that may
# have been used to pass arguments
+ stack_size += 6*WORD + 8*8
for reg in [edi, esi, edx, ecx, r8, r9]:
mc.PUSH_r(reg.value)
mc.SUB_ri(esp.value, 8*8)
@@ -220,11 +249,13 @@
#
if IS_X86_32:
mc.LEA_rb(eax.value, +8)
+ stack_size += 2*WORD
+ mc.PUSH_r(eax.value) # alignment
mc.PUSH_r(eax.value)
elif IS_X86_64:
mc.LEA_rb(edi.value, +16)
- mc.AND_ri(esp.value, -16)
#
+ # esp is now aligned to a multiple of 16 again
mc.CALL(imm(slowpathaddr))
#
mc.MOV(eax, heap(self.cpu.pos_exception()))
@@ -232,16 +263,16 @@
mc.J_il8(rx86.Conditions['NZ'], 0)
jnz_location = mc.get_relative_pos()
#
- if IS_X86_64:
+ if IS_X86_32:
+ mc.ADD_ri(esp.value, 2*WORD)
+ elif IS_X86_64:
# restore the registers
for i in range(7, -1, -1):
mc.MOVSD_xs(i, 8*i)
- for i, reg in [(6, r9), (5, r8), (4, ecx),
- (3, edx), (2, esi), (1, edi)]:
- mc.MOV_rb(reg.value, -8*i)
+ mc.ADD_ri(esp.value, 8*8)
+ for reg in [r9, r8, ecx, edx, esi, edi]:
+ mc.POP_r(reg.value)
#
- mc.MOV_rr(esp.value, ebp.value)
- mc.POP_r(ebp.value)
mc.RET()
#
# patch the JNZ above
@@ -266,9 +297,7 @@
# function, and will instead return to the caller's caller. Note
# also that we completely ignore the saved arguments, because we
# are interrupting the function.
- mc.MOV_rr(esp.value, ebp.value)
- mc.POP_r(ebp.value)
- mc.ADD_ri(esp.value, WORD)
+ mc.ADD_ri(esp.value, stack_size)
mc.RET()
#
rawstart = mc.materialize(self.cpu.asmmemmgr, [])
@@ -537,7 +566,7 @@
def _get_offset_of_ebp_from_esp(self, allocated_depth):
# Given that [EBP] is where we saved EBP, i.e. in the last word
# of our fixed frame, then the 'words' value is:
- words = (self.cpu.FRAME_FIXED_SIZE - 1) + allocated_depth
+ words = (FRAME_FIXED_SIZE - 1) + allocated_depth
# align, e.g. for Mac OS X
aligned_words = align_stack_words(words+2)-2 # 2 = EIP+EBP
return -WORD * aligned_words
@@ -550,6 +579,10 @@
for regloc in self.cpu.CALLEE_SAVE_REGISTERS:
self.mc.PUSH_r(regloc.value)
+ gcrootmap = self.cpu.gc_ll_descr.gcrootmap
+ if gcrootmap and gcrootmap.is_shadow_stack:
+ self._call_header_shadowstack(gcrootmap)
+
def _call_header_with_stack_check(self):
if self.stack_check_slowpath == 0:
pass # no stack check (e.g. not translated)
@@ -571,12 +604,32 @@
def _call_footer(self):
self.mc.LEA_rb(esp.value, -len(self.cpu.CALLEE_SAVE_REGISTERS) * WORD)
+ gcrootmap = self.cpu.gc_ll_descr.gcrootmap
+ if gcrootmap and gcrootmap.is_shadow_stack:
+ self._call_footer_shadowstack(gcrootmap)
+
for i in range(len(self.cpu.CALLEE_SAVE_REGISTERS)-1, -1, -1):
self.mc.POP_r(self.cpu.CALLEE_SAVE_REGISTERS[i].value)
self.mc.POP_r(ebp.value)
self.mc.RET()
+ def _call_header_shadowstack(self, gcrootmap):
+ # we need to put two words into the shadowstack: the MARKER
+ # and the address of the frame (ebp, actually)
+ rst = gcrootmap.get_root_stack_top_addr()
+ assert rx86.fits_in_32bits(rst)
+ self.mc.MOV_rj(eax.value, rst) # MOV eax, [rootstacktop]
+ self.mc.LEA_rm(edx.value, (eax.value, 2*WORD)) # LEA edx, [eax+2*WORD]
+ self.mc.MOV_mi((eax.value, 0), gcrootmap.MARKER) # MOV [eax], MARKER
+ self.mc.MOV_mr((eax.value, WORD), ebp.value) # MOV [eax+WORD], ebp
+ self.mc.MOV_jr(rst, edx.value) # MOV [rootstacktop], edx
+
+ def _call_footer_shadowstack(self, gcrootmap):
+ rst = gcrootmap.get_root_stack_top_addr()
+ assert rx86.fits_in_32bits(rst)
+ self.mc.SUB_ji8(rst, 2*WORD) # SUB [rootstacktop], 2*WORD
+
def _assemble_bootstrap_direct_call(self, arglocs, jmppos, stackdepth):
if IS_X86_64:
return self._assemble_bootstrap_direct_call_64(arglocs, jmppos, stackdepth)
@@ -686,8 +739,8 @@
nonfloatlocs, floatlocs = arglocs
self._call_header()
stackadjustpos = self._patchable_stackadjust()
- tmp = X86RegisterManager.all_regs[0]
- xmmtmp = X86XMMRegisterManager.all_regs[0]
+ tmp = eax
+ xmmtmp = xmm0
self.mc.begin_reuse_scratch_register()
for i in range(len(nonfloatlocs)):
loc = nonfloatlocs[i]
@@ -896,9 +949,9 @@
self.implement_guard(guard_token, checkfalsecond)
return genop_cmp_guard_float
- def _emit_call(self, x, arglocs, start=0, tmp=eax):
+ def _emit_call(self, force_index, x, arglocs, start=0, tmp=eax):
if IS_X86_64:
- return self._emit_call_64(x, arglocs, start)
+ return self._emit_call_64(force_index, x, arglocs, start)
p = 0
n = len(arglocs)
@@ -924,9 +977,9 @@
self._regalloc.reserve_param(p//WORD)
# x is a location
self.mc.CALL(x)
- self.mark_gc_roots()
+ self.mark_gc_roots(force_index)
- def _emit_call_64(self, x, arglocs, start=0):
+ def _emit_call_64(self, force_index, x, arglocs, start):
src_locs = []
dst_locs = []
xmm_src_locs = []
@@ -984,12 +1037,27 @@
self._regalloc.reserve_param(len(pass_on_stack))
self.mc.CALL(x)
- self.mark_gc_roots()
+ self.mark_gc_roots(force_index)
def call(self, addr, args, res):
- self._emit_call(imm(addr), args)
+ force_index = self.write_new_force_index()
+ self._emit_call(force_index, imm(addr), args)
assert res is eax
+ def write_new_force_index(self):
+ # for shadowstack only: get a new, unused force_index number and
+ # write it to FORCE_INDEX_OFS. Used to record the call shape
+ # (i.e. where the GC pointers are in the stack) around a CALL
+ # instruction that doesn't already have a force_index.
+ gcrootmap = self.cpu.gc_ll_descr.gcrootmap
+ if gcrootmap and gcrootmap.is_shadow_stack:
+ clt = self.current_clt
+ force_index = clt.reserve_and_record_some_faildescr_index()
+ self.mc.MOV_bi(FORCE_INDEX_OFS, force_index)
+ return force_index
+ else:
+ return 0
+
genop_int_neg = _unaryop("NEG")
genop_int_invert = _unaryop("NOT")
genop_int_add = _binaryop("ADD", True)
@@ -1205,6 +1273,11 @@
assert isinstance(loc_vtable, ImmedLoc)
self.mc.MOV(mem(loc, self.cpu.vtable_offset), loc_vtable)
+ def set_new_array_length(self, loc, ofs_length, loc_num_elem):
+ assert isinstance(loc, RegLoc)
+ assert isinstance(loc_num_elem, ImmedLoc)
+ self.mc.MOV(mem(loc, ofs_length), loc_num_elem)
+
# XXX genop_new is abused for all varsized mallocs with Boehm, for now
# (instead of genop_new_array, genop_newstr, genop_newunicode)
def genop_new(self, op, arglocs, result_loc):
@@ -1783,6 +1856,10 @@
self.pending_guard_tokens.append(guard_token)
def genop_call(self, op, arglocs, resloc):
+ force_index = self.write_new_force_index()
+ self._genop_call(op, arglocs, resloc, force_index)
+
+ def _genop_call(self, op, arglocs, resloc, force_index):
sizeloc = arglocs[0]
assert isinstance(sizeloc, ImmedLoc)
size = sizeloc.value
@@ -1796,8 +1873,8 @@
tmp = ecx
else:
tmp = eax
-
- self._emit_call(x, arglocs, 3, tmp=tmp)
+
+ self._emit_call(force_index, x, arglocs, 3, tmp=tmp)
if IS_X86_32 and isinstance(resloc, StackLoc) and resloc.width == 8:
# a float or a long long return
@@ -1828,7 +1905,7 @@
faildescr = guard_op.getdescr()
fail_index = self.cpu.get_fail_descr_number(faildescr)
self.mc.MOV_bi(FORCE_INDEX_OFS, fail_index)
- self.genop_call(op, arglocs, result_loc)
+ self._genop_call(op, arglocs, result_loc, fail_index)
self.mc.CMP_bi(FORCE_INDEX_OFS, 0)
self.implement_guard(guard_token, 'L')
@@ -1842,8 +1919,8 @@
assert len(arglocs) - 2 == len(descr._x86_arglocs[0])
#
# Write a call to the direct_bootstrap_code of the target assembler
- self._emit_call(imm(descr._x86_direct_bootstrap_code), arglocs, 2,
- tmp=eax)
+ self._emit_call(fail_index, imm(descr._x86_direct_bootstrap_code),
+ arglocs, 2, tmp=eax)
if op.result is None:
assert result_loc is None
value = self.cpu.done_with_this_frame_void_v
@@ -1868,7 +1945,7 @@
jd = descr.outermost_jitdriver_sd
assert jd is not None
asm_helper_adr = self.cpu.cast_adr_to_int(jd.assembler_helper_adr)
- self._emit_call(imm(asm_helper_adr), [eax, arglocs[1]], 0,
+ self._emit_call(fail_index, imm(asm_helper_adr), [eax, arglocs[1]], 0,
tmp=ecx)
if IS_X86_32 and isinstance(result_loc, StackLoc) and result_loc.type == FLOAT:
self.mc.FSTP_b(result_loc.value)
@@ -1895,7 +1972,7 @@
# load the return value from fail_boxes_xxx[0]
kind = op.result.type
if kind == FLOAT:
- xmmtmp = X86XMMRegisterManager.all_regs[0]
+ xmmtmp = xmm0
adr = self.fail_boxes_float.get_addr_for_num(0)
self.mc.MOVSD(xmmtmp, heap(adr))
self.mc.MOVSD(result_loc, xmmtmp)
@@ -1990,11 +2067,16 @@
not_implemented("not implemented operation (guard): %s" %
op.getopname())
- def mark_gc_roots(self):
+ def mark_gc_roots(self, force_index, use_copy_area=False):
+ if force_index < 0:
+ return # not needed
gcrootmap = self.cpu.gc_ll_descr.gcrootmap
if gcrootmap:
- mark = self._regalloc.get_mark_gc_roots(gcrootmap)
- self.mc.insert_gcroot_marker(mark)
+ mark = self._regalloc.get_mark_gc_roots(gcrootmap, use_copy_area)
+ if gcrootmap.is_shadow_stack:
+ gcrootmap.write_callshape(mark, force_index)
+ else:
+ self.mc.insert_gcroot_marker(mark)
def target_arglocs(self, loop_token):
return loop_token._x86_arglocs
@@ -2006,8 +2088,7 @@
else:
self.mc.JMP(imm(loop_token._x86_loop_code))
- def malloc_cond_fixedsize(self, nursery_free_adr, nursery_top_adr,
- size, tid):
+ def malloc_cond(self, nursery_free_adr, nursery_top_adr, size, tid):
size = max(size, self.cpu.gc_ll_descr.minimal_size_in_nursery)
self.mc.MOV(eax, heap(nursery_free_adr))
self.mc.LEA_rm(edx.value, (eax.value, size))
@@ -2015,7 +2096,7 @@
self.mc.J_il8(rx86.Conditions['NA'], 0) # patched later
jmp_adr = self.mc.get_relative_pos()
- # See comments in _build_malloc_fixedsize_slowpath for the
+ # See comments in _build_malloc_slowpath for the
# details of the two helper functions that we are calling below.
# First, we need to call two of them and not just one because we
# need to have a mark_gc_roots() in between. Then the calling
@@ -2025,19 +2106,27 @@
# result in EAX; slowpath_addr2 additionally returns in EDX a
# copy of heap(nursery_free_adr), so that the final MOV below is
# a no-op.
- slowpath_addr1 = self.malloc_fixedsize_slowpath1
+
# reserve room for the argument to the real malloc and the
# 8 saved XMM regs
self._regalloc.reserve_param(1+16)
- self.mc.CALL(imm(slowpath_addr1))
- self.mark_gc_roots()
- slowpath_addr2 = self.malloc_fixedsize_slowpath2
+
+ gcrootmap = self.cpu.gc_ll_descr.gcrootmap
+ shadow_stack = (gcrootmap is not None and gcrootmap.is_shadow_stack)
+ if not shadow_stack:
+ # there are two helpers to call only with asmgcc
+ slowpath_addr1 = self.malloc_slowpath1
+ self.mc.CALL(imm(slowpath_addr1))
+ self.mark_gc_roots(self.write_new_force_index(),
+ use_copy_area=shadow_stack)
+ slowpath_addr2 = self.malloc_slowpath2
self.mc.CALL(imm(slowpath_addr2))
offset = self.mc.get_relative_pos() - jmp_adr
assert 0 < offset <= 127
self.mc.overwrite(jmp_adr-1, chr(offset))
# on 64-bits, 'tid' is a value that fits in 31 bits
+ assert rx86.fits_in_32bits(tid)
self.mc.MOV_mi((eax.value, 0), tid)
self.mc.MOV(heap(nursery_free_adr), edx)
diff --git a/pypy/module/cpyext/include/traceback.h b/pypy/module/cpyext/include/traceback.h
new file mode 100644
--- /dev/null
+++ b/pypy/module/cpyext/include/traceback.h
@@ -0,0 +1,12 @@
+#ifndef Py_TRACEBACK_H
+#define Py_TRACEBACK_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef PyObject PyTracebackObject;
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* !Py_TRACEBACK_H */
diff --git a/pypy/jit/metainterp/test/test_loop.py b/pypy/jit/metainterp/test/test_loop.py
--- a/pypy/jit/metainterp/test/test_loop.py
+++ b/pypy/jit/metainterp/test/test_loop.py
@@ -2,7 +2,7 @@
from pypy.rlib.jit import JitDriver
from pypy.rlib.objectmodel import compute_hash
from pypy.jit.metainterp.warmspot import ll_meta_interp, get_stats
-from pypy.jit.metainterp.test.test_basic import LLJitMixin, OOJitMixin
+from pypy.jit.metainterp.test.support import LLJitMixin, OOJitMixin
from pypy.jit.codewriter.policy import StopAtXPolicy
from pypy.jit.metainterp.resoperation import rop
from pypy.jit.metainterp import history
More information about the Pypy-commit
mailing list