aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'pypy/module')
-rw-r--r--pypy/module/__builtin__/descriptor.py3
-rw-r--r--pypy/module/__pypy__/__init__.py7
-rw-r--r--pypy/module/__pypy__/interp_magic.py14
-rw-r--r--pypy/module/__pypy__/test/test_special.py4
-rw-r--r--pypy/module/_rawffi/test/test__rawffi.py1
-rw-r--r--pypy/module/_rawffi/test/test_nested.py1
-rw-r--r--pypy/module/_stackless/test/conftest.py7
-rw-r--r--pypy/module/array/interp_array.py2
-rw-r--r--pypy/module/cpyext/api.py16
-rw-r--r--pypy/module/cpyext/cdatetime.py13
-rw-r--r--pypy/module/cpyext/presetup.py3
-rw-r--r--pypy/module/cpyext/pyobject.py16
-rw-r--r--pypy/module/cpyext/test/test_borrow.py1
-rw-r--r--pypy/module/cpyext/test/test_cpyext.py10
-rw-r--r--pypy/module/cpyext/typeobject.py31
-rw-r--r--pypy/module/gc/__init__.py1
-rw-r--r--pypy/module/gc/app_referents.py14
-rw-r--r--pypy/module/gc/interp_gc.py4
-rw-r--r--pypy/module/gc/referents.py6
-rw-r--r--pypy/module/gc/test/test_gc.py27
-rw-r--r--pypy/module/imp/importing.py25
-rw-r--r--pypy/module/imp/interp_imp.py8
-rw-r--r--pypy/module/imp/test/test_app.py3
-rw-r--r--pypy/module/imp/test/test_import.py11
-rw-r--r--pypy/module/posix/interp_posix.py3
-rw-r--r--pypy/module/pypyjit/interp_jit.py16
-rw-r--r--pypy/module/pypyjit/policy.py7
-rw-r--r--pypy/module/pypyjit/test/test_policy.py8
-rw-r--r--pypy/module/pypyjit/test/test_pypy_c.py69
-rw-r--r--pypy/module/rctime/interp_time.py2
-rw-r--r--pypy/module/signal/__init__.py6
-rw-r--r--pypy/module/signal/interp_signal.py24
-rw-r--r--pypy/module/signal/test/test_signal.py42
-rw-r--r--pypy/module/sys/__init__.py1
-rw-r--r--pypy/module/sys/version.py2
-rw-r--r--pypy/module/sys/vm.py4
-rw-r--r--pypy/module/thread/gil.py17
-rw-r--r--pypy/module/thread/test/test_gil.py2
38 files changed, 360 insertions, 71 deletions
diff --git a/pypy/module/__builtin__/descriptor.py b/pypy/module/__builtin__/descriptor.py
index dbad647609..6c51fa3d27 100644
--- a/pypy/module/__builtin__/descriptor.py
+++ b/pypy/module/__builtin__/descriptor.py
@@ -96,6 +96,8 @@ class C(B):
)
class W_Property(Wrappable):
+ _immutable_fields_ = ["w_fget", "w_fset", "w_fdel"]
+
def init(self, space, w_fget=None, w_fset=None, w_fdel=None, w_doc=None):
self.w_fget = w_fget
self.w_fset = w_fset
@@ -183,4 +185,3 @@ class C(object):
fget = interp_attrproperty_w('w_fget', W_Property),
fset = interp_attrproperty_w('w_fset', W_Property),
)
-
diff --git a/pypy/module/__pypy__/__init__.py b/pypy/module/__pypy__/__init__.py
index 3b1d69e2fe..c3fe0ce594 100644
--- a/pypy/module/__pypy__/__init__.py
+++ b/pypy/module/__pypy__/__init__.py
@@ -23,5 +23,12 @@ class Module(MixedModule):
'interp_magic.method_cache_counter')
self.extra_interpdef('reset_method_cache_counter',
'interp_magic.reset_method_cache_counter')
+ if self.space.config.objspace.std.withmapdict:
+ self.extra_interpdef('mapdict_cache_counter',
+ 'interp_magic.mapdict_cache_counter')
PYC_MAGIC = get_pyc_magic(self.space)
self.extra_interpdef('PYC_MAGIC', 'space.wrap(%d)' % PYC_MAGIC)
+ #
+ from pypy.jit.backend import detect_cpu
+ model = detect_cpu.autodetect_main_model_and_size()
+ self.extra_interpdef('cpumodel', 'space.wrap(%r)' % model)
diff --git a/pypy/module/__pypy__/interp_magic.py b/pypy/module/__pypy__/interp_magic.py
index 71a7c89eba..0dafafe546 100644
--- a/pypy/module/__pypy__/interp_magic.py
+++ b/pypy/module/__pypy__/interp_magic.py
@@ -2,6 +2,7 @@ from pypy.interpreter.error import OperationError
from pypy.interpreter.gateway import ObjSpace
from pypy.rlib.objectmodel import we_are_translated
from pypy.objspace.std.typeobject import MethodCache
+from pypy.objspace.std.mapdict import IndexCache
def internal_repr(space, w_object):
return space.wrap('%r' % (w_object,))
@@ -36,4 +37,17 @@ def reset_method_cache_counter(space):
cache = space.fromcache(MethodCache)
cache.misses = {}
cache.hits = {}
+ if space.config.objspace.std.withmapdict:
+ cache = space.fromcache(IndexCache)
+ cache.misses = {}
+ cache.hits = {}
+def mapdict_cache_counter(space, name):
+ """Return a tuple (index_cache_hits, index_cache_misses) for lookups
+ in the mapdict cache with the given attribute name."""
+ assert space.config.objspace.std.withmethodcachecounter
+ assert space.config.objspace.std.withmapdict
+ cache = space.fromcache(IndexCache)
+ return space.newtuple([space.newint(cache.hits.get(name, 0)),
+ space.newint(cache.misses.get(name, 0))])
+mapdict_cache_counter.unwrap_spec = [ObjSpace, str]
diff --git a/pypy/module/__pypy__/test/test_special.py b/pypy/module/__pypy__/test/test_special.py
index 516247822d..af0cd80210 100644
--- a/pypy/module/__pypy__/test/test_special.py
+++ b/pypy/module/__pypy__/test/test_special.py
@@ -17,3 +17,7 @@ class AppTest(object):
from __pypy__ import isfake
import select
assert isfake(select)
+
+ def test_cpumodel(self):
+ import __pypy__
+ assert hasattr(__pypy__, 'cpumodel')
diff --git a/pypy/module/_rawffi/test/test__rawffi.py b/pypy/module/_rawffi/test/test__rawffi.py
index a232b9422e..81d60ec085 100644
--- a/pypy/module/_rawffi/test/test__rawffi.py
+++ b/pypy/module/_rawffi/test/test__rawffi.py
@@ -296,6 +296,7 @@ class AppTestFfi:
assert _rawffi.charp2string(res[0]) is None
arg1.free()
arg2.free()
+ a.free()
def test_raw_callable(self):
import _rawffi
diff --git a/pypy/module/_rawffi/test/test_nested.py b/pypy/module/_rawffi/test/test_nested.py
index 077dfe3f78..e0bbd87a84 100644
--- a/pypy/module/_rawffi/test/test_nested.py
+++ b/pypy/module/_rawffi/test/test_nested.py
@@ -107,7 +107,6 @@ class AppTestNested:
assert S.fieldoffset('x') == 0
assert S.fieldoffset('ar') == A5alignment
s = S()
- s = S()
s.x = 'G'
raises(TypeError, 's.ar')
assert s.fieldaddress('ar') == s.buffer + S.fieldoffset('ar')
diff --git a/pypy/module/_stackless/test/conftest.py b/pypy/module/_stackless/test/conftest.py
new file mode 100644
index 0000000000..1c5e26a206
--- /dev/null
+++ b/pypy/module/_stackless/test/conftest.py
@@ -0,0 +1,7 @@
+import sys
+import py.test
+
+def pytest_runtest_setup(item):
+ if sys.platform == 'win32':
+ py.test.skip("stackless tests segfault on Windows")
+
diff --git a/pypy/module/array/interp_array.py b/pypy/module/array/interp_array.py
index 2c81b7fcff..ff62c17bee 100644
--- a/pypy/module/array/interp_array.py
+++ b/pypy/module/array/interp_array.py
@@ -27,7 +27,7 @@ def w_array(space, w_cls, typecode, w_args=None):
typecode = typecode[0]
if space.is_w(w_cls, space.gettypeobject(W_ArrayBase.typedef)):
- if len(w_args.keywords_w) > 0:
+ if w_args.keywords: # XXX this might be forbidden fishing
msg = 'array.array() does not take keyword arguments'
raise OperationError(space.w_TypeError, space.wrap(msg))
diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py
index fc1577c7fa..7805d6f3e2 100644
--- a/pypy/module/cpyext/api.py
+++ b/pypy/module/cpyext/api.py
@@ -226,7 +226,7 @@ def cpython_api(argtypes, restype, error=_NOT_SPECIFIED, external=True):
def unwrapper(space, *args):
from pypy.module.cpyext.pyobject import Py_DecRef
from pypy.module.cpyext.pyobject import make_ref, from_ref
- from pypy.module.cpyext.pyobject import BorrowPair
+ from pypy.module.cpyext.pyobject import Reference
newargs = ()
to_decref = []
assert len(args) == len(api_function.argtypes)
@@ -270,8 +270,8 @@ def cpython_api(argtypes, restype, error=_NOT_SPECIFIED, external=True):
return api_function.error_value
if res is None:
return None
- elif isinstance(res, BorrowPair):
- return res.w_borrowed
+ elif isinstance(res, Reference):
+ return res.get_wrapped(space)
else:
return res
finally:
@@ -473,7 +473,7 @@ def make_wrapper(space, callable):
@specialize.ll()
def wrapper(*args):
from pypy.module.cpyext.pyobject import make_ref, from_ref
- from pypy.module.cpyext.pyobject import BorrowPair
+ from pypy.module.cpyext.pyobject import Reference
# we hope that malloc removal removes the newtuple() that is
# inserted exactly here by the varargs specializer
llop.gc_stack_bottom(lltype.Void) # marker for trackgcroot.py
@@ -525,7 +525,7 @@ def make_wrapper(space, callable):
elif is_PyObject(callable.api_func.restype):
if result is None:
retval = make_ref(space, None)
- elif isinstance(result, BorrowPair):
+ elif isinstance(result, Reference):
retval = result.get_ref(space)
elif not rffi._isllptr(result):
retval = rffi.cast(callable.api_func.restype,
@@ -908,8 +908,10 @@ def load_extension_module(space, path, name):
from pypy.rlib import rdynload
try:
ll_libname = rffi.str2charp(path)
- dll = rdynload.dlopen(ll_libname)
- lltype.free(ll_libname, flavor='raw')
+ try:
+ dll = rdynload.dlopen(ll_libname)
+ finally:
+ lltype.free(ll_libname, flavor='raw')
except rdynload.DLOpenError, e:
raise operationerrfmt(
space.w_ImportError,
diff --git a/pypy/module/cpyext/cdatetime.py b/pypy/module/cpyext/cdatetime.py
index 3081233375..6aa54f695e 100644
--- a/pypy/module/cpyext/cdatetime.py
+++ b/pypy/module/cpyext/cdatetime.py
@@ -4,7 +4,7 @@ from pypy.module.cpyext.pyobject import PyObject, make_ref, Py_DecRef
from pypy.module.cpyext.api import (
cpython_api, CANNOT_FAIL, cpython_struct, PyObjectFields)
from pypy.module.cpyext.import_ import PyImport_Import
-from pypy.module.cpyext.typeobject import PyTypeObjectPtr
+from pypy.module.cpyext.typeobject import PyTypeObjectPtr, render_immortal
from pypy.module.cpyext.state import State
from pypy.interpreter.error import OperationError
from pypy.tool.sourcetools import func_renamer
@@ -22,25 +22,34 @@ PyDateTime_CAPI = cpython_struct(
@cpython_api([], lltype.Ptr(PyDateTime_CAPI),
error=lltype.nullptr(PyDateTime_CAPI))
def _PyDateTime_Import(space):
- datetimeAPI = lltype.malloc(PyDateTime_CAPI, flavor='raw')
+ datetimeAPI = lltype.malloc(PyDateTime_CAPI, flavor='raw',
+ track_allocation=False)
if not we_are_translated():
datetimeAPI_dealloc(space)
space.fromcache(State).datetimeAPI = datetimeAPI
w_datetime = PyImport_Import(space, space.wrap("datetime"))
+
w_type = space.getattr(w_datetime, space.wrap("date"))
datetimeAPI.c_DateType = rffi.cast(
PyTypeObjectPtr, make_ref(space, w_type))
+ render_immortal(datetimeAPI.c_DateType, w_type)
+
w_type = space.getattr(w_datetime, space.wrap("datetime"))
datetimeAPI.c_DateTimeType = rffi.cast(
PyTypeObjectPtr, make_ref(space, w_type))
+ render_immortal(datetimeAPI.c_DateTimeType, w_type)
+
w_type = space.getattr(w_datetime, space.wrap("time"))
datetimeAPI.c_TimeType = rffi.cast(
PyTypeObjectPtr, make_ref(space, w_type))
+ render_immortal(datetimeAPI.c_TimeType, w_type)
+
w_type = space.getattr(w_datetime, space.wrap("timedelta"))
datetimeAPI.c_DeltaType = rffi.cast(
PyTypeObjectPtr, make_ref(space, w_type))
+ render_immortal(datetimeAPI.c_DeltaType, w_type)
return datetimeAPI
diff --git a/pypy/module/cpyext/presetup.py b/pypy/module/cpyext/presetup.py
index 5a1605f048..16c205ad79 100644
--- a/pypy/module/cpyext/presetup.py
+++ b/pypy/module/cpyext/presetup.py
@@ -21,6 +21,8 @@ from distutils import sysconfig
from pypy.conftest import gettestobjspace
from pypy.module.cpyext.api import build_bridge
+from pypy.module.imp.importing import get_so_extension
+
usemodules = ['cpyext', 'thread']
if sys.platform == 'win32':
usemodules.append('_winreg') # necessary in distutils
@@ -35,6 +37,7 @@ def get_python_inc(plat_specific=0, prefix=None):
def patch_distutils():
sysconfig.get_python_inc = get_python_inc
+ sysconfig.get_config_vars()['SO'] = get_so_extension(space)
patch_distutils()
diff --git a/pypy/module/cpyext/pyobject.py b/pypy/module/cpyext/pyobject.py
index e596398e5c..a0372dd475 100644
--- a/pypy/module/cpyext/pyobject.py
+++ b/pypy/module/cpyext/pyobject.py
@@ -424,7 +424,18 @@ def make_borrowed_ref(space, w_container, w_borrowed):
state = space.fromcache(RefcountState)
return state.make_borrowed(w_container, w_borrowed)
-class BorrowPair:
+class Reference:
+ def __init__(self, pyobj):
+ assert not isinstance(pyobj, W_Root)
+ self.pyobj = pyobj
+
+ def get_ref(self, space):
+ return self.pyobj
+
+ def get_wrapped(self, space):
+ return from_ref(space, self.pyobj)
+
+class BorrowPair(Reference):
"""
Delays the creation of a borrowed reference.
"""
@@ -435,6 +446,9 @@ class BorrowPair:
def get_ref(self, space):
return make_borrowed_ref(space, self.w_container, self.w_borrowed)
+ def get_wrapped(self, space):
+ return self.w_borrowed
+
def borrow_from(container, borrowed):
return BorrowPair(container, borrowed)
diff --git a/pypy/module/cpyext/test/test_borrow.py b/pypy/module/cpyext/test/test_borrow.py
index 30fc28f4b5..e02a39854d 100644
--- a/pypy/module/cpyext/test/test_borrow.py
+++ b/pypy/module/cpyext/test/test_borrow.py
@@ -31,6 +31,7 @@ class AppTestBorrow(AppTestCpythonExtensionBase):
g = PyTuple_GetItem(t, 0); // borrows reference again
printf("Refcnt4: %i\\n", f->ob_refcnt);
printf("COMPARE: %i\\n", f == g);
+ fflush(stdout);
Py_DECREF(t);
Py_RETURN_TRUE;
"""),
diff --git a/pypy/module/cpyext/test/test_cpyext.py b/pypy/module/cpyext/test/test_cpyext.py
index 60e993c6a5..e27435c23b 100644
--- a/pypy/module/cpyext/test/test_cpyext.py
+++ b/pypy/module/cpyext/test/test_cpyext.py
@@ -42,7 +42,7 @@ class AppTestApi:
raises(ImportError, cpyext.load_module, "missing.file", "foo")
raises(ImportError, cpyext.load_module, self.libc, "invalid.function")
-def compile_module(modname, **kwds):
+def compile_module(space, modname, **kwds):
"""
Build an extension module and return the filename of the resulting native
code file.
@@ -65,10 +65,8 @@ def compile_module(modname, **kwds):
[], eci,
outputfilename=str(dirname/modname),
standalone=False)
- if sys.platform == 'win32':
- pydname = soname.new(purebasename=modname, ext='.pyd')
- else:
- pydname = soname.new(purebasename=modname, ext='.so')
+ from pypy.module.imp.importing import get_so_extension
+ pydname = soname.new(purebasename=modname, ext=get_so_extension(space))
soname.rename(pydname)
return str(pydname)
@@ -153,7 +151,7 @@ class AppTestCpythonExtensionBase(LeakCheckingTest):
kwds["link_files"] = [str(api_library + '.so')]
if sys.platform == 'linux2':
kwds["compile_extra"]=["-Werror=implicit-function-declaration"]
- return compile_module(name, **kwds)
+ return compile_module(self.space, name, **kwds)
def import_module(self, name, init=None, body='', load_it=True, filename=None):
diff --git a/pypy/module/cpyext/typeobject.py b/pypy/module/cpyext/typeobject.py
index 1796ebc374..e400a4ccbf 100644
--- a/pypy/module/cpyext/typeobject.py
+++ b/pypy/module/cpyext/typeobject.py
@@ -182,10 +182,10 @@ def tp_new_wrapper(space, self, w_args, w_kwds):
subtype = rffi.cast(PyTypeObjectPtr, make_ref(space, w_subtype))
try:
- obj = generic_cpy_call(space, tp_new, subtype, w_args, w_kwds)
+ w_obj = generic_cpy_call(space, tp_new, subtype, w_args, w_kwds)
finally:
Py_DecRef(space, w_subtype)
- return obj
+ return w_obj
@specialize.memo()
def get_new_method_def(space):
@@ -193,10 +193,14 @@ def get_new_method_def(space):
if state.new_method_def:
return state.new_method_def
from pypy.module.cpyext.modsupport import PyMethodDef
- ptr = lltype.malloc(PyMethodDef, flavor="raw", zero=True)
+ ptr = lltype.malloc(PyMethodDef, flavor="raw", zero=True,
+ immortal=True)
ptr.c_ml_name = rffi.str2charp("__new__")
+ lltype.render_immortal(ptr.c_ml_name)
rffi.setintfield(ptr, 'c_ml_flags', METH_VARARGS | METH_KEYWORDS)
- ptr.c_ml_doc = rffi.str2charp("T.__new__(S, ...) -> a new object with type S, a subtype of T")
+ ptr.c_ml_doc = rffi.str2charp(
+ "T.__new__(S, ...) -> a new object with type S, a subtype of T")
+ lltype.render_immortal(ptr.c_ml_doc)
state.new_method_def = ptr
return ptr
@@ -429,6 +433,12 @@ def type_attach(space, py_obj, w_type):
finish_type_1(space, pto)
finish_type_2(space, pto, w_type)
+ if space.type(w_type).is_cpytype():
+ # XXX Types with a C metatype are never freed, try to see why...
+ render_immortal(pto, w_type)
+ lltype.render_immortal(pto)
+ lltype.render_immortal(pto.c_tp_name)
+
pto.c_tp_basicsize = rffi.sizeof(typedescr.basestruct)
if pto.c_tp_base:
if pto.c_tp_base.c_tp_basicsize > pto.c_tp_basicsize:
@@ -534,12 +544,25 @@ def type_realize(space, py_obj):
w_obj.ready()
finish_type_2(space, py_type, w_obj)
+ render_immortal(py_type, w_obj)
state = space.fromcache(RefcountState)
state.non_heaptypes_w.append(w_obj)
return w_obj
+def render_immortal(py_type, w_obj):
+ lltype.render_immortal(py_type.c_tp_bases)
+ lltype.render_immortal(py_type.c_tp_mro)
+
+ assert isinstance(w_obj, W_TypeObject)
+ if w_obj.is_cpytype():
+ lltype.render_immortal(py_type.c_tp_dict)
+ else:
+ lltype.render_immortal(py_type.c_tp_name)
+ if not w_obj.is_cpytype() and w_obj.is_heaptype():
+ lltype.render_immortal(py_type)
+
def finish_type_1(space, pto):
"""
Sets up tp_bases, necessary before creating the interpreter type.
diff --git a/pypy/module/gc/__init__.py b/pypy/module/gc/__init__.py
index e76bbfaad3..e003d7b683 100644
--- a/pypy/module/gc/__init__.py
+++ b/pypy/module/gc/__init__.py
@@ -29,6 +29,7 @@ class Module(MixedModule):
'get_referents': 'referents.get_referents',
'get_referrers': 'referents.get_referrers',
'_dump_rpy_heap': 'referents._dump_rpy_heap',
+ 'get_typeids_z': 'referents.get_typeids_z',
'GcRef': 'referents.W_GcRef',
})
MixedModule.__init__(self, space, w_name)
diff --git a/pypy/module/gc/app_referents.py b/pypy/module/gc/app_referents.py
index 461cb989ac..b97a5baa05 100644
--- a/pypy/module/gc/app_referents.py
+++ b/pypy/module/gc/app_referents.py
@@ -14,11 +14,25 @@ def dump_rpy_heap(file):
and [addr1]..[addrn] are addresses of other objects that this object
points to. The full dump is a list of such objects, with a marker
[0][0][0][-1] inserted after all GC roots, before all non-roots.
+
+ If the argument is a filename and the 'zlib' module is available,
+ we also write a 'typeids.txt' in the same directory, if none exists.
"""
if isinstance(file, str):
f = open(file, 'wb')
gc._dump_rpy_heap(f.fileno())
f.close()
+ try:
+ import zlib, os
+ except ImportError:
+ pass
+ else:
+ filename2 = os.path.join(os.path.dirname(file), 'typeids.txt')
+ if not os.path.exists(filename2):
+ data = zlib.decompress(gc.get_typeids_z())
+ f = open(filename2, 'wb')
+ f.write(data)
+ f.close()
else:
if isinstance(file, int):
fd = file
diff --git a/pypy/module/gc/interp_gc.py b/pypy/module/gc/interp_gc.py
index 541316c494..a22dd1e644 100644
--- a/pypy/module/gc/interp_gc.py
+++ b/pypy/module/gc/interp_gc.py
@@ -10,6 +10,10 @@ def collect(space):
from pypy.objspace.std.typeobject import MethodCache
cache = space.fromcache(MethodCache)
cache.clear()
+ if space.config.objspace.std.withmapdict:
+ from pypy.objspace.std.mapdict import IndexCache
+ cache = space.fromcache(IndexCache)
+ cache.clear()
rgc.collect()
return space.wrap(0)
diff --git a/pypy/module/gc/referents.py b/pypy/module/gc/referents.py
index 0aba55771b..8233419611 100644
--- a/pypy/module/gc/referents.py
+++ b/pypy/module/gc/referents.py
@@ -177,3 +177,9 @@ def _dump_rpy_heap(space, fd):
if not ok:
raise missing_operation(space)
_dump_rpy_heap.unwrap_spec = [ObjSpace, int]
+
+def get_typeids_z(space):
+ a = rgc.get_typeids_z()
+ s = ''.join([a[i] for i in range(len(a))])
+ return space.wrap(s)
+get_typeids_z.unwrap_spec = [ObjSpace]
diff --git a/pypy/module/gc/test/test_gc.py b/pypy/module/gc/test/test_gc.py
index dcca7a853f..295fcf1813 100644
--- a/pypy/module/gc/test/test_gc.py
+++ b/pypy/module/gc/test/test_gc.py
@@ -117,6 +117,33 @@ class AppTestGcMethodCache(object):
pass
C().f() # Fill the method cache
rlist.append(weakref.ref(C))
+ for i in range(10):
+ f()
+ gc.collect() # the classes C should all go away here
+ # the last class won't go in mapdict, as long as the code object of f
+ # is around
+ rlist.pop()
+ for r in rlist:
+ assert r() is None
+
+class AppTestGcMapDictIndexCache(AppTestGcMethodCache):
+ def setup_class(cls):
+ cls.space = gettestobjspace(**{"objspace.std.withmethodcache": True,
+ "objspace.std.withmapdict": True})
+
+
+ def test_clear_index_cache(self):
+ import gc, weakref
+ rlist = []
+ def f():
+ class C(object):
+ def f(self):
+ pass
+ c = C()
+ c.x = 1
+ getattr(c, "x") # fill the index cache without using the local cache
+ getattr(c, "x")
+ rlist.append(weakref.ref(C))
for i in range(5):
f()
gc.collect() # the classes C should all go away here
diff --git a/pypy/module/imp/importing.py b/pypy/module/imp/importing.py
index b69c621e42..bb0314fb50 100644
--- a/pypy/module/imp/importing.py
+++ b/pypy/module/imp/importing.py
@@ -12,7 +12,7 @@ from pypy.interpreter.eval import Code
from pypy.rlib import streamio, jit
from pypy.rlib.streamio import StreamErrors
from pypy.rlib.rarithmetic import intmask
-from pypy.rlib.objectmodel import we_are_translated
+from pypy.rlib.objectmodel import we_are_translated, specialize
SEARCH_ERROR = 0
PY_SOURCE = 1
@@ -25,10 +25,26 @@ PY_FROZEN = 7
# PY_CODERESOURCE = 8
IMP_HOOK = 9
-if sys.platform.startswith('win'):
- so_extension = ".pyd"
+if sys.platform == 'win32':
+ SO = ".pyd"
else:
- so_extension = ".so"
+ SO = ".so"
+DEFAULT_SOABI = 'pypy-14'
+
+@specialize.memo()
+def get_so_extension(space):
+ if space.config.objspace.soabi is not None:
+ soabi = space.config.objspace.soabi
+ else:
+ soabi = DEFAULT_SOABI
+
+ if not soabi:
+ return SO
+
+ if not space.config.translating:
+ soabi += 'i'
+
+ return '.' + soabi + SO
def find_modtype(space, filepart):
"""Check which kind of module to import for the given filepart,
@@ -53,6 +69,7 @@ def find_modtype(space, filepart):
return PY_COMPILED, ".pyc", "rb"
if space.config.objspace.usemodules.cpyext:
+ so_extension = get_so_extension(space)
pydfile = filepart + so_extension
if os.path.exists(pydfile) and case_ok(pydfile):
return C_EXTENSION, so_extension, "rb"
diff --git a/pypy/module/imp/interp_imp.py b/pypy/module/imp/interp_imp.py
index e94453b1dc..fea66141b4 100644
--- a/pypy/module/imp/interp_imp.py
+++ b/pypy/module/imp/interp_imp.py
@@ -8,10 +8,16 @@ import struct
def get_suffixes(space):
w = space.wrap
- return space.newlist([
+ suffixes_w = []
+ if space.config.objspace.usemodules.cpyext:
+ suffixes_w.append(
+ space.newtuple([w(importing.get_so_extension(space)),
+ w('rb'), w(importing.C_EXTENSION)]))
+ suffixes_w.extend([
space.newtuple([w('.py'), w('U'), w(importing.PY_SOURCE)]),
space.newtuple([w('.pyc'), w('rb'), w(importing.PY_COMPILED)]),
])
+ return space.newlist(suffixes_w)
def get_magic(space):
x = importing.get_pyc_magic(space)
diff --git a/pypy/module/imp/test/test_app.py b/pypy/module/imp/test/test_app.py
index e96588fbf2..49b3ad5f0f 100644
--- a/pypy/module/imp/test/test_app.py
+++ b/pypy/module/imp/test/test_app.py
@@ -47,6 +47,9 @@ class AppTestImpModule:
elif mode == self.imp.PY_COMPILED:
assert suffix in ('.pyc', '.pyo')
assert type == 'rb'
+ elif mode == self.imp.C_EXTENSION:
+ assert suffix.endswith(('.pyd', '.so'))
+ assert type == 'rb'
def test_obscure_functions(self):
diff --git a/pypy/module/imp/test/test_import.py b/pypy/module/imp/test/test_import.py
index 056fe9caf9..5a27ab84df 100644
--- a/pypy/module/imp/test/test_import.py
+++ b/pypy/module/imp/test/test_import.py
@@ -473,6 +473,17 @@ class AppTestImport:
except ImportError:
pass
+class TestAbi:
+ def test_abi_tag(self):
+ space1 = gettestobjspace(soabi='TEST')
+ space2 = gettestobjspace(soabi='')
+ if sys.platform == 'win32':
+ assert importing.get_so_extension(space1) == '.TESTi.pyd'
+ assert importing.get_so_extension(space2) == '.pyd'
+ else:
+ assert importing.get_so_extension(space1) == '.TESTi.so'
+ assert importing.get_so_extension(space2) == '.so'
+
def _getlong(data):
x = marshal.dumps(data)
return x[-4:]
diff --git a/pypy/module/posix/interp_posix.py b/pypy/module/posix/interp_posix.py
index 47c98ad319..042e20f16f 100644
--- a/pypy/module/posix/interp_posix.py
+++ b/pypy/module/posix/interp_posix.py
@@ -454,7 +454,8 @@ class State:
self.w_environ = space.newdict()
if _WIN:
self.cryptProviderPtr = lltype.malloc(
- rffi.CArray(HCRYPTPROV), 1, zero=True, flavor='raw')
+ rffi.CArray(HCRYPTPROV), 1, zero=True,
+ flavor='raw', immortal=True)
def startup(self, space):
_convertenviron(space, self.w_environ)
def _freeze_(self):
diff --git a/pypy/module/pypyjit/interp_jit.py b/pypy/module/pypyjit/interp_jit.py
index e2a71a04b4..77057a1879 100644
--- a/pypy/module/pypyjit/interp_jit.py
+++ b/pypy/module/pypyjit/interp_jit.py
@@ -6,6 +6,7 @@ This is transformed to become a JIT by code elsewhere: pypy/jit/*
from pypy.tool.pairtype import extendabletype
from pypy.rlib.rarithmetic import r_uint, intmask
from pypy.rlib.jit import JitDriver, hint, we_are_jitted, dont_look_inside
+from pypy.rlib.jit import current_trace_length
import pypy.interpreter.pyopcode # for side-effects
from pypy.interpreter.error import OperationError, operationerrfmt
from pypy.interpreter.gateway import ObjSpace, Arguments, W_Root
@@ -80,9 +81,22 @@ class __extend__(PyFrame):
def jump_absolute(self, jumpto, _, ec=None):
if we_are_jitted():
+ # Normally, the tick counter is decremented by 100 for every
+ # Python opcode. Here, to better support JIT compilation of
+ # small loops, we decrement it by a possibly smaller constant.
+ # We get the maximum 100 when the (unoptimized) trace length
+ # is at least 3200 (a bit randomly).
+ trace_length = r_uint(current_trace_length())
+ decr_by = trace_length // 32
+ if decr_by < 1:
+ decr_by = 1
+ elif decr_by > 100: # also if current_trace_length() returned -1
+ decr_by = 100
+ #
self.last_instr = intmask(jumpto)
- ec.bytecode_trace(self)
+ ec.bytecode_trace(self, intmask(decr_by))
jumpto = r_uint(self.last_instr)
+ #
pypyjitdriver.can_enter_jit(frame=self, ec=ec, next_instr=jumpto,
pycode=self.getcode())
return jumpto
diff --git a/pypy/module/pypyjit/policy.py b/pypy/module/pypyjit/policy.py
index 20a6452b2a..d80893476c 100644
--- a/pypy/module/pypyjit/policy.py
+++ b/pypy/module/pypyjit/policy.py
@@ -6,7 +6,8 @@ class PyPyJitPolicy(JitPolicy):
if (modname == '__builtin__.operation' or
modname == '__builtin__.abstractinst' or
modname == '__builtin__.interp_classobj' or
- modname == '__builtin__.functional'):
+ modname == '__builtin__.functional' or
+ modname == '__builtin__.descriptor'):
return True
if '.' in modname:
modname, _ = modname.split('.', 1)
@@ -19,7 +20,7 @@ class PyPyJitPolicy(JitPolicy):
# this function should never actually return True directly
# but instead call the base implementation
mod = func.__module__ or '?'
-
+
if mod.startswith('pypy.objspace.'):
# gc_id operation
if func.__name__ == 'id__ANY':
@@ -36,5 +37,5 @@ class PyPyJitPolicy(JitPolicy):
modname = mod[len('pypy.module.'):]
if not self.look_inside_pypy_module(modname):
return False
-
+
return True
diff --git a/pypy/module/pypyjit/test/test_policy.py b/pypy/module/pypyjit/test/test_policy.py
index 02ac51ae06..1f781e10de 100644
--- a/pypy/module/pypyjit/test/test_policy.py
+++ b/pypy/module/pypyjit/test/test_policy.py
@@ -12,7 +12,7 @@ def test_bigint():
def test_rlocale():
from pypy.rlib.rlocale import setlocale
- assert not pypypolicy.look_inside_function(setlocale)
+ assert not pypypolicy.look_inside_function(setlocale)
def test_geninterp():
d = {'_geninterp_': True}
@@ -28,6 +28,10 @@ def test_pyparser():
from pypy.interpreter.pyparser import parser
assert not pypypolicy.look_inside_function(parser.Grammar.__init__.im_func)
+def test_property():
+ from pypy.module.__builtin__.descriptor import W_Property
+ assert pypypolicy.look_inside_function(W_Property.get.im_func)
+
def test_pypy_module():
from pypy.module._random.interp_random import W_Random
assert not pypypolicy.look_inside_function(W_Random.random)
@@ -35,6 +39,7 @@ def test_pypy_module():
assert pypypolicy.look_inside_pypy_module('__builtin__.operation')
assert pypypolicy.look_inside_pypy_module('__builtin__.abstractinst')
assert pypypolicy.look_inside_pypy_module('__builtin__.functional')
+ assert pypypolicy.look_inside_pypy_module('__builtin__.descriptor')
assert pypypolicy.look_inside_pypy_module('exceptions.interp_exceptions')
for modname in 'pypyjit', 'signal', 'micronumpy', 'math', 'imp':
assert pypypolicy.look_inside_pypy_module(modname)
@@ -42,4 +47,3 @@ def test_pypy_module():
def test_see_jit_module():
assert pypypolicy.look_inside_pypy_module('pypyjit.interp_jit')
-
diff --git a/pypy/module/pypyjit/test/test_pypy_c.py b/pypy/module/pypyjit/test/test_pypy_c.py
index 43550aa6b6..c9be155293 100644
--- a/pypy/module/pypyjit/test/test_pypy_c.py
+++ b/pypy/module/pypyjit/test/test_pypy_c.py
@@ -422,10 +422,75 @@ class PyPyCJITTests(object):
([1000], 49500),
([10000], 495000),
([100000], 4950000))
- assert len(self.loops) == 2
+ assert len(self.loops) == 3
op, = self.get_by_bytecode("CALL_FUNCTION_KW")
# XXX a bit too many guards, but better than before
- assert len(op.get_opnames("guard")) <= 10
+ assert len(op.get_opnames("guard")) <= 12
+
+ def test_stararg_virtual(self):
+ self.run_source('''
+ d = {}
+
+ def g(*args):
+ return len(args)
+ def h(a, b, c):
+ return c
+
+ def main(x):
+ s = 0
+ for i in range(x):
+ l = [i, x, 2]
+ s += g(*l)
+ s += h(*l)
+ s += g(i, x, 2)
+ for i in range(x):
+ l = [x, 2]
+ s += g(i, *l)
+ s += h(i, *l)
+ return s
+ ''', 100000, ([100], 1300),
+ ([1000], 13000),
+ ([10000], 130000),
+ ([100000], 1300000))
+ assert len(self.loops) == 2
+ ops = self.get_by_bytecode("CALL_FUNCTION_VAR")
+ assert len(ops) == 4
+ for op in ops:
+ assert len(op.get_opnames("new")) == 0
+ assert len(op.get_opnames("call_may_force")) == 0
+
+ ops = self.get_by_bytecode("CALL_FUNCTION")
+ for op in ops:
+ assert len(op.get_opnames("new")) == 0
+ assert len(op.get_opnames("call_may_force")) == 0
+
+ def test_stararg(self):
+ self.run_source('''
+ d = {}
+
+ def g(*args):
+ return args[-1]
+ def h(*args):
+ return len(args)
+
+ def main(x):
+ s = 0
+ l = []
+ i = 0
+ while i < x:
+ l.append(1)
+ s += g(*l)
+ i = h(*l)
+ return s
+ ''', 100000, ([100], 100),
+ ([1000], 1000),
+ ([2000], 2000),
+ ([4000], 4000))
+ assert len(self.loops) == 1
+ ops = self.get_by_bytecode("CALL_FUNCTION_VAR")
+ for op in ops:
+ assert len(op.get_opnames("new_with_vtable")) == 0
+ assert len(op.get_opnames("call_may_force")) == 0
def test_virtual_instance(self):
self.run_source('''
diff --git a/pypy/module/rctime/interp_time.py b/pypy/module/rctime/interp_time.py
index 9a06bef3f9..dbb51df6d8 100644
--- a/pypy/module/rctime/interp_time.py
+++ b/pypy/module/rctime/interp_time.py
@@ -69,7 +69,7 @@ if _POSIX:
CLOCKS_PER_SEC = cConfig.CLOCKS_PER_SEC
clock_t = cConfig.clock_t
tm = cConfig.tm
-glob_buf = lltype.malloc(tm, flavor='raw', zero=True)
+glob_buf = lltype.malloc(tm, flavor='raw', zero=True, immortal=True)
if cConfig.has_gettimeofday:
c_gettimeofday = external('gettimeofday', [rffi.VOIDP, rffi.VOIDP], rffi.INT)
diff --git a/pypy/module/signal/__init__.py b/pypy/module/signal/__init__.py
index 613de46930..a861feddff 100644
--- a/pypy/module/signal/__init__.py
+++ b/pypy/module/signal/__init__.py
@@ -34,9 +34,7 @@ class Module(MixedModule):
MixedModule.__init__(self, space, *args)
# add the signal-checking callback as an action on the space
space.check_signal_action = interp_signal.CheckSignalAction(space)
- space.actionflag.register_action(space.check_signal_action)
- # use the C-level pypysig_occurred variable as the action flag
- # (the result is that the C-level signal handler will directly
- # set the flag for the CheckSignalAction)
+ space.actionflag.register_periodic_action(space.check_signal_action,
+ use_bytecode_counter=False)
space.actionflag.__class__ = interp_signal.SignalActionFlag
# xxx yes I know the previous line is a hack
diff --git a/pypy/module/signal/interp_signal.py b/pypy/module/signal/interp_signal.py
index 26efaecfb2..73b1904075 100644
--- a/pypy/module/signal/interp_signal.py
+++ b/pypy/module/signal/interp_signal.py
@@ -1,6 +1,7 @@
from pypy.interpreter.error import OperationError
from pypy.interpreter.baseobjspace import W_Root, ObjSpace
from pypy.interpreter.executioncontext import AsyncAction, AbstractActionFlag
+from pypy.interpreter.executioncontext import PeriodicAsyncAction
import signal as cpy_signal
from pypy.rpython.lltypesystem import lltype, rffi
from pypy.translator.tool.cbuild import ExternalCompilationInfo
@@ -52,19 +53,29 @@ c_pause = external('pause', [], rffi.INT)
class SignalActionFlag(AbstractActionFlag):
- def get(self):
+ # This class uses the C-level pypysig_counter variable as the tick
+ # counter. The C-level signal handler will reset it to -1 whenever
+ # a signal is received.
+
+ def get_ticker(self):
p = pypysig_getaddr_occurred()
return p.c_value
- def set(self, value):
+
+ def reset_ticker(self, value):
p = pypysig_getaddr_occurred()
p.c_value = value
+ def decrement_ticker(self, by):
+ p = pypysig_getaddr_occurred()
+ value = p.c_value
+ if self.has_bytecode_counter: # this 'if' is constant-folded
+ value -= by
+ p.c_value = value
+ return value
-class CheckSignalAction(AsyncAction):
- """An action that is automatically invoked when a signal is received."""
- # The C-level signal handler sets the bit 30 of pypysig_occurred:
- bitmask = 1 << 30
+class CheckSignalAction(PeriodicAsyncAction):
+ """An action that is automatically invoked when a signal is received."""
def __init__(self, space):
AsyncAction.__init__(self, space)
@@ -73,7 +84,6 @@ class CheckSignalAction(AsyncAction):
# need a helper action in case signals arrive in a non-main thread
self.pending_signals = {}
self.reissue_signal_action = ReissueSignalAction(space)
- space.actionflag.register_action(self.reissue_signal_action)
else:
self.reissue_signal_action = None
diff --git a/pypy/module/signal/test/test_signal.py b/pypy/module/signal/test/test_signal.py
index 10c29a531f..729c404a8b 100644
--- a/pypy/module/signal/test/test_signal.py
+++ b/pypy/module/signal/test/test_signal.py
@@ -1,6 +1,38 @@
import os, py
+import signal as cpy_signal
from pypy.conftest import gettestobjspace
+
+class TestCheckSignals:
+
+ def setup_class(cls):
+ if not hasattr(os, 'kill') or not hasattr(os, 'getpid'):
+ py.test.skip("requires os.kill() and os.getpid()")
+ cls.space = gettestobjspace(usemodules=['signal'])
+
+ def test_checksignals(self):
+ space = self.space
+ w_received = space.appexec([], """():
+ import signal
+ received = []
+ def myhandler(signum, frame):
+ received.append(signum)
+ signal.signal(signal.SIGUSR1, myhandler)
+ return received""")
+ #
+ assert not space.is_true(w_received)
+ #
+ # send the signal now
+ os.kill(os.getpid(), cpy_signal.SIGUSR1)
+ #
+ # myhandler() should not be immediately called
+ assert not space.is_true(w_received)
+ #
+ # calling ec.checksignals() should call it
+ space.getexecutioncontext().checksignals()
+ assert space.is_true(w_received)
+
+
class AppTestSignal:
def setup_class(cls):
@@ -24,18 +56,12 @@ class AppTestSignal:
signal.signal(signal.SIGUSR1, myhandler)
posix.kill(posix.getpid(), signal.SIGUSR1)
- for i in range(10000):
- # wait a bit for the signal to be delivered to the handler
- if received:
- break
+ # the signal should be delivered to the handler immediately
assert received == [signal.SIGUSR1]
del received[:]
posix.kill(posix.getpid(), signal.SIGUSR1)
- for i in range(10000):
- # wait a bit for the signal to be delivered to the handler
- if received:
- break
+ # the signal should be delivered to the handler immediately
assert received == [signal.SIGUSR1]
del received[:]
diff --git a/pypy/module/sys/__init__.py b/pypy/module/sys/__init__.py
index 7e3b8ab9ba..492ad1560e 100644
--- a/pypy/module/sys/__init__.py
+++ b/pypy/module/sys/__init__.py
@@ -10,7 +10,6 @@ class Module(MixedModule):
if space.config.translating:
del self.__class__.interpleveldefs['pypy_getudir']
super(Module, self).__init__(space, w_name)
- self.checkinterval = 100
self.recursionlimit = 100
self.w_default_encoder = None
self.defaultencoding = "ascii"
diff --git a/pypy/module/sys/version.py b/pypy/module/sys/version.py
index 4b6bd08fd4..6d80545fee 100644
--- a/pypy/module/sys/version.py
+++ b/pypy/module/sys/version.py
@@ -8,7 +8,7 @@ import os
CPYTHON_VERSION = (2, 5, 2, "beta", 42) #XXX # sync patchlevel.h
CPYTHON_API_VERSION = 1012 #XXX # sync with include/modsupport.h
-PYPY_VERSION = (1, 3, 0, "beta", '?') #XXX # sync patchlevel.h
+PYPY_VERSION = (1, 4, 0, "beta", '?') #XXX # sync patchlevel.h
# the last item is replaced by the svn revision ^^^
TRIM_URL_UP_TO = 'svn/pypy/'
diff --git a/pypy/module/sys/vm.py b/pypy/module/sys/vm.py
index 154cce149e..a21324aac0 100644
--- a/pypy/module/sys/vm.py
+++ b/pypy/module/sys/vm.py
@@ -67,7 +67,7 @@ def getrecursionlimit(space):
def setcheckinterval(space, interval):
"""Tell the Python interpreter to check for asynchronous events every
n instructions. This also affects how often thread switches occur."""
- space.actionflag.setcheckinterval(space, interval)
+ space.actionflag.setcheckinterval(interval)
setcheckinterval.unwrap_spec = [ObjSpace, int]
def getcheckinterval(space):
@@ -77,7 +77,7 @@ def getcheckinterval(space):
# return 0. The idea is that according to the CPython docs, <= 0
# means "check every virtual instruction, maximizing responsiveness
# as well as overhead".
- result = space.sys.checkinterval
+ result = space.actionflag.getcheckinterval()
if result <= 1:
result = 0
return space.wrap(result)
diff --git a/pypy/module/thread/gil.py b/pypy/module/thread/gil.py
index 87fee7de2c..500ca17058 100644
--- a/pypy/module/thread/gil.py
+++ b/pypy/module/thread/gil.py
@@ -20,7 +20,8 @@ class GILThreadLocals(OSThreadLocals):
def initialize(self, space):
# add the GIL-releasing callback as an action on the space
- space.actionflag.register_action(GILReleaseAction(space))
+ space.actionflag.register_periodic_action(GILReleaseAction(space),
+ use_bytecode_counter=True)
def setup_threads(self, space):
"""Enable threads in the object space, if they haven't already been."""
@@ -44,7 +45,6 @@ class GILThreadLocals(OSThreadLocals):
# test_compile_lock. As a workaround, we repatch these global
# fields systematically.
spacestate.ll_GIL = self.ll_GIL
- spacestate.actionflag = space.actionflag
invoke_around_extcall(before_external_call, after_external_call)
return result
@@ -68,18 +68,17 @@ class SpaceState:
def _freeze_(self):
self.ll_GIL = thread.null_ll_lock
- self.actionflag = None
- self.set_actionflag_bit_after_thread_switch = 0
+ self.action_after_thread_switch = None
+ # ^^^ set by AsyncAction.fire_after_thread_switch()
return False
def after_thread_switch(self):
# this is support logic for the signal module, to help it deliver
# signals to the main thread.
- actionflag = self.actionflag
- if actionflag is not None:
- flag = actionflag.get()
- flag |= self.set_actionflag_bit_after_thread_switch
- actionflag.set(flag)
+ action = self.action_after_thread_switch
+ if action is not None:
+ self.action_after_thread_switch = None
+ action.fire()
spacestate = SpaceState()
spacestate._freeze_()
diff --git a/pypy/module/thread/test/test_gil.py b/pypy/module/thread/test/test_gil.py
index b2dacf0a06..03db6e7f92 100644
--- a/pypy/module/thread/test/test_gil.py
+++ b/pypy/module/thread/test/test_gil.py
@@ -8,7 +8,7 @@ class FakeEC(object):
pass
class FakeActionFlag(object):
- def register_action(self, action):
+ def register_periodic_action(self, action, use_bytecode_counter):
pass
def get(self):
return 0