[pypy-svn] r79389 - in pypy/branch/jitypes2: . lib-python/modified-2.5.2/distutils lib_pypy/_ctypes lib_pypy/ctypes_config_cache/test pypy pypy/annotation pypy/config pypy/doc pypy/doc/config pypy/interpreter pypy/interpreter/test pypy/jit/backend/llsupport pypy/jit/backend/llsupport/test pypy/jit/backend/test pypy/jit/backend/x86 pypy/jit/codewriter pypy/jit/codewriter/test pypy/jit/metainterp pypy/jit/metainterp/optimizeopt pypy/jit/metainterp/test pypy/jit/tool pypy/jit/tool/test pypy/module/__pypy__ pypy/module/_rawffi/test pypy/module/_stackless/test pypy/module/array pypy/module/array/benchmark pypy/module/array/test pypy/module/cpyext pypy/module/cpyext/test pypy/module/gc pypy/module/gc/test pypy/module/imp pypy/module/imp/test pypy/module/posix pypy/module/pypyjit pypy/module/pypyjit/test pypy/module/rctime pypy/module/sys pypy/module/sys/test pypy/objspace/flow pypy/objspace/std pypy/objspace/std/test pypy/rlib pypy/rlib/test pypy/rpython pypy/rpython/lltypesystem pypy/rpython/memory pypy/rpython/memory/gc pypy/rpython/memory/gc/test pypy/rpython/memory/gctransform pypy/rpython/memory/test pypy/rpython/test pypy/tool pypy/tool/release pypy/tool/release/test pypy/translator/c pypy/translator/c/gcc pypy/translator/c/gcc/test pypy/translator/c/src pypy/translator/c/test pypy/translator/cli/src pypy/translator/goal pypy/translator/goal/test2 pypy/translator/platform
antocuni at codespeak.net
antocuni at codespeak.net
Tue Nov 23 13:26:41 CET 2010
Author: antocuni
Date: Tue Nov 23 13:26:19 2010
New Revision: 79389
Added:
pypy/branch/jitypes2/pypy/doc/config/objspace.soabi.txt
- copied unchanged from r79388, pypy/trunk/pypy/doc/config/objspace.soabi.txt
pypy/branch/jitypes2/pypy/doc/config/objspace.translationmodules.txt
- copied unchanged from r79388, pypy/trunk/pypy/doc/config/objspace.translationmodules.txt
pypy/branch/jitypes2/pypy/doc/release-1.4.0beta.txt
- copied unchanged from r79388, pypy/trunk/pypy/doc/release-1.4.0beta.txt
pypy/branch/jitypes2/pypy/jit/tool/log-template.gnumeric
- copied unchanged from r79388, pypy/trunk/pypy/jit/tool/log-template.gnumeric
pypy/branch/jitypes2/pypy/jit/tool/log2gnumeric.py
- copied unchanged from r79388, pypy/trunk/pypy/jit/tool/log2gnumeric.py
pypy/branch/jitypes2/pypy/jit/tool/loopcounter.py
- copied unchanged from r79388, pypy/trunk/pypy/jit/tool/loopcounter.py
pypy/branch/jitypes2/pypy/jit/tool/test/test_loopcounter.py
- copied unchanged from r79388, pypy/trunk/pypy/jit/tool/test/test_loopcounter.py
pypy/branch/jitypes2/pypy/jit/tool/test/test_oparser.py
- copied unchanged from r79388, pypy/trunk/pypy/jit/tool/test/test_oparser.py
pypy/branch/jitypes2/pypy/module/_stackless/test/conftest.py
- copied unchanged from r79388, pypy/trunk/pypy/module/_stackless/test/conftest.py
pypy/branch/jitypes2/pypy/tool/gcdump.py
- copied unchanged from r79388, pypy/trunk/pypy/tool/gcdump.py
pypy/branch/jitypes2/pypy/translator/c/src/asm_gcc_x86_64.h
- copied unchanged from r79388, pypy/trunk/pypy/translator/c/src/asm_gcc_x86_64.h
Removed:
pypy/branch/jitypes2/pypy/jit/metainterp/test/test_oparser.py
Modified:
pypy/branch/jitypes2/ (props changed)
pypy/branch/jitypes2/lib-python/modified-2.5.2/distutils/sysconfig_pypy.py
pypy/branch/jitypes2/lib_pypy/_ctypes/function.py
pypy/branch/jitypes2/lib_pypy/ctypes_config_cache/test/test_cache.py
pypy/branch/jitypes2/pypy/ (props changed)
pypy/branch/jitypes2/pypy/annotation/bookkeeper.py
pypy/branch/jitypes2/pypy/annotation/builtin.py
pypy/branch/jitypes2/pypy/config/pypyoption.py
pypy/branch/jitypes2/pypy/config/translationoption.py
pypy/branch/jitypes2/pypy/conftest.py
pypy/branch/jitypes2/pypy/doc/release-1.4.0.txt
pypy/branch/jitypes2/pypy/interpreter/argument.py
pypy/branch/jitypes2/pypy/interpreter/test/test_argument.py
pypy/branch/jitypes2/pypy/jit/backend/llsupport/descr.py
pypy/branch/jitypes2/pypy/jit/backend/llsupport/gc.py
pypy/branch/jitypes2/pypy/jit/backend/llsupport/test/test_descr.py
pypy/branch/jitypes2/pypy/jit/backend/llsupport/test/test_gc.py
pypy/branch/jitypes2/pypy/jit/backend/test/runner_test.py
pypy/branch/jitypes2/pypy/jit/backend/x86/assembler.py
pypy/branch/jitypes2/pypy/jit/codewriter/assembler.py
pypy/branch/jitypes2/pypy/jit/codewriter/call.py
pypy/branch/jitypes2/pypy/jit/codewriter/codewriter.py
pypy/branch/jitypes2/pypy/jit/codewriter/effectinfo.py
pypy/branch/jitypes2/pypy/jit/codewriter/jtransform.py
pypy/branch/jitypes2/pypy/jit/codewriter/test/test_jtransform.py
pypy/branch/jitypes2/pypy/jit/metainterp/compile.py
pypy/branch/jitypes2/pypy/jit/metainterp/optimizeopt/optimizer.py (contents, props changed)
pypy/branch/jitypes2/pypy/jit/metainterp/optimizeopt/string.py
pypy/branch/jitypes2/pypy/jit/metainterp/pyjitpl.py
pypy/branch/jitypes2/pypy/jit/metainterp/resoperation.py
pypy/branch/jitypes2/pypy/jit/metainterp/resume.py
pypy/branch/jitypes2/pypy/jit/metainterp/test/test_compile.py
pypy/branch/jitypes2/pypy/jit/metainterp/test/test_exception.py
pypy/branch/jitypes2/pypy/jit/metainterp/test/test_optimizeopt.py
pypy/branch/jitypes2/pypy/jit/metainterp/test/test_recursive.py
pypy/branch/jitypes2/pypy/jit/metainterp/test/test_resoperation.py
pypy/branch/jitypes2/pypy/jit/metainterp/test/test_resume.py
pypy/branch/jitypes2/pypy/jit/metainterp/test/test_virtualref.py
pypy/branch/jitypes2/pypy/jit/metainterp/test/test_ztranslation.py
pypy/branch/jitypes2/pypy/jit/metainterp/virtualizable.py
pypy/branch/jitypes2/pypy/jit/metainterp/warmspot.py
pypy/branch/jitypes2/pypy/jit/tool/pypytrace-mode.el
pypy/branch/jitypes2/pypy/module/__pypy__/__init__.py
pypy/branch/jitypes2/pypy/module/__pypy__/interp_magic.py
pypy/branch/jitypes2/pypy/module/_rawffi/test/test__rawffi.py
pypy/branch/jitypes2/pypy/module/_rawffi/test/test_nested.py
pypy/branch/jitypes2/pypy/module/array/benchmark/Makefile (props changed)
pypy/branch/jitypes2/pypy/module/array/benchmark/intimg.c (props changed)
pypy/branch/jitypes2/pypy/module/array/benchmark/intimgtst.c (props changed)
pypy/branch/jitypes2/pypy/module/array/benchmark/intimgtst.py (props changed)
pypy/branch/jitypes2/pypy/module/array/benchmark/loop.c (props changed)
pypy/branch/jitypes2/pypy/module/array/benchmark/sum.c (props changed)
pypy/branch/jitypes2/pypy/module/array/benchmark/sumtst.c (props changed)
pypy/branch/jitypes2/pypy/module/array/benchmark/sumtst.py (props changed)
pypy/branch/jitypes2/pypy/module/array/interp_array.py
pypy/branch/jitypes2/pypy/module/array/test/test_array_old.py (props changed)
pypy/branch/jitypes2/pypy/module/cpyext/api.py
pypy/branch/jitypes2/pypy/module/cpyext/cdatetime.py
pypy/branch/jitypes2/pypy/module/cpyext/presetup.py
pypy/branch/jitypes2/pypy/module/cpyext/pyobject.py
pypy/branch/jitypes2/pypy/module/cpyext/test/test_borrow.py
pypy/branch/jitypes2/pypy/module/cpyext/test/test_cpyext.py
pypy/branch/jitypes2/pypy/module/cpyext/typeobject.py
pypy/branch/jitypes2/pypy/module/gc/__init__.py
pypy/branch/jitypes2/pypy/module/gc/app_referents.py
pypy/branch/jitypes2/pypy/module/gc/interp_gc.py
pypy/branch/jitypes2/pypy/module/gc/referents.py
pypy/branch/jitypes2/pypy/module/gc/test/test_gc.py
pypy/branch/jitypes2/pypy/module/imp/importing.py
pypy/branch/jitypes2/pypy/module/imp/interp_imp.py
pypy/branch/jitypes2/pypy/module/imp/test/test_app.py
pypy/branch/jitypes2/pypy/module/imp/test/test_import.py
pypy/branch/jitypes2/pypy/module/posix/interp_posix.py
pypy/branch/jitypes2/pypy/module/pypyjit/__init__.py
pypy/branch/jitypes2/pypy/module/pypyjit/test/test_pypy_c.py
pypy/branch/jitypes2/pypy/module/rctime/interp_time.py
pypy/branch/jitypes2/pypy/module/sys/state.py
pypy/branch/jitypes2/pypy/module/sys/test/test_initialpath.py
pypy/branch/jitypes2/pypy/objspace/flow/model.py
pypy/branch/jitypes2/pypy/objspace/std/callmethod.py
pypy/branch/jitypes2/pypy/objspace/std/mapdict.py
pypy/branch/jitypes2/pypy/objspace/std/test/test_dictmultiobject.py
pypy/branch/jitypes2/pypy/objspace/std/test/test_mapdict.py
pypy/branch/jitypes2/pypy/rlib/clibffi.py
pypy/branch/jitypes2/pypy/rlib/rerased.py (props changed)
pypy/branch/jitypes2/pypy/rlib/rgc.py
pypy/branch/jitypes2/pypy/rlib/test/test_rerased.py (props changed)
pypy/branch/jitypes2/pypy/rpython/annlowlevel.py
pypy/branch/jitypes2/pypy/rpython/llinterp.py
pypy/branch/jitypes2/pypy/rpython/lltypesystem/llarena.py
pypy/branch/jitypes2/pypy/rpython/lltypesystem/llmemory.py
pypy/branch/jitypes2/pypy/rpython/lltypesystem/lloperation.py
pypy/branch/jitypes2/pypy/rpython/lltypesystem/lltype.py
pypy/branch/jitypes2/pypy/rpython/lltypesystem/rffi.py
pypy/branch/jitypes2/pypy/rpython/memory/gc/base.py
pypy/branch/jitypes2/pypy/rpython/memory/gc/generation.py
pypy/branch/jitypes2/pypy/rpython/memory/gc/inspector.py
pypy/branch/jitypes2/pypy/rpython/memory/gc/minimark.py
pypy/branch/jitypes2/pypy/rpython/memory/gc/semispace.py
pypy/branch/jitypes2/pypy/rpython/memory/gc/test/test_minimark.py
pypy/branch/jitypes2/pypy/rpython/memory/gctransform/framework.py
pypy/branch/jitypes2/pypy/rpython/memory/support.py
pypy/branch/jitypes2/pypy/rpython/memory/test/test_gc.py
pypy/branch/jitypes2/pypy/rpython/rbuiltin.py
pypy/branch/jitypes2/pypy/rpython/test/test_rpbc.py
pypy/branch/jitypes2/pypy/tool/release/force-builds.py
pypy/branch/jitypes2/pypy/tool/release/make_release.py
pypy/branch/jitypes2/pypy/tool/release/package.py
pypy/branch/jitypes2/pypy/tool/release/test/test_package.py
pypy/branch/jitypes2/pypy/tool/terminal.py
pypy/branch/jitypes2/pypy/translator/c/gcc/test/test_trackgcroot.py
pypy/branch/jitypes2/pypy/translator/c/gcc/trackgcroot.py
pypy/branch/jitypes2/pypy/translator/c/genc.py
pypy/branch/jitypes2/pypy/translator/c/node.py
pypy/branch/jitypes2/pypy/translator/c/src/asm_gcc_x86.h
pypy/branch/jitypes2/pypy/translator/c/src/debug_print.h
pypy/branch/jitypes2/pypy/translator/c/src/g_include.h
pypy/branch/jitypes2/pypy/translator/c/test/test_lltyped.py
pypy/branch/jitypes2/pypy/translator/c/test/test_newgc.py
pypy/branch/jitypes2/pypy/translator/c/test/test_standalone.py
pypy/branch/jitypes2/pypy/translator/cli/src/pypylib.cs
pypy/branch/jitypes2/pypy/translator/goal/app_main.py
pypy/branch/jitypes2/pypy/translator/goal/targetpypystandalone.py
pypy/branch/jitypes2/pypy/translator/goal/test2/test_app_main.py
pypy/branch/jitypes2/pypy/translator/platform/linux.py
pypy/branch/jitypes2/pypy/translator/platform/posix.py
Log:
merge from trunk: svn merge svn+ssh://codespeak.net/svn/pypy/trunk -r78974:HEAD
Modified: pypy/branch/jitypes2/lib-python/modified-2.5.2/distutils/sysconfig_pypy.py
==============================================================================
--- pypy/branch/jitypes2/lib-python/modified-2.5.2/distutils/sysconfig_pypy.py (original)
+++ pypy/branch/jitypes2/lib-python/modified-2.5.2/distutils/sysconfig_pypy.py Tue Nov 23 13:26:19 2010
@@ -3,6 +3,7 @@
import sys
import os
+import imp
from distutils.errors import DistutilsPlatformError
@@ -47,11 +48,17 @@
_config_vars = None
+def _get_so_extension():
+ for ext, mod, typ in imp.get_suffixes():
+ if typ == imp.C_EXTENSION:
+ return ext
+
def _init_posix():
"""Initialize the module as appropriate for POSIX systems."""
g = {}
g['EXE'] = ""
- g['SO'] = ".so"
+ g['SO'] = _get_so_extension() or ".so"
+ g['SOABI'] = g['SO'].rsplit('.')[0]
global _config_vars
_config_vars = g
@@ -61,7 +68,8 @@
"""Initialize the module as appropriate for NT"""
g = {}
g['EXE'] = ".exe"
- g['SO'] = ".pyd"
+ g['SO'] = _get_so_extension() or ".pyd"
+ g['SOABI'] = g['SO'].rsplit('.')[0]
global _config_vars
_config_vars = g
Modified: pypy/branch/jitypes2/lib_pypy/_ctypes/function.py
==============================================================================
--- pypy/branch/jitypes2/lib_pypy/_ctypes/function.py (original)
+++ pypy/branch/jitypes2/lib_pypy/_ctypes/function.py Tue Nov 23 13:26:19 2010
@@ -30,6 +30,7 @@
from_address = cdata_from_address
+
class CFuncPtr(_CData):
__metaclass__ = CFuncPtrType
@@ -174,8 +175,8 @@
restype = self._restype_
funcptr = self._getfuncptr(argtypes, restype, thisarg)
- return funcptr(*args)
- #return funcptr(args[0])
+ #return funcptr(*args)
+ return funcptr(args[0])
#resbuffer = funcptr(*[arg._buffer for _, arg in argsandobjs])
#return self._build_result(restype, resbuffer, argtypes, argsandobjs)
@@ -217,6 +218,8 @@
ffi_argtypes = [self._shape_to_ffi_type(shape) for shape in argshapes]
ffi_restype = self._shape_to_ffi_type(resshape)
self._ptr = cdll.getfunc(self.name, ffi_argtypes, ffi_restype)
+ if len(ffi_argtypes) == 1:
+ self.__class__ = _FuncPtr_1_arg # black magic
return self._ptr
except AttributeError:
if self._flags_ & _rawffi.FUNCFLAG_CDECL:
@@ -393,3 +396,26 @@
self._ptr.free()
self._ptr = None
self._needs_free = False
+
+
+# hack hack
+
+#import ctypes
+class _FuncPtr_1_arg(CFuncPtr):
+
+ def _rollback(self, *args):
+ self.__class__ = CFuncPtr
+ return self(*args)
+
+ def __call__(self, arg0):
+ if self.callable is not None or self._com_index:
+ return self._rollback(arg0)
+
+ #argtypes, argsandobjs = self._wrap_args(argtypes, args)
+
+ argtypes = self._argtypes_
+ restype = self._restype_
+ thisarg = None
+ funcptr = self._getfuncptr(argtypes, restype, thisarg)
+ return funcptr(arg0)
+
Modified: pypy/branch/jitypes2/lib_pypy/ctypes_config_cache/test/test_cache.py
==============================================================================
--- pypy/branch/jitypes2/lib_pypy/ctypes_config_cache/test/test_cache.py (original)
+++ pypy/branch/jitypes2/lib_pypy/ctypes_config_cache/test/test_cache.py Tue Nov 23 13:26:19 2010
@@ -7,9 +7,8 @@
def run(filename, outputname):
filepath = dirpath.join(filename)
- tmpdir2 = udir.ensure('testcache-' + filename, dir=True)
- tmpdir = tmpdir2.ensure('ctypes_config_cache', dir=True)
- tmpdir.join('__init__.py').write('\n')
+ tmpdir = udir.ensure('testcache-' + os.path.splitext(filename)[0],
+ dir=True)
tmpdir.join('dumpcache.py').write(dirpath.join('dumpcache.py').read())
path = sys.path[:]
try:
@@ -23,14 +22,12 @@
assert outputpath.check(exists=1)
modname = os.path.splitext(outputname)[0]
try:
- sys.path.insert(0, str(tmpdir2))
+ sys.path.insert(0, str(tmpdir))
d = {}
- exec "from ctypes_config_cache import %s" % modname in d
- mod = d[modname]
+ execfile(str(outputpath), d)
finally:
sys.path[:] = path
- sys.modules.pop('ctypes_config_cache', None)
- return mod.__dict__
+ return d
def test_syslog():
Modified: pypy/branch/jitypes2/pypy/annotation/bookkeeper.py
==============================================================================
--- pypy/branch/jitypes2/pypy/annotation/bookkeeper.py (original)
+++ pypy/branch/jitypes2/pypy/annotation/bookkeeper.py Tue Nov 23 13:26:19 2010
@@ -87,13 +87,6 @@
else:
return obj.knowntype.__name__
- def consider_tuple_iter(self, tup):
- ctxt = "[%s]" % sys._getframe(4).f_code.co_name
- if tup.is_constant():
- return ctxt, tup.const
- else:
- return ctxt, tuple([self.typerepr(x) for x in tup.items])
-
def consider_tuple_random_getitem(self, tup):
return tuple([self.typerepr(x) for x in tup.items])
Modified: pypy/branch/jitypes2/pypy/annotation/builtin.py
==============================================================================
--- pypy/branch/jitypes2/pypy/annotation/builtin.py (original)
+++ pypy/branch/jitypes2/pypy/annotation/builtin.py Tue Nov 23 13:26:19 2010
@@ -453,6 +453,9 @@
#p = lltype.malloc(T, flavor=s_flavor.const)
#lltype.free(p, flavor=s_flavor.const)
+def render_immortal(s_p, s_track_allocation=None):
+ assert s_track_allocation is None or s_track_allocation.is_constant()
+
def typeOf(s_val):
lltype = annotation_to_lltype(s_val, info="in typeOf(): ")
return immutablevalue(lltype)
@@ -520,6 +523,7 @@
BUILTIN_ANALYZERS[lltype.malloc] = malloc
BUILTIN_ANALYZERS[lltype.free] = free
+BUILTIN_ANALYZERS[lltype.render_immortal] = render_immortal
BUILTIN_ANALYZERS[lltype.typeOf] = typeOf
BUILTIN_ANALYZERS[lltype.cast_primitive] = cast_primitive
BUILTIN_ANALYZERS[lltype.nullptr] = nullptr
Modified: pypy/branch/jitypes2/pypy/config/pypyoption.py
==============================================================================
--- pypy/branch/jitypes2/pypy/config/pypyoption.py (original)
+++ pypy/branch/jitypes2/pypy/config/pypyoption.py Tue Nov 23 13:26:19 2010
@@ -34,6 +34,11 @@
"_bisect", "_ffi"]
))
+translation_modules = default_modules.copy()
+translation_modules.update(dict.fromkeys(
+ ["fcntl", "rctime", "select", "signal", "_rawffi", "zlib",
+ "struct", "md5", "cStringIO", "array"]))
+
working_oo_modules = default_modules.copy()
working_oo_modules.update(dict.fromkeys(
["md5", "sha", "cStringIO", "itertools"]
@@ -149,6 +154,12 @@
cmdline="--allworkingmodules",
negation=True),
+ BoolOption("translationmodules",
+ "use only those modules that are needed to run translate.py on pypy",
+ default=False,
+ cmdline="--translationmodules",
+ suggests=[("objspace.allworkingmodules", False)]),
+
BoolOption("geninterp", "specify whether geninterp should be used",
cmdline=None,
default=True),
@@ -164,6 +175,11 @@
default=False,
requires=[("objspace.usepycfiles", True)]),
+ StrOption("soabi",
+ "Tag to differentiate extension modules built for different Python interpreters",
+ cmdline="--soabi",
+ default=None),
+
BoolOption("honor__builtins__",
"Honor the __builtins__ key of a module dictionary",
default=False),
@@ -369,6 +385,11 @@
modules = [name for name in modules if name not in essential_modules]
config.objspace.usemodules.suggest(**dict.fromkeys(modules, True))
+def enable_translationmodules(config):
+ modules = translation_modules
+ modules = [name for name in modules if name not in essential_modules]
+ config.objspace.usemodules.suggest(**dict.fromkeys(modules, True))
+
if __name__ == '__main__':
config = get_pypy_config()
Modified: pypy/branch/jitypes2/pypy/config/translationoption.py
==============================================================================
--- pypy/branch/jitypes2/pypy/config/translationoption.py (original)
+++ pypy/branch/jitypes2/pypy/config/translationoption.py Tue Nov 23 13:26:19 2010
@@ -115,7 +115,7 @@
default="auto", cmdline="--jit-backend"),
ChoiceOption("jit_debug", "the amount of debugging dumps made by the JIT",
["off", "profile", "steps", "detailed"],
- default="profile", # XXX for now
+ default="off",
cmdline="--jit-debug"),
ChoiceOption("jit_profiler", "integrate profiler support into the JIT",
["off", "oprofile"],
Modified: pypy/branch/jitypes2/pypy/conftest.py
==============================================================================
--- pypy/branch/jitypes2/pypy/conftest.py (original)
+++ pypy/branch/jitypes2/pypy/conftest.py Tue Nov 23 13:26:19 2010
@@ -327,6 +327,31 @@
class PyPyTestFunction(py.test.collect.Function):
# All PyPy test items catch and display OperationErrors specially.
#
+ def runtest(self):
+ self.runtest_open()
+ try:
+ self.runtest_perform()
+ finally:
+ self.runtest_close()
+ self.runtest_finish()
+
+ def runtest_open(self):
+ leakfinder.start_tracking_allocations()
+
+ def runtest_perform(self):
+ super(PyPyTestFunction, self).runtest()
+
+ def runtest_close(self):
+ if leakfinder.TRACK_ALLOCATIONS:
+ self._pypytest_leaks = leakfinder.stop_tracking_allocations(False)
+ else: # stop_tracking_allocations() already called
+ self._pypytest_leaks = None
+
+ def runtest_finish(self):
+ # check for leaks, but only if the test passed so far
+ if self._pypytest_leaks:
+ raise leakfinder.MallocMismatch(self._pypytest_leaks)
+
def execute_appex(self, space, target, *args):
try:
target(*args)
@@ -353,16 +378,9 @@
def _keywords(self):
return super(IntTestFunction, self)._keywords() + ['interplevel']
- def runtest(self):
+ def runtest_perform(self):
try:
- leakfinder.start_tracking_allocations()
- try:
- super(IntTestFunction, self).runtest()
- finally:
- if leakfinder.TRACK_ALLOCATIONS:
- leaks = leakfinder.stop_tracking_allocations(False)
- else:
- leaks = None # stop_tracking_allocations() already called
+ super(IntTestFunction, self).runtest_perform()
except OperationError, e:
check_keyboard_interrupt(e)
raise
@@ -375,14 +393,15 @@
py.test.skip('%s: %s' % (e.__class__.__name__, e))
cls = cls.__bases__[0]
raise
+
+ def runtest_finish(self):
if 'pygame' in sys.modules:
global _pygame_imported
if not _pygame_imported:
_pygame_imported = True
assert option.view, ("should not invoke Pygame "
"if conftest.option.view is False")
- if leaks: # check for leaks, but only if the test passed so far
- raise leakfinder.MallocMismatch(leaks)
+ super(IntTestFunction, self).runtest_finish()
class AppTestFunction(PyPyTestFunction):
def _prunetraceback(self, traceback):
@@ -395,7 +414,7 @@
def _keywords(self):
return ['applevel'] + super(AppTestFunction, self)._keywords()
- def runtest(self):
+ def runtest_perform(self):
target = self.obj
if option.runappdirect:
return target()
@@ -427,7 +446,7 @@
space.setattr(w_instance, space.wrap(name[2:]),
getattr(instance, name))
- def runtest(self):
+ def runtest_perform(self):
target = self.obj
if option.runappdirect:
return target()
Modified: pypy/branch/jitypes2/pypy/doc/release-1.4.0.txt
==============================================================================
--- pypy/branch/jitypes2/pypy/doc/release-1.4.0.txt (original)
+++ pypy/branch/jitypes2/pypy/doc/release-1.4.0.txt Tue Nov 23 13:26:19 2010
@@ -4,21 +4,25 @@
Hello.
-We're pleased to announce release of PyPy 1.4. This is a major breaktrhough
-in our long journey, since PyPy 1.4 is the first PyPy release that can translate
-itself faster than CPython. Since today, we plan to start using
-PyPy for our own development.
+We're pleased to announce the 1.4 release of PyPy. This is a major breakthrough
+in our long journey, as PyPy 1.4 is the first PyPy release that can translate
+itself faster than CPython. Starting today, we plan to start using PyPy for our
+own development.
Among other features, this release includes numerous performance improvements
-(which made fast self-hosting possible), 64jit backend as well as serious
-stabilization. As of now, we can consider 32bit version of PyPy stable enough
-to run in production.
+(which made fast self-hosting possible), a 64-bit JIT backend, as well
+as serious stabilization. As of now, we can consider the 32-bit and 64-bit
+linux versions of PyPy stable enoughto run in production.
More highlights
===============
-Virtualenv support: now PyPy is fully compatible with virtualenv_: note that
-to use it, you need a recent version of virtualenv (>= 1.5).
+* Virtualenv support: now PyPy is fully compatible with virtualenv_: note that
+ to use it, you need a recent version of virtualenv (>= 1.5).
-XXX write me: better regular expressions
+* Faster (and JITted) regular expressions - huge boost in speeding up
+ sre module.
+* Faster (and JITted) calls to functions like map().
+
+.. _virtualenv: http://pypi.python.org/pypi/virtualenv
Modified: pypy/branch/jitypes2/pypy/interpreter/argument.py
==============================================================================
--- pypy/branch/jitypes2/pypy/interpreter/argument.py (original)
+++ pypy/branch/jitypes2/pypy/interpreter/argument.py Tue Nov 23 13:26:19 2010
@@ -64,7 +64,7 @@
return not self == other
- # make it look tuply for the annotator
+ # make it look tuply for its use in the annotator
def __len__(self):
return 3
@@ -103,10 +103,11 @@
make_sure_not_resized(self.keywords_w)
make_sure_not_resized(self.arguments_w)
- if ((w_stararg is not None and w_stararg) or
- (w_starstararg is not None and w_starstararg)):
- self._combine_wrapped(w_stararg, w_starstararg)
- # if we have a call where * or ** args are used at the callsite
+ if w_stararg is not None and space.is_true(w_stararg):
+ self._combine_starargs_wrapped(w_stararg)
+ if w_starstararg is not None and space.is_true(w_starstararg):
+ self._combine_starstarargs_wrapped(w_starstararg)
+ # if we have a call where **args are used at the callsite
# we shouldn't let the JIT see the argument matching
self._dont_jit = True
else:
@@ -142,42 +143,48 @@
def _combine_wrapped(self, w_stararg, w_starstararg):
"unpack the *arg and **kwd into arguments_w and keywords_w"
- # unpack the * arguments
if w_stararg is not None:
- self.arguments_w = (self.arguments_w +
- self.space.fixedview(w_stararg))
- # unpack the ** arguments
+ self._combine_starargs_wrapped(w_stararg)
if w_starstararg is not None:
- space = self.space
- if not space.is_true(space.isinstance(w_starstararg, space.w_dict)):
+ self._combine_starstarargs_wrapped(w_starstararg)
+
+ def _combine_starargs_wrapped(self, w_stararg):
+ # unpack the * arguments
+ self.arguments_w = (self.arguments_w +
+ self.space.fixedview(w_stararg))
+
+ def _combine_starstarargs_wrapped(self, w_starstararg):
+ # unpack the ** arguments
+ space = self.space
+ if not space.is_true(space.isinstance(w_starstararg, space.w_dict)):
+ raise OperationError(space.w_TypeError,
+ space.wrap("argument after ** must be "
+ "a dictionary"))
+ keywords_w = [None] * space.int_w(space.len(w_starstararg))
+ keywords = [None] * space.int_w(space.len(w_starstararg))
+ i = 0
+ for w_key in space.unpackiterable(w_starstararg):
+ try:
+ key = space.str_w(w_key)
+ except OperationError, e:
+ if not e.match(space, space.w_TypeError):
+ raise
raise OperationError(space.w_TypeError,
- space.wrap("argument after ** must be "
- "a dictionary"))
- keywords_w = [None] * space.int_w(space.len(w_starstararg))
- keywords = [None] * space.int_w(space.len(w_starstararg))
- i = 0
- for w_key in space.unpackiterable(w_starstararg):
- try:
- key = space.str_w(w_key)
- except OperationError, e:
- if not e.match(space, space.w_TypeError):
- raise
- raise OperationError(space.w_TypeError,
- space.wrap("keywords must be strings"))
- if self.keywords and key in self.keywords:
- raise operationerrfmt(self.space.w_TypeError,
- "got multiple values "
- "for keyword argument "
- "'%s'", key)
- keywords[i] = key
- keywords_w[i] = space.getitem(w_starstararg, w_key)
- i += 1
- if self.keywords is None:
- self.keywords = keywords
- self.keywords_w = keywords_w
- else:
- self.keywords = self.keywords + keywords
- self.keywords_w = self.keywords_w + keywords_w
+ space.wrap("keywords must be strings"))
+ if self.keywords and key in self.keywords:
+ raise operationerrfmt(self.space.w_TypeError,
+ "got multiple values "
+ "for keyword argument "
+ "'%s'", key)
+ keywords[i] = key
+ keywords_w[i] = space.getitem(w_starstararg, w_key)
+ i += 1
+ if self.keywords is None:
+ self.keywords = keywords
+ self.keywords_w = keywords_w
+ else:
+ self.keywords = self.keywords + keywords
+ self.keywords_w = self.keywords_w + keywords_w
def fixedunpack(self, argcount):
"""The simplest argument parsing: get the 'argcount' arguments,
@@ -226,6 +233,10 @@
# argnames = list of formal parameter names
# scope_w = resulting list of wrapped values
#
+
+ # some comments about the JIT: it assumes that signature is a constant,
+ # so all values coming from there can be assumed constant. It assumes
+ # that the length of the defaults_w does not vary too much.
co_argcount = signature.num_argnames() # expected formal arguments, without */**
has_vararg = signature.has_vararg()
has_kwarg = signature.has_kwarg()
@@ -245,12 +256,6 @@
args_w = self.arguments_w
num_args = len(args_w)
- keywords = self.keywords
- keywords_w = self.keywords_w
- num_kwds = 0
- if keywords is not None:
- num_kwds = len(keywords)
-
avail = num_args + upfront
if input_argcount < co_argcount:
@@ -260,15 +265,24 @@
else:
take = num_args
+ # letting the JIT unroll this loop is safe, because take is always
+ # smaller than co_argcount
for i in range(take):
scope_w[i + input_argcount] = args_w[i]
input_argcount += take
+ keywords = self.keywords
+ keywords_w = self.keywords_w
+ num_kwds = 0
+ if keywords is not None:
+ num_kwds = len(keywords)
# the code assumes that keywords can potentially be large, but that
# argnames is typically not too large
num_remainingkwds = num_kwds
used_keywords = None
if keywords:
+ # letting JIT unroll the loop is *only* safe if the callsite didn't
+ # use **args because num_kwds can be arbitrarily large otherwise.
used_keywords = [False] * num_kwds
for i in range(num_kwds):
name = keywords[i]
@@ -276,7 +290,7 @@
if j < 0:
continue
elif j < input_argcount:
- # check that no keyword argument conflicts with these note
+ # check that no keyword argument conflicts with these. note
# that for this purpose we ignore the first blindargs,
# which were put into place by prepend(). This way,
# keywords do not conflict with the hidden extra argument
@@ -388,9 +402,10 @@
space = self.space
w_args = space.newtuple(self.arguments_w)
w_kwds = space.newdict()
- for i in range(len(self.keywords)):
- space.setitem(w_kwds, space.wrap(self.keywords[i]),
- self.keywords_w[i])
+ if self.keywords is not None:
+ for i in range(len(self.keywords)):
+ space.setitem(w_kwds, space.wrap(self.keywords[i]),
+ self.keywords_w[i])
return w_args, w_kwds
class ArgumentsForTranslation(Arguments):
Modified: pypy/branch/jitypes2/pypy/interpreter/test/test_argument.py
==============================================================================
--- pypy/branch/jitypes2/pypy/interpreter/test/test_argument.py (original)
+++ pypy/branch/jitypes2/pypy/interpreter/test/test_argument.py Tue Nov 23 13:26:19 2010
@@ -52,12 +52,17 @@
assert y == "d"
assert z == "e"
+class dummy_wrapped_dict(dict):
+ def __nonzero__(self):
+ raise NotImplementedError
class DummySpace(object):
def newtuple(self, items):
return tuple(items)
def is_true(self, obj):
+ if isinstance(obj, dummy_wrapped_dict):
+ return bool(dict(obj))
return bool(obj)
def fixedview(self, it):
@@ -229,7 +234,7 @@
kwds_w = dict(kwds[:i])
keywords = kwds_w.keys()
keywords_w = kwds_w.values()
- w_kwds = dict(kwds[i:])
+ w_kwds = dummy_wrapped_dict(kwds[i:])
if i == 2:
w_kwds = None
assert len(keywords) == len(keywords_w)
@@ -265,7 +270,7 @@
kwds_w = dict(kwds[:i])
keywords = kwds_w.keys()
keywords_w = kwds_w.values()
- w_kwds = dict(kwds[i:])
+ w_kwds = dummy_wrapped_dict(kwds[i:])
if i == 3:
w_kwds = None
args = Arguments(space, [1, 2], keywords, keywords_w, w_starstararg=w_kwds)
@@ -448,7 +453,11 @@
assert set(args.keywords) == set(['a', 'b'])
assert args.keywords_w[args.keywords.index('a')] == 2
assert args.keywords_w[args.keywords.index('b')] == 3
-
+
+ args = Arguments(space, [1])
+ w_args, w_kwds = args.topacked()
+ assert w_args == (1, )
+ assert not w_kwds
class TestErrorHandling(object):
def test_missing_args(self):
Modified: pypy/branch/jitypes2/pypy/jit/backend/llsupport/descr.py
==============================================================================
--- pypy/branch/jitypes2/pypy/jit/backend/llsupport/descr.py (original)
+++ pypy/branch/jitypes2/pypy/jit/backend/llsupport/descr.py Tue Nov 23 13:26:19 2010
@@ -130,6 +130,7 @@
# ArrayDescrs
_A = lltype.GcArray(lltype.Signed) # a random gcarray
+_AF = lltype.GcArray(lltype.Float) # an array of C doubles
class BaseArrayDescr(AbstractDescr):
@@ -171,16 +172,21 @@
_clsname = 'GcPtrArrayDescr'
_is_array_of_pointers = True
-_CA = rffi.CArray(lltype.Signed)
+class FloatArrayDescr(BaseArrayDescr):
+ _clsname = 'FloatArrayDescr'
+ _is_array_of_floats = True
+ def get_base_size(self, translate_support_code):
+ basesize, _, _ = symbolic.get_array_token(_AF, translate_support_code)
+ return basesize
+ def get_item_size(self, translate_support_code):
+ return symbolic.get_size(lltype.Float, translate_support_code)
class BaseArrayNoLengthDescr(BaseArrayDescr):
def get_base_size(self, translate_support_code):
- basesize, _, _ = symbolic.get_array_token(_CA, translate_support_code)
- return basesize
+ return 0
def get_ofs_length(self, translate_support_code):
- _, _, ofslength = symbolic.get_array_token(_CA, translate_support_code)
- return ofslength
+ return -1
class NonGcPtrArrayNoLengthDescr(BaseArrayNoLengthDescr):
_clsname = 'NonGcPtrArrayNoLengthDescr'
@@ -192,6 +198,8 @@
_is_array_of_pointers = True
def getArrayDescrClass(ARRAY):
+ if ARRAY.OF is lltype.Float:
+ return FloatArrayDescr
return getDescrClass(ARRAY.OF, BaseArrayDescr, GcPtrArrayDescr,
NonGcPtrArrayDescr, 'Array', 'get_item_size',
'_is_array_of_floats', '_is_item_signed')
@@ -219,7 +227,8 @@
basesize, itemsize, ofslength = symbolic.get_array_token(ARRAY, False)
assert basesize == arraydescr.get_base_size(False)
assert itemsize == arraydescr.get_item_size(False)
- assert ofslength == arraydescr.get_ofs_length(False)
+ if not ARRAY._hints.get('nolength', False):
+ assert ofslength == arraydescr.get_ofs_length(False)
if isinstance(ARRAY, lltype.GcArray):
gccache.init_array_descr(ARRAY, arraydescr)
cache[ARRAY] = arraydescr
Modified: pypy/branch/jitypes2/pypy/jit/backend/llsupport/gc.py
==============================================================================
--- pypy/branch/jitypes2/pypy/jit/backend/llsupport/gc.py (original)
+++ pypy/branch/jitypes2/pypy/jit/backend/llsupport/gc.py Tue Nov 23 13:26:19 2010
@@ -573,6 +573,9 @@
# GETFIELD_RAW from the array 'gcrefs.list'.
#
newops = []
+ # we can only remember one malloc since the next malloc can possibly
+ # collect
+ last_malloc = None
for op in operations:
if op.getopnum() == rop.DEBUG_MERGE_POINT:
continue
@@ -590,22 +593,32 @@
[ConstInt(addr)], box,
self.single_gcref_descr))
op.setarg(i, box)
+ if op.is_malloc():
+ last_malloc = op.result
+ elif op.can_malloc():
+ last_malloc = None
# ---------- write barrier for SETFIELD_GC ----------
if op.getopnum() == rop.SETFIELD_GC:
- v = op.getarg(1)
- if isinstance(v, BoxPtr) or (isinstance(v, ConstPtr) and
- bool(v.value)): # store a non-NULL
- self._gen_write_barrier(newops, op.getarg(0), v)
- op = op.copy_and_change(rop.SETFIELD_RAW)
+ val = op.getarg(0)
+ # no need for a write barrier in the case of previous malloc
+ if val is not last_malloc:
+ v = op.getarg(1)
+ if isinstance(v, BoxPtr) or (isinstance(v, ConstPtr) and
+ bool(v.value)): # store a non-NULL
+ self._gen_write_barrier(newops, op.getarg(0), v)
+ op = op.copy_and_change(rop.SETFIELD_RAW)
# ---------- write barrier for SETARRAYITEM_GC ----------
if op.getopnum() == rop.SETARRAYITEM_GC:
- v = op.getarg(2)
- if isinstance(v, BoxPtr) or (isinstance(v, ConstPtr) and
- bool(v.value)): # store a non-NULL
- # XXX detect when we should produce a
- # write_barrier_from_array
- self._gen_write_barrier(newops, op.getarg(0), v)
- op = op.copy_and_change(rop.SETARRAYITEM_RAW)
+ val = op.getarg(0)
+ # no need for a write barrier in the case of previous malloc
+ if val is not last_malloc:
+ v = op.getarg(2)
+ if isinstance(v, BoxPtr) or (isinstance(v, ConstPtr) and
+ bool(v.value)): # store a non-NULL
+ # XXX detect when we should produce a
+ # write_barrier_from_array
+ self._gen_write_barrier(newops, op.getarg(0), v)
+ op = op.copy_and_change(rop.SETARRAYITEM_RAW)
# ----------
newops.append(op)
del operations[:]
Modified: pypy/branch/jitypes2/pypy/jit/backend/llsupport/test/test_descr.py
==============================================================================
--- pypy/branch/jitypes2/pypy/jit/backend/llsupport/test/test_descr.py (original)
+++ pypy/branch/jitypes2/pypy/jit/backend/llsupport/test/test_descr.py Tue Nov 23 13:26:19 2010
@@ -5,6 +5,7 @@
from pypy.rpython.annlowlevel import llhelper
from pypy.jit.metainterp.history import BoxInt, BoxFloat, BoxPtr
from pypy.jit.metainterp import history
+import struct
def test_get_size_descr():
c0 = GcCache(False)
@@ -130,11 +131,13 @@
assert not descr3.is_array_of_floats()
assert descr4.is_array_of_floats()
#
- WORD = rffi.sizeof(lltype.Signed)
- assert descr1.get_base_size(False) == WORD
- assert descr2.get_base_size(False) == WORD
- assert descr3.get_base_size(False) == WORD
- assert descr4.get_base_size(False) == WORD
+ def get_alignment(code):
+ # Retrieve default alignment for the compiler/platform
+ return struct.calcsize('l' + code) - struct.calcsize(code)
+ assert descr1.get_base_size(False) == get_alignment('c')
+ assert descr2.get_base_size(False) == get_alignment('p')
+ assert descr3.get_base_size(False) == get_alignment('p')
+ assert descr4.get_base_size(False) == get_alignment('d')
assert descr1.get_ofs_length(False) == 0
assert descr2.get_ofs_length(False) == 0
assert descr3.get_ofs_length(False) == 0
Modified: pypy/branch/jitypes2/pypy/jit/backend/llsupport/test/test_gc.py
==============================================================================
--- pypy/branch/jitypes2/pypy/jit/backend/llsupport/test/test_gc.py (original)
+++ pypy/branch/jitypes2/pypy/jit/backend/llsupport/test/test_gc.py Tue Nov 23 13:26:19 2010
@@ -6,7 +6,9 @@
from pypy.jit.backend.llsupport.gc import *
from pypy.jit.backend.llsupport import symbolic
from pypy.jit.metainterp.gc import get_description
-
+from pypy.jit.tool.oparser import parse
+from pypy.rpython.lltypesystem.rclass import OBJECT, OBJECT_VTABLE
+from pypy.jit.metainterp.test.test_optimizeopt import equaloplists
def test_boehm():
gc_ll_descr = GcLLDescr_boehm(None, None, None)
@@ -114,7 +116,7 @@
assert gcrootmap._gcmap[i*2+1] == expected_shapeaddr[i]
-class FakeLLOp:
+class FakeLLOp(object):
def __init__(self):
self.record = []
@@ -148,19 +150,19 @@
return llhelper(FPTRTYPE, self._write_barrier_failing_case)
-class TestFramework:
+class TestFramework(object):
gc = 'hybrid'
def setup_method(self, meth):
- class config_:
- class translation:
+ class config_(object):
+ class translation(object):
gc = self.gc
gcrootfinder = 'asmgcc'
gctransformer = 'framework'
gcremovetypeptr = False
- class FakeTranslator:
+ class FakeTranslator(object):
config = config_
- class FakeCPU:
+ class FakeCPU(object):
def cast_adr_to_int(self, adr):
ptr = llmemory.cast_adr_to_ptr(adr, gc_ll_descr.WB_FUNCPTR)
assert ptr._obj._callable == llop1._write_barrier_failing_case
@@ -278,11 +280,11 @@
def test_rewrite_assembler_1(self):
# check rewriting of ConstPtrs
- class MyFakeCPU:
+ class MyFakeCPU(object):
def cast_adr_to_int(self, adr):
assert adr == "some fake address"
return 43
- class MyFakeGCRefList:
+ class MyFakeGCRefList(object):
def get_address_of_gcref(self, s_gcref1):
assert s_gcref1 == s_gcref
return "some fake address"
@@ -311,10 +313,10 @@
def test_rewrite_assembler_1_cannot_move(self):
# check rewriting of ConstPtrs
- class MyFakeCPU:
+ class MyFakeCPU(object):
def cast_adr_to_int(self, adr):
xxx # should not be called
- class MyFakeGCRefList:
+ class MyFakeGCRefList(object):
def get_address_of_gcref(self, s_gcref1):
seen.append(s_gcref1)
assert s_gcref1 == s_gcref
@@ -394,6 +396,68 @@
assert operations[1].getarg(2) == v_value
assert operations[1].getdescr() == array_descr
+ def test_rewrite_assembler_initialization_store(self):
+ S = lltype.GcStruct('S', ('parent', OBJECT),
+ ('x', lltype.Signed))
+ s_vtable = lltype.malloc(OBJECT_VTABLE, immortal=True)
+ xdescr = get_field_descr(self.gc_ll_descr, S, 'x')
+ ops = parse("""
+ [p1]
+ p0 = new_with_vtable(ConstClass(s_vtable))
+ setfield_gc(p0, p1, descr=xdescr)
+ jump()
+ """, namespace=locals())
+ expected = parse("""
+ [p1]
+ p0 = new_with_vtable(ConstClass(s_vtable))
+ # no write barrier
+ setfield_gc(p0, p1, descr=xdescr)
+ jump()
+ """, namespace=locals())
+ self.gc_ll_descr.rewrite_assembler(self.fake_cpu, ops.operations)
+ equaloplists(ops.operations, expected.operations)
+
+ def test_rewrite_assembler_initialization_store_2(self):
+ S = lltype.GcStruct('S', ('parent', OBJECT),
+ ('x', lltype.Signed))
+ s_vtable = lltype.malloc(OBJECT_VTABLE, immortal=True)
+ wbdescr = self.gc_ll_descr.write_barrier_descr
+ xdescr = get_field_descr(self.gc_ll_descr, S, 'x')
+ ops = parse("""
+ [p1]
+ p0 = new_with_vtable(ConstClass(s_vtable))
+ p3 = new_with_vtable(ConstClass(s_vtable))
+ setfield_gc(p0, p1, descr=xdescr)
+ jump()
+ """, namespace=locals())
+ expected = parse("""
+ [p1]
+ p0 = new_with_vtable(ConstClass(s_vtable))
+ p3 = new_with_vtable(ConstClass(s_vtable))
+ cond_call_gc_wb(p0, p1, descr=wbdescr)
+ setfield_raw(p0, p1, descr=xdescr)
+ jump()
+ """, namespace=locals())
+ self.gc_ll_descr.rewrite_assembler(self.fake_cpu, ops.operations)
+ equaloplists(ops.operations, expected.operations)
+
+ def test_rewrite_assembler_initialization_store_3(self):
+ A = lltype.GcArray(lltype.Ptr(lltype.GcStruct('S')))
+ arraydescr = get_array_descr(self.gc_ll_descr, A)
+ ops = parse("""
+ [p1]
+ p0 = new_array(3, descr=arraydescr)
+ setarrayitem_gc(p0, 0, p1, descr=arraydescr)
+ jump()
+ """, namespace=locals())
+ expected = parse("""
+ [p1]
+ p0 = new_array(3, descr=arraydescr)
+ setarrayitem_gc(p0, 0, p1, descr=arraydescr)
+ jump()
+ """, namespace=locals())
+ self.gc_ll_descr.rewrite_assembler(self.fake_cpu, ops.operations)
+ equaloplists(ops.operations, expected.operations)
class TestFrameworkMiniMark(TestFramework):
gc = 'minimark'
Modified: pypy/branch/jitypes2/pypy/jit/backend/test/runner_test.py
==============================================================================
--- pypy/branch/jitypes2/pypy/jit/backend/test/runner_test.py (original)
+++ pypy/branch/jitypes2/pypy/jit/backend/test/runner_test.py Tue Nov 23 13:26:19 2010
@@ -2168,12 +2168,14 @@
# Tested with a function that intentionally does not cast the
# result to RESTYPE, but makes sure that we return the whole
# value in eax or rax.
- eci = ExternalCompilationInfo(separate_module_sources=["""
+ eci = ExternalCompilationInfo(
+ separate_module_sources=["""
long fn_test_result_of_call(long x)
{
return x + 1;
}
- """])
+ """],
+ export_symbols=['fn_test_result_of_call'])
f = rffi.llexternal('fn_test_result_of_call', [lltype.Signed],
RESTYPE, compilation_info=eci, _nowrapper=True)
value = intmask(0xFFEEDDCCBBAA9988)
@@ -2199,12 +2201,14 @@
# Tested with a function that intentionally does not cast the
# result to RESTYPE, but makes sure that we return the whole
# value in eax or rax.
- eci = ExternalCompilationInfo(separate_module_sources=["""
+ eci = ExternalCompilationInfo(
+ separate_module_sources=["""
long fn_test_result_of_call(long x)
{
return x + 1;
}
- """])
+ """],
+ export_symbols=['fn_test_result_of_call'])
f = rffi.llexternal('fn_test_result_of_call', [lltype.Signed],
RESTYPE, compilation_info=eci, _nowrapper=True)
value = intmask(0xFFEEDDCCBBAA9988)
Modified: pypy/branch/jitypes2/pypy/jit/backend/x86/assembler.py
==============================================================================
--- pypy/branch/jitypes2/pypy/jit/backend/x86/assembler.py (original)
+++ pypy/branch/jitypes2/pypy/jit/backend/x86/assembler.py Tue Nov 23 13:26:19 2010
@@ -1773,13 +1773,18 @@
self.implement_guard(guard_token, 'L')
def genop_discard_cond_call_gc_wb(self, op, arglocs):
- # use 'mc._mc' directly instead of 'mc', to avoid
- # bad surprizes if the code buffer is mostly full
+ # Write code equivalent to write_barrier() in the GC: it checks
+ # a flag in the object at arglocs[0], and if set, it calls the
+ # function remember_young_pointer() from the GC. The two arguments
+ # to the call are in arglocs[:2]. The rest, arglocs[2:], contains
+ # registers that need to be saved and restored across the call.
descr = op.getdescr()
if we_are_translated():
cls = self.cpu.gc_ll_descr.has_write_barrier_class()
assert cls is not None and isinstance(descr, cls)
loc_base = arglocs[0]
+ # ensure that enough bytes are available to write the whole
+ # following piece of code atomically (for the JZ)
self.mc.ensure_bytes_available(256)
self.mc.TEST8_mi((loc_base.value, descr.jit_wb_if_flag_byteofs),
descr.jit_wb_if_flag_singlebyte)
@@ -1787,36 +1792,39 @@
jz_location = self.mc.get_relative_pos()
# the following is supposed to be the slow path, so whenever possible
# we choose the most compact encoding over the most efficient one.
- # XXX improve a bit, particularly for IS_X86_64.
- for i in range(len(arglocs)-1, -1, -1):
+ if IS_X86_32:
+ limit = -1 # push all arglocs on the stack
+ elif IS_X86_64:
+ limit = 1 # push only arglocs[2:] on the stack
+ for i in range(len(arglocs)-1, limit, -1):
loc = arglocs[i]
if isinstance(loc, RegLoc):
self.mc.PUSH_r(loc.value)
else:
- if IS_X86_64:
- self.mc.MOV_ri(X86_64_SCRATCH_REG.value, loc.getint())
- self.mc.PUSH_r(X86_64_SCRATCH_REG.value)
- else:
- self.mc.PUSH_i32(loc.getint())
-
+ assert not IS_X86_64 # there should only be regs in arglocs[2:]
+ self.mc.PUSH_i32(loc.getint())
if IS_X86_64:
# We clobber these registers to pass the arguments, but that's
# okay, because consider_cond_call_gc_wb makes sure that any
- # caller-save registers with values in them are present in arglocs,
- # so they are saved on the stack above and restored below
- self.mc.MOV_rs(edi.value, 0)
- self.mc.MOV_rs(esi.value, 8)
+ # caller-save registers with values in them are present in
+ # arglocs[2:] too, so they are saved on the stack above and
+ # restored below.
+ remap_frame_layout(self, arglocs[:2], [edi, esi],
+ X86_64_SCRATCH_REG)
# misaligned stack in the call, but it's ok because the write barrier
# is not going to call anything more. Also, this assumes that the
- # write barrier does not touch the xmm registers.
+ # write barrier does not touch the xmm registers. (Slightly delicate
+ # assumption, given that the write barrier can end up calling the
+ # platform's malloc() from AddressStack.append(). XXX may need to
+ # be done properly)
self.mc.CALL(imm(descr.get_write_barrier_fn(self.cpu)))
- for i in range(len(arglocs)):
+ if IS_X86_32:
+ self.mc.ADD_ri(esp.value, 2*WORD)
+ for i in range(2, len(arglocs)):
loc = arglocs[i]
- if isinstance(loc, RegLoc):
- self.mc.POP_r(loc.value)
- else:
- self.mc.ADD_ri(esp.value, WORD) # ignore the pushed constant
+ assert isinstance(loc, RegLoc)
+ self.mc.POP_r(loc.value)
# patch the JZ above
offset = self.mc.get_relative_pos() - jz_location
assert 0 < offset <= 127
Modified: pypy/branch/jitypes2/pypy/jit/codewriter/assembler.py
==============================================================================
--- pypy/branch/jitypes2/pypy/jit/codewriter/assembler.py (original)
+++ pypy/branch/jitypes2/pypy/jit/codewriter/assembler.py Tue Nov 23 13:26:19 2010
@@ -233,10 +233,9 @@
addr = llmemory.cast_ptr_to_adr(value)
self.list_of_addr2name.append((addr, name))
- def finished(self):
+ def finished(self, callinfocollection):
# Helper called at the end of assembling. Registers the extra
# functions shown in _callinfo_for_oopspec.
- from pypy.jit.codewriter.effectinfo import _callinfo_for_oopspec
- for _, func in _callinfo_for_oopspec.values():
+ for func in callinfocollection.all_function_addresses_as_int():
func = heaptracker.int2adr(func)
self.see_raw_object(func.ptr)
Modified: pypy/branch/jitypes2/pypy/jit/codewriter/call.py
==============================================================================
--- pypy/branch/jitypes2/pypy/jit/codewriter/call.py (original)
+++ pypy/branch/jitypes2/pypy/jit/codewriter/call.py Tue Nov 23 13:26:19 2010
@@ -7,7 +7,7 @@
from pypy.jit.codewriter.jitcode import JitCode
from pypy.jit.codewriter.effectinfo import VirtualizableAnalyzer
from pypy.jit.codewriter.effectinfo import effectinfo_from_writeanalyze
-from pypy.jit.codewriter.effectinfo import EffectInfo
+from pypy.jit.codewriter.effectinfo import EffectInfo, CallInfoCollection
from pypy.translator.simplify import get_funcobj, get_functype
from pypy.rpython.lltypesystem import lltype, llmemory
from pypy.translator.backendopt.canraise import RaiseAnalyzer
@@ -23,6 +23,7 @@
self.jitdrivers_sd = jitdrivers_sd
self.jitcodes = {} # map {graph: jitcode}
self.unfinished_graphs = [] # list of graphs with pending jitcodes
+ self.callinfocollection = CallInfoCollection()
if hasattr(cpu, 'rtyper'): # for tests
self.rtyper = cpu.rtyper
translator = self.rtyper.annotator.translator
Modified: pypy/branch/jitypes2/pypy/jit/codewriter/codewriter.py
==============================================================================
--- pypy/branch/jitypes2/pypy/jit/codewriter/codewriter.py (original)
+++ pypy/branch/jitypes2/pypy/jit/codewriter/codewriter.py Tue Nov 23 13:26:19 2010
@@ -73,7 +73,7 @@
count += 1
if not count % 500:
log.info("Produced %d jitcodes" % count)
- self.assembler.finished()
+ self.assembler.finished(self.callcontrol.callinfocollection)
heaptracker.finish_registering(self.cpu)
log.info("there are %d JitCode instances." % count)
Modified: pypy/branch/jitypes2/pypy/jit/codewriter/effectinfo.py
==============================================================================
--- pypy/branch/jitypes2/pypy/jit/codewriter/effectinfo.py (original)
+++ pypy/branch/jitypes2/pypy/jit/codewriter/effectinfo.py Tue Nov 23 13:26:19 2010
@@ -144,30 +144,44 @@
# ____________________________________________________________
-_callinfo_for_oopspec = {} # {oopspecindex: (calldescr, func_as_int)}
-
-def callinfo_for_oopspec(oopspecindex):
- """A function that returns the calldescr and the function
- address (as an int) of one of the OS_XYZ functions defined above.
- Don't use this if there might be several implementations of the same
- OS_XYZ specialized by type, e.g. OS_ARRAYCOPY."""
- try:
- return _callinfo_for_oopspec[oopspecindex]
- except KeyError:
- return (None, 0)
-
-
-def _funcptr_for_oopspec_memo(oopspecindex):
- from pypy.jit.codewriter import heaptracker
- _, func_as_int = callinfo_for_oopspec(oopspecindex)
- funcadr = heaptracker.int2adr(func_as_int)
- return funcadr.ptr
-_funcptr_for_oopspec_memo._annspecialcase_ = 'specialize:memo'
-
-def funcptr_for_oopspec(oopspecindex):
- """A memo function that returns a pointer to the function described
- by OS_XYZ (as a real low-level function pointer)."""
- funcptr = _funcptr_for_oopspec_memo(oopspecindex)
- assert funcptr
- return funcptr
-funcptr_for_oopspec._annspecialcase_ = 'specialize:arg(0)'
+class CallInfoCollection(object):
+ def __init__(self):
+ # {oopspecindex: (calldescr, func_as_int)}
+ self._callinfo_for_oopspec = {}
+
+ def _freeze_(self):
+ return True
+
+ def add(self, oopspecindex, calldescr, func_as_int):
+ self._callinfo_for_oopspec[oopspecindex] = calldescr, func_as_int
+
+ def has_oopspec(self, oopspecindex):
+ return oopspecindex in self._callinfo_for_oopspec
+
+ def all_function_addresses_as_int(self):
+ return [func for (_, func) in self._callinfo_for_oopspec.values()]
+
+ def callinfo_for_oopspec(self, oopspecindex):
+ """A function that returns the calldescr and the function
+ address (as an int) of one of the OS_XYZ functions defined above.
+ Don't use this if there might be several implementations of the same
+ OS_XYZ specialized by type, e.g. OS_ARRAYCOPY."""
+ try:
+ return self._callinfo_for_oopspec[oopspecindex]
+ except KeyError:
+ return (None, 0)
+
+ def _funcptr_for_oopspec_memo(self, oopspecindex):
+ from pypy.jit.codewriter import heaptracker
+ _, func_as_int = self.callinfo_for_oopspec(oopspecindex)
+ funcadr = heaptracker.int2adr(func_as_int)
+ return funcadr.ptr
+ _funcptr_for_oopspec_memo._annspecialcase_ = 'specialize:memo'
+
+ def funcptr_for_oopspec(self, oopspecindex):
+ """A memo function that returns a pointer to the function described
+ by OS_XYZ (as a real low-level function pointer)."""
+ funcptr = self._funcptr_for_oopspec_memo(oopspecindex)
+ assert funcptr
+ return funcptr
+ funcptr_for_oopspec._annspecialcase_ = 'specialize:arg(1)'
Modified: pypy/branch/jitypes2/pypy/jit/codewriter/jtransform.py
==============================================================================
--- pypy/branch/jitypes2/pypy/jit/codewriter/jtransform.py (original)
+++ pypy/branch/jitypes2/pypy/jit/codewriter/jtransform.py Tue Nov 23 13:26:19 2010
@@ -6,7 +6,7 @@
from pypy.objspace.flow.model import Block, Link, c_last_exception
from pypy.jit.codewriter.flatten import ListOfKind, IndirectCallTargets
from pypy.jit.codewriter import support, heaptracker
-from pypy.jit.codewriter.effectinfo import EffectInfo, _callinfo_for_oopspec
+from pypy.jit.codewriter.effectinfo import EffectInfo
from pypy.jit.codewriter.policy import log
from pypy.jit.metainterp.typesystem import deref, arrayItem
from pypy.rlib import objectmodel
@@ -843,9 +843,16 @@
"general mix-up of jitdrivers?")
ops = self.promote_greens(op.args[2:], jitdriver)
num_green_args = len(jitdriver.greens)
+ redlists = self.make_three_lists(op.args[2+num_green_args:])
+ for redlist in redlists:
+ for v in redlist:
+ assert isinstance(v, Variable), (
+ "Constant specified red in jit_merge_point()")
+ assert len(dict.fromkeys(redlist)) == len(list(redlist)), (
+ "duplicate red variable on jit_merge_point()")
args = ([Constant(self.portal_jd.index, lltype.Signed)] +
self.make_three_lists(op.args[2:2+num_green_args]) +
- self.make_three_lists(op.args[2+num_green_args:]))
+ redlists)
op1 = SpaceOperation('jit_merge_point', args, None)
op2 = SpaceOperation('-live-', [], None)
# ^^^ we need a -live- for the case of do_recursive_call()
@@ -1084,7 +1091,8 @@
else:
func = heaptracker.adr2int(
llmemory.cast_ptr_to_adr(op.args[0].value))
- _callinfo_for_oopspec[oopspecindex] = calldescr, func
+ self.callcontrol.callinfocollection.add(oopspecindex,
+ calldescr, func)
op1 = self.rewrite_call(op, 'residual_call',
[op.args[0], calldescr],
args=args)
@@ -1095,7 +1103,7 @@
def _register_extra_helper(self, oopspecindex, oopspec_name,
argtypes, resulttype):
# a bit hackish
- if oopspecindex in _callinfo_for_oopspec:
+ if self.callcontrol.callinfocollection.has_oopspec(oopspecindex):
return
c_func, TP = support.builtin_func_for_spec(self.cpu.rtyper,
oopspec_name, argtypes,
@@ -1109,7 +1117,7 @@
else:
func = heaptracker.adr2int(
llmemory.cast_ptr_to_adr(c_func.value))
- _callinfo_for_oopspec[oopspecindex] = calldescr, func
+ self.callcontrol.callinfocollection.add(oopspecindex, calldescr, func)
def _handle_stroruni_call(self, op, oopspec_name, args):
SoU = args[0].concretetype # Ptr(STR) or Ptr(UNICODE)
Modified: pypy/branch/jitypes2/pypy/jit/codewriter/test/test_jtransform.py
==============================================================================
--- pypy/branch/jitypes2/pypy/jit/codewriter/test/test_jtransform.py (original)
+++ pypy/branch/jitypes2/pypy/jit/codewriter/test/test_jtransform.py Tue Nov 23 13:26:19 2010
@@ -74,7 +74,20 @@
def calldescr_canraise(self, calldescr):
return False
+class FakeCallInfoCollection:
+ def __init__(self):
+ self.seen = []
+ def add(self, oopspecindex, calldescr, func):
+ self.seen.append((oopspecindex, calldescr, func))
+ def has_oopspec(self, oopspecindex):
+ for i, c, f in self.seen:
+ if i == oopspecindex:
+ return True
+ return False
+
class FakeBuiltinCallControl:
+ def __init__(self):
+ self.callinfocollection = FakeCallInfoCollection()
def guess_call_kind(self, op):
return 'builtin'
def getcalldescr(self, op, oopspecindex=None):
@@ -810,7 +823,8 @@
v2 = varoftype(PSTR)
v3 = varoftype(PSTR)
op = SpaceOperation('direct_call', [const(func), v1, v2], v3)
- tr = Transformer(FakeCPU(), FakeBuiltinCallControl())
+ cc = FakeBuiltinCallControl()
+ tr = Transformer(FakeCPU(), cc)
op1 = tr.rewrite_operation(op)
assert op1.opname == 'residual_call_r_r'
assert op1.args[0].value == func
@@ -819,9 +833,10 @@
assert op1.result == v3
#
# check the callinfo_for_oopspec
- got = effectinfo.callinfo_for_oopspec(effectinfo.EffectInfo.OS_UNI_CONCAT)
- assert got[0] == op1.args[1] # the calldescr
- assert heaptracker.int2adr(got[1]) == llmemory.cast_ptr_to_adr(func)
+ got = cc.callinfocollection.seen[0]
+ assert got[0] == effectinfo.EffectInfo.OS_UNI_CONCAT
+ assert got[1] == op1.args[1] # the calldescr
+ assert heaptracker.int2adr(got[2]) == llmemory.cast_ptr_to_adr(func)
def test_str_slice():
# test that the oopspec is present and correctly transformed
@@ -893,7 +908,8 @@
v2 = varoftype(PUNICODE)
v3 = varoftype(lltype.Bool)
op = SpaceOperation('direct_call', [const(func), v1, v2], v3)
- tr = Transformer(FakeCPU(), FakeBuiltinCallControl())
+ cc = FakeBuiltinCallControl()
+ tr = Transformer(FakeCPU(), cc)
op1 = tr.rewrite_operation(op)
assert op1.opname == 'residual_call_r_i'
assert op1.args[0].value == func
@@ -901,9 +917,9 @@
assert op1.args[2] == ListOfKind('ref', [v1, v2])
assert op1.result == v3
# test that the OS_UNIEQ_* functions are registered
- cifo = effectinfo._callinfo_for_oopspec
- assert effectinfo.EffectInfo.OS_UNIEQ_SLICE_NONNULL in cifo
- assert effectinfo.EffectInfo.OS_UNIEQ_CHECKNULL_CHAR in cifo
+ cic = cc.callinfocollection
+ assert cic.has_oopspec(effectinfo.EffectInfo.OS_UNIEQ_SLICE_NONNULL)
+ assert cic.has_oopspec(effectinfo.EffectInfo.OS_UNIEQ_CHECKNULL_CHAR)
def test_list_ll_arraycopy():
from pypy.rlib.rgc import ll_arraycopy
Modified: pypy/branch/jitypes2/pypy/jit/metainterp/compile.py
==============================================================================
--- pypy/branch/jitypes2/pypy/jit/metainterp/compile.py (original)
+++ pypy/branch/jitypes2/pypy/jit/metainterp/compile.py Tue Nov 23 13:26:19 2010
@@ -1,4 +1,5 @@
+from pypy.rpython.lltypesystem import lltype
from pypy.rpython.ootypesystem import ootype
from pypy.objspace.flow.model import Constant, Variable
from pypy.rlib.objectmodel import we_are_translated
@@ -14,6 +15,7 @@
from pypy.jit.metainterp.specnode import NotSpecNode, more_general_specnodes
from pypy.jit.metainterp.typesystem import llhelper, oohelper
from pypy.jit.metainterp.optimizeutil import InvalidLoop
+from pypy.jit.metainterp.resume import NUMBERING
from pypy.jit.codewriter import heaptracker
def giveup():
@@ -48,13 +50,12 @@
# ____________________________________________________________
-def compile_new_loop(metainterp, old_loop_tokens, greenkey, start):
+def compile_new_loop(metainterp, old_loop_tokens, start):
"""Try to compile a new loop by closing the current history back
to the first operation.
"""
history = metainterp.history
loop = create_empty_loop(metainterp)
- loop.greenkey = greenkey
loop.inputargs = history.inputargs
for box in loop.inputargs:
assert isinstance(box, Box)
@@ -207,8 +208,7 @@
}
class ResumeDescr(AbstractFailDescr):
- def __init__(self, original_greenkey):
- self.original_greenkey = original_greenkey
+ pass
class ResumeGuardDescr(ResumeDescr):
_counter = 0 # if < 0, there is one counter per value;
@@ -217,7 +217,7 @@
# this class also gets the following attributes stored by resume.py code
rd_snapshot = None
rd_frame_info_list = None
- rd_numb = None
+ rd_numb = lltype.nullptr(NUMBERING)
rd_consts = None
rd_virtuals = None
rd_pendingfields = None
@@ -227,8 +227,7 @@
CNT_FLOAT = -0x60000000
CNT_MASK = 0x1FFFFFFF
- def __init__(self, metainterp_sd, original_greenkey):
- ResumeDescr.__init__(self, original_greenkey)
+ def __init__(self, metainterp_sd):
self.metainterp_sd = metainterp_sd
def store_final_boxes(self, guard_op, boxes):
@@ -332,14 +331,14 @@
res.rd_pendingfields = self.rd_pendingfields
def _clone_if_mutable(self):
- res = ResumeGuardDescr(self.metainterp_sd, self.original_greenkey)
+ res = ResumeGuardDescr(self.metainterp_sd)
self.copy_all_attrbutes_into(res)
return res
class ResumeGuardForcedDescr(ResumeGuardDescr):
- def __init__(self, metainterp_sd, original_greenkey, jitdriver_sd):
- ResumeGuardDescr.__init__(self, metainterp_sd, original_greenkey)
+ def __init__(self, metainterp_sd, jitdriver_sd):
+ ResumeGuardDescr.__init__(self, metainterp_sd)
self.jitdriver_sd = jitdriver_sd
def handle_fail(self, metainterp_sd, jitdriver_sd):
@@ -406,7 +405,6 @@
def _clone_if_mutable(self):
res = ResumeGuardForcedDescr(self.metainterp_sd,
- self.original_greenkey,
self.jitdriver_sd)
self.copy_all_attrbutes_into(res)
return res
@@ -473,9 +471,8 @@
class ResumeFromInterpDescr(ResumeDescr):
- def __init__(self, original_greenkey, redkey):
- ResumeDescr.__init__(self, original_greenkey)
- self.redkey = redkey
+ def __init__(self, original_greenkey):
+ self.original_greenkey = original_greenkey
def compile_and_attach(self, metainterp, new_loop):
# We managed to create a bridge going from the interpreter
@@ -484,10 +481,8 @@
# with completely unoptimized arguments, as in the interpreter.
metainterp_sd = metainterp.staticdata
jitdriver_sd = metainterp.jitdriver_sd
- metainterp.history.inputargs = self.redkey
- new_loop_token = make_loop_token(len(self.redkey), jitdriver_sd)
- new_loop.greenkey = self.original_greenkey
- new_loop.inputargs = self.redkey
+ redargs = new_loop.inputargs
+ new_loop_token = make_loop_token(len(redargs), jitdriver_sd)
new_loop.token = new_loop_token
send_loop_to_backend(metainterp_sd, new_loop, "entry bridge")
# send the new_loop to warmspot.py, to be called directly the next time
Modified: pypy/branch/jitypes2/pypy/jit/metainterp/optimizeopt/optimizer.py
==============================================================================
--- pypy/branch/jitypes2/pypy/jit/metainterp/optimizeopt/optimizer.py (original)
+++ pypy/branch/jitypes2/pypy/jit/metainterp/optimizeopt/optimizer.py Tue Nov 23 13:26:19 2010
@@ -299,7 +299,9 @@
return CVAL_ZERO
def propagate_all_forward(self):
- self.exception_might_have_happened = False
+ self.exception_might_have_happened = True
+ # ^^^ at least at the start of bridges. For loops, we could set
+ # it to False, but we probably don't care
self.newoperations = []
self.i = 0
while self.i < len(self.loop.operations):
Modified: pypy/branch/jitypes2/pypy/jit/metainterp/optimizeopt/string.py
==============================================================================
--- pypy/branch/jitypes2/pypy/jit/metainterp/optimizeopt/string.py (original)
+++ pypy/branch/jitypes2/pypy/jit/metainterp/optimizeopt/string.py Tue Nov 23 13:26:19 2010
@@ -9,7 +9,7 @@
from pypy.jit.metainterp.optimizeopt.optimizer import CONST_0, CONST_1
from pypy.jit.metainterp.optimizeopt.optimizer import llhelper
from pypy.jit.metainterp.optimizeutil import _findall
-from pypy.jit.codewriter.effectinfo import EffectInfo, callinfo_for_oopspec
+from pypy.jit.codewriter.effectinfo import EffectInfo
from pypy.jit.codewriter import heaptracker
from pypy.rlib.unroll import unrolling_iterable
from pypy.rlib.objectmodel import specialize, we_are_translated
@@ -593,7 +593,8 @@
def generate_modified_call(self, oopspecindex, args, result, mode):
oopspecindex += mode.OS_offset
- calldescr, func = callinfo_for_oopspec(oopspecindex)
+ cic = self.optimizer.metainterp_sd.callinfocollection
+ calldescr, func = cic.callinfo_for_oopspec(oopspecindex)
op = ResOperation(rop.CALL, [ConstInt(func)] + args, result,
descr=calldescr)
self.optimizer.newoperations.append(op)
Modified: pypy/branch/jitypes2/pypy/jit/metainterp/pyjitpl.py
==============================================================================
--- pypy/branch/jitypes2/pypy/jit/metainterp/pyjitpl.py (original)
+++ pypy/branch/jitypes2/pypy/jit/metainterp/pyjitpl.py Tue Nov 23 13:26:19 2010
@@ -14,7 +14,7 @@
from pypy.jit.metainterp.logger import Logger
from pypy.jit.metainterp.jitprof import EmptyProfiler
from pypy.jit.metainterp.jitprof import GUARDS, RECORDED_OPS, ABORT_ESCAPE
-from pypy.jit.metainterp.jitprof import ABORT_TOO_LONG, ABORT_BRIDGE
+from pypy.jit.metainterp.jitprof import ABORT_TOO_LONG
from pypy.jit.metainterp.jitexc import JitException, get_llexception
from pypy.rlib.rarithmetic import intmask
from pypy.rlib.objectmodel import specialize
@@ -94,6 +94,18 @@
else: raise AssertionError(argcode)
outvalue[startindex+i] = reg
+ def _put_back_list_of_boxes(self, outvalue, startindex, position):
+ code = self.bytecode
+ length = ord(code[position])
+ position += 1
+ for i in range(length):
+ index = ord(code[position+i])
+ box = outvalue[startindex+i]
+ if box.type == history.INT: self.registers_i[index] = box
+ elif box.type == history.REF: self.registers_r[index] = box
+ elif box.type == history.FLOAT: self.registers_f[index] = box
+ else: raise AssertionError(box.type)
+
def get_current_position_info(self):
return self.jitcode.get_live_vars_info(self.pc)
@@ -814,8 +826,9 @@
for i in range(num_green_args):
assert isinstance(varargs[i], Const)
- @arguments("orgpc", "int", "boxes3", "boxes3")
- def opimpl_jit_merge_point(self, orgpc, jdindex, greenboxes, redboxes):
+ @arguments("orgpc", "int", "boxes3", "jitcode_position", "boxes3")
+ def opimpl_jit_merge_point(self, orgpc, jdindex, greenboxes,
+ jcposition, redboxes):
any_operation = len(self.metainterp.history.operations) > 0
jitdriver_sd = self.metainterp.staticdata.jitdrivers_sd[jdindex]
self.verify_green_args(jitdriver_sd, greenboxes)
@@ -843,6 +856,10 @@
self.pc = orgpc
self.metainterp.reached_loop_header(greenboxes, redboxes)
self.pc = saved_pc
+ # no exception, which means that the jit_merge_point did not
+ # close the loop. We have to put the possibly-modified list
+ # 'redboxes' back into the registers where it comes from.
+ put_back_list_of_boxes3(self, jcposition, redboxes)
else:
# warning! careful here. We have to return from the current
# frame containing the jit_merge_point, and then use
@@ -1048,14 +1065,11 @@
else:
moreargs = list(extraargs)
metainterp_sd = metainterp.staticdata
- original_greenkey = metainterp.resumekey.original_greenkey
if opnum == rop.GUARD_NOT_FORCED:
resumedescr = compile.ResumeGuardForcedDescr(metainterp_sd,
- original_greenkey,
metainterp.jitdriver_sd)
else:
- resumedescr = compile.ResumeGuardDescr(metainterp_sd,
- original_greenkey)
+ resumedescr = compile.ResumeGuardDescr(metainterp_sd)
guard_op = metainterp.history.record(opnum, moreargs, None,
descr=resumedescr)
virtualizable_boxes = None
@@ -1261,6 +1275,7 @@
#
self.jitdrivers_sd = codewriter.callcontrol.jitdrivers_sd
self.virtualref_info = codewriter.callcontrol.virtualref_info
+ self.callinfocollection = codewriter.callcontrol.callinfocollection
self.setup_jitdrivers_sd(optimizer)
#
# store this information for fastpath of call_assembler
@@ -1624,7 +1639,7 @@
assert jitdriver_sd is self.jitdriver_sd
self.create_empty_history()
try:
- original_boxes = self.initialize_original_boxes(jitdriver_sd,*args)
+ original_boxes = self.initialize_original_boxes(jitdriver_sd, *args)
return self._compile_and_run_once(original_boxes)
finally:
self.staticdata.profiler.end_tracing()
@@ -1635,9 +1650,8 @@
self.current_merge_points = [(original_boxes, 0)]
num_green_args = self.jitdriver_sd.num_green_args
original_greenkey = original_boxes[:num_green_args]
- redkey = original_boxes[num_green_args:]
- self.resumekey = compile.ResumeFromInterpDescr(original_greenkey,
- redkey)
+ self.resumekey = compile.ResumeFromInterpDescr(original_greenkey)
+ self.history.inputargs = original_boxes[num_green_args:]
self.seen_loop_header_for_jdindex = -1
try:
self.interpret()
@@ -1659,11 +1673,7 @@
debug_stop('jit-tracing')
def _handle_guard_failure(self, key):
- original_greenkey = key.original_greenkey
- # notice that here we just put the greenkey
- # use -1 to mark that we will have to give up
- # because we cannot reconstruct the beginning of the proper loop
- self.current_merge_points = [(original_greenkey, -1)]
+ self.current_merge_points = []
self.resumekey = key
self.seen_loop_header_for_jdindex = -1
try:
@@ -1727,7 +1737,7 @@
num_green_args = self.jitdriver_sd.num_green_args
for j in range(len(self.current_merge_points)-1, -1, -1):
original_boxes, start = self.current_merge_points[j]
- assert len(original_boxes) == len(live_arg_boxes) or start < 0
+ assert len(original_boxes) == len(live_arg_boxes)
for i in range(num_green_args):
box1 = original_boxes[i]
box2 = live_arg_boxes[i]
@@ -1736,10 +1746,6 @@
break
else:
# Found! Compile it as a loop.
- if start < 0:
- # we cannot reconstruct the beginning of the proper loop
- raise SwitchToBlackhole(ABORT_BRIDGE)
-
# raises in case it works -- which is the common case
self.compile(original_boxes, live_arg_boxes, start)
# creation of the loop was cancelled!
@@ -1804,8 +1810,7 @@
greenkey = original_boxes[:num_green_args]
old_loop_tokens = self.get_compiled_merge_points(greenkey)
self.history.record(rop.JUMP, live_arg_boxes[num_green_args:], None)
- loop_token = compile.compile_new_loop(self, old_loop_tokens,
- greenkey, start)
+ loop_token = compile.compile_new_loop(self, old_loop_tokens, start)
if loop_token is not None: # raise if it *worked* correctly
raise GenerateMergePoint(live_arg_boxes, loop_token)
self.history.operations.pop() # remove the JUMP
@@ -2305,6 +2310,8 @@
else:
raise AssertionError("bad argcode")
position += 1
+ elif argtype == "jitcode_position":
+ value = position
else:
raise AssertionError("bad argtype: %r" % (argtype,))
args += (value,)
@@ -2349,3 +2356,15 @@
argtypes = unrolling_iterable(unboundmethod.argtypes)
handler.func_name = 'handler_' + name
return handler
+
+def put_back_list_of_boxes3(frame, position, newvalue):
+ code = frame.bytecode
+ length1 = ord(code[position])
+ position2 = position + 1 + length1
+ length2 = ord(code[position2])
+ position3 = position2 + 1 + length2
+ length3 = ord(code[position3])
+ assert len(newvalue) == length1 + length2 + length3
+ frame._put_back_list_of_boxes(newvalue, 0, position)
+ frame._put_back_list_of_boxes(newvalue, length1, position2)
+ frame._put_back_list_of_boxes(newvalue, length1 + length2, position3)
Modified: pypy/branch/jitypes2/pypy/jit/metainterp/resoperation.py
==============================================================================
--- pypy/branch/jitypes2/pypy/jit/metainterp/resoperation.py (original)
+++ pypy/branch/jitypes2/pypy/jit/metainterp/resoperation.py Tue Nov 23 13:26:19 2010
@@ -143,6 +143,16 @@
def can_raise(self):
return rop._CANRAISE_FIRST <= self.getopnum() <= rop._CANRAISE_LAST
+ def is_malloc(self):
+ # a slightly different meaning from can_malloc
+ return rop._MALLOC_FIRST <= self.getopnum() <= rop._MALLOC_LAST
+
+ def can_malloc(self):
+ return self.is_call() or self.is_malloc()
+
+ def is_call(self):
+ return rop._CALL_FIRST <= self.getopnum() <= rop._CALL_LAST
+
def is_ovf(self):
return rop._OVF_FIRST <= self.getopnum() <= rop._OVF_LAST
@@ -441,9 +451,13 @@
'GETARRAYITEM_RAW/2d',
'GETFIELD_GC/1d',
'GETFIELD_RAW/1d',
+ '_MALLOC_FIRST',
'NEW/0d',
'NEW_WITH_VTABLE/1',
'NEW_ARRAY/1d',
+ 'NEWSTR/1',
+ 'NEWUNICODE/1',
+ '_MALLOC_LAST',
'FORCE_TOKEN/0',
'VIRTUAL_REF/2', # removed before it's passed to the backend
'_NOSIDEEFFECT_LAST', # ----- end of no_side_effect operations -----
@@ -452,10 +466,8 @@
'SETARRAYITEM_RAW/3d',
'SETFIELD_GC/2d',
'SETFIELD_RAW/2d',
- 'NEWSTR/1',
'STRSETITEM/3',
'UNICODESETITEM/3',
- 'NEWUNICODE/1',
#'RUNTIMENEW/1', # ootype operation
'COND_CALL_GC_WB/2d', # [objptr, newvalue] (for the write barrier)
'DEBUG_MERGE_POINT/2', # debugging only
@@ -465,6 +477,7 @@
'COPYUNICODECONTENT/5',
'_CANRAISE_FIRST', # ----- start of can_raise operations -----
+ '_CALL_FIRST',
'CALL/*d',
'CALL_ASSEMBLER/*d', # call already compiled assembler
'CALL_MAY_FORCE/*d',
@@ -473,6 +486,7 @@
#'OOSEND_PURE', # ootype operation
'CALL_PURE/*d', # removed before it's passed to the backend
# CALL_PURE(result, func, arg_1,..,arg_n)
+ '_CALL_LAST',
'_CANRAISE_LAST', # ----- end of can_raise operations -----
'_OVF_FIRST', # ----- start of is_ovf operations -----
Modified: pypy/branch/jitypes2/pypy/jit/metainterp/resume.py
==============================================================================
--- pypy/branch/jitypes2/pypy/jit/metainterp/resume.py (original)
+++ pypy/branch/jitypes2/pypy/jit/metainterp/resume.py Tue Nov 23 13:26:19 2010
@@ -4,8 +4,7 @@
from pypy.jit.metainterp.history import INT, REF, FLOAT, HOLE
from pypy.jit.metainterp.resoperation import rop
from pypy.jit.metainterp import jitprof
-from pypy.jit.codewriter.effectinfo import EffectInfo, callinfo_for_oopspec
-from pypy.jit.codewriter.effectinfo import funcptr_for_oopspec
+from pypy.jit.codewriter.effectinfo import EffectInfo
from pypy.rpython.lltypesystem import lltype, llmemory, rffi, rstr
from pypy.rlib import rarithmetic
from pypy.rlib.objectmodel import we_are_translated, specialize
@@ -66,12 +65,21 @@
snapshot = Snapshot(snapshot, boxes)
storage.rd_snapshot = snapshot
-class Numbering(object):
- __slots__ = ('prev', 'nums')
-
- def __init__(self, prev, nums):
- self.prev = prev
- self.nums = nums
+#
+# The following is equivalent to the RPython-level declaration:
+#
+# class Numbering: __slots__ = ['prev', 'nums']
+#
+# except that it is more compact in translated programs, because the
+# array 'nums' is inlined in the single NUMBERING object. This is
+# important because this is often the biggest single consumer of memory
+# in a pypy-c-jit.
+#
+NUMBERINGP = lltype.Ptr(lltype.GcForwardReference())
+NUMBERING = lltype.GcStruct('Numbering',
+ ('prev', NUMBERINGP),
+ ('nums', lltype.Array(rffi.SHORT)))
+NUMBERINGP.TO.become(NUMBERING)
TAGMASK = 3
@@ -163,7 +171,7 @@
def number(self, values, snapshot):
if snapshot is None:
- return None, {}, 0
+ return lltype.nullptr(NUMBERING), {}, 0
if snapshot in self.numberings:
numb, liveboxes, v = self.numberings[snapshot]
return numb, liveboxes.copy(), v
@@ -172,7 +180,7 @@
n = len(liveboxes)-v
boxes = snapshot.boxes
length = len(boxes)
- nums = [UNASSIGNED] * length
+ numb = lltype.malloc(NUMBERING, length)
for i in range(length):
box = boxes[i]
value = values.get(box, None)
@@ -191,9 +199,9 @@
tagged = tag(n, TAGBOX)
n += 1
liveboxes[box] = tagged
- nums[i] = tagged
+ numb.nums[i] = tagged
#
- numb = Numbering(numb1, nums)
+ numb.prev = numb1
self.numberings[snapshot] = numb, liveboxes, v
return numb, liveboxes.copy(), v
@@ -298,7 +306,7 @@
# compute the numbering
storage = self.storage
# make sure that nobody attached resume data to this guard yet
- assert storage.rd_numb is None
+ assert not storage.rd_numb
numb, liveboxes_from_env, v = self.memo.number(values,
storage.rd_snapshot)
self.liveboxes_from_env = liveboxes_from_env
@@ -723,34 +731,36 @@
self.boxes_f = boxes_f
self._prepare_next_section(info)
- def consume_virtualizable_boxes(self, vinfo, nums):
+ def consume_virtualizable_boxes(self, vinfo, numb):
# we have to ignore the initial part of 'nums' (containing vrefs),
# find the virtualizable from nums[-1], and use it to know how many
# boxes of which type we have to return. This does not write
# anything into the virtualizable.
- virtualizablebox = self.decode_ref(nums[-1])
+ index = len(numb.nums) - 1
+ virtualizablebox = self.decode_ref(numb.nums[index])
virtualizable = vinfo.unwrap_virtualizable_box(virtualizablebox)
- return vinfo.load_list_of_boxes(virtualizable, self, nums)
+ return vinfo.load_list_of_boxes(virtualizable, self, numb)
- def consume_virtualref_boxes(self, nums, end):
+ def consume_virtualref_boxes(self, numb, end):
# Returns a list of boxes, assumed to be all BoxPtrs.
# We leave up to the caller to call vrefinfo.continue_tracing().
assert (end & 1) == 0
- return [self.decode_ref(nums[i]) for i in range(end)]
+ return [self.decode_ref(numb.nums[i]) for i in range(end)]
def consume_vref_and_vable_boxes(self, vinfo, ginfo):
- nums = self.cur_numb.nums
- self.cur_numb = self.cur_numb.prev
+ numb = self.cur_numb
+ self.cur_numb = numb.prev
if vinfo is not None:
- virtualizable_boxes = self.consume_virtualizable_boxes(vinfo, nums)
- end = len(nums) - len(virtualizable_boxes)
+ virtualizable_boxes = self.consume_virtualizable_boxes(vinfo, numb)
+ end = len(numb.nums) - len(virtualizable_boxes)
elif ginfo is not None:
- virtualizable_boxes = [self.decode_ref(nums[-1])]
- end = len(nums) - 1
+ index = len(numb.nums) - 1
+ virtualizable_boxes = [self.decode_ref(numb.nums[index])]
+ end = len(numb.nums) - 1
else:
virtualizable_boxes = None
- end = len(nums)
- virtualref_boxes = self.consume_virtualref_boxes(nums, end)
+ end = len(numb.nums)
+ virtualref_boxes = self.consume_virtualref_boxes(numb, end)
return virtualizable_boxes, virtualref_boxes
def allocate_with_vtable(self, known_class):
@@ -774,14 +784,16 @@
strbox, ConstInt(index), charbox)
def concat_strings(self, str1num, str2num):
- calldescr, func = callinfo_for_oopspec(EffectInfo.OS_STR_CONCAT)
+ cic = self.metainterp.staticdata.callinfocollection
+ calldescr, func = cic.callinfo_for_oopspec(EffectInfo.OS_STR_CONCAT)
str1box = self.decode_box(str1num, REF)
str2box = self.decode_box(str2num, REF)
return self.metainterp.execute_and_record_varargs(
rop.CALL, [ConstInt(func), str1box, str2box], calldescr)
def slice_string(self, strnum, startnum, lengthnum):
- calldescr, func = callinfo_for_oopspec(EffectInfo.OS_STR_SLICE)
+ cic = self.metainterp.staticdata.callinfocollection
+ calldescr, func = cic.callinfo_for_oopspec(EffectInfo.OS_STR_SLICE)
strbox = self.decode_box(strnum, REF)
startbox = self.decode_box(startnum, INT)
lengthbox = self.decode_box(lengthnum, INT)
@@ -800,14 +812,16 @@
strbox, ConstInt(index), charbox)
def concat_unicodes(self, str1num, str2num):
- calldescr, func = callinfo_for_oopspec(EffectInfo.OS_UNI_CONCAT)
+ cic = self.metainterp.staticdata.callinfocollection
+ calldescr, func = cic.callinfo_for_oopspec(EffectInfo.OS_UNI_CONCAT)
str1box = self.decode_box(str1num, REF)
str2box = self.decode_box(str2num, REF)
return self.metainterp.execute_and_record_varargs(
rop.CALL, [ConstInt(func), str1box, str2box], calldescr)
def slice_unicode(self, strnum, startnum, lengthnum):
- calldescr, func = callinfo_for_oopspec(EffectInfo.OS_UNI_SLICE)
+ cic = self.metainterp.staticdata.callinfocollection
+ calldescr, func = cic.callinfo_for_oopspec(EffectInfo.OS_UNI_SLICE)
strbox = self.decode_box(strnum, REF)
startbox = self.decode_box(startnum, INT)
lengthbox = self.decode_box(lengthnum, INT)
@@ -903,8 +917,8 @@
def blackhole_from_resumedata(blackholeinterpbuilder, jitdriver_sd, storage,
all_virtuals=None):
- resumereader = ResumeDataDirectReader(blackholeinterpbuilder.cpu, storage,
- all_virtuals)
+ resumereader = ResumeDataDirectReader(blackholeinterpbuilder.metainterp_sd,
+ storage, all_virtuals)
vinfo = jitdriver_sd.virtualizable_info
ginfo = jitdriver_sd.greenfield_info
vrefinfo = blackholeinterpbuilder.metainterp_sd.virtualref_info
@@ -939,7 +953,7 @@
return firstbh
def force_from_resumedata(metainterp_sd, storage, vinfo, ginfo):
- resumereader = ResumeDataDirectReader(metainterp_sd.cpu, storage)
+ resumereader = ResumeDataDirectReader(metainterp_sd, storage)
resumereader.handling_async_forcing()
vrefinfo = metainterp_sd.virtualref_info
resumereader.consume_vref_and_vable(vrefinfo, vinfo, ginfo)
@@ -953,8 +967,9 @@
# 1: in handle_async_forcing
# 2: resuming from the GUARD_NOT_FORCED
- def __init__(self, cpu, storage, all_virtuals=None):
- self._init(cpu, storage)
+ def __init__(self, metainterp_sd, storage, all_virtuals=None):
+ self._init(metainterp_sd.cpu, storage)
+ self.callinfocollection = metainterp_sd.callinfocollection
if all_virtuals is None: # common case
self._prepare(storage)
else:
@@ -973,23 +988,24 @@
info = blackholeinterp.get_current_position_info()
self._prepare_next_section(info)
- def consume_virtualref_info(self, vrefinfo, nums, end):
+ def consume_virtualref_info(self, vrefinfo, numb, end):
# we have to decode a list of references containing pairs
# [..., virtual, vref, ...] stopping at 'end'
assert (end & 1) == 0
for i in range(0, end, 2):
- virtual = self.decode_ref(nums[i])
- vref = self.decode_ref(nums[i+1])
+ virtual = self.decode_ref(numb.nums[i])
+ vref = self.decode_ref(numb.nums[i+1])
# For each pair, we store the virtual inside the vref.
vrefinfo.continue_tracing(vref, virtual)
- def consume_vable_info(self, vinfo, nums):
+ def consume_vable_info(self, vinfo, numb):
# we have to ignore the initial part of 'nums' (containing vrefs),
# find the virtualizable from nums[-1], load all other values
# from the CPU stack, and copy them into the virtualizable
if vinfo is None:
- return len(nums)
- virtualizable = self.decode_ref(nums[-1])
+ return len(numb.nums)
+ index = len(numb.nums) - 1
+ virtualizable = self.decode_ref(numb.nums[index])
virtualizable = vinfo.cast_gcref_to_vtype(virtualizable)
if self.resume_after_guard_not_forced == 1:
# in the middle of handle_async_forcing()
@@ -1001,7 +1017,7 @@
# is and stays 0. Note the call to reset_vable_token() in
# warmstate.py.
assert not virtualizable.vable_token
- return vinfo.write_from_resume_data_partial(virtualizable, self, nums)
+ return vinfo.write_from_resume_data_partial(virtualizable, self, numb)
def load_value_of_type(self, TYPE, tagged):
from pypy.jit.metainterp.warmstate import specialize_value
@@ -1018,12 +1034,12 @@
load_value_of_type._annspecialcase_ = 'specialize:arg(1)'
def consume_vref_and_vable(self, vrefinfo, vinfo, ginfo):
- nums = self.cur_numb.nums
- self.cur_numb = self.cur_numb.prev
+ numb = self.cur_numb
+ self.cur_numb = numb.prev
if self.resume_after_guard_not_forced != 2:
- end_vref = self.consume_vable_info(vinfo, nums)
+ end_vref = self.consume_vable_info(vinfo, numb)
if ginfo is not None: end_vref -= 1
- self.consume_virtualref_info(vrefinfo, nums, end_vref)
+ self.consume_virtualref_info(vrefinfo, numb, end_vref)
def allocate_with_vtable(self, known_class):
from pypy.jit.metainterp.executor import exec_new_with_vtable
@@ -1047,7 +1063,8 @@
str2 = self.decode_ref(str2num)
str1 = lltype.cast_opaque_ptr(lltype.Ptr(rstr.STR), str1)
str2 = lltype.cast_opaque_ptr(lltype.Ptr(rstr.STR), str2)
- funcptr = funcptr_for_oopspec(EffectInfo.OS_STR_CONCAT)
+ cic = self.callinfocollection
+ funcptr = cic.funcptr_for_oopspec(EffectInfo.OS_STR_CONCAT)
result = funcptr(str1, str2)
return lltype.cast_opaque_ptr(llmemory.GCREF, result)
@@ -1056,7 +1073,8 @@
start = self.decode_int(startnum)
length = self.decode_int(lengthnum)
str = lltype.cast_opaque_ptr(lltype.Ptr(rstr.STR), str)
- funcptr = funcptr_for_oopspec(EffectInfo.OS_STR_SLICE)
+ cic = self.callinfocollection
+ funcptr = cic.funcptr_for_oopspec(EffectInfo.OS_STR_SLICE)
result = funcptr(str, start, start + length)
return lltype.cast_opaque_ptr(llmemory.GCREF, result)
@@ -1072,7 +1090,8 @@
str2 = self.decode_ref(str2num)
str1 = lltype.cast_opaque_ptr(lltype.Ptr(rstr.UNICODE), str1)
str2 = lltype.cast_opaque_ptr(lltype.Ptr(rstr.UNICODE), str2)
- funcptr = funcptr_for_oopspec(EffectInfo.OS_UNI_CONCAT)
+ cic = self.callinfocollection
+ funcptr = cic.funcptr_for_oopspec(EffectInfo.OS_UNI_CONCAT)
result = funcptr(str1, str2)
return lltype.cast_opaque_ptr(llmemory.GCREF, result)
@@ -1081,7 +1100,8 @@
start = self.decode_int(startnum)
length = self.decode_int(lengthnum)
str = lltype.cast_opaque_ptr(lltype.Ptr(rstr.UNICODE), str)
- funcptr = funcptr_for_oopspec(EffectInfo.OS_UNI_SLICE)
+ cic = self.callinfocollection
+ funcptr = cic.funcptr_for_oopspec(EffectInfo.OS_UNI_SLICE)
result = funcptr(str, start, start + length)
return lltype.cast_opaque_ptr(llmemory.GCREF, result)
@@ -1172,8 +1192,9 @@
'at', compute_unique_id(frameinfo))
frameinfo = frameinfo.prev
numb = storage.rd_numb
- while numb is not None:
- debug_print('\tnumb', str([untag(i) for i in numb.nums]),
+ while numb:
+ debug_print('\tnumb', str([untag(numb.nums[i])
+ for i in range(len(numb.nums))]),
'at', compute_unique_id(numb))
numb = numb.prev
for const in storage.rd_consts:
Modified: pypy/branch/jitypes2/pypy/jit/metainterp/test/test_compile.py
==============================================================================
--- pypy/branch/jitypes2/pypy/jit/metainterp/test/test_compile.py (original)
+++ pypy/branch/jitypes2/pypy/jit/metainterp/test/test_compile.py Tue Nov 23 13:26:19 2010
@@ -85,7 +85,7 @@
metainterp.history.inputargs = loop.inputargs[:]
#
loop_tokens = []
- loop_token = compile_new_loop(metainterp, loop_tokens, [], 0)
+ loop_token = compile_new_loop(metainterp, loop_tokens, 0)
assert loop_tokens == [loop_token]
assert loop_token.number == 1
assert staticdata.globaldata.loopnumbering == 2
@@ -101,7 +101,7 @@
metainterp.history.operations = loop.operations[:]
metainterp.history.inputargs = loop.inputargs[:]
#
- loop_token_2 = compile_new_loop(metainterp, loop_tokens, [], 0)
+ loop_token_2 = compile_new_loop(metainterp, loop_tokens, 0)
assert loop_token_2 is loop_token
assert loop_tokens == [loop_token]
assert len(cpu.seen) == 0
Modified: pypy/branch/jitypes2/pypy/jit/metainterp/test/test_exception.py
==============================================================================
--- pypy/branch/jitypes2/pypy/jit/metainterp/test/test_exception.py (original)
+++ pypy/branch/jitypes2/pypy/jit/metainterp/test/test_exception.py Tue Nov 23 13:26:19 2010
@@ -1,6 +1,6 @@
import py, sys
from pypy.jit.metainterp.test.test_basic import LLJitMixin, OOJitMixin
-from pypy.rlib.jit import JitDriver, OPTIMIZER_SIMPLE
+from pypy.rlib.jit import JitDriver, OPTIMIZER_SIMPLE, dont_look_inside
from pypy.rlib.rarithmetic import ovfcheck, LONG_BIT, intmask
from pypy.jit.codewriter.policy import StopAtXPolicy
@@ -588,6 +588,33 @@
res = self.interp_operations(f, [99])
assert res == 21
+ def test_bug_exc1_noexc_exc2(self):
+ myjitdriver = JitDriver(greens=[], reds=['i'])
+ @dont_look_inside
+ def rescall(i):
+ if i < 10:
+ raise KeyError
+ if i < 20:
+ return None
+ raise ValueError
+ def f(i):
+ while i < 30:
+ myjitdriver.can_enter_jit(i=i)
+ myjitdriver.jit_merge_point(i=i)
+ try:
+ rescall(i)
+ except KeyError:
+ assert i < 10
+ except ValueError:
+ assert i >= 20
+ else:
+ assert 10 <= i < 20
+ i += 1
+ return i
+ res = self.meta_interp(f, [0], inline=True)
+ assert res == 30
+
+
class MyError(Exception):
def __init__(self, n):
self.n = n
Modified: pypy/branch/jitypes2/pypy/jit/metainterp/test/test_optimizeopt.py
==============================================================================
--- pypy/branch/jitypes2/pypy/jit/metainterp/test/test_optimizeopt.py (original)
+++ pypy/branch/jitypes2/pypy/jit/metainterp/test/test_optimizeopt.py Tue Nov 23 13:26:19 2010
@@ -41,7 +41,7 @@
b1 = BoxInt()
opt = optimizeopt.Optimizer(FakeMetaInterpStaticData(LLtypeMixin.cpu),
None)
- fdescr = ResumeGuardDescr(None, None)
+ fdescr = ResumeGuardDescr(None)
op = ResOperation(rop.GUARD_TRUE, ['dummy'], None, descr=fdescr)
# setup rd data
fi0 = resume.FrameInfo(None, "code0", 11)
@@ -51,12 +51,12 @@
#
opt.store_final_boxes_in_guard(op)
if op.getfailargs() == [b0, b1]:
- assert fdescr.rd_numb.nums == [tag(1, TAGBOX)]
- assert fdescr.rd_numb.prev.nums == [tag(0, TAGBOX)]
+ assert list(fdescr.rd_numb.nums) == [tag(1, TAGBOX)]
+ assert list(fdescr.rd_numb.prev.nums) == [tag(0, TAGBOX)]
else:
assert op.getfailargs() == [b1, b0]
- assert fdescr.rd_numb.nums == [tag(0, TAGBOX)]
- assert fdescr.rd_numb.prev.nums == [tag(1, TAGBOX)]
+ assert list(fdescr.rd_numb.nums) == [tag(0, TAGBOX)]
+ assert list(fdescr.rd_numb.prev.nums) == [tag(1, TAGBOX)]
assert fdescr.rd_virtuals is None
assert fdescr.rd_consts == []
@@ -264,6 +264,8 @@
metainterp_sd = FakeMetaInterpStaticData(self.cpu)
if hasattr(self, 'vrefinfo'):
metainterp_sd.virtualref_info = self.vrefinfo
+ if hasattr(self, 'callinfocollection'):
+ metainterp_sd.callinfocollection = self.callinfocollection
optimize_loop_1(metainterp_sd, loop)
#
expected = self.parse(optops)
@@ -787,8 +789,12 @@
i3 = call(i2, descr=nonwritedescr)
jump(i1) # the exception is considered lost when we loop back
"""
+ # note that 'guard_no_exception' at the very start must be kept
+ # around: bridges may start with one. (In case of loops we could
+ # remove it, but we probably don't care.)
expected = """
[i]
+ guard_no_exception() []
i1 = int_add(i, 3)
i2 = call(i1, descr=nonwritedescr)
guard_no_exception() [i1, i2]
@@ -4180,22 +4186,20 @@
# ----------
def optimize_strunicode_loop_extradescrs(self, ops, spectext, optops):
from pypy.jit.metainterp.optimizeopt import string
- def my_callinfo_for_oopspec(oopspecindex):
- calldescrtype = type(LLtypeMixin.strequaldescr)
- for value in LLtypeMixin.__dict__.values():
- if isinstance(value, calldescrtype):
- if (value.get_extra_info() and
- value.get_extra_info().oopspecindex == oopspecindex):
- # returns 0 for 'func' in this test
- return value, 0
- raise AssertionError("not found: oopspecindex=%d" % oopspecindex)
+ class FakeCallInfoCollection:
+ def callinfo_for_oopspec(self, oopspecindex):
+ calldescrtype = type(LLtypeMixin.strequaldescr)
+ for value in LLtypeMixin.__dict__.values():
+ if isinstance(value, calldescrtype):
+ extra = value.get_extra_info()
+ if extra and extra.oopspecindex == oopspecindex:
+ # returns 0 for 'func' in this test
+ return value, 0
+ raise AssertionError("not found: oopspecindex=%d" %
+ oopspecindex)
#
- saved = string.callinfo_for_oopspec
- try:
- string.callinfo_for_oopspec = my_callinfo_for_oopspec
- self.optimize_strunicode_loop(ops, spectext, optops)
- finally:
- string.callinfo_for_oopspec = saved
+ self.callinfocollection = FakeCallInfoCollection()
+ self.optimize_strunicode_loop(ops, spectext, optops)
def test_str_equal_noop1(self):
ops = """
Modified: pypy/branch/jitypes2/pypy/jit/metainterp/test/test_recursive.py
==============================================================================
--- pypy/branch/jitypes2/pypy/jit/metainterp/test/test_recursive.py (original)
+++ pypy/branch/jitypes2/pypy/jit/metainterp/test/test_recursive.py Tue Nov 23 13:26:19 2010
@@ -1142,6 +1142,19 @@
res = self.meta_interp(main, [], inline=True, trace_limit=tlimit)
assert ''.join(res.chars) == 'ABCDEFGHIabcdefghijJ' * 5
+ def test_no_duplicates_bug(self):
+ driver = JitDriver(greens = ['codeno'], reds = ['i'],
+ get_printable_location = lambda codeno: str(codeno))
+ def portal(codeno, i):
+ while i > 0:
+ driver.can_enter_jit(codeno=codeno, i=i)
+ driver.jit_merge_point(codeno=codeno, i=i)
+ if codeno > 0:
+ break
+ portal(i, i)
+ i -= 1
+ self.meta_interp(portal, [0, 10], inline=True)
+
class TestLLtype(RecursiveTests, LLJitMixin):
pass
Modified: pypy/branch/jitypes2/pypy/jit/metainterp/test/test_resoperation.py
==============================================================================
--- pypy/branch/jitypes2/pypy/jit/metainterp/test/test_resoperation.py (original)
+++ pypy/branch/jitypes2/pypy/jit/metainterp/test/test_resoperation.py Tue Nov 23 13:26:19 2010
@@ -61,3 +61,10 @@
assert op.getarglist() == ['a', 'b']
assert op.result == 'c'
assert op.getdescr() is mydescr
+
+def test_can_malloc():
+ mydescr = AbstractDescr()
+ assert rop.ResOperation(rop.rop.NEW, [], 'b').can_malloc()
+ call = rop.ResOperation(rop.rop.CALL, ['a', 'b'], 'c', descr=mydescr)
+ assert call.can_malloc()
+ assert not rop.ResOperation(rop.rop.INT_ADD, ['a', 'b'], 'c').can_malloc()
Modified: pypy/branch/jitypes2/pypy/jit/metainterp/test/test_resume.py
==============================================================================
--- pypy/branch/jitypes2/pypy/jit/metainterp/test/test_resume.py (original)
+++ pypy/branch/jitypes2/pypy/jit/metainterp/test/test_resume.py Tue Nov 23 13:26:19 2010
@@ -51,6 +51,7 @@
class MyMetaInterp:
_already_allocated_resume_virtuals = None
+ callinfocollection = None
def __init__(self, cpu=None):
if cpu is None:
@@ -141,6 +142,13 @@
assert bh.written_f == expected_f
+def Numbering(prev, nums):
+ numb = lltype.malloc(NUMBERING, len(nums))
+ numb.prev = prev or lltype.nullptr(NUMBERING)
+ for i in range(len(nums)):
+ numb.nums[i] = nums[i]
+ return numb
+
def test_simple_read():
#b1, b2, b3 = [BoxInt(), BoxPtr(), BoxInt()]
c1, c2, c3 = [ConstInt(111), ConstInt(222), ConstInt(333)]
@@ -156,12 +164,12 @@
storage.rd_numb = numb
#
cpu = MyCPU([42, gcref1, -66])
- reader = ResumeDataDirectReader(cpu, storage)
+ metainterp = MyMetaInterp(cpu)
+ reader = ResumeDataDirectReader(metainterp, storage)
_next_section(reader, 42, 111, gcrefnull, 42, gcref1)
_next_section(reader, 222, 333)
_next_section(reader, 42, gcref1, -66)
#
- metainterp = MyMetaInterp(cpu)
reader = ResumeDataBoxReader(storage, metainterp)
bi, br, bf = [None]*3, [None]*2, [None]*0
info = MyBlackholeInterp([lltype.Signed, lltype.Signed,
@@ -193,7 +201,7 @@
storage.rd_numb = numb
#
cpu = MyCPU([])
- reader = ResumeDataDirectReader(cpu, storage)
+ reader = ResumeDataDirectReader(MyMetaInterp(cpu), storage)
_next_section(reader, 100)
@@ -211,7 +219,7 @@
class FakeMetainterp(object):
_already_allocated_resume_virtuals = None
cpu = None
- reader = ResumeDataDirectReader(None, FakeStorage())
+ reader = ResumeDataDirectReader(MyMetaInterp(None), FakeStorage())
assert reader.force_all_virtuals() == ["allocated", reader.virtual_default]
# ____________________________________________________________
@@ -390,15 +398,15 @@
assert fi1.pc == 3
def test_Numbering_create():
- l = [1, 2]
+ l = [rffi.r_short(1), rffi.r_short(2)]
numb = Numbering(None, l)
- assert numb.prev is None
- assert numb.nums is l
+ assert not numb.prev
+ assert list(numb.nums) == l
- l1 = ['b3']
+ l1 = [rffi.r_short(3)]
numb1 = Numbering(numb, l1)
- assert numb1.prev is numb
- assert numb1.nums is l1
+ assert numb1.prev == numb
+ assert list(numb1.nums) == l1
def test_capture_resumedata():
b1, b2, b3 = [BoxInt(), BoxPtr(), BoxInt()]
@@ -764,11 +772,12 @@
assert liveboxes == {b1: tag(0, TAGBOX), b2: tag(1, TAGBOX),
b3: tag(2, TAGBOX)}
- assert numb.nums == [tag(3, TAGINT), tag(2, TAGBOX), tag(0, TAGBOX),
- tag(1, TAGINT)]
- assert numb.prev.nums == [tag(0, TAGBOX), tag(1, TAGINT), tag(1, TAGBOX),
- tag(0, TAGBOX), tag(2, TAGINT)]
- assert numb.prev.prev is None
+ assert list(numb.nums) == [tag(3, TAGINT), tag(2, TAGBOX), tag(0, TAGBOX),
+ tag(1, TAGINT)]
+ assert list(numb.prev.nums) == [tag(0, TAGBOX), tag(1, TAGINT),
+ tag(1, TAGBOX),
+ tag(0, TAGBOX), tag(2, TAGINT)]
+ assert not numb.prev.prev
numb2, liveboxes2, v = memo.number({}, snap2)
assert v == 0
@@ -776,9 +785,9 @@
assert liveboxes2 == {b1: tag(0, TAGBOX), b2: tag(1, TAGBOX),
b3: tag(2, TAGBOX)}
assert liveboxes2 is not liveboxes
- assert numb2.nums == [tag(3, TAGINT), tag(2, TAGBOX), tag(0, TAGBOX),
- tag(3, TAGINT)]
- assert numb2.prev is numb.prev
+ assert list(numb2.nums) == [tag(3, TAGINT), tag(2, TAGBOX), tag(0, TAGBOX),
+ tag(3, TAGINT)]
+ assert numb2.prev == numb.prev
env3 = [c3, b3, b1, c3]
snap3 = Snapshot(snap, env3)
@@ -799,9 +808,9 @@
assert v == 0
assert liveboxes3 == {b1: tag(0, TAGBOX), b2: tag(1, TAGBOX)}
- assert numb3.nums == [tag(3, TAGINT), tag(4, TAGINT), tag(0, TAGBOX),
- tag(3, TAGINT)]
- assert numb3.prev is numb.prev
+ assert list(numb3.nums) == [tag(3, TAGINT), tag(4, TAGINT), tag(0, TAGBOX),
+ tag(3, TAGINT)]
+ assert numb3.prev == numb.prev
# virtual
env4 = [c3, b4, b1, c3]
@@ -812,9 +821,9 @@
assert liveboxes4 == {b1: tag(0, TAGBOX), b2: tag(1, TAGBOX),
b4: tag(0, TAGVIRTUAL)}
- assert numb4.nums == [tag(3, TAGINT), tag(0, TAGVIRTUAL), tag(0, TAGBOX),
- tag(3, TAGINT)]
- assert numb4.prev is numb.prev
+ assert list(numb4.nums) == [tag(3, TAGINT), tag(0, TAGVIRTUAL),
+ tag(0, TAGBOX), tag(3, TAGINT)]
+ assert numb4.prev == numb.prev
env5 = [b1, b4, b5]
snap5 = Snapshot(snap4, env5)
@@ -825,9 +834,9 @@
assert liveboxes5 == {b1: tag(0, TAGBOX), b2: tag(1, TAGBOX),
b4: tag(0, TAGVIRTUAL), b5: tag(1, TAGVIRTUAL)}
- assert numb5.nums == [tag(0, TAGBOX), tag(0, TAGVIRTUAL),
- tag(1, TAGVIRTUAL)]
- assert numb5.prev is numb4
+ assert list(numb5.nums) == [tag(0, TAGBOX), tag(0, TAGVIRTUAL),
+ tag(1, TAGVIRTUAL)]
+ assert numb5.prev == numb4
def test_ResumeDataLoopMemo_number_boxes():
memo = ResumeDataLoopMemo(FakeMetaInterpStaticData())
@@ -925,7 +934,7 @@
liveboxes = modifier.finish({})
assert storage.rd_snapshot is None
cpu = MyCPU([])
- reader = ResumeDataDirectReader(cpu, storage)
+ reader = ResumeDataDirectReader(MyMetaInterp(cpu), storage)
_next_section(reader, sys.maxint, 2**16, -65)
_next_section(reader, 2, 3)
_next_section(reader, sys.maxint, 1, sys.maxint, 2**16)
Modified: pypy/branch/jitypes2/pypy/jit/metainterp/test/test_virtualref.py
==============================================================================
--- pypy/branch/jitypes2/pypy/jit/metainterp/test/test_virtualref.py (original)
+++ pypy/branch/jitypes2/pypy/jit/metainterp/test/test_virtualref.py Tue Nov 23 13:26:19 2010
@@ -88,7 +88,11 @@
cpu.get_latest_value_int = lambda i:guard_op.getfailargs()[i].getint()
cpu.get_latest_value_ref = lambda i:guard_op.getfailargs()[i].getref_base()
cpu.clear_latest_values = lambda count: None
- resumereader = ResumeDataDirectReader(cpu, guard_op.getdescr())
+ class FakeMetaInterpSd:
+ callinfocollection = None
+ FakeMetaInterpSd.cpu = cpu
+ resumereader = ResumeDataDirectReader(FakeMetaInterpSd(),
+ guard_op.getdescr())
vrefinfo = self.metainterp.staticdata.virtualref_info
lst = []
vrefinfo.continue_tracing = lambda vref, virtual: \
Modified: pypy/branch/jitypes2/pypy/jit/metainterp/test/test_ztranslation.py
==============================================================================
--- pypy/branch/jitypes2/pypy/jit/metainterp/test/test_ztranslation.py (original)
+++ pypy/branch/jitypes2/pypy/jit/metainterp/test/test_ztranslation.py Tue Nov 23 13:26:19 2010
@@ -79,7 +79,7 @@
res = ll_meta_interp(main, [40, 5], CPUClass=self.CPUClass,
type_system=self.type_system)
assert res == main(40, 5)
- res = rpython_ll_meta_interp(main, [40, 5], loops=2,
+ res = rpython_ll_meta_interp(main, [40, 5],
CPUClass=self.CPUClass,
type_system=self.type_system,
optimizer=OPTIMIZER_FULL,
@@ -120,7 +120,7 @@
res = ll_meta_interp(main, [40], CPUClass=self.CPUClass,
type_system=self.type_system)
assert res == main(40)
- res = rpython_ll_meta_interp(main, [40], loops=2, CPUClass=self.CPUClass,
+ res = rpython_ll_meta_interp(main, [40], CPUClass=self.CPUClass,
type_system=self.type_system,
optimizer=OPTIMIZER_FULL,
ProfilerClass=Profiler)
Modified: pypy/branch/jitypes2/pypy/jit/metainterp/virtualizable.py
==============================================================================
--- pypy/branch/jitypes2/pypy/jit/metainterp/virtualizable.py (original)
+++ pypy/branch/jitypes2/pypy/jit/metainterp/virtualizable.py Tue Nov 23 13:26:19 2010
@@ -100,48 +100,48 @@
i = i + 1
assert len(boxes) == i + 1
#
- def write_from_resume_data_partial(virtualizable, reader, nums):
+ def write_from_resume_data_partial(virtualizable, reader, numb):
# Load values from the reader (see resume.py) described by
# the list of numbers 'nums', and write them in their proper
# place in the 'virtualizable'. This works from the end of
# the list and returns the index in 'nums' of the start of
# the virtualizable data found, allowing the caller to do
# further processing with the start of the list.
- i = len(nums) - 1
+ i = len(numb.nums) - 1
assert i >= 0
for ARRAYITEMTYPE, fieldname in unroll_array_fields_rev:
lst = getattr(virtualizable, fieldname)
for j in range(getlength(lst)-1, -1, -1):
i -= 1
assert i >= 0
- x = reader.load_value_of_type(ARRAYITEMTYPE, nums[i])
+ x = reader.load_value_of_type(ARRAYITEMTYPE, numb.nums[i])
setarrayitem(lst, j, x)
for FIELDTYPE, fieldname in unroll_static_fields_rev:
i -= 1
assert i >= 0
- x = reader.load_value_of_type(FIELDTYPE, nums[i])
+ x = reader.load_value_of_type(FIELDTYPE, numb.nums[i])
setattr(virtualizable, fieldname, x)
return i
#
- def load_list_of_boxes(virtualizable, reader, nums):
+ def load_list_of_boxes(virtualizable, reader, numb):
# Uses 'virtualizable' only to know the length of the arrays;
# does not write anything into it. The returned list is in
# the format expected of virtualizable_boxes, so it ends in
# the virtualizable itself.
- i = len(nums) - 1
+ i = len(numb.nums) - 1
assert i >= 0
- boxes = [reader.decode_box_of_type(self.VTYPEPTR, nums[i])]
+ boxes = [reader.decode_box_of_type(self.VTYPEPTR, numb.nums[i])]
for ARRAYITEMTYPE, fieldname in unroll_array_fields_rev:
lst = getattr(virtualizable, fieldname)
for j in range(getlength(lst)-1, -1, -1):
i -= 1
assert i >= 0
- box = reader.decode_box_of_type(ARRAYITEMTYPE, nums[i])
+ box = reader.decode_box_of_type(ARRAYITEMTYPE,numb.nums[i])
boxes.append(box)
for FIELDTYPE, fieldname in unroll_static_fields_rev:
i -= 1
assert i >= 0
- box = reader.decode_box_of_type(FIELDTYPE, nums[i])
+ box = reader.decode_box_of_type(FIELDTYPE, numb.nums[i])
boxes.append(box)
boxes.reverse()
return boxes
Modified: pypy/branch/jitypes2/pypy/jit/metainterp/warmspot.py
==============================================================================
--- pypy/branch/jitypes2/pypy/jit/metainterp/warmspot.py (original)
+++ pypy/branch/jitypes2/pypy/jit/metainterp/warmspot.py Tue Nov 23 13:26:19 2010
@@ -98,8 +98,7 @@
repeat -= 1
return res
-def rpython_ll_meta_interp(function, args, backendopt=True,
- loops='not used right now', **kwds):
+def rpython_ll_meta_interp(function, args, backendopt=True, **kwds):
return ll_meta_interp(function, args, backendopt=backendopt,
translate_support_code=True, **kwds)
Modified: pypy/branch/jitypes2/pypy/jit/tool/pypytrace-mode.el
==============================================================================
--- pypy/branch/jitypes2/pypy/jit/tool/pypytrace-mode.el (original)
+++ pypy/branch/jitypes2/pypy/jit/tool/pypytrace-mode.el Tue Nov 23 13:26:19 2010
@@ -26,7 +26,7 @@
("<.*FieldDescr \\([^ ]*\\)" (1 'font-lock-variable-name-face))
;; comment out debug_merge_point, but then highlight specific part of it
("^debug_merge_point.*" . font-lock-comment-face)
- ("^\\(debug_merge_point\\).*code object\\(.*\\), file \\('.*'\\), \\(line .*\\)> \\(.*\\)')"
+ ("^\\(debug_merge_point\\).*code object\\(.*\\), file \\('.*'\\), \\(line .*\\)> \\(.*\\)"
(1 'compilation-warning t)
(2 'escape-glyph t)
(3 'font-lock-string-face t)
Modified: pypy/branch/jitypes2/pypy/module/__pypy__/__init__.py
==============================================================================
--- pypy/branch/jitypes2/pypy/module/__pypy__/__init__.py (original)
+++ pypy/branch/jitypes2/pypy/module/__pypy__/__init__.py Tue Nov 23 13:26:19 2010
@@ -23,6 +23,9 @@
'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)
#
Modified: pypy/branch/jitypes2/pypy/module/__pypy__/interp_magic.py
==============================================================================
--- pypy/branch/jitypes2/pypy/module/__pypy__/interp_magic.py (original)
+++ pypy/branch/jitypes2/pypy/module/__pypy__/interp_magic.py Tue Nov 23 13:26:19 2010
@@ -2,6 +2,7 @@
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 @@
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]
Modified: pypy/branch/jitypes2/pypy/module/_rawffi/test/test__rawffi.py
==============================================================================
--- pypy/branch/jitypes2/pypy/module/_rawffi/test/test__rawffi.py (original)
+++ pypy/branch/jitypes2/pypy/module/_rawffi/test/test__rawffi.py Tue Nov 23 13:26:19 2010
@@ -296,6 +296,7 @@
assert _rawffi.charp2string(res[0]) is None
arg1.free()
arg2.free()
+ a.free()
def test_raw_callable(self):
import _rawffi
Modified: pypy/branch/jitypes2/pypy/module/_rawffi/test/test_nested.py
==============================================================================
--- pypy/branch/jitypes2/pypy/module/_rawffi/test/test_nested.py (original)
+++ pypy/branch/jitypes2/pypy/module/_rawffi/test/test_nested.py Tue Nov 23 13:26:19 2010
@@ -107,7 +107,6 @@
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')
Modified: pypy/branch/jitypes2/pypy/module/array/interp_array.py
==============================================================================
--- pypy/branch/jitypes2/pypy/module/array/interp_array.py (original)
+++ pypy/branch/jitypes2/pypy/module/array/interp_array.py Tue Nov 23 13:26:19 2010
@@ -27,7 +27,7 @@
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))
Modified: pypy/branch/jitypes2/pypy/module/cpyext/api.py
==============================================================================
--- pypy/branch/jitypes2/pypy/module/cpyext/api.py (original)
+++ pypy/branch/jitypes2/pypy/module/cpyext/api.py Tue Nov 23 13:26:19 2010
@@ -226,7 +226,7 @@
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 @@
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 @@
@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 @@
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 @@
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,
Modified: pypy/branch/jitypes2/pypy/module/cpyext/cdatetime.py
==============================================================================
--- pypy/branch/jitypes2/pypy/module/cpyext/cdatetime.py (original)
+++ pypy/branch/jitypes2/pypy/module/cpyext/cdatetime.py Tue Nov 23 13:26:19 2010
@@ -4,7 +4,7 @@
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 @@
@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
Modified: pypy/branch/jitypes2/pypy/module/cpyext/presetup.py
==============================================================================
--- pypy/branch/jitypes2/pypy/module/cpyext/presetup.py (original)
+++ pypy/branch/jitypes2/pypy/module/cpyext/presetup.py Tue Nov 23 13:26:19 2010
@@ -21,6 +21,8 @@
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 patch_distutils():
sysconfig.get_python_inc = get_python_inc
+ sysconfig.get_config_vars()['SO'] = get_so_extension(space)
patch_distutils()
Modified: pypy/branch/jitypes2/pypy/module/cpyext/pyobject.py
==============================================================================
--- pypy/branch/jitypes2/pypy/module/cpyext/pyobject.py (original)
+++ pypy/branch/jitypes2/pypy/module/cpyext/pyobject.py Tue Nov 23 13:26:19 2010
@@ -424,7 +424,18 @@
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 @@
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)
Modified: pypy/branch/jitypes2/pypy/module/cpyext/test/test_borrow.py
==============================================================================
--- pypy/branch/jitypes2/pypy/module/cpyext/test/test_borrow.py (original)
+++ pypy/branch/jitypes2/pypy/module/cpyext/test/test_borrow.py Tue Nov 23 13:26:19 2010
@@ -31,6 +31,7 @@
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;
"""),
Modified: pypy/branch/jitypes2/pypy/module/cpyext/test/test_cpyext.py
==============================================================================
--- pypy/branch/jitypes2/pypy/module/cpyext/test/test_cpyext.py (original)
+++ pypy/branch/jitypes2/pypy/module/cpyext/test/test_cpyext.py Tue Nov 23 13:26:19 2010
@@ -42,7 +42,7 @@
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 @@
[], 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 @@
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):
Modified: pypy/branch/jitypes2/pypy/module/cpyext/typeobject.py
==============================================================================
--- pypy/branch/jitypes2/pypy/module/cpyext/typeobject.py (original)
+++ pypy/branch/jitypes2/pypy/module/cpyext/typeobject.py Tue Nov 23 13:26:19 2010
@@ -182,10 +182,10 @@
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 @@
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 @@
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 @@
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.
Modified: pypy/branch/jitypes2/pypy/module/gc/__init__.py
==============================================================================
--- pypy/branch/jitypes2/pypy/module/gc/__init__.py (original)
+++ pypy/branch/jitypes2/pypy/module/gc/__init__.py Tue Nov 23 13:26:19 2010
@@ -29,6 +29,7 @@
'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)
Modified: pypy/branch/jitypes2/pypy/module/gc/app_referents.py
==============================================================================
--- pypy/branch/jitypes2/pypy/module/gc/app_referents.py (original)
+++ pypy/branch/jitypes2/pypy/module/gc/app_referents.py Tue Nov 23 13:26:19 2010
@@ -14,11 +14,25 @@
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
Modified: pypy/branch/jitypes2/pypy/module/gc/interp_gc.py
==============================================================================
--- pypy/branch/jitypes2/pypy/module/gc/interp_gc.py (original)
+++ pypy/branch/jitypes2/pypy/module/gc/interp_gc.py Tue Nov 23 13:26:19 2010
@@ -10,6 +10,10 @@
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)
Modified: pypy/branch/jitypes2/pypy/module/gc/referents.py
==============================================================================
--- pypy/branch/jitypes2/pypy/module/gc/referents.py (original)
+++ pypy/branch/jitypes2/pypy/module/gc/referents.py Tue Nov 23 13:26:19 2010
@@ -177,3 +177,9 @@
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]
Modified: pypy/branch/jitypes2/pypy/module/gc/test/test_gc.py
==============================================================================
--- pypy/branch/jitypes2/pypy/module/gc/test/test_gc.py (original)
+++ pypy/branch/jitypes2/pypy/module/gc/test/test_gc.py Tue Nov 23 13:26:19 2010
@@ -117,6 +117,33 @@
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
Modified: pypy/branch/jitypes2/pypy/module/imp/importing.py
==============================================================================
--- pypy/branch/jitypes2/pypy/module/imp/importing.py (original)
+++ pypy/branch/jitypes2/pypy/module/imp/importing.py Tue Nov 23 13:26:19 2010
@@ -12,7 +12,7 @@
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_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'
+
+ at 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 @@
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"
Modified: pypy/branch/jitypes2/pypy/module/imp/interp_imp.py
==============================================================================
--- pypy/branch/jitypes2/pypy/module/imp/interp_imp.py (original)
+++ pypy/branch/jitypes2/pypy/module/imp/interp_imp.py Tue Nov 23 13:26:19 2010
@@ -8,10 +8,16 @@
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)
Modified: pypy/branch/jitypes2/pypy/module/imp/test/test_app.py
==============================================================================
--- pypy/branch/jitypes2/pypy/module/imp/test/test_app.py (original)
+++ pypy/branch/jitypes2/pypy/module/imp/test/test_app.py Tue Nov 23 13:26:19 2010
@@ -47,6 +47,9 @@
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):
Modified: pypy/branch/jitypes2/pypy/module/imp/test/test_import.py
==============================================================================
--- pypy/branch/jitypes2/pypy/module/imp/test/test_import.py (original)
+++ pypy/branch/jitypes2/pypy/module/imp/test/test_import.py Tue Nov 23 13:26:19 2010
@@ -473,6 +473,17 @@
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:]
Modified: pypy/branch/jitypes2/pypy/module/posix/interp_posix.py
==============================================================================
--- pypy/branch/jitypes2/pypy/module/posix/interp_posix.py (original)
+++ pypy/branch/jitypes2/pypy/module/posix/interp_posix.py Tue Nov 23 13:26:19 2010
@@ -454,7 +454,8 @@
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):
Modified: pypy/branch/jitypes2/pypy/module/pypyjit/__init__.py
==============================================================================
--- pypy/branch/jitypes2/pypy/module/pypyjit/__init__.py (original)
+++ pypy/branch/jitypes2/pypy/module/pypyjit/__init__.py Tue Nov 23 13:26:19 2010
@@ -15,6 +15,5 @@
# add the 'defaults' attribute
from pypy.rlib.jit import PARAMETERS
space = self.space
- # XXX this is not really the default compiled into a pypy-c-jit XXX
w_obj = space.wrap(PARAMETERS)
space.setattr(space.wrap(self), space.wrap('defaults'), w_obj)
Modified: pypy/branch/jitypes2/pypy/module/pypyjit/test/test_pypy_c.py
==============================================================================
--- pypy/branch/jitypes2/pypy/module/pypyjit/test/test_pypy_c.py (original)
+++ pypy/branch/jitypes2/pypy/module/pypyjit/test/test_pypy_c.py Tue Nov 23 13:26:19 2010
@@ -377,10 +377,75 @@
([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('''
Modified: pypy/branch/jitypes2/pypy/module/rctime/interp_time.py
==============================================================================
--- pypy/branch/jitypes2/pypy/module/rctime/interp_time.py (original)
+++ pypy/branch/jitypes2/pypy/module/rctime/interp_time.py Tue Nov 23 13:26:19 2010
@@ -69,7 +69,7 @@
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)
Modified: pypy/branch/jitypes2/pypy/module/sys/state.py
==============================================================================
--- pypy/branch/jitypes2/pypy/module/sys/state.py (original)
+++ pypy/branch/jitypes2/pypy/module/sys/state.py Tue Nov 23 13:26:19 2010
@@ -33,6 +33,8 @@
raise OSError(errno.ENOTDIR, path)
+platform = sys.platform
+
def getinitialpath(prefix):
from pypy.module.sys.version import CPYTHON_VERSION
dirname = '%d.%d.%d' % (CPYTHON_VERSION[0],
@@ -51,6 +53,15 @@
importlist.append(lib_pypy)
importlist.append(python_std_lib_modified)
importlist.append(python_std_lib)
+ #
+ # List here the extra platform-specific paths.
+ if platform != 'win32':
+ importlist.append(os.path.join(python_std_lib, 'plat-'+platform))
+ if platform == 'darwin':
+ platmac = os.path.join(python_std_lib, 'plat-mac')
+ importlist.append(platmac)
+ importlist.append(os.path.join(platmac, 'lib-scriptpackages'))
+ #
return importlist
def pypy_initial_path(space, srcdir):
Modified: pypy/branch/jitypes2/pypy/module/sys/test/test_initialpath.py
==============================================================================
--- pypy/branch/jitypes2/pypy/module/sys/test/test_initialpath.py (original)
+++ pypy/branch/jitypes2/pypy/module/sys/test/test_initialpath.py Tue Nov 23 13:26:19 2010
@@ -15,4 +15,5 @@
def test_stdlib_in_prefix(tmpdir):
dirs = build_hierarchy(tmpdir)
path = getinitialpath(str(tmpdir))
- assert path == map(str, dirs)
+ # we get at least 'dirs', and maybe more (e.g. plat-linux2)
+ assert path[:len(dirs)] == map(str, dirs)
Modified: pypy/branch/jitypes2/pypy/objspace/flow/model.py
==============================================================================
--- pypy/branch/jitypes2/pypy/objspace/flow/model.py (original)
+++ pypy/branch/jitypes2/pypy/objspace/flow/model.py Tue Nov 23 13:26:19 2010
@@ -355,7 +355,7 @@
return "%r = %s(%s)" % (self.result, self.opname,
", ".join(map(repr, self.args)))
-class Atom:
+class Atom(object):
def __init__(self, name):
self.__name__ = name # make save_global happy
def __repr__(self):
Modified: pypy/branch/jitypes2/pypy/objspace/std/callmethod.py
==============================================================================
--- pypy/branch/jitypes2/pypy/objspace/std/callmethod.py (original)
+++ pypy/branch/jitypes2/pypy/objspace/std/callmethod.py Tue Nov 23 13:26:19 2010
@@ -13,6 +13,9 @@
from pypy.interpreter import function
from pypy.objspace.descroperation import object_getattribute
from pypy.rlib import jit, rstack # for resume points
+from pypy.objspace.std.mapdict import LOOKUP_METHOD_mapdict, \
+ LOOKUP_METHOD_mapdict_fill_cache_method
+
# This module exports two extra methods for StdObjSpaceFrame implementing
# the LOOKUP_METHOD and CALL_METHOD opcodes in an efficient way, as well
@@ -30,6 +33,13 @@
#
space = f.space
w_obj = f.popvalue()
+
+ if space.config.objspace.std.withmapdict and not jit.we_are_jitted():
+ # mapdict has an extra-fast version of this function
+ from pypy.objspace.std.mapdict import LOOKUP_METHOD_mapdict
+ if LOOKUP_METHOD_mapdict(f, nameindex, w_obj):
+ return
+
w_name = f.getname_w(nameindex)
w_value = None
@@ -50,6 +60,11 @@
# nothing in the instance
f.pushvalue(w_descr)
f.pushvalue(w_obj)
+ if (space.config.objspace.std.withmapdict and
+ not jit.we_are_jitted()):
+ # let mapdict cache stuff
+ LOOKUP_METHOD_mapdict_fill_cache_method(
+ f.getcode(), nameindex, w_obj, w_type, w_descr)
return
if w_value is None:
w_value = space.getattr(w_obj, w_name)
Modified: pypy/branch/jitypes2/pypy/objspace/std/mapdict.py
==============================================================================
--- pypy/branch/jitypes2/pypy/objspace/std/mapdict.py (original)
+++ pypy/branch/jitypes2/pypy/objspace/std/mapdict.py Tue Nov 23 13:26:19 2010
@@ -1,4 +1,5 @@
from pypy.rlib import jit, objectmodel, debug
+from pypy.rlib.rarithmetic import intmask, r_uint
from pypy.interpreter.baseobjspace import W_Root
from pypy.objspace.std.dictmultiobject import W_DictMultiObject
@@ -15,24 +16,70 @@
# we want to propagate knowledge that the result cannot be negative
class AbstractAttribute(object):
- _immutable_fields_ = ['w_cls']
+ _immutable_fields_ = ['terminator']
cache_attrs = None
_size_estimate = 0
- def __init__(self, space, w_cls):
+ def __init__(self, space, terminator):
self.space = space
- self.w_cls = w_cls
+ assert isinstance(terminator, Terminator)
+ self.terminator = terminator
def read(self, obj, selector):
- raise NotImplementedError("abstract base class")
+ index = self.index(selector)
+ if index < 0:
+ return self.terminator._read_terminator(obj, selector)
+ return obj._mapdict_read_storage(index)
def write(self, obj, selector, w_value):
- raise NotImplementedError("abstract base class")
+ index = self.index(selector)
+ if index < 0:
+ return self.terminator._write_terminator(obj, selector, w_value)
+ obj._mapdict_write_storage(index, w_value)
+ return True
def delete(self, obj, selector):
return None
def index(self, selector):
+ if (self.space.config.objspace.std.withmethodcache and
+ not jit.we_are_jitted()):
+ return self._index_cache(selector)
+ else:
+ return self._index(selector)
+
+ @jit.dont_look_inside
+ def _index_cache(self, selector):
+ space = self.space
+ cache = space.fromcache(IndexCache)
+ SHIFT2 = r_uint.BITS - space.config.objspace.std.methodcachesizeexp
+ SHIFT1 = SHIFT2 - 5
+ attrs_as_int = objectmodel.current_object_addr_as_int(self)
+ # ^^^Note: see comment in typeobject.py for
+ # _pure_lookup_where_with_method_cache()
+ hash_selector = objectmodel.compute_hash(selector)
+ product = intmask(attrs_as_int * hash_selector)
+ index_hash = (r_uint(product) ^ (r_uint(product) << SHIFT1)) >> SHIFT2
+ # ^^^Note2: same comment too
+ cached_attr = cache.attrs[index_hash]
+ if cached_attr is self:
+ cached_selector = cache.selectors[index_hash]
+ if cached_selector == selector:
+ index = cache.indices[index_hash]
+ if space.config.objspace.std.withmethodcachecounter:
+ name = selector[0]
+ cache.hits[name] = cache.hits.get(name, 0) + 1
+ return index
+ index = self._index(selector)
+ cache.attrs[index_hash] = self
+ cache.selectors[index_hash] = selector
+ cache.indices[index_hash] = index
+ if space.config.objspace.std.withmethodcachecounter:
+ name = selector[0]
+ cache.misses[name] = cache.misses.get(name, 0) + 1
+ return index
+
+ def _index(self, selector):
return -1
def copy(self, obj):
@@ -42,7 +89,7 @@
raise NotImplementedError("abstract base class")
def get_terminator(self):
- raise NotImplementedError("abstract base class")
+ return self.terminator
def set_terminator(self, obj, terminator):
raise NotImplementedError("abstract base class")
@@ -95,15 +142,20 @@
raise NotImplementedError("abstract base class")
def __repr__(self):
- return "<%s w_cls=%s>" % (self.__class__.__name__, self.w_cls)
+ return "<%s>" % (self.__class__.__name__,)
class Terminator(AbstractAttribute):
+ _immutable_fields_ = ['w_cls']
- def read(self, obj, selector):
+ def __init__(self, space, w_cls):
+ AbstractAttribute.__init__(self, space, self)
+ self.w_cls = w_cls
+
+ def _read_terminator(self, obj, selector):
return None
- def write(self, obj, selector, w_value):
+ def _write_terminator(self, obj, selector, w_value):
obj._get_mapdict_map().add_attr(obj, selector, w_value)
return True
@@ -116,9 +168,6 @@
def length(self):
return 0
- def get_terminator(self):
- return self
-
def set_terminator(self, obj, terminator):
result = Object()
result.space = self.space
@@ -128,6 +177,9 @@
def remove_dict_entries(self, obj):
return self.copy(obj)
+ def __repr__(self):
+ return "<%s w_cls=%s>" % (self.__class__.__name__, self.w_cls)
+
class DictTerminator(Terminator):
_immutable_fields_ = ['devolved_dict_terminator']
def __init__(self, space, w_cls):
@@ -142,27 +194,27 @@
class NoDictTerminator(Terminator):
- def write(self, obj, selector, w_value):
+ def _write_terminator(self, obj, selector, w_value):
if selector[1] == DICT:
return False
- return Terminator.write(self, obj, selector, w_value)
+ return Terminator._write_terminator(self, obj, selector, w_value)
class DevolvedDictTerminator(Terminator):
- def read(self, obj, selector):
+ def _read_terminator(self, obj, selector):
if selector[1] == DICT:
w_dict = obj.getdict()
space = self.space
return space.finditem_str(w_dict, selector[0])
- return Terminator.read(self, obj, selector)
+ return Terminator._read_terminator(self, obj, selector)
- def write(self, obj, selector, w_value):
+ def _write_terminator(self, obj, selector, w_value):
if selector[1] == DICT:
w_dict = obj.getdict()
space = self.space
space.setitem_str(w_dict, selector[0], w_value)
return True
- return Terminator.write(self, obj, selector, w_value)
+ return Terminator._write_terminator(self, obj, selector, w_value)
def delete(self, obj, selector):
from pypy.interpreter.error import OperationError
@@ -189,7 +241,7 @@
class PlainAttribute(AbstractAttribute):
_immutable_fields_ = ['selector', 'position', 'back']
def __init__(self, selector, back):
- AbstractAttribute.__init__(self, back.space, back.w_cls)
+ AbstractAttribute.__init__(self, back.space, back.terminator)
self.selector = selector
self.position = back.length()
self.back = back
@@ -199,17 +251,6 @@
w_value = self.read(obj, self.selector)
new_obj._get_mapdict_map().add_attr(new_obj, self.selector, w_value)
- def read(self, obj, selector):
- if selector == self.selector:
- return obj._mapdict_read_storage(self.position)
- return self.back.read(obj, selector)
-
- def write(self, obj, selector, w_value):
- if selector == self.selector:
- obj._mapdict_write_storage(self.position, w_value)
- return True
- return self.back.write(obj, selector, w_value)
-
def delete(self, obj, selector):
if selector == self.selector:
# ok, attribute is deleted
@@ -219,10 +260,10 @@
self._copy_attr(obj, new_obj)
return new_obj
- def index(self, selector):
+ def _index(self, selector):
if selector == self.selector:
return self.position
- return self.back.index(selector)
+ return self.back._index(selector)
def copy(self, obj):
new_obj = self.back.copy(obj)
@@ -232,9 +273,6 @@
def length(self):
return self.position + 1
- def get_terminator(self):
- return self.back.get_terminator()
-
def set_terminator(self, obj, terminator):
new_obj = self.back.set_terminator(obj, terminator)
self._copy_attr(obj, new_obj)
@@ -268,6 +306,24 @@
# RPython reasons
w_obj._set_mapdict_storage_and_map(new_obj.storage, new_obj.map)
+class IndexCache(object):
+ def __init__(self, space):
+ assert space.config.objspace.std.withmethodcache
+ SIZE = 1 << space.config.objspace.std.methodcachesizeexp
+ self.attrs = [None] * SIZE
+ self._empty_selector = (None, INVALID)
+ self.selectors = [self._empty_selector] * SIZE
+ self.indices = [0] * SIZE
+ if space.config.objspace.std.withmethodcachecounter:
+ self.hits = {}
+ self.misses = {}
+
+ def clear(self):
+ for i in range(len(self.attrs)):
+ self.attrs[i] = None
+ for i in range(len(self.selectors)):
+ self.selectors[i] = self._empty_selector
+
# ____________________________________________________________
# object implementation
@@ -328,7 +384,7 @@
assert flag
def getclass(self, space):
- return self._get_mapdict_map().w_cls
+ return self._get_mapdict_map().terminator.w_cls
def setclass(self, space, w_cls):
new_obj = self._get_mapdict_map().set_terminator(self, w_cls.terminator)
@@ -373,6 +429,7 @@
self.storage = make_sure_not_resized([None] * map.size_estimate())
def _mapdict_read_storage(self, index):
+ assert index >= 0
return self.storage[index]
def _mapdict_write_storage(self, index, value):
self.storage[index] = value
@@ -440,6 +497,7 @@
return rerased.unerase_fixedsizelist(erased, W_Root)
def _mapdict_read_storage(self, index):
+ assert index >= 0
for i in rangenmin1:
if index == i:
erased = getattr(self, "_value%s" % i)
@@ -604,30 +662,54 @@
map = None
version_tag = None
index = 0
+ w_method = None # for callmethod
success_counter = 0
failure_counter = 0
+ def is_valid_for_obj(self, w_obj):
+ map = w_obj._get_mapdict_map()
+ return self.is_valid_for_map(map)
+
+ def is_valid_for_map(self, map):
+ if map is self.map:
+ version_tag = map.terminator.w_cls.version_tag()
+ if version_tag is self.version_tag:
+ # everything matches, it's incredibly fast
+ if map.space.config.objspace.std.withmethodcachecounter:
+ self.success_counter += 1
+ return True
+ return False
+
INVALID_CACHE_ENTRY = CacheEntry()
INVALID_CACHE_ENTRY.map = objectmodel.instantiate(AbstractAttribute)
# different from any real map ^^^
-INVALID_CACHE_ENTRY.map.w_cls = None
+INVALID_CACHE_ENTRY.map.terminator = None
+
def init_mapdict_cache(pycode):
num_entries = len(pycode.co_names_w)
pycode._mapdict_caches = [INVALID_CACHE_ENTRY] * num_entries
+def _fill_cache(pycode, nameindex, map, version_tag, index, w_method=None):
+ entry = pycode._mapdict_caches[nameindex]
+ if entry is INVALID_CACHE_ENTRY:
+ entry = CacheEntry()
+ pycode._mapdict_caches[nameindex] = entry
+ entry.map = map
+ entry.version_tag = version_tag
+ entry.index = index
+ entry.w_method = w_method
+ if pycode.space.config.objspace.std.withmethodcachecounter:
+ entry.failure_counter += 1
+
def LOAD_ATTR_caching(pycode, w_obj, nameindex):
# this whole mess is to make the interpreter quite a bit faster; it's not
# used if we_are_jitted().
entry = pycode._mapdict_caches[nameindex]
map = w_obj._get_mapdict_map()
- if map is entry.map:
- version_tag = map.w_cls.version_tag()
- if version_tag is entry.version_tag:
- # everything matches, it's incredibly fast
- if pycode.space.config.objspace.std.withmethodcachecounter:
- entry.success_counter += 1
- return w_obj._mapdict_read_storage(entry.index)
+ if entry.is_valid_for_map(map) and entry.w_method is None:
+ # everything matches, it's incredibly fast
+ return w_obj._mapdict_read_storage(entry.index)
return LOAD_ATTR_slowpath(pycode, w_obj, nameindex, map)
LOAD_ATTR_caching._always_inline_ = True
@@ -635,7 +717,7 @@
space = pycode.space
w_name = pycode.co_names_w[nameindex]
if map is not None:
- w_type = map.w_cls
+ w_type = map.terminator.w_cls
w_descr = w_type.getattribute_if_not_from_object()
if w_descr is not None:
return space._handle_getattribute(w_descr, w_obj, w_name)
@@ -655,17 +737,30 @@
if selector[1] != INVALID:
index = map.index(selector)
if index >= 0:
- entry = pycode._mapdict_caches[nameindex]
- if entry is INVALID_CACHE_ENTRY:
- entry = CacheEntry()
- pycode._mapdict_caches[nameindex] = entry
- entry.map = map
- entry.version_tag = version_tag
- entry.index = index
- if space.config.objspace.std.withmethodcachecounter:
- entry.failure_counter += 1
+ _fill_cache(pycode, nameindex, map, version_tag, index)
return w_obj._mapdict_read_storage(index)
if space.config.objspace.std.withmethodcachecounter:
INVALID_CACHE_ENTRY.failure_counter += 1
return space.getattr(w_obj, w_name)
LOAD_ATTR_slowpath._dont_inline_ = True
+
+def LOOKUP_METHOD_mapdict(f, nameindex, w_obj):
+ space = f.space
+ pycode = f.getcode()
+ entry = pycode._mapdict_caches[nameindex]
+ if entry.is_valid_for_obj(w_obj):
+ w_method = entry.w_method
+ if w_method is not None:
+ f.pushvalue(w_method)
+ f.pushvalue(w_obj)
+ return True
+ return False
+
+def LOOKUP_METHOD_mapdict_fill_cache_method(pycode, nameindex, w_obj, w_type, w_method):
+ version_tag = w_type.version_tag()
+ if version_tag is None:
+ return
+ map = w_obj._get_mapdict_map()
+ if map is None:
+ return
+ _fill_cache(pycode, nameindex, map, version_tag, -1, w_method)
Modified: pypy/branch/jitypes2/pypy/objspace/std/test/test_dictmultiobject.py
==============================================================================
--- pypy/branch/jitypes2/pypy/objspace/std/test/test_dictmultiobject.py (original)
+++ pypy/branch/jitypes2/pypy/objspace/std/test/test_dictmultiobject.py Tue Nov 23 13:26:19 2010
@@ -616,6 +616,7 @@
withdictmeasurement = False
withsmalldicts = False
withcelldict = False
+ withmethodcache = False
class opcodes:
CALL_LIKELY_BUILTIN = False
Modified: pypy/branch/jitypes2/pypy/objspace/std/test/test_mapdict.py
==============================================================================
--- pypy/branch/jitypes2/pypy/objspace/std/test/test_mapdict.py (original)
+++ pypy/branch/jitypes2/pypy/objspace/std/test/test_mapdict.py Tue Nov 23 13:26:19 2010
@@ -24,13 +24,13 @@
hasdict = False
def test_plain_attribute():
- space = " "
w_cls = "class"
aa = PlainAttribute(("b", DICT),
PlainAttribute(("a", DICT),
Terminator(space, w_cls)))
assert aa.space is space
- assert aa.w_cls is w_cls
+ assert aa.terminator.w_cls is w_cls
+ assert aa.get_terminator() is aa.terminator
obj = Object()
obj.map, obj.storage = aa, [10, 20]
@@ -604,7 +604,8 @@
from pypy.interpreter import gateway
cls.space = gettestobjspace(
**{"objspace.std.withmapdict": True,
- "objspace.std.withmethodcachecounter": True})
+ "objspace.std.withmethodcachecounter": True,
+ "objspace.opcodes.CALL_METHOD": True})
#
def check(space, w_func, name):
w_code = space.getattr(w_func, space.wrap('func_code'))
@@ -785,6 +786,135 @@
res = self.check(f, 'x')
assert res == (0, 0, 1)
+ def test_call_method_uses_cache(self):
+ # bit sucky
+ global C
+
+ class C(object):
+ def m(*args):
+ return args
+ C.sm = staticmethod(C.m.im_func)
+ C.cm = classmethod(C.m.im_func)
+
+ exec """if 1:
+
+ def f():
+ c = C()
+ res = c.m(1)
+ assert res == (c, 1)
+ return 42
+
+ def g():
+ c = C()
+ res = c.sm(1)
+ assert res == (1, )
+ return 42
+
+ def h():
+ c = C()
+ res = c.cm(1)
+ assert res == (C, 1)
+ return 42
+ """
+ res = self.check(f, 'm')
+ assert res == (1, 0, 0)
+ res = self.check(f, 'm')
+ assert res == (0, 1, 0)
+ res = self.check(f, 'm')
+ assert res == (0, 1, 0)
+ res = self.check(f, 'm')
+ assert res == (0, 1, 0)
+
+ # static methods are not cached
+ res = self.check(g, 'sm')
+ assert res == (0, 0, 0)
+ res = self.check(g, 'sm')
+ assert res == (0, 0, 0)
+
+ # neither are class methods
+ res = self.check(h, 'cm')
+ assert res == (0, 0, 0)
+ res = self.check(h, 'cm')
+ assert res == (0, 0, 0)
+
+ def test_mix_cache_bug(self):
+ # bit sucky
+ global C
+
+ class C(object):
+ def m(*args):
+ return args
+
+ exec """if 1:
+
+ def f():
+ c = C()
+ res = c.m(1)
+ assert res == (c, 1)
+ bm = c.m
+ res = bm(1)
+ assert res == (c, 1)
+ return 42
+
+ """
+ res = self.check(f, 'm')
+ assert res == (1, 1, 1)
+ res = self.check(f, 'm')
+ assert res == (0, 2, 1)
+ res = self.check(f, 'm')
+ assert res == (0, 2, 1)
+ res = self.check(f, 'm')
+ assert res == (0, 2, 1)
+
+class AppTestGlobalCaching(AppTestWithMapDict):
+ def setup_class(cls):
+ cls.space = gettestobjspace(
+ **{"objspace.std.withmethodcachecounter": True,
+ "objspace.std.withmapdict": True,
+ "objspace.opcodes.CALL_METHOD": True})
+
+ def test_mix_classes(self):
+ import __pypy__
+ class A(object):
+ def f(self):
+ return 42
+ class B(object):
+ def f(self):
+ return 43
+ class C(object):
+ def f(self):
+ return 44
+ l = [A(), B(), C()] * 10
+ __pypy__.reset_method_cache_counter()
+ # 'exec' to make sure that a.f() is compiled with CALL_METHOD
+ exec """for i, a in enumerate(l):
+ assert a.f() == 42 + i % 3
+"""
+ cache_counter = __pypy__.mapdict_cache_counter("f")
+ assert cache_counter[0] >= 15
+ assert cache_counter[1] >= 3 # should be (27, 3)
+ assert sum(cache_counter) == 30
+
+ def test_mix_classes_attribute(self):
+ import __pypy__
+ class A(object):
+ def __init__(self):
+ self.x = 42
+ class B(object):
+ def __init__(self):
+ self.x = 43
+ class C(object):
+ def __init__(self):
+ self.x = 44
+ l = [A(), B(), C()] * 10
+ __pypy__.reset_method_cache_counter()
+ for i, a in enumerate(l):
+ assert a.x == 42 + i % 3
+ cache_counter = __pypy__.mapdict_cache_counter("x")
+ assert cache_counter[0] >= 15
+ assert cache_counter[1] >= 3 # should be (27, 3)
+ assert sum(cache_counter) == 30
+
class TestDictSubclassShortcutBug(object):
def setup_class(cls):
cls.space = gettestobjspace(
Modified: pypy/branch/jitypes2/pypy/rlib/clibffi.py
==============================================================================
--- pypy/branch/jitypes2/pypy/rlib/clibffi.py (original)
+++ pypy/branch/jitypes2/pypy/rlib/clibffi.py Tue Nov 23 13:26:19 2010
@@ -432,7 +432,8 @@
flags=FUNCFLAG_CDECL):
AbstractFuncPtr.__init__(self, "callback", argtypes, restype, flags)
self.ll_closure = closureHeap.alloc()
- self.ll_userdata = lltype.malloc(USERDATA_P.TO, flavor='raw')
+ self.ll_userdata = lltype.malloc(USERDATA_P.TO, flavor='raw',
+ track_allocation=False)
self.ll_userdata.callback = rffi.llhelper(CALLBACK_TP, func)
self.ll_userdata.addarg = additional_arg
res = c_ffi_prep_closure(self.ll_closure, self.ll_cif,
@@ -447,7 +448,7 @@
closureHeap.free(self.ll_closure)
self.ll_closure = lltype.nullptr(FFI_CLOSUREP.TO)
if self.ll_userdata:
- lltype.free(self.ll_userdata, flavor='raw')
+ lltype.free(self.ll_userdata, flavor='raw', track_allocation=False)
self.ll_userdata = lltype.nullptr(USERDATA_P.TO)
class RawFuncPtr(AbstractFuncPtr):
Modified: pypy/branch/jitypes2/pypy/rlib/rgc.py
==============================================================================
--- pypy/branch/jitypes2/pypy/rlib/rgc.py (original)
+++ pypy/branch/jitypes2/pypy/rlib/rgc.py Tue Nov 23 13:26:19 2010
@@ -379,6 +379,11 @@
"NOT_RPYTHON"
raise NotImplementedError
+def get_typeids_z():
+ "NOT_RPYTHON"
+ raise NotImplementedError
+
+ARRAY_OF_CHAR = lltype.Array(lltype.Char)
NULL_GCREF = lltype.nullptr(llmemory.GCREF.TO)
class _GcRef(object):
@@ -530,3 +535,12 @@
vlist = hop.inputargs(lltype.Signed)
hop.exception_is_here()
return hop.genop('gc_dump_rpy_heap', vlist, resulttype = hop.r_result)
+
+class Entry(ExtRegistryEntry):
+ _about_ = get_typeids_z
+ def compute_result_annotation(self):
+ from pypy.annotation.model import SomePtr
+ return SomePtr(lltype.Ptr(ARRAY_OF_CHAR))
+ def specialize_call(self, hop):
+ hop.exception_is_here()
+ return hop.genop('gc_typeids_z', [], resulttype = hop.r_result)
Modified: pypy/branch/jitypes2/pypy/rpython/annlowlevel.py
==============================================================================
--- pypy/branch/jitypes2/pypy/rpython/annlowlevel.py (original)
+++ pypy/branch/jitypes2/pypy/rpython/annlowlevel.py Tue Nov 23 13:26:19 2010
@@ -136,7 +136,7 @@
return funcdesc.cachedgraph(TYPE, alt_name=valid_identifier(alt_name))
-class MixLevelHelperAnnotator:
+class MixLevelHelperAnnotator(object):
def __init__(self, rtyper):
self.rtyper = rtyper
Modified: pypy/branch/jitypes2/pypy/rpython/llinterp.py
==============================================================================
--- pypy/branch/jitypes2/pypy/rpython/llinterp.py (original)
+++ pypy/branch/jitypes2/pypy/rpython/llinterp.py Tue Nov 23 13:26:19 2010
@@ -912,6 +912,9 @@
def op_gc_dump_rpy_heap(self):
raise NotImplementedError("gc_dump_rpy_heap")
+ def op_gc_typeids_z(self):
+ raise NotImplementedError("gc_typeids_z")
+
def op_do_malloc_fixedsize_clear(self):
raise NotImplementedError("do_malloc_fixedsize_clear")
Modified: pypy/branch/jitypes2/pypy/rpython/lltypesystem/llarena.py
==============================================================================
--- pypy/branch/jitypes2/pypy/rpython/lltypesystem/llarena.py (original)
+++ pypy/branch/jitypes2/pypy/rpython/lltypesystem/llarena.py Tue Nov 23 13:26:19 2010
@@ -440,7 +440,8 @@
[rffi.INT],
rffi.INT,
sandboxsafe=True, _nowrapper=True)
- _dev_zero = rffi.str2charp_immortal('/dev/zero') # prebuilt
+ _dev_zero = rffi.str2charp('/dev/zero') # prebuilt
+ lltype.render_immortal(_dev_zero)
def clear_large_memory_chunk(baseaddr, size):
# on some Unixy platforms, reading from /dev/zero is the fastest way
Modified: pypy/branch/jitypes2/pypy/rpython/lltypesystem/llmemory.py
==============================================================================
--- pypy/branch/jitypes2/pypy/rpython/lltypesystem/llmemory.py (original)
+++ pypy/branch/jitypes2/pypy/rpython/lltypesystem/llmemory.py Tue Nov 23 13:26:19 2010
@@ -766,8 +766,10 @@
return '<%s>' % (self,)
def __str__(self):
return 'gctransformed_wref(%s)' % (self._ptr,)
- def _normalizedcontainer(self):
- return self._ptr._obj
+ def _normalizedcontainer(self, check=True):
+ return self._ptr._getobj(check=check)._normalizedcontainer(check=check)
+ def _was_freed(self):
+ return self._ptr._was_freed()
# ____________________________________________________________
Modified: pypy/branch/jitypes2/pypy/rpython/lltypesystem/lloperation.py
==============================================================================
--- pypy/branch/jitypes2/pypy/rpython/lltypesystem/lloperation.py (original)
+++ pypy/branch/jitypes2/pypy/rpython/lltypesystem/lloperation.py Tue Nov 23 13:26:19 2010
@@ -476,6 +476,7 @@
'gc_get_rpy_type_index': LLOp(),
'gc_is_rpy_instance' : LLOp(),
'gc_dump_rpy_heap' : LLOp(),
+ 'gc_typeids_z' : LLOp(),
# ------- JIT & GC interaction, only for some GCs ----------
Modified: pypy/branch/jitypes2/pypy/rpython/lltypesystem/lltype.py
==============================================================================
--- pypy/branch/jitypes2/pypy/rpython/lltypesystem/lltype.py (original)
+++ pypy/branch/jitypes2/pypy/rpython/lltypesystem/lltype.py Tue Nov 23 13:26:19 2010
@@ -1868,6 +1868,13 @@
leakfinder.remember_free(p._obj0)
p._obj0._free()
+def render_immortal(p, track_allocation=True):
+ T = typeOf(p)
+ if not isinstance(T, Ptr) or p._togckind() != 'raw':
+ raise TypeError, "free(): only for pointers to non-gc containers"
+ if track_allocation:
+ leakfinder.remember_free(p._obj0)
+
def _make_scoped_allocator(T):
class ScopedAlloc:
def __init__(self, n=None, zero=False):
Modified: pypy/branch/jitypes2/pypy/rpython/lltypesystem/rffi.py
==============================================================================
--- pypy/branch/jitypes2/pypy/rpython/lltypesystem/rffi.py (original)
+++ pypy/branch/jitypes2/pypy/rpython/lltypesystem/rffi.py Tue Nov 23 13:26:19 2010
@@ -607,15 +607,6 @@
return array
str2charp._annenforceargs_ = [strtype]
- def str2charp_immortal(s):
- "NOT_RPYTHON"
- array = lltype.malloc(TYPEP.TO, len(s) + 1, flavor='raw',
- immortal=True)
- for i in range(len(s)):
- array[i] = s[i]
- array[len(s)] = lastchar
- return array
-
def free_charp(cp):
lltype.free(cp, flavor='raw')
@@ -734,19 +725,19 @@
l = [cp[i] for i in range(size)]
return emptystr.join(l)
- return (str2charp, str2charp_immortal, free_charp, charp2str,
+ return (str2charp, free_charp, charp2str,
get_nonmovingbuffer, free_nonmovingbuffer,
alloc_buffer, str_from_buffer, keep_buffer_alive_until_here,
charp2strn, charpsize2str,
)
-(str2charp, str2charp_immortal, free_charp, charp2str,
+(str2charp, free_charp, charp2str,
get_nonmovingbuffer, free_nonmovingbuffer,
alloc_buffer, str_from_buffer, keep_buffer_alive_until_here,
charp2strn, charpsize2str,
) = make_string_mappings(str)
-(unicode2wcharp, unicode2wcharp_immortal, free_wcharp, wcharp2unicode,
+(unicode2wcharp, free_wcharp, wcharp2unicode,
get_nonmoving_unicodebuffer, free_nonmoving_unicodebuffer,
alloc_unicodebuffer, unicode_from_buffer, keep_unicodebuffer_alive_until_here,
wcharp2unicoden, wcharpsize2unicode,
Modified: pypy/branch/jitypes2/pypy/rpython/memory/gc/base.py
==============================================================================
--- pypy/branch/jitypes2/pypy/rpython/memory/gc/base.py (original)
+++ pypy/branch/jitypes2/pypy/rpython/memory/gc/base.py Tue Nov 23 13:26:19 2010
@@ -247,6 +247,21 @@
(not self.config.taggedpointers or
llmemory.cast_adr_to_int(addr) & 1 == 0))
+ def enumerate_all_roots(self, callback, arg):
+ """For each root object, invoke callback(obj, arg).
+ 'callback' should not be a bound method.
+ Note that this method is not suitable for actually doing the
+ collection in a moving GC, because you cannot write back a
+ modified address. It is there only for inspection.
+ """
+ # overridden in some subclasses, for GCs which have an additional
+ # list of last generation roots
+ callback2, attrname = _convert_callback_formats(callback) # :-/
+ setattr(self, attrname, arg)
+ self.root_walker.walk_roots(callback2, callback2, callback2)
+ self.run_finalizers.foreach(callback, arg)
+ enumerate_all_roots._annspecialcase_ = 'specialize:arg(1)'
+
def debug_check_consistency(self):
"""To use after a collection. If self.DEBUG is set, this
enumerates all roots and traces all objects to check if we didn't
@@ -260,8 +275,7 @@
self._debug_pending = self.AddressStack()
if not we_are_translated():
self.root_walker._walk_prebuilt_gc(self._debug_record)
- callback = GCBase._debug_callback
- self.root_walker.walk_roots(callback, callback, callback)
+ self.enumerate_all_roots(GCBase._debug_callback, self)
pending = self._debug_pending
while pending.non_empty():
obj = pending.pop()
@@ -275,9 +289,8 @@
seen.add(obj)
self.debug_check_object(obj)
self._debug_pending.append(obj)
- def _debug_callback(self, root):
- obj = root.address[0]
- ll_assert(bool(obj), "NULL address from walk_roots()")
+ @staticmethod
+ def _debug_callback(obj, self):
self._debug_record(obj)
def _debug_callback2(self, pointer, ignored):
obj = pointer.address[0]
@@ -432,3 +445,17 @@
if factor != 1:
return 0.0
return value
+
+def _convert_callback_formats(callback):
+ callback = getattr(callback, 'im_func', callback)
+ if callback not in _converted_callback_formats:
+ def callback2(gc, root):
+ obj = root.address[0]
+ ll_assert(bool(obj), "NULL address from walk_roots()")
+ callback(obj, getattr(gc, attrname))
+ attrname = '_callback2_arg%d' % len(_converted_callback_formats)
+ _converted_callback_formats[callback] = callback2, attrname
+ return _converted_callback_formats[callback]
+
+_convert_callback_formats._annspecialcase_ = 'specialize:memo'
+_converted_callback_formats = {}
Modified: pypy/branch/jitypes2/pypy/rpython/memory/gc/generation.py
==============================================================================
--- pypy/branch/jitypes2/pypy/rpython/memory/gc/generation.py (original)
+++ pypy/branch/jitypes2/pypy/rpython/memory/gc/generation.py Tue Nov 23 13:26:19 2010
@@ -572,16 +572,10 @@
def _compute_current_nursery_hash(self, obj):
return intmask(llmemory.cast_adr_to_int(obj) + self.nursery_hash_base)
- def heap_stats_walk_roots(self):
- self.last_generation_root_objects.foreach(
- self._track_heap_ext, None)
- self.root_walker.walk_roots(
- SemiSpaceGC._track_heap_root,
- SemiSpaceGC._track_heap_root,
- SemiSpaceGC._track_heap_root)
-
- def _track_heap_ext(self, adr, ignored):
- self.trace(adr, self.track_heap_parent, adr)
+ def enumerate_all_roots(self, callback, arg):
+ self.last_generation_root_objects.foreach(callback, arg)
+ SemiSpaceGC.enumerate_all_roots(self, callback, arg)
+ enumerate_all_roots._annspecialcase_ = 'specialize:arg(1)'
def debug_check_object(self, obj):
"""Check the invariants about 'obj' that should be true
Modified: pypy/branch/jitypes2/pypy/rpython/memory/gc/inspector.py
==============================================================================
--- pypy/branch/jitypes2/pypy/rpython/memory/gc/inspector.py (original)
+++ pypy/branch/jitypes2/pypy/rpython/memory/gc/inspector.py Tue Nov 23 13:26:19 2010
@@ -4,25 +4,22 @@
from pypy.rpython.lltypesystem import lltype, llmemory, rffi
from pypy.rlib.objectmodel import free_non_gc_object
from pypy.rpython.module.ll_os import underscore_on_windows
-from pypy.rlib import rposix
+from pypy.rlib import rposix, rgc
from pypy.rpython.memory.support import AddressDict, get_address_stack
# ---------- implementation of pypy.rlib.rgc.get_rpy_roots() ----------
-def _counting_rpy_root(gc, root):
+def _counting_rpy_root(obj, gc):
gc._count_rpy += 1
def _do_count_rpy_roots(gc):
gc._count_rpy = 0
- gc.root_walker.walk_roots(
- _counting_rpy_root,
- _counting_rpy_root,
- _counting_rpy_root)
+ gc.enumerate_all_roots(_counting_rpy_root, gc)
return gc._count_rpy
-def _append_rpy_root(gc, root):
+def _append_rpy_root(obj, gc):
# Can use the gc list, but should not allocate!
# It is essential that the list is not resizable!
lst = gc._list_rpy
@@ -30,15 +27,12 @@
if index >= len(lst):
raise ValueError
gc._count_rpy = index + 1
- lst[index] = llmemory.cast_adr_to_ptr(root.address[0], llmemory.GCREF)
+ lst[index] = llmemory.cast_adr_to_ptr(obj, llmemory.GCREF)
def _do_append_rpy_roots(gc, lst):
gc._count_rpy = 0
gc._list_rpy = lst
- gc.root_walker.walk_roots(
- _append_rpy_root,
- _append_rpy_root,
- _append_rpy_root)
+ gc.enumerate_all_roots(_append_rpy_root, gc)
gc._list_rpy = None
def get_rpy_roots(gc):
@@ -101,8 +95,7 @@
# ----------
raw_os_write = rffi.llexternal(underscore_on_windows+'write',
- [rffi.INT, rffi.CArrayPtr(lltype.Signed),
- rffi.SIZE_T],
+ [rffi.INT, llmemory.Address, rffi.SIZE_T],
rffi.SIZE_T,
sandboxsafe=True, _nowrapper=True)
@@ -131,7 +124,7 @@
if self.buf_count > 0:
bytes = self.buf_count * rffi.sizeof(rffi.LONG)
count = raw_os_write(self.fd,
- self.writebuffer,
+ rffi.cast(llmemory.Address, self.writebuffer),
rffi.cast(rffi.SIZE_T, bytes))
if rffi.cast(lltype.Signed, count) != bytes:
raise OSError(rposix.get_errno(), "raw_os_write failed")
@@ -140,7 +133,7 @@
def write(self, value):
x = self.buf_count
- self.writebuffer[x] = llmemory.raw_malloc_usage(value)
+ self.writebuffer[x] = value
x += 1
self.buf_count = x
if x == self.BUFSIZE:
@@ -173,12 +166,7 @@
self.pending.append(obj)
def add_roots(self):
- self.gc._heap_dumper = self
- self.gc.root_walker.walk_roots(
- _hd_add_root,
- _hd_add_root,
- _hd_add_root)
- self.gc._heap_dumper = None
+ self.gc.enumerate_all_roots(_hd_add_root, self)
pendingroots = self.pending
self.pending = AddressStack()
self.walk(pendingroots)
@@ -189,8 +177,8 @@
while pending.non_empty():
self.writeobj(pending.pop())
-def _hd_add_root(gc, root):
- gc._heap_dumper.add(root.address[0])
+def _hd_add_root(obj, heap_dumper):
+ heap_dumper.add(obj)
def dump_rpy_heap(gc, fd):
heapdumper = HeapDumper(gc, fd)
@@ -199,3 +187,7 @@
heapdumper.flush()
heapdumper.delete()
return True
+
+def get_typeids_z(gc):
+ srcaddress = gc.root_walker.gcdata.typeids_z
+ return llmemory.cast_adr_to_ptr(srcaddress, lltype.Ptr(rgc.ARRAY_OF_CHAR))
Modified: pypy/branch/jitypes2/pypy/rpython/memory/gc/minimark.py
==============================================================================
--- pypy/branch/jitypes2/pypy/rpython/memory/gc/minimark.py (original)
+++ pypy/branch/jitypes2/pypy/rpython/memory/gc/minimark.py Tue Nov 23 13:26:19 2010
@@ -1,3 +1,36 @@
+""" MiniMark GC.
+
+Environment variables can be used to fine-tune the following parameters:
+
+ PYPY_GC_NURSERY The nursery size. Defaults to half the size of
+ the L2 cache. Try values like '1.2MB'.
+
+ PYPY_GC_MAJOR_COLLECT Major collection memory factor. Default is '1.82',
+ which means trigger a major collection when the
+ memory consumed equals 1.82 times the memory
+ really used at the end of the previous major
+ collection.
+
+ PYPY_GC_GROWTH Major collection threshold's max growth rate.
+ Default is '1.3'. Useful to collect more often
+ than normally on sudden memory growth, e.g. when
+ there is a temporary peak in memory usage.
+
+ PYPY_GC_MAX The max heap size. If coming near this limit, it
+ will first collect more often, then raise an
+ RPython MemoryError, and if that is not enough,
+ crash the program with a fatal error. Try values
+ like '1.6GB'.
+
+ PYPY_GC_MIN Don't collect while the memory size is below this
+ limit. Useful to avoid spending all the time in
+ the GC in very small programs. Defaults to 8
+ times the nursery.
+"""
+# XXX Should find a way to bound the major collection threshold by the
+# XXX total addressable size. Maybe by keeping some minimarkpage arenas
+# XXX pre-reserved, enough for a few nursery collections? What about
+# XXX raw-malloced memory?
import sys
from pypy.rpython.lltypesystem import lltype, llmemory, llarena, llgroup
from pypy.rpython.lltypesystem.lloperation import llop
@@ -87,13 +120,8 @@
TRANSLATION_PARAMS = {
# Automatically adjust the size of the nursery and the
- # 'major_collection_threshold' from the environment. For
- # 'nursery_size' it will look it up in the env var
- # PYPY_GC_NURSERY and fall back to half the size of
- # the L2 cache. For 'major_collection_threshold' it will look
- # it up in the env var PYPY_GC_MAJOR_COLLECT. It also sets
- # 'max_heap_size' to PYPY_GC_MAX. Finally, PYPY_GC_MIN sets
- # the minimal value of 'next_major_collection_threshold'.
+ # 'major_collection_threshold' from the environment.
+ # See docstring at the start of the file.
"read_from_env": True,
# The size of the nursery. Note that this is only used as a
@@ -121,6 +149,13 @@
# we trigger the next major collection.
"major_collection_threshold": 1.82,
+ # Threshold to avoid that the total heap size grows by a factor of
+ # major_collection_threshold at every collection: it can only
+ # grow at most by the following factor from one collection to the
+ # next. Used e.g. when there is a sudden, temporary peak in memory
+ # usage; this avoids that the upper bound grows too fast.
+ "growth_rate_max": 1.3,
+
# The number of array indices that are mapped to a single bit in
# write_barrier_from_array(). Must be a power of two. The default
# value of 128 means that card pages are 512 bytes (1024 on 64-bits)
@@ -146,6 +181,7 @@
arena_size=64*WORD,
small_request_threshold=5*WORD,
major_collection_threshold=2.5,
+ growth_rate_max=2.5, # for tests
card_page_indices=0,
large_object=8*WORD,
large_object_gcptrs=10*WORD,
@@ -157,6 +193,7 @@
self.nursery_size = nursery_size
self.small_request_threshold = small_request_threshold
self.major_collection_threshold = major_collection_threshold
+ self.growth_rate_max = growth_rate_max
self.num_major_collects = 0
self.min_heap_size = 0.0
self.max_heap_size = 0.0
@@ -257,9 +294,13 @@
newsize = max(newsize, minsize)
#
major_coll = base.read_float_from_env('PYPY_GC_MAJOR_COLLECT')
- if major_coll >= 1.0:
+ if major_coll > 1.0:
self.major_collection_threshold = major_coll
#
+ growth = base.read_float_from_env('PYPY_GC_GROWTH')
+ if growth > 1.0:
+ self.growth_rate_max = growth
+ #
min_heap_size = base.read_uint_from_env('PYPY_GC_MIN')
if min_heap_size > 0:
self.min_heap_size = float(min_heap_size)
@@ -295,11 +336,19 @@
# initialize the threshold
self.min_heap_size = max(self.min_heap_size, self.nursery_size *
self.major_collection_threshold)
+ self.next_major_collection_threshold = self.min_heap_size
self.set_major_threshold_from(0.0)
debug_stop("gc-set-nursery-size")
- def set_major_threshold_from(self, threshold):
+
+ def set_major_threshold_from(self, threshold, reserving_size=0):
# Set the next_major_collection_threshold.
+ threshold_max = (self.next_major_collection_threshold *
+ self.growth_rate_max)
+ if threshold > threshold_max:
+ threshold = threshold_max
+ #
+ threshold += reserving_size
if threshold < self.min_heap_size:
threshold = self.min_heap_size
#
@@ -922,7 +971,7 @@
#
# Now all live nursery objects should be out. Update the
# young weakrefs' targets.
- if self.young_objects_with_weakrefs.length() > 0:
+ if self.young_objects_with_weakrefs.non_empty():
self.invalidate_young_weakrefs()
#
# Clear this mapping.
@@ -1016,7 +1065,7 @@
obj = oldlist.pop()
#
# Add the flag GCFLAG_NO_YOUNG_PTRS. All live objects should have
- # this flag after a nursery collection.
+ # this flag set after a nursery collection.
self.header(obj).tid |= GCFLAG_NO_YOUNG_PTRS
#
# Trace the 'obj' to replace pointers to nursery with pointers
@@ -1079,7 +1128,7 @@
# nursery are kept unchanged in this step.
llmemory.raw_memcopy(obj - size_gc_header, newhdr, totalsize)
#
- # Set the old object's tid to -1 (containing all flags) and
+ # Set the old object's tid to -42 (containing all flags) and
# replace the old object's content with the target address.
# A bit of no-ops to convince llarena that we are changing
# the layout, in non-translated versions.
@@ -1198,8 +1247,8 @@
# have allocated 'major_collection_threshold' times more than
# we currently have.
bounded = self.set_major_threshold_from(
- (self.get_total_memory_used() * self.major_collection_threshold)
- + reserving_size)
+ self.get_total_memory_used() * self.major_collection_threshold,
+ reserving_size)
#
# Max heap size: gives an upper bound on the threshold. If we
# already have at least this much allocated, raise MemoryError.
@@ -1288,6 +1337,11 @@
self.run_finalizers.foreach(self._collect_obj,
self.objects_to_trace)
+ def enumerate_all_roots(self, callback, arg):
+ self.prebuilt_root_objects.foreach(callback, arg)
+ MovingGCBase.enumerate_all_roots(self, callback, arg)
+ enumerate_all_roots._annspecialcase_ = 'specialize:arg(1)'
+
@staticmethod
def _collect_obj(obj, objects_to_trace):
objects_to_trace.append(obj)
@@ -1339,7 +1393,7 @@
if self.is_valid_gc_object(obj):
if self.is_in_nursery(obj):
#
- # The object not a tagged pointer, and is it still in the
+ # The object is not a tagged pointer, and it is still in the
# nursery. Find or allocate a "shadow" object, which is
# where the object will be moved by the next minor
# collection
Modified: pypy/branch/jitypes2/pypy/rpython/memory/gc/semispace.py
==============================================================================
--- pypy/branch/jitypes2/pypy/rpython/memory/gc/semispace.py (original)
+++ pypy/branch/jitypes2/pypy/rpython/memory/gc/semispace.py Tue Nov 23 13:26:19 2010
@@ -693,15 +693,10 @@
self._ll_typeid_map[idx].size += llmemory.raw_malloc_usage(totsize)
self.trace(adr, self.track_heap_parent, adr)
- def _track_heap_root(self, root):
- self.track_heap(root.address[0])
+ @staticmethod
+ def _track_heap_root(obj, self):
+ self.track_heap(obj)
- def heap_stats_walk_roots(self):
- self.root_walker.walk_roots(
- SemiSpaceGC._track_heap_root,
- SemiSpaceGC._track_heap_root,
- SemiSpaceGC._track_heap_root)
-
def heap_stats(self):
self._tracked_dict = self.AddressDict()
max_tid = self.root_walker.gcdata.max_type_id
@@ -714,7 +709,7 @@
while i < max_tid:
self._tracked_dict.add(llmemory.cast_ptr_to_adr(ll_typeid_map[i]))
i += 1
- self.heap_stats_walk_roots()
+ self.enumerate_all_roots(SemiSpaceGC._track_heap_root, self)
self._ll_typeid_map = lltype.nullptr(ARRAY_TYPEID_MAP)
self._tracked_dict.delete()
return ll_typeid_map
Modified: pypy/branch/jitypes2/pypy/rpython/memory/gc/test/test_minimark.py
==============================================================================
--- pypy/branch/jitypes2/pypy/rpython/memory/gc/test/test_minimark.py (original)
+++ pypy/branch/jitypes2/pypy/rpython/memory/gc/test/test_minimark.py Tue Nov 23 13:26:19 2010
@@ -28,3 +28,42 @@
assert gc.card_marking_bytes_for_length(P+P+1) == 3
assert gc.card_marking_bytes_for_length(P+P+P+P+P+P+P+P) == 8
assert gc.card_marking_bytes_for_length(P+P+P+P+P+P+P+P+1) == 9
+
+def test_set_major_threshold():
+ gc = MiniMarkGC(None, major_collection_threshold=2.0,
+ growth_rate_max=1.5)
+ gc.min_heap_size = 100.0
+ gc.max_heap_size = 300.0
+ gc.next_major_collection_threshold = 0.0
+ # first, we don't grow past min_heap_size
+ for i in range(5):
+ gc.set_major_threshold_from(100.0)
+ assert gc.next_major_collection_threshold == 100.0
+ # then we grow a lot
+ b = gc.set_major_threshold_from(100 * 2.0)
+ assert b is False
+ assert gc.next_major_collection_threshold == 150.0
+ b = gc.set_major_threshold_from(150 * 2.0)
+ assert b is False
+ assert gc.next_major_collection_threshold == 225.0
+ b = gc.set_major_threshold_from(225 * 2.0)
+ assert b is True
+ assert gc.next_major_collection_threshold == 300.0 # max reached
+ b = gc.set_major_threshold_from(300 * 2.0)
+ assert b is True
+ assert gc.next_major_collection_threshold == 300.0
+ # then we shrink instantly
+ b = gc.set_major_threshold_from(100.0)
+ assert b is False
+ assert gc.next_major_collection_threshold == 100.0
+ # then we grow a bit
+ b = gc.set_major_threshold_from(100 * 1.25)
+ assert b is False
+ assert gc.next_major_collection_threshold == 125.0
+ b = gc.set_major_threshold_from(125 * 1.25)
+ assert b is False
+ assert gc.next_major_collection_threshold == 156.25
+ # check that we cannot shrink below min_heap_size
+ b = gc.set_major_threshold_from(42.7)
+ assert b is False
+ assert gc.next_major_collection_threshold == 100.0
Modified: pypy/branch/jitypes2/pypy/rpython/memory/gctransform/framework.py
==============================================================================
--- pypy/branch/jitypes2/pypy/rpython/memory/gctransform/framework.py (original)
+++ pypy/branch/jitypes2/pypy/rpython/memory/gctransform/framework.py Tue Nov 23 13:26:19 2010
@@ -172,6 +172,7 @@
gcdata.static_root_nongcend = a_random_address # patched in finish()
gcdata.static_root_end = a_random_address # patched in finish()
gcdata.max_type_id = 13 # patched in finish()
+ gcdata.typeids_z = a_random_address # patched in finish()
self.gcdata = gcdata
self.malloc_fnptr_cache = {}
@@ -212,6 +213,9 @@
data_classdef.generalize_attr(
'max_type_id',
annmodel.SomeInteger())
+ data_classdef.generalize_attr(
+ 'typeids_z',
+ annmodel.SomeAddress())
annhelper = annlowlevel.MixLevelHelperAnnotator(self.translator.rtyper)
@@ -415,6 +419,11 @@
[s_gc, annmodel.SomeInteger()],
annmodel.s_Bool,
minimal_transform=False)
+ self.get_typeids_z_ptr = getfn(inspector.get_typeids_z,
+ [s_gc],
+ annmodel.SomePtr(
+ lltype.Ptr(rgc.ARRAY_OF_CHAR)),
+ minimal_transform=False)
self.set_max_heap_size_ptr = getfn(GCClass.set_max_heap_size.im_func,
[s_gc,
@@ -572,7 +581,14 @@
newgcdependencies = []
newgcdependencies.append(ll_static_roots_inside)
ll_instance.inst_max_type_id = len(group.members)
- self.write_typeid_list()
+ typeids_z = self.write_typeid_list()
+ ll_typeids_z = lltype.malloc(rgc.ARRAY_OF_CHAR,
+ len(typeids_z),
+ immortal=True)
+ for i in range(len(typeids_z)):
+ ll_typeids_z[i] = typeids_z[i]
+ ll_instance.inst_typeids_z = llmemory.cast_ptr_to_adr(ll_typeids_z)
+ newgcdependencies.append(ll_typeids_z)
return newgcdependencies
def get_finish_tables(self):
@@ -599,6 +615,11 @@
for index in range(len(self.layoutbuilder.type_info_group.members)):
f.write("member%-4d %s\n" % (index, all_ids.get(index, '?')))
f.close()
+ try:
+ import zlib
+ return zlib.compress(udir.join("typeids.txt").read(), 9)
+ except ImportError:
+ return ''
def transform_graph(self, graph):
func = getattr(graph, 'func', None)
@@ -988,6 +1009,13 @@
resultvar=hop.spaceop.result)
self.pop_roots(hop, livevars)
+ def gct_gc_typeids_z(self, hop):
+ livevars = self.push_roots(hop)
+ hop.genop("direct_call",
+ [self.get_typeids_z_ptr, self.c_const_gc],
+ resultvar=hop.spaceop.result)
+ self.pop_roots(hop, livevars)
+
def gct_malloc_nonmovable_varsize(self, hop):
TYPE = hop.spaceop.result.concretetype
if self.gcdata.gc.can_malloc_nonmovable():
@@ -1210,7 +1238,7 @@
sizeofaddr = llmemory.sizeof(llmemory.Address)
-class BaseRootWalker:
+class BaseRootWalker(object):
need_root_stack = False
def __init__(self, gctransformer):
Modified: pypy/branch/jitypes2/pypy/rpython/memory/support.py
==============================================================================
--- pypy/branch/jitypes2/pypy/rpython/memory/support.py (original)
+++ pypy/branch/jitypes2/pypy/rpython/memory/support.py Tue Nov 23 13:26:19 2010
@@ -112,7 +112,7 @@
cur = next
free_non_gc_object(self)
- def length(self):
+ def _length_estimate(self):
chunk = self.chunk
count = self.used_in_last_chunk
while chunk:
@@ -135,7 +135,7 @@
foreach._annspecialcase_ = 'specialize:arg(1)'
def stack2dict(self):
- result = AddressDict(self.length())
+ result = AddressDict(self._length_estimate())
self.foreach(_add_in_dict, result)
return result
Modified: pypy/branch/jitypes2/pypy/rpython/memory/test/test_gc.py
==============================================================================
--- pypy/branch/jitypes2/pypy/rpython/memory/test/test_gc.py (original)
+++ pypy/branch/jitypes2/pypy/rpython/memory/test/test_gc.py Tue Nov 23 13:26:19 2010
@@ -278,6 +278,105 @@
res = self.interpret(f, [])
assert res
+ def test_bug_1(self):
+ import weakref
+ class B(object):
+ pass
+ def g():
+ b = B()
+ llop.gc__collect(lltype.Void) # force 'b' to be old
+ ref = weakref.ref(B())
+ b.ref = ref
+ return ref
+ def f():
+ ref = g()
+ llop.gc__collect(lltype.Void)
+ llop.gc__collect(lltype.Void)
+ result = (ref() is None)
+ return result
+ res = self.interpret(f, [])
+ assert res
+
+ def test_cycle_with_weakref_and_del(self):
+ import weakref, gc
+ class A(object):
+ count = 0
+ a = A()
+ class B(object):
+ def __del__(self):
+ # when __del__ is called, the weakref to c should be dead
+ if self.ref() is None:
+ a.count += 10 # ok
+ else:
+ a.count = 666 # not ok
+ class C(object):
+ pass
+ def g():
+ c = C()
+ c.b = B()
+ ref = weakref.ref(c)
+ c.b.ref = ref
+ return ref
+ def f():
+ ref = g()
+ llop.gc__collect(lltype.Void)
+ llop.gc__collect(lltype.Void)
+ result = a.count + (ref() is None)
+ return result
+ res = self.interpret(f, [])
+ assert res == 11
+
+ def test_weakref_to_object_with_finalizer_ordering(self):
+ import weakref, gc
+ class A(object):
+ count = 0
+ a = A()
+ class B(object):
+ def __del__(self):
+ # when __del__ is called, the weakref to myself is still valid
+ # in RPython (at least with most GCs; this test might be
+ # skipped for specific GCs)
+ if self.ref() is self:
+ a.count += 10 # ok
+ else:
+ a.count = 666 # not ok
+ def g():
+ b = B()
+ ref = weakref.ref(b)
+ b.ref = ref
+ return ref
+ def f():
+ ref = g()
+ llop.gc__collect(lltype.Void)
+ llop.gc__collect(lltype.Void)
+ result = a.count + (ref() is None)
+ return result
+ res = self.interpret(f, [])
+ assert res == 11
+
+ def test_weakref_bug_1(self):
+ import weakref
+ class A(object):
+ pass
+ class B(object):
+ def __del__(self):
+ self.wref().x += 1
+ def g(a):
+ b = B()
+ b.wref = weakref.ref(a)
+ # the only way to reach this weakref is via B, which is an
+ # object with finalizer (but the weakref itself points to
+ # a, which does not go away but will move during the next
+ # gc.collect)
+ def f():
+ a = A()
+ a.x = 10
+ g(a)
+ llop.gc__collect(lltype.Void)
+ return a.x
+ res = self.interpret(f, [])
+ assert res == 11
+
def test_id(self):
class A(object):
pass
@@ -635,6 +734,9 @@
class TestMarkSweepGC(GCTest):
from pypy.rpython.memory.gc.marksweep import MarkSweepGC as GCClass
+ def test_weakref_to_object_with_finalizer_ordering(self):
+ py.test.skip("Does not work")
+
class TestSemiSpaceGC(GCTest, snippet.SemiSpaceGCTests):
from pypy.rpython.memory.gc.semispace import SemiSpaceGC as GCClass
GC_CAN_MOVE = True
Modified: pypy/branch/jitypes2/pypy/rpython/rbuiltin.py
==============================================================================
--- pypy/branch/jitypes2/pypy/rpython/rbuiltin.py (original)
+++ pypy/branch/jitypes2/pypy/rpython/rbuiltin.py Tue Nov 23 13:26:19 2010
@@ -386,6 +386,14 @@
hop.exception_cannot_occur()
hop.genop('free', vlist)
+def rtype_render_immortal(hop, i_track_allocation=None):
+ vlist = [hop.inputarg(hop.args_r[0], arg=0)]
+ v_track_allocation = parse_kwds(hop,
+ (i_track_allocation, None))
+ hop.exception_cannot_occur()
+ if i_track_allocation is None or v_track_allocation.value:
+ hop.genop('track_alloc_stop', vlist)
+
def rtype_const_result(hop):
hop.exception_cannot_occur()
return hop.inputconst(hop.r_result.lowleveltype, hop.s_result.const)
@@ -523,6 +531,7 @@
BUILTIN_TYPER[lltype.malloc] = rtype_malloc
BUILTIN_TYPER[lltype.free] = rtype_free
+BUILTIN_TYPER[lltype.render_immortal] = rtype_render_immortal
BUILTIN_TYPER[lltype.cast_primitive] = rtype_cast_primitive
BUILTIN_TYPER[lltype.cast_pointer] = rtype_cast_pointer
BUILTIN_TYPER[lltype.cast_opaque_ptr] = rtype_cast_opaque_ptr
Modified: pypy/branch/jitypes2/pypy/rpython/test/test_rpbc.py
==============================================================================
--- pypy/branch/jitypes2/pypy/rpython/test/test_rpbc.py (original)
+++ pypy/branch/jitypes2/pypy/rpython/test/test_rpbc.py Tue Nov 23 13:26:19 2010
@@ -1547,7 +1547,7 @@
def test_always_raising_methods(self):
class Base:
def m(self):
- raise NotImplementedError
+ raise KeyError
class A(Base):
def m(self):
return 42
@@ -1560,11 +1560,11 @@
o = B()
try:
o.m()
- except NotImplementedError:
- pass
+ except KeyError:
+ assert 0
return B().m()
- self.interpret_raises(NotImplementedError, f, [7])
+ self.interpret_raises(KeyError, f, [7])
def test_possible_missing_attribute_access(self):
py.test.skip("Should explode or give some warning")
Modified: pypy/branch/jitypes2/pypy/tool/release/force-builds.py
==============================================================================
--- pypy/branch/jitypes2/pypy/tool/release/force-builds.py (original)
+++ pypy/branch/jitypes2/pypy/tool/release/force-builds.py Tue Nov 23 13:26:19 2010
@@ -20,11 +20,12 @@
'own-linux-x86-32',
'own-linux-x86-64',
# 'own-macosx-x86-32',
- 'pypy-c-app-level-linux-x86-32',
- 'pypy-c-app-level-linux-x86-64',
+# 'pypy-c-app-level-linux-x86-32',
+# 'pypy-c-app-level-linux-x86-64',
'pypy-c-stackless-app-level-linux-x86-32',
'pypy-c-app-level-win-x86-32',
'pypy-c-jit-linux-x86-32',
+ 'pypy-c-jit-linux-x86-64',
# 'pypy-c-jit-macosx-x86-32',
'pypy-c-jit-win-x86-32',
]
Modified: pypy/branch/jitypes2/pypy/tool/release/make_release.py
==============================================================================
--- pypy/branch/jitypes2/pypy/tool/release/make_release.py (original)
+++ pypy/branch/jitypes2/pypy/tool/release/make_release.py Tue Nov 23 13:26:19 2010
@@ -4,7 +4,7 @@
into release packages. Note: you must run apropriate buildbots first and
make sure there are no failures. Use force-builds.py from the same directory.
-Usage: make_release.py release/<release name>
+Usage: make_release.py release/<release name> release_version
"""
import autopath
@@ -30,7 +30,8 @@
else:
xml = override_xml
dom = minidom.parseString(xml)
- refs = [node.getAttribute('href') for node in dom.getElementsByTagName('a')]
+ refs = [node.getAttribute('href') for node in dom.getElementsByTagName('a')
+ if 'pypy' in node.getAttribute('href')]
# all refs are of form: pypy-{type}-{revision}-{platform}.tar.bz2
r = re.compile('pypy-c-([\w\d]+)-(\d+)-([\w\d]+).tar.bz2$')
d = {}
@@ -76,7 +77,7 @@
t.add('pypy-%s' % release)
alltars.append(name)
t.close()
- shutil.rmtree(str(tmpdir.join('pypy-1.3')))
+ shutil.rmtree(str(tmpdir.join('pypy-' + release)))
for name in alltars:
print "Uploading %s" % name
os.system('scp %s codespeak.net:/www/pypy.org/htdocs/download' % name)
@@ -84,8 +85,8 @@
os.chdir(olddir)
if __name__ == '__main__':
- if len(sys.argv) != 2:
+ if len(sys.argv) != 3:
print __doc__
sys.exit(1)
- main(sys.argv[1], release='1.3')
+ main(sys.argv[1], release=sys.argv[2])
Modified: pypy/branch/jitypes2/pypy/tool/release/package.py
==============================================================================
--- pypy/branch/jitypes2/pypy/tool/release/package.py (original)
+++ pypy/branch/jitypes2/pypy/tool/release/package.py Tue Nov 23 13:26:19 2010
@@ -1,8 +1,12 @@
#!/usr/bin/env python
""" A sample script that packages PyPy, provided that it's already built.
-Usage:
+It uses 'pypy/translator/goal/pypy-c' and parts of the rest of the working
+copy. Usage:
-package.py pypydir [name-of-archive] [name-of-pypy-c]
+ package.py root-pypy-dir [name-of-archive] [name-of-pypy-c]
+
+Usually you would do: package.py ../../.. pypy-VER-PLATFORM.
+The output is found in the directory /tmp/usession-YOURNAME/build/.
"""
import autopath
@@ -32,7 +36,7 @@
class PyPyCNotFound(Exception):
pass
-def package(basedir, name='pypy-nightly', rename_pypy_c='pypy-c',
+def package(basedir, name='pypy-nightly', rename_pypy_c='pypy',
copy_to_dir = None, override_pypy_c = None):
basedir = py.path.local(basedir)
if sys.platform == 'win32':
@@ -64,6 +68,10 @@
headers = includedir.listdir('*.h') + includedir.listdir('*.inl')
for n in headers:
shutil.copy(str(n), str(pypydir.join('include')))
+ #
+ spdir = pypydir.ensure('site-packages', dir=True)
+ shutil.copy(str(basedir.join('site-packages', 'README')), str(spdir))
+ #
pypydir.ensure('bin', dir=True)
archive_pypy_c = pypydir.join('bin', rename_pypy_c)
shutil.copy(str(pypy_c), str(archive_pypy_c))
Modified: pypy/branch/jitypes2/pypy/tool/release/test/test_package.py
==============================================================================
--- pypy/branch/jitypes2/pypy/tool/release/test/test_package.py (original)
+++ pypy/branch/jitypes2/pypy/tool/release/test/test_package.py Tue Nov 23 13:26:19 2010
@@ -18,7 +18,7 @@
prefix = builddir.join(test)
cpyver = '%d.%d.%d' % CPYTHON_VERSION[:3]
assert prefix.join('lib-python', cpyver, 'test').check()
- assert prefix.join('bin', 'pypy-c').check()
+ assert prefix.join('bin', 'pypy').check()
assert prefix.join('lib_pypy', 'syslog.py').check()
assert not prefix.join('lib_pypy', 'py').check()
assert not prefix.join('lib_pypy', 'ctypes_configure').check()
Modified: pypy/branch/jitypes2/pypy/tool/terminal.py
==============================================================================
--- pypy/branch/jitypes2/pypy/tool/terminal.py (original)
+++ pypy/branch/jitypes2/pypy/tool/terminal.py Tue Nov 23 13:26:19 2010
@@ -62,9 +62,10 @@
for control in CONTROLS:
# Set the control escape sequence
setattr(MODULE, control, curses.tigetstr(CONTROLS[control]) or '')
- for value in VALUES:
- # Set terminal related values
- setattr(MODULE, value, curses.tigetnum(VALUES[value]))
+ if hasattr(curses, 'tigetnum'):
+ for value in VALUES:
+ # Set terminal related values
+ setattr(MODULE, value, curses.tigetnum(VALUES[value]))
def render(text):
"""Helper function to apply controls easily
@@ -74,7 +75,16 @@
return text % MODULE.__dict__
try:
- import curses
+ if '__pypy__' in sys.builtin_module_names:
+ # this is not really the whole curses, but our _minimal_curses it's
+ # better than nothing
+ import _minimal_curses as curses
+ # a bit of a hack: we have tigetstr but not tigetnum, so we call
+ # default() to have default values, then setup() will overwrite the
+ # ones it can
+ default()
+ else:
+ import curses
setup()
except Exception, e:
# There is a failure; set all attributes to default
Modified: pypy/branch/jitypes2/pypy/translator/c/gcc/test/test_trackgcroot.py
==============================================================================
--- pypy/branch/jitypes2/pypy/translator/c/gcc/test/test_trackgcroot.py (original)
+++ pypy/branch/jitypes2/pypy/translator/c/gcc/test/test_trackgcroot.py Tue Nov 23 13:26:19 2010
@@ -98,14 +98,13 @@
"""
lines = source.splitlines(True)
parts = list(DarwinAssemblerParser().find_functions(iter(lines)))
- assert len(parts) == 7
+ assert len(parts) == 6
assert parts[0] == (False, lines[:3])
assert parts[1] == (True, lines[3:7])
assert parts[2] == (True, lines[7:11])
- assert parts[3] == (True, lines[11:13])
- assert parts[4] == (False, lines[13:18])
- assert parts[5] == (True, lines[18:20])
- assert parts[6] == (False, lines[20:])
+ assert parts[3] == (True, lines[11:18])
+ assert parts[4] == (True, lines[18:20])
+ assert parts[5] == (False, lines[20:])
def test_computegcmaptable():
tests = []
Modified: pypy/branch/jitypes2/pypy/translator/c/gcc/trackgcroot.py
==============================================================================
--- pypy/branch/jitypes2/pypy/translator/c/gcc/trackgcroot.py (original)
+++ pypy/branch/jitypes2/pypy/translator/c/gcc/trackgcroot.py Tue Nov 23 13:26:19 2010
@@ -1405,6 +1405,7 @@
'const_data'
]
r_sectionstart = re.compile(r"\t\.("+'|'.join(OTHERSECTIONS)+").*$")
+ sections_doesnt_end_function = {'cstring': True, 'const': True}
def find_functions(self, iterlines):
functionlines = []
@@ -1412,20 +1413,20 @@
in_function = False
for n, line in enumerate(iterlines):
if self.r_textstart.match(line):
- assert not in_text, "unexpected repeated .text start: %d" % n
in_text = True
elif self.r_sectionstart.match(line):
- if in_function:
+ sectionname = self.r_sectionstart.match(line).group(1)
+ if (in_function and
+ sectionname not in self.sections_doesnt_end_function):
yield in_function, functionlines
functionlines = []
+ in_function = False
in_text = False
- in_function = False
elif in_text and self.FunctionGcRootTracker.r_functionstart.match(line):
yield in_function, functionlines
functionlines = []
in_function = True
functionlines.append(line)
-
if functionlines:
yield in_function, functionlines
@@ -1442,23 +1443,6 @@
format = "mingw32"
FunctionGcRootTracker = Mingw32FunctionGcRootTracker
- def find_functions(self, iterlines):
- functionlines = []
- in_text = False
- in_function = False
- for n, line in enumerate(iterlines):
- if self.r_textstart.match(line):
- in_text = True
- elif self.r_sectionstart.match(line):
- in_text = False
- elif in_text and self.FunctionGcRootTracker.r_functionstart.match(line):
- yield in_function, functionlines
- functionlines = []
- in_function = True
- functionlines.append(line)
- if functionlines:
- yield in_function, functionlines
-
class MsvcAssemblerParser(AssemblerParser):
format = "msvc"
FunctionGcRootTracker = MsvcFunctionGcRootTracker
Modified: pypy/branch/jitypes2/pypy/translator/c/genc.py
==============================================================================
--- pypy/branch/jitypes2/pypy/translator/c/genc.py (original)
+++ pypy/branch/jitypes2/pypy/translator/c/genc.py Tue Nov 23 13:26:19 2010
@@ -553,7 +553,7 @@
('debug', '', '$(MAKE) CFLAGS="$(DEBUGFLAGS) -DRPY_ASSERT" $(TARGET)'),
('debug_exc', '', '$(MAKE) CFLAGS="$(DEBUGFLAGS) -DRPY_ASSERT -DDO_LOG_EXC" $(TARGET)'),
('debug_mem', '', '$(MAKE) CFLAGS="$(DEBUGFLAGS) -DRPY_ASSERT -DTRIVIAL_MALLOC_DEBUG" $(TARGET)'),
- ('no_obmalloc', '', '$(MAKE) CFLAGS="-g -O1 -DRPY_ASSERT -DNO_OBMALLOC" $(TARGET)'),
+ ('no_obmalloc', '', '$(MAKE) CFLAGS="-g -O2 -DRPY_ASSERT -DNO_OBMALLOC" $(TARGET)'),
('linuxmemchk', '', '$(MAKE) CFLAGS="$(DEBUGFLAGS) -DRPY_ASSERT -DLINUXMEMCHK" $(TARGET)'),
('llsafer', '', '$(MAKE) CFLAGS="-O2 -DRPY_LL_ASSERT" $(TARGET)'),
('lldebug', '', '$(MAKE) CFLAGS="$(DEBUGFLAGS) -DRPY_ASSERT -DRPY_LL_ASSERT" $(TARGET)'),
Modified: pypy/branch/jitypes2/pypy/translator/c/node.py
==============================================================================
--- pypy/branch/jitypes2/pypy/translator/c/node.py (original)
+++ pypy/branch/jitypes2/pypy/translator/c/node.py Tue Nov 23 13:26:19 2010
@@ -714,7 +714,11 @@
s = ''.join([self.obj.getitem(i) for i in range(len(self.obj.items))])
else:
s = ''.join(self.obj.items)
- yield '\t%s%s' % (length, c_char_array_constant(s))
+ array_constant = c_char_array_constant(s)
+ if array_constant.startswith('{') and barebonearray(T):
+ assert array_constant.endswith('}')
+ array_constant = array_constant[1:-1].strip()
+ yield '\t%s%s' % (length, array_constant)
yield '}'
else:
barebone = barebonearray(T)
Modified: pypy/branch/jitypes2/pypy/translator/c/src/asm_gcc_x86.h
==============================================================================
--- pypy/branch/jitypes2/pypy/translator/c/src/asm_gcc_x86.h (original)
+++ pypy/branch/jitypes2/pypy/translator/c/src/asm_gcc_x86.h Tue Nov 23 13:26:19 2010
@@ -2,6 +2,8 @@
* It replaces some complex macros with native assembler instructions.
*/
+#if 0 /* --- disabled: does not give any speed-up --- */
+
#undef OP_INT_ADD_OVF
#define OP_INT_ADD_OVF(x,y,r) \
asm volatile( \
@@ -50,6 +52,13 @@
: "0"(x), "g"(y) /* inputs */ \
: "cc", "memory") /* clobber */
+extern void op_int_overflowed(void)
+ asm ("_op_int_overflowed")
+ __attribute__((used));
+
+#endif /* 0 */
+
+
/* Pentium only! */
#define READ_TIMESTAMP(val) \
asm volatile("rdtsc" : "=A" (val))
@@ -62,19 +71,15 @@
// I don't know how important it is, comment talks about time warps
-/* prototypes */
-
-extern void op_int_overflowed(void)
- asm ("_op_int_overflowed")
- __attribute__((used));
-
/* implementations */
#ifndef PYPY_NOT_MAIN_FILE
+# if 0 /* disabled */
void op_int_overflowed(void)
{
FAIL_OVF("integer operation");
}
+# endif
#endif
Modified: pypy/branch/jitypes2/pypy/translator/c/src/debug_print.h
==============================================================================
--- pypy/branch/jitypes2/pypy/translator/c/src/debug_print.h (original)
+++ pypy/branch/jitypes2/pypy/translator/c/src/debug_print.h Tue Nov 23 13:26:19 2010
@@ -10,6 +10,7 @@
but not any nested debug_print
:fname full logging
prefix:fname conditional logging
+ prefix1,prefix2:fname conditional logging with multiple selections
Conditional logging means that it only includes the debug_start/debug_stop
sections whose name match 'prefix'. Other sections are ignored, including
@@ -70,6 +71,8 @@
static void pypy_debug_open(void)
{
char *filename = getenv("PYPYLOG");
+ if (filename)
+ unsetenv("PYPYLOG"); /* don't pass it to subprocesses */
if (filename && filename[0])
{
char *colon = strchr(filename, ':');
@@ -139,12 +142,22 @@
#endif
-static bool_t startswith(const char *str, const char *substr)
+static bool_t startswithoneof(const char *str, const char *substr)
{
- while (*substr)
- if (*str++ != *substr++)
- return 0;
- return 1;
+ const char *p = str;
+ for (; *substr; substr++)
+ {
+ if (*substr != ',')
+ {
+ if (p && *p++ != *substr)
+ p = NULL; /* mismatch */
+ }
+ else if (p != NULL)
+ return 1; /* match */
+ else
+ p = str; /* mismatched, retry with the next */
+ }
+ return p != NULL;
}
#if defined(_MSC_VER) || defined(__MINGW32__)
@@ -175,7 +188,7 @@
if (!debug_profile)
{
/* non-profiling version */
- if (!debug_prefix || !startswith(category, debug_prefix))
+ if (!debug_prefix || !startswithoneof(category, debug_prefix))
{
/* wrong section name, or no PYPYLOG at all, skip it */
return;
Modified: pypy/branch/jitypes2/pypy/translator/c/src/g_include.h
==============================================================================
--- pypy/branch/jitypes2/pypy/translator/c/src/g_include.h (original)
+++ pypy/branch/jitypes2/pypy/translator/c/src/g_include.h Tue Nov 23 13:26:19 2010
@@ -39,10 +39,13 @@
#include "src/instrument.h"
/* optional assembler bits */
-// disabled: does not give any speed-up
-//#if defined(__GNUC__) && defined(__i386__)
-//# include "src/asm_gcc_x86.h"
-//#endif
+#if defined(__GNUC__) && defined(__i386__)
+# include "src/asm_gcc_x86.h"
+#endif
+
+#if defined(__GNUC__) && defined(__amd64__)
+# include "src/asm_gcc_x86_64.h"
+#endif
#if defined(__GNUC__) && defined(__ppc__)
# include "src/asm_ppc.h"
Modified: pypy/branch/jitypes2/pypy/translator/c/test/test_lltyped.py
==============================================================================
--- pypy/branch/jitypes2/pypy/translator/c/test/test_lltyped.py (original)
+++ pypy/branch/jitypes2/pypy/translator/c/test/test_lltyped.py Tue Nov 23 13:26:19 2010
@@ -1,6 +1,7 @@
import py
from pypy.rpython.lltypesystem.lltype import *
from pypy.translator.c.test import test_typed
+from pypy.tool.sourcetools import func_with_new_name
class TestLowLevelType(test_typed.CompilationTestCase):
@@ -655,6 +656,45 @@
fn = self.getcompiled(llf)
fn()
+ def test_prebuilt_raw_arrays(self):
+ from pypy.rpython.lltypesystem import rffi, ll2ctypes
+ #
+ def make_test_function(cast, haslength, length):
+ a = malloc(A, length, flavor='raw', immortal=True)
+ # two cases: a zero-terminated array if length == 6 or 1030,
+ # a non-zero-terminated array if length == 557 or 1031
+ for i in range(length):
+ a[i] = cast(256 - 5 + i)
+ def llf():
+ for i in range(length):
+ if a[i] != cast(256 - 5 + i):
+ return False
+ if haslength and len(a) != length:
+ return False
+ return True
+ return func_with_new_name(llf, repr((A, haslength, length)))
+ #
+ testfns = []
+ records = []
+ for OF, cast in [(Void, lambda n: None),
+ (Char, lambda n: chr(n & 0xFF)),
+ (Signed, lambda n: n)]:
+ for A, haslength in [(rffi.CArray(OF), False),
+ (Array(OF), True)]:
+ for length in [0, 6, 557, 1030, 1031]:
+ testfns.append(make_test_function(cast, haslength, length))
+ records.append((A, haslength, length))
+ def llf():
+ i = 0
+ for fn in testfns:
+ if not fn():
+ return i # returns the index of the failing function
+ i += 1
+ return -42
+ fn = self.getcompiled(llf)
+ res = fn()
+ assert res == -42, "failing function: %r" % (records[res],)
+
def test_prebuilt_ll2ctypes_array(self):
from pypy.rpython.lltypesystem import rffi, ll2ctypes
A = rffi.CArray(Char)
@@ -841,3 +881,17 @@
assert res == -98765432
res = fn(1)
assert res == -9999999
+
+ def test_render_immortal(self):
+ A = FixedSizeArray(Signed, 1)
+ a1 = malloc(A, flavor='raw')
+ render_immortal(a1)
+ a1[0] = 42
+ def llf():
+ a2 = malloc(A, flavor='raw')
+ render_immortal(a2)
+ a2[0] = 3
+ return a1[0] + a2[0]
+ fn = self.getcompiled(llf)
+ assert fn() == 45
+
Modified: pypy/branch/jitypes2/pypy/translator/c/test/test_newgc.py
==============================================================================
--- pypy/branch/jitypes2/pypy/translator/c/test/test_newgc.py (original)
+++ pypy/branch/jitypes2/pypy/translator/c/test/test_newgc.py Tue Nov 23 13:26:19 2010
@@ -1096,6 +1096,42 @@
assert os.path.exists(self.filename_dump)
assert os.path.getsize(self.filename_dump) > 64
+ filename_dump_typeids_z = str(udir.join('test_typeids_z'))
+ def define_write_typeids_z(self):
+ U = lltype.GcForwardReference()
+ U.become(lltype.GcStruct('U', ('next', lltype.Ptr(U)),
+ ('x', lltype.Signed)))
+ S = lltype.GcStruct('S', ('u', lltype.Ptr(U)))
+ A = lltype.GcArray(lltype.Ptr(S))
+ filename = self.filename_dump_typeids_z
+
+ def fn():
+ s = lltype.malloc(S)
+ s.u = lltype.malloc(U)
+ s.u.next = lltype.malloc(U)
+ s.u.next.next = lltype.malloc(U)
+ a = lltype.malloc(A, 1000)
+ s2 = lltype.malloc(S)
+ #
+ p = rgc.get_typeids_z()
+ s = ''.join([p[i] for i in range(len(p))])
+ fd = os.open(filename, os.O_WRONLY | os.O_CREAT, 0666)
+ os.write(fd, s)
+ os.close(fd)
+ return 0
+
+ return fn
+
+ def test_write_typeids_z(self):
+ self.run("write_typeids_z")
+ f = open(self.filename_dump_typeids_z)
+ data_z = f.read()
+ f.close()
+ import zlib
+ data = zlib.decompress(data_z)
+ assert data.startswith('member0')
+ assert 'GcArray of * GcStruct S {' in data
+
class TestSemiSpaceGC(TestUsingFramework, snippet.SemiSpaceGCTestDefines):
gcpolicy = "semispace"
should_be_moving = True
@@ -1179,21 +1215,22 @@
b = 0
c = 0
for i in range(len(tb)):
- if tb[i].count == 10:
+ if tb[i].count == 10: # the type of S
a += 1
nr = i
for i in range(len(tb)):
- if tb[i].count == 3:
+ if tb[i].count == 3: # the type GcArray(Ptr(S))
b += 1
c += tb[i].links[nr]
- # we don't count b here since there can be more singletons,
+ # b can be 1 or 2 here since _heap_stats() is free to return or
+ # ignore the three GcStructs that point to the GcArray(Ptr(S)).
# important one is c, a is for check
return c * 100 + b * 10 + a
return f
def test_gc_heap_stats(self):
res = self.run("gc_heap_stats")
- assert res == 3011
+ assert res == 3011 or res == 3021
def definestr_string_builder(cls):
def fn(_):
Modified: pypy/branch/jitypes2/pypy/translator/c/test/test_standalone.py
==============================================================================
--- pypy/branch/jitypes2/pypy/translator/c/test/test_standalone.py (original)
+++ pypy/branch/jitypes2/pypy/translator/c/test/test_standalone.py Tue Nov 23 13:26:19 2010
@@ -368,12 +368,27 @@
assert not err
assert path.check(file=1)
data = path.read()
- assert 'toplevel' in path.read()
- assert 'mycat' not in path.read()
- assert 'foo 2 bar 3' not in path.read()
+ assert 'toplevel' in data
+ assert 'mycat' not in data
+ assert 'foo 2 bar 3' not in data
assert 'cat2' in data
assert 'baz' in data
assert 'bok' not in data
+ # check with PYPYLOG=myc,cat2:somefilename (includes mycat and cat2)
+ path = udir.join('test_debug_xxx_myc_cat2.log')
+ out, err = cbuilder.cmdexec("", err=True,
+ env={'PYPYLOG': 'myc,cat2:%s' % path})
+ assert out.strip() == 'got:bcda.'
+ assert not err
+ assert path.check(file=1)
+ data = path.read()
+ assert 'toplevel' in data
+ assert '{mycat' in data
+ assert 'mycat}' in data
+ assert 'foo 2 bar 3' in data
+ assert 'cat2' in data
+ assert 'baz' in data
+ assert 'bok' in data
#
# finally, check compiling with logging disabled
from pypy.config.pypyoption import get_pypy_config
Modified: pypy/branch/jitypes2/pypy/translator/cli/src/pypylib.cs
==============================================================================
--- pypy/branch/jitypes2/pypy/translator/cli/src/pypylib.cs (original)
+++ pypy/branch/jitypes2/pypy/translator/cli/src/pypylib.cs Tue Nov 23 13:26:19 2010
@@ -83,8 +83,12 @@
return Double.NegativeInfinity;
else if (s == "nan")
return Double.NaN;
- else
- return System.Convert.ToDouble(s);
+ else {
+ System.Globalization.NumberFormatInfo formatter;
+ formatter = new System.Globalization.NumberFormatInfo();
+ formatter.NumberDecimalSeparator = ".";
+ return System.Convert.ToDouble(s, formatter);
+ }
}
}
Modified: pypy/branch/jitypes2/pypy/translator/goal/app_main.py
==============================================================================
--- pypy/branch/jitypes2/pypy/translator/goal/app_main.py (original)
+++ pypy/branch/jitypes2/pypy/translator/goal/app_main.py Tue Nov 23 13:26:19 2010
@@ -326,10 +326,6 @@
except:
print >> sys.stderr, "'import site' failed"
- # update sys.path *after* loading site.py, in case there is a
- # "site.py" file in the script's directory.
- sys.path.insert(0, '')
-
if warnoptions:
sys.warnoptions.append(warnoptions)
from warnings import _processoptions
@@ -366,6 +362,9 @@
try:
if run_command:
# handle the "-c" command
+ # Put '' on sys.path
+ sys.path.insert(0, '')
+
def run_it():
exec cmd in mainmodule.__dict__
success = run_toplevel(run_it)
@@ -378,6 +377,13 @@
elif run_stdin:
# handle the case where no command/filename/module is specified
# on the command-line.
+
+ # update sys.path *after* loading site.py, in case there is a
+ # "site.py" file in the script's directory. Only run this if we're
+ # executing the interactive prompt, if we're running a script we
+ # put it's directory on sys.path
+ sys.path.insert(0, '')
+
if go_interactive or sys.stdin.isatty():
# If stdin is a tty or if "-i" is specified, we print
# a banner and run $PYTHONSTARTUP.
Modified: pypy/branch/jitypes2/pypy/translator/goal/targetpypystandalone.py
==============================================================================
--- pypy/branch/jitypes2/pypy/translator/goal/targetpypystandalone.py (original)
+++ pypy/branch/jitypes2/pypy/translator/goal/targetpypystandalone.py Tue Nov 23 13:26:19 2010
@@ -28,9 +28,14 @@
w_call_finish_gateway = space.wrap(gateway.interp2app(call_finish))
w_call_startup_gateway = space.wrap(gateway.interp2app(call_startup))
w_os = setup_nanos(space)
+ withjit = space.config.objspace.usemodules.pypyjit
def entry_point(argv):
space.timer.start("Entrypoint")
+ if withjit:
+ from pypy.jit.backend.hlinfo import highleveljitinfo
+ highleveljitinfo.sys_executable = argv[0]
+
#debug("entry point starting")
#for arg in argv:
# debug(" argv -> " + arg)
@@ -150,6 +155,9 @@
if config.objspace.allworkingmodules:
from pypy.config.pypyoption import enable_allworkingmodules
enable_allworkingmodules(config)
+ if config.objspace.translationmodules:
+ from pypy.config.pypyoption import enable_translationmodules
+ enable_translationmodules(config)
if config.translation.type_system == 'ootype':
config.objspace.usemodules.suggest(rbench=True)
Modified: pypy/branch/jitypes2/pypy/translator/goal/test2/test_app_main.py
==============================================================================
--- pypy/branch/jitypes2/pypy/translator/goal/test2/test_app_main.py (original)
+++ pypy/branch/jitypes2/pypy/translator/goal/test2/test_app_main.py Tue Nov 23 13:26:19 2010
@@ -95,6 +95,11 @@
child.expect('>>> ')
child.sendline('__name__')
child.expect("'__main__'")
+ child.expect('>>> ')
+ child.sendline('import sys')
+ child.expect('>>> ')
+ child.sendline("'' in sys.path")
+ child.expect("True")
def test_run_script(self):
child = self.spawn([demo_script])
@@ -463,8 +468,10 @@
yield
finally:
old_cwd.chdir()
- os.putenv('PYTHONPATH', old_pythonpath)
-
+ # Can't call putenv with a None argument.
+ if old_pythonpath is not None:
+ os.putenv('PYTHONPATH', old_pythonpath)
+
tmpdir.join('site.py').write('print "SHOULD NOT RUN"')
runme_py = tmpdir.join('runme.py')
runme_py.write('print "some text"')
@@ -485,9 +492,12 @@
with chdir_and_unset_pythonpath(tmpdir):
data = self.run(cmdline2, python_flags='-S')
-
assert data.startswith("some new text\n")
assert repr(str(tmpdir.join('otherpath'))) in data
+ assert "''" not in data
+
+ data = self.run('-c "import sys; print sys.path"')
+ assert data.startswith("[''")
class AppTestAppMain:
@@ -524,7 +534,8 @@
newpath = app_main.get_library_path('/tmp/pypy-c') # stdlib not found
assert newpath == sys.path
newpath = app_main.get_library_path(self.fake_exe)
- assert newpath == self.expected_path
+ # we get at least 'expected_path', and maybe more (e.g.plat-linux2)
+ assert newpath[:len(self.expected_path)] == self.expected_path
finally:
sys.path.pop()
@@ -537,7 +548,9 @@
app_main.os = os
pypy_c = os.path.join(self.trunkdir, 'pypy', 'translator', 'goal', 'pypy-c')
newpath = app_main.get_library_path(pypy_c)
- assert len(newpath) == 3
+ # we get at least lib_pypy, lib-python/modified-X.Y.Z,
+ # lib-python/X.Y.Z, and maybe more (e.g. plat-linux2)
+ assert len(newpath) >= 3
for p in newpath:
assert p.startswith(self.trunkdir)
finally:
Modified: pypy/branch/jitypes2/pypy/translator/platform/linux.py
==============================================================================
--- pypy/branch/jitypes2/pypy/translator/platform/linux.py (original)
+++ pypy/branch/jitypes2/pypy/translator/platform/linux.py Tue Nov 23 13:26:19 2010
@@ -27,6 +27,8 @@
class Linux(BaseLinux):
+ shared_only = () # it seems that on 32-bit linux, compiling with -fPIC
+ # gives assembler that asmgcc is not happy about.
def library_dirs_for_libffi_a(self):
# places where we need to look for libffi.a
return self.library_dirs_for_libffi() + ['/usr/lib']
Modified: pypy/branch/jitypes2/pypy/translator/platform/posix.py
==============================================================================
--- pypy/branch/jitypes2/pypy/translator/platform/posix.py (original)
+++ pypy/branch/jitypes2/pypy/translator/platform/posix.py Tue Nov 23 13:26:19 2010
@@ -104,12 +104,10 @@
else:
target_name = exe_name.basename
- cflags = self.cflags
- if sys.maxint > 2147483647: # XXX XXX XXX sort this out
- if shared:
- cflags = self.cflags + self.shared_only
- else:
- cflags = self.cflags + self.standalone_only
+ if shared:
+ cflags = self.cflags + self.shared_only
+ else:
+ cflags = self.cflags + self.standalone_only
m = GnuMakefile(path)
m.exe_name = exe_name
More information about the Pypy-commit
mailing list