[pypy-svn] pypy out-of-line-guards-2: merge default
arigo
commits-noreply at bitbucket.org
Sun Apr 10 21:50:39 CEST 2011
Author: Armin Rigo <arigo at tunes.org>
Branch: out-of-line-guards-2
Changeset: r43270:e0139924067c
Date: 2011-04-09 12:27 +0200
http://bitbucket.org/pypy/pypy/changeset/e0139924067c/
Log: merge default
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/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/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/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/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/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/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))
@@ -155,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
@@ -2,6 +2,7 @@
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
@@ -22,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
@@ -35,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):
@@ -588,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)
@@ -666,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)
@@ -689,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):
@@ -837,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/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/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/_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/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/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/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,8 +364,8 @@
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_ji8 = insn(rex_w, '\x83', orbyte(base), '\x05', immediate(1),
+ 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))
@@ -460,10 +476,12 @@
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))
@@ -511,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)))
@@ -537,7 +555,7 @@
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
@@ -645,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
@@ -686,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/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/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/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/module/thread/__init__.py b/pypy/module/thread/__init__.py
--- a/pypy/module/thread/__init__.py
+++ b/pypy/module/thread/__init__.py
@@ -17,8 +17,8 @@
'_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/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/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/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()
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/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/config/translationoption.py b/pypy/config/translationoption.py
--- a/pypy/config/translationoption.py
+++ b/pypy/config/translationoption.py
@@ -343,7 +343,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):
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/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/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_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):
@@ -4960,6 +4960,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/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
@@ -517,12 +517,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?
@@ -541,6 +539,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/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/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/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/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
@@ -860,15 +860,27 @@
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)
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_fixedsize_slowpath().
+ # 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)
@@ -885,16 +897,16 @@
self.rm.force_allocate_reg(tmp_box, selected_reg=reg)
self.rm.possibly_free_var(tmp_box)
- self.assembler.malloc_cond_fixedsize(
+ 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]
@@ -904,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:
@@ -963,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)
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/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/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/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
@@ -578,6 +578,26 @@
res = self.interpret(fn, [3, 3])
assert res == 123
+ 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):
@@ -682,26 +702,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/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/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
@@ -45,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()
@@ -167,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
@@ -205,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)
@@ -221,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
@@ -255,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 = '''
@@ -275,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 = '''
@@ -290,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/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/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/module/imp/importing.py b/pypy/module/imp/importing.py
--- a/pypy/module/imp/importing.py
+++ b/pypy/module/imp/importing.py
@@ -91,9 +91,10 @@
else:
# XXX that's slow
def case_ok(filename):
- index1 = filename.rfind(os.sep)
- index2 = filename.rfind(os.altsep)
- index = max(index1, index2)
+ 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/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/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/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())
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/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):
@@ -388,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/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/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/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/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()
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
@@ -160,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/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/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/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/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/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/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/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/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/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/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
@@ -501,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)
@@ -1148,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/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/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/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/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/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/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_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/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/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/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/interpreter/function.py b/pypy/interpreter/function.py
--- a/pypy/interpreter/function.py
+++ b/pypy/interpreter/function.py
@@ -28,7 +28,9 @@
self.items = items
def getitems(self):
- return jit.hint(self, promote=True).items
+ ## XXX! we would like: return jit.hint(self, promote=True).items
+ ## XXX! but it gives horrible performance in some cases
+ return self.items
def getitem(self, idx):
return self.getitems()[idx]
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/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/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[:] = []
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/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/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/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):
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.
@@ -1116,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
@@ -1965,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/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/module/cpyext/typeobject.py b/pypy/module/cpyext/typeobject.py
--- a/pypy/module/cpyext/typeobject.py
+++ b/pypy/module/cpyext/typeobject.py
@@ -7,10 +7,10 @@
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
@@ -361,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
@@ -381,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
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
@@ -245,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,
@@ -385,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/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/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):
@@ -51,3 +53,23 @@
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/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/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/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/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
@@ -135,7 +135,7 @@
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/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/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/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/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py
--- a/pypy/interpreter/baseobjspace.py
+++ b/pypy/interpreter/baseobjspace.py
@@ -1350,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/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/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/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/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/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/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,16 @@
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"))
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,18 @@
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, getattrofunc, setattrofunc, lenfunc, ssizeargfunc,
ssizessizeargfunc, ssizeobjargproc, iternextfunc, initproc, richcmpfunc,
- hashfunc, descrgetfunc, descrsetfunc, objobjproc)
+ 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
@@ -193,18 +195,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):
@@ -571,12 +614,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/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/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/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
@@ -77,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
@@ -123,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())
@@ -171,7 +171,7 @@
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.
@@ -183,7 +183,7 @@
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
- addr = self.cpu.gc_ll_descr.get_malloc_fixedsize_slowpath_addr()
+ addr = self.cpu.gc_ll_descr.get_malloc_slowpath_addr()
#
if gcrootmap is not None and gcrootmap.is_shadow_stack:
# ---- shadowstack ----
@@ -208,7 +208,7 @@
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_fixedsize_slowpath1 = rawstart
+ self.malloc_slowpath1 = rawstart
# ---------- second helper for the slow path of malloc ----------
mc = codebuf.MachineCodeBlockWrapper()
#
@@ -219,7 +219,7 @@
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):
_, _, slowpathaddr = self.cpu.insert_stack_check()
@@ -951,7 +951,7 @@
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)
@@ -979,7 +979,7 @@
self.mc.CALL(x)
self.mark_gc_roots(force_index)
- def _emit_call_64(self, force_index, x, arglocs, start=0):
+ def _emit_call_64(self, force_index, x, arglocs, start):
src_locs = []
dst_locs = []
xmm_src_locs = []
@@ -1273,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):
@@ -2083,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))
@@ -2092,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
@@ -2111,11 +2115,11 @@
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_fixedsize_slowpath1
+ 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_fixedsize_slowpath2
+ slowpath_addr2 = self.malloc_slowpath2
self.mc.CALL(imm(slowpath_addr2))
offset = self.mc.get_relative_pos() - jmp_adr
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 */
More information about the Pypy-commit
mailing list