[pypy-svn] r70836 - in pypy/branch/stringbuilder2: . ctypes_configure lib-python lib-python/modified-2.5.2/test pypy pypy/config pypy/doc pypy/doc/config pypy/doc/jit pypy/interpreter pypy/interpreter/test pypy/jit/backend pypy/jit/backend/llgraph pypy/jit/backend/llgraph/test pypy/jit/backend/llsupport pypy/jit/backend/llvm/test pypy/jit/backend/test pypy/jit/backend/x86 pypy/jit/backend/x86/test pypy/jit/metainterp pypy/jit/metainterp/test pypy/jit/tool pypy/jit/tool/test pypy/lib pypy/lib/_ctypes pypy/lib/app_test pypy/lib/app_test/ctypes_tests pypy/module/__builtin__ pypy/module/__builtin__/test pypy/module/__pypy__ pypy/module/_demo pypy/module/_demo/test pypy/module/_stackless pypy/module/exceptions pypy/module/imp pypy/module/imp/test pypy/module/oracle pypy/module/posix pypy/module/posix/test pypy/module/pypyjit pypy/module/pypyjit/test pypy/module/sys pypy/module/thread pypy/module/zipimport pypy/module/zipimport/test pypy/objspace pypy/objspace/flow pypy/objspace/std pypy/objspace/std/test pypy/objspace/test pypy/rlib pypy/rlib/test pypy/rpython pypy/rpython/lltypesystem pypy/rpython/lltypesystem/test pypy/rpython/memory/gctransform pypy/rpython/memory/gctransform/test pypy/rpython/module pypy/rpython/test pypy/rpython/tool pypy/tool pypy/tool/test pypy/translator pypy/translator/backendopt pypy/translator/backendopt/test pypy/translator/benchmark pypy/translator/benchmark/test pypy/translator/c pypy/translator/c/src pypy/translator/c/test pypy/translator/cli pypy/translator/goal pypy/translator/jvm pypy/translator/platform pypy/translator/platform/test pypy/translator/test
fijal at codespeak.net
fijal at codespeak.net
Mon Jan 25 15:25:54 CET 2010
Author: fijal
Date: Mon Jan 25 15:25:48 2010
New Revision: 70836
Added:
pypy/branch/stringbuilder2/lib-python/modified-2.5.2/test/test_runpy.py
- copied unchanged from r70835, pypy/trunk/lib-python/modified-2.5.2/test/test_runpy.py
pypy/branch/stringbuilder2/pypy/doc/config/objspace.usemodules.imp.txt
- copied unchanged from r70835, pypy/trunk/pypy/doc/config/objspace.usemodules.imp.txt
pypy/branch/stringbuilder2/pypy/jit/backend/x86/test/test_virtualref.py
- copied unchanged from r70835, pypy/trunk/pypy/jit/backend/x86/test/test_virtualref.py
pypy/branch/stringbuilder2/pypy/jit/metainterp/test/test_virtualref.py
- copied unchanged from r70835, pypy/trunk/pypy/jit/metainterp/test/test_virtualref.py
pypy/branch/stringbuilder2/pypy/jit/metainterp/virtualref.py
- copied unchanged from r70835, pypy/trunk/pypy/jit/metainterp/virtualref.py
pypy/branch/stringbuilder2/pypy/module/_demo/test/ (props changed)
- copied from r70835, pypy/trunk/pypy/module/_demo/test/
pypy/branch/stringbuilder2/pypy/module/imp/ (props changed)
- copied from r70835, pypy/trunk/pypy/module/imp/
pypy/branch/stringbuilder2/pypy/module/pypyjit/test/test_pyframe.py
- copied unchanged from r70835, pypy/trunk/pypy/module/pypyjit/test/test_pyframe.py
pypy/branch/stringbuilder2/pypy/rlib/_jit_vref.py
- copied unchanged from r70835, pypy/trunk/pypy/rlib/_jit_vref.py
pypy/branch/stringbuilder2/pypy/rlib/test/test__jit_vref.py
- copied unchanged from r70835, pypy/trunk/pypy/rlib/test/test__jit_vref.py
pypy/branch/stringbuilder2/pypy/tool/package.py
- copied unchanged from r70835, pypy/trunk/pypy/tool/package.py
pypy/branch/stringbuilder2/pypy/tool/test/test_package.py
- copied unchanged from r70835, pypy/trunk/pypy/tool/test/test_package.py
pypy/branch/stringbuilder2/pypy/translator/c/src/debug_print.h
- copied unchanged from r70835, pypy/trunk/pypy/translator/c/src/debug_print.h
pypy/branch/stringbuilder2/pypy/translator/c/src/debug_traceback.h
- copied unchanged from r70835, pypy/trunk/pypy/translator/c/src/debug_traceback.h
Removed:
pypy/branch/stringbuilder2/lib-python/modified-2.5.2/test/test___all__.py
pypy/branch/stringbuilder2/lib-python/modified-2.5.2/test/test_importhooks.py
pypy/branch/stringbuilder2/pypy/lib/app_test/test_imp_extra.py
pypy/branch/stringbuilder2/pypy/lib/imp.py
pypy/branch/stringbuilder2/pypy/module/__builtin__/app_misc.py
pypy/branch/stringbuilder2/pypy/module/__builtin__/importing.py
pypy/branch/stringbuilder2/pypy/module/__builtin__/test/test_import.py
pypy/branch/stringbuilder2/pypy/module/thread/importlock.py
pypy/branch/stringbuilder2/pypy/translator/benchmark/test/
pypy/branch/stringbuilder2/pypy/translator/c/src/debug.h
pypy/branch/stringbuilder2/pypy/translator/c/src/debuginfo.h
pypy/branch/stringbuilder2/pypy/translator/c/src/trace.h
Modified:
pypy/branch/stringbuilder2/LICENSE
pypy/branch/stringbuilder2/ctypes_configure/cbuild.py
pypy/branch/stringbuilder2/lib-python/ (props changed)
pypy/branch/stringbuilder2/lib-python/conftest.py
pypy/branch/stringbuilder2/lib-python/modified-2.5.2/test/infinite_reload.py
pypy/branch/stringbuilder2/lib-python/modified-2.5.2/test/test_import.py
pypy/branch/stringbuilder2/pypy/ (props changed)
pypy/branch/stringbuilder2/pypy/config/pypyoption.py
pypy/branch/stringbuilder2/pypy/doc/coding-guide.txt
pypy/branch/stringbuilder2/pypy/doc/config/objspace.std.withcelldict.txt
pypy/branch/stringbuilder2/pypy/doc/confrest.py
pypy/branch/stringbuilder2/pypy/doc/getting-started.txt
pypy/branch/stringbuilder2/pypy/doc/jit/pyjitpl5.txt
pypy/branch/stringbuilder2/pypy/interpreter/argument.py
pypy/branch/stringbuilder2/pypy/interpreter/baseobjspace.py
pypy/branch/stringbuilder2/pypy/interpreter/error.py
pypy/branch/stringbuilder2/pypy/interpreter/executioncontext.py
pypy/branch/stringbuilder2/pypy/interpreter/function.py
pypy/branch/stringbuilder2/pypy/interpreter/gateway.py
pypy/branch/stringbuilder2/pypy/interpreter/generator.py
pypy/branch/stringbuilder2/pypy/interpreter/mixedmodule.py
pypy/branch/stringbuilder2/pypy/interpreter/module.py
pypy/branch/stringbuilder2/pypy/interpreter/pycode.py
pypy/branch/stringbuilder2/pypy/interpreter/pyframe.py
pypy/branch/stringbuilder2/pypy/interpreter/pyopcode.py
pypy/branch/stringbuilder2/pypy/interpreter/pytraceback.py
pypy/branch/stringbuilder2/pypy/interpreter/test/test_executioncontext.py
pypy/branch/stringbuilder2/pypy/interpreter/test/test_gateway.py
pypy/branch/stringbuilder2/pypy/interpreter/test/test_module.py
pypy/branch/stringbuilder2/pypy/interpreter/test/test_zzpickle_and_slow.py
pypy/branch/stringbuilder2/pypy/jit/backend/llgraph/llimpl.py
pypy/branch/stringbuilder2/pypy/jit/backend/llgraph/runner.py
pypy/branch/stringbuilder2/pypy/jit/backend/llgraph/test/test_llgraph.py
pypy/branch/stringbuilder2/pypy/jit/backend/llsupport/gc.py
pypy/branch/stringbuilder2/pypy/jit/backend/llvm/test/conftest.py (props changed)
pypy/branch/stringbuilder2/pypy/jit/backend/model.py
pypy/branch/stringbuilder2/pypy/jit/backend/test/runner_test.py
pypy/branch/stringbuilder2/pypy/jit/backend/test/support.py
pypy/branch/stringbuilder2/pypy/jit/backend/test/test_random.py
pypy/branch/stringbuilder2/pypy/jit/backend/x86/assembler.py
pypy/branch/stringbuilder2/pypy/jit/backend/x86/regalloc.py
pypy/branch/stringbuilder2/pypy/jit/backend/x86/runner.py
pypy/branch/stringbuilder2/pypy/jit/backend/x86/test/test_gc_integration.py (contents, props changed)
pypy/branch/stringbuilder2/pypy/jit/backend/x86/test/test_recursive.py
pypy/branch/stringbuilder2/pypy/jit/backend/x86/test/test_regalloc.py
pypy/branch/stringbuilder2/pypy/jit/backend/x86/test/test_runner.py
pypy/branch/stringbuilder2/pypy/jit/backend/x86/test/test_tlc.py
pypy/branch/stringbuilder2/pypy/jit/backend/x86/test/test_ztranslation.py
pypy/branch/stringbuilder2/pypy/jit/metainterp/codewriter.py
pypy/branch/stringbuilder2/pypy/jit/metainterp/compile.py
pypy/branch/stringbuilder2/pypy/jit/metainterp/effectinfo.py
pypy/branch/stringbuilder2/pypy/jit/metainterp/executor.py
pypy/branch/stringbuilder2/pypy/jit/metainterp/history.py
pypy/branch/stringbuilder2/pypy/jit/metainterp/jitprof.py
pypy/branch/stringbuilder2/pypy/jit/metainterp/logger.py (props changed)
pypy/branch/stringbuilder2/pypy/jit/metainterp/optimizeopt.py
pypy/branch/stringbuilder2/pypy/jit/metainterp/optimizeutil.py
pypy/branch/stringbuilder2/pypy/jit/metainterp/policy.py
pypy/branch/stringbuilder2/pypy/jit/metainterp/pyjitpl.py
pypy/branch/stringbuilder2/pypy/jit/metainterp/resoperation.py
pypy/branch/stringbuilder2/pypy/jit/metainterp/resume.py
pypy/branch/stringbuilder2/pypy/jit/metainterp/support.py
pypy/branch/stringbuilder2/pypy/jit/metainterp/test/test_basic.py
pypy/branch/stringbuilder2/pypy/jit/metainterp/test/test_codewriter.py
pypy/branch/stringbuilder2/pypy/jit/metainterp/test/test_compile.py
pypy/branch/stringbuilder2/pypy/jit/metainterp/test/test_effectinfo.py
pypy/branch/stringbuilder2/pypy/jit/metainterp/test/test_executor.py
pypy/branch/stringbuilder2/pypy/jit/metainterp/test/test_history.py
pypy/branch/stringbuilder2/pypy/jit/metainterp/test/test_jitprof.py
pypy/branch/stringbuilder2/pypy/jit/metainterp/test/test_optimizefindnode.py
pypy/branch/stringbuilder2/pypy/jit/metainterp/test/test_optimizeopt.py
pypy/branch/stringbuilder2/pypy/jit/metainterp/test/test_pyjitpl.py
pypy/branch/stringbuilder2/pypy/jit/metainterp/test/test_recursive.py
pypy/branch/stringbuilder2/pypy/jit/metainterp/test/test_resume.py
pypy/branch/stringbuilder2/pypy/jit/metainterp/test/test_virtualizable.py
pypy/branch/stringbuilder2/pypy/jit/metainterp/test/test_warmspot.py
pypy/branch/stringbuilder2/pypy/jit/metainterp/test/test_warmstate.py
pypy/branch/stringbuilder2/pypy/jit/metainterp/test/test_ztranslation.py
pypy/branch/stringbuilder2/pypy/jit/metainterp/virtualizable.py
pypy/branch/stringbuilder2/pypy/jit/metainterp/warmspot.py
pypy/branch/stringbuilder2/pypy/jit/metainterp/warmstate.py
pypy/branch/stringbuilder2/pypy/jit/tool/jitoutput.py
pypy/branch/stringbuilder2/pypy/jit/tool/showstats.py
pypy/branch/stringbuilder2/pypy/jit/tool/test/test_jitoutput.py
pypy/branch/stringbuilder2/pypy/lib/_ctypes/array.py
pypy/branch/stringbuilder2/pypy/lib/_ctypes/primitive.py
pypy/branch/stringbuilder2/pypy/lib/_ctypes/structure.py
pypy/branch/stringbuilder2/pypy/lib/_ctypes/union.py
pypy/branch/stringbuilder2/pypy/lib/app_test/ctypes_tests/test_keepalive.py
pypy/branch/stringbuilder2/pypy/lib/app_test/test_runpy.py
pypy/branch/stringbuilder2/pypy/module/__builtin__/__init__.py
pypy/branch/stringbuilder2/pypy/module/__builtin__/descriptor.py
pypy/branch/stringbuilder2/pypy/module/__builtin__/test/test_descriptor.py
pypy/branch/stringbuilder2/pypy/module/__pypy__/__init__.py
pypy/branch/stringbuilder2/pypy/module/_demo/__init__.py
pypy/branch/stringbuilder2/pypy/module/_stackless/interp_coroutine.py
pypy/branch/stringbuilder2/pypy/module/exceptions/ (props changed)
pypy/branch/stringbuilder2/pypy/module/imp/test/ (props changed)
pypy/branch/stringbuilder2/pypy/module/oracle/__init__.py
pypy/branch/stringbuilder2/pypy/module/oracle/interp_error.py
pypy/branch/stringbuilder2/pypy/module/posix/__init__.py
pypy/branch/stringbuilder2/pypy/module/posix/interp_posix.py
pypy/branch/stringbuilder2/pypy/module/posix/test/test_posix2.py
pypy/branch/stringbuilder2/pypy/module/pypyjit/interp_jit.py
pypy/branch/stringbuilder2/pypy/module/pypyjit/test/test_pypy_c.py
pypy/branch/stringbuilder2/pypy/module/sys/vm.py
pypy/branch/stringbuilder2/pypy/module/thread/__init__.py
pypy/branch/stringbuilder2/pypy/module/zipimport/__init__.py
pypy/branch/stringbuilder2/pypy/module/zipimport/interp_zipimport.py
pypy/branch/stringbuilder2/pypy/module/zipimport/test/test_zipimport.py
pypy/branch/stringbuilder2/pypy/objspace/descroperation.py
pypy/branch/stringbuilder2/pypy/objspace/flow/flowcontext.py
pypy/branch/stringbuilder2/pypy/objspace/std/celldict.py
pypy/branch/stringbuilder2/pypy/objspace/std/objspace.py
pypy/branch/stringbuilder2/pypy/objspace/std/rangeobject.py
pypy/branch/stringbuilder2/pypy/objspace/std/test/test_celldict.py
pypy/branch/stringbuilder2/pypy/objspace/std/test/test_setobject.py (props changed)
pypy/branch/stringbuilder2/pypy/objspace/std/test/test_userobject.py
pypy/branch/stringbuilder2/pypy/objspace/test/test_descriptor.py
pypy/branch/stringbuilder2/pypy/objspace/test/test_descroperation.py
pypy/branch/stringbuilder2/pypy/rlib/debug.py
pypy/branch/stringbuilder2/pypy/rlib/jit.py
pypy/branch/stringbuilder2/pypy/rlib/rgc.py
pypy/branch/stringbuilder2/pypy/rpython/llinterp.py
pypy/branch/stringbuilder2/pypy/rpython/lltypesystem/ll2ctypes.py
pypy/branch/stringbuilder2/pypy/rpython/lltypesystem/lloperation.py
pypy/branch/stringbuilder2/pypy/rpython/lltypesystem/opimpl.py
pypy/branch/stringbuilder2/pypy/rpython/lltypesystem/rclass.py
pypy/branch/stringbuilder2/pypy/rpython/lltypesystem/rlist.py
pypy/branch/stringbuilder2/pypy/rpython/lltypesystem/test/test_ll2ctypes.py
pypy/branch/stringbuilder2/pypy/rpython/memory/gctransform/framework.py
pypy/branch/stringbuilder2/pypy/rpython/memory/gctransform/test/test_framework.py
pypy/branch/stringbuilder2/pypy/rpython/module/ll_os.py
pypy/branch/stringbuilder2/pypy/rpython/rlist.py
pypy/branch/stringbuilder2/pypy/rpython/rptr.py
pypy/branch/stringbuilder2/pypy/rpython/rtyper.py
pypy/branch/stringbuilder2/pypy/rpython/rvirtualizable2.py
pypy/branch/stringbuilder2/pypy/rpython/test/test_rlist.py
pypy/branch/stringbuilder2/pypy/rpython/test/test_rptr.py
pypy/branch/stringbuilder2/pypy/rpython/test/test_rvirtualizable2.py
pypy/branch/stringbuilder2/pypy/rpython/tool/rffi_platform.py
pypy/branch/stringbuilder2/pypy/tool/gcc_cache.py
pypy/branch/stringbuilder2/pypy/tool/udir.py
pypy/branch/stringbuilder2/pypy/translator/backendopt/test/test_writeanalyze.py
pypy/branch/stringbuilder2/pypy/translator/backendopt/writeanalyze.py
pypy/branch/stringbuilder2/pypy/translator/benchmark/ (props changed)
pypy/branch/stringbuilder2/pypy/translator/benchmark/bench-custom.py
pypy/branch/stringbuilder2/pypy/translator/benchmark/benchmarks.py
pypy/branch/stringbuilder2/pypy/translator/benchmark/jitbench.py
pypy/branch/stringbuilder2/pypy/translator/benchmark/result.py
pypy/branch/stringbuilder2/pypy/translator/c/funcgen.py
pypy/branch/stringbuilder2/pypy/translator/c/gc.py
pypy/branch/stringbuilder2/pypy/translator/c/genc.py
pypy/branch/stringbuilder2/pypy/translator/c/src/g_include.h
pypy/branch/stringbuilder2/pypy/translator/c/src/main.h
pypy/branch/stringbuilder2/pypy/translator/c/test/test_boehm.py
pypy/branch/stringbuilder2/pypy/translator/c/test/test_genc.py
pypy/branch/stringbuilder2/pypy/translator/c/test/test_refcount.py (props changed)
pypy/branch/stringbuilder2/pypy/translator/c/test/test_stackless.py
pypy/branch/stringbuilder2/pypy/translator/c/test/test_standalone.py
pypy/branch/stringbuilder2/pypy/translator/cli/opcodes.py
pypy/branch/stringbuilder2/pypy/translator/driver.py
pypy/branch/stringbuilder2/pypy/translator/exceptiontransform.py
pypy/branch/stringbuilder2/pypy/translator/goal/app_main.py
pypy/branch/stringbuilder2/pypy/translator/jvm/opcodes.py
pypy/branch/stringbuilder2/pypy/translator/platform/__init__.py
pypy/branch/stringbuilder2/pypy/translator/platform/darwin.py
pypy/branch/stringbuilder2/pypy/translator/platform/linux.py
pypy/branch/stringbuilder2/pypy/translator/platform/posix.py
pypy/branch/stringbuilder2/pypy/translator/platform/test/test_darwin.py
pypy/branch/stringbuilder2/pypy/translator/platform/test/test_platform.py
pypy/branch/stringbuilder2/pypy/translator/test/test_exceptiontransform.py
Log:
merge from trunk:
svn merge -r 70153:HEAD svn+ssh://codespeak.net/svn/pypy/trunk .
Modified: pypy/branch/stringbuilder2/LICENSE
==============================================================================
--- pypy/branch/stringbuilder2/LICENSE (original)
+++ pypy/branch/stringbuilder2/LICENSE Mon Jan 25 15:25:48 2010
@@ -27,7 +27,7 @@
DEALINGS IN THE SOFTWARE.
-PyPy Copyright holders 2003-2009
+PyPy Copyright holders 2003-2010
-----------------------------------
Except when otherwise stated (look for LICENSE files or information at
@@ -86,6 +86,7 @@
Guenter Jantzen
Dinu Gherman
Georg Brandl
+ Benjamin Peterson
Ben Young
Nicolas Chauvat
Jean-Paul Calderone
Modified: pypy/branch/stringbuilder2/ctypes_configure/cbuild.py
==============================================================================
--- pypy/branch/stringbuilder2/ctypes_configure/cbuild.py (original)
+++ pypy/branch/stringbuilder2/ctypes_configure/cbuild.py Mon Jan 25 15:25:48 2010
@@ -5,8 +5,6 @@
debug = 0
-log = py.log.Producer("cbuild")
-
configdir = py.path.local.make_numbered_dir(prefix='ctypes_configure')
class ExternalCompilationInfo(object):
@@ -327,7 +325,7 @@
def log_spawned_cmd(spawn):
def spawn_and_log(cmd, *args, **kwds):
if debug:
- log.execute(' '.join(cmd))
+ print ' '.join(cmd)
return spawn(cmd, *args, **kwds)
return spawn_and_log
Modified: pypy/branch/stringbuilder2/lib-python/conftest.py
==============================================================================
--- pypy/branch/stringbuilder2/lib-python/conftest.py (original)
+++ pypy/branch/stringbuilder2/lib-python/conftest.py Mon Jan 25 15:25:48 2010
@@ -311,7 +311,7 @@
RegrTest('test_normalization.py'),
RegrTest('test_ntpath.py'),
RegrTest('test_opcodes.py', core=True),
- RegrTest('test_openpty.py', skip="unsupported extension module"),
+ RegrTest('test_openpty.py'),
RegrTest('test_operations.py', core=True),
RegrTest('test_operator.py', core=True),
RegrTest('test_optparse.py'),
Modified: pypy/branch/stringbuilder2/lib-python/modified-2.5.2/test/infinite_reload.py
==============================================================================
--- pypy/branch/stringbuilder2/lib-python/modified-2.5.2/test/infinite_reload.py (original)
+++ pypy/branch/stringbuilder2/lib-python/modified-2.5.2/test/infinite_reload.py Mon Jan 25 15:25:48 2010
@@ -3,8 +3,5 @@
# reload()ing. This module is imported by test_import.py:test_infinite_reload
# to make sure this doesn't happen any more.
-print 1
import infinite_reload
-print 2
reload(infinite_reload)
-print 3
Modified: pypy/branch/stringbuilder2/lib-python/modified-2.5.2/test/test_import.py
==============================================================================
--- pypy/branch/stringbuilder2/lib-python/modified-2.5.2/test/test_import.py (original)
+++ pypy/branch/stringbuilder2/lib-python/modified-2.5.2/test/test_import.py Mon Jan 25 15:25:48 2010
@@ -1,4 +1,4 @@
-from test.test_support import TESTFN, TestFailed, check_impl_detail
+from test.test_support import TESTFN, TestFailed
import os
import random
@@ -56,6 +56,11 @@
os.unlink(source)
try:
+ #--- the block below is to check that "reload" manages to import
+ #--- the .pyc file alone. We don't support it in PyPy in the default
+ #--- configuration.
+ return
+
try:
reload(mod)
except ImportError, err:
@@ -238,5 +243,4 @@
finally:
sys.path.pop(0)
-if check_impl_detail():
- test_infinite_reload()
+test_infinite_reload()
Modified: pypy/branch/stringbuilder2/pypy/config/pypyoption.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/config/pypyoption.py (original)
+++ pypy/branch/stringbuilder2/pypy/config/pypyoption.py Mon Jan 25 15:25:48 2010
@@ -16,7 +16,7 @@
default_modules = essential_modules.copy()
default_modules.update(dict.fromkeys(
- ["_codecs", "gc", "_weakref", "marshal", "errno",
+ ["_codecs", "gc", "_weakref", "marshal", "errno", "imp",
"math", "_sre", "_pickle_support", "operator",
"parser", "symbol", "token", "_ast", "_random", "__pypy__",
"_testing"]))
@@ -345,7 +345,7 @@
config.objspace.std.suggest(withprebuiltint=True)
config.objspace.std.suggest(withrangelist=True)
config.objspace.std.suggest(withprebuiltchar=True)
- config.objspace.std.suggest(withsharingdict=True)
+ config.objspace.std.suggest(withinlineddict=True)
config.objspace.std.suggest(withstrslice=True)
config.objspace.std.suggest(withstrjoin=True)
# xxx other options? ropes maybe?
Modified: pypy/branch/stringbuilder2/pypy/doc/coding-guide.txt
==============================================================================
--- pypy/branch/stringbuilder2/pypy/doc/coding-guide.txt (original)
+++ pypy/branch/stringbuilder2/pypy/doc/coding-guide.txt Mon Jan 25 15:25:48 2010
@@ -160,7 +160,8 @@
An example can be found in the current implementation which is quite
elegant: For the definition of all the opcodes of the Python
interpreter, the module ``dis`` is imported and used to initialize our
-bytecode interpreter. (See ``__initclass__`` in `pyopcode.py`_). This
+bytecode interpreter. (See ``__initclass__`` in
+`pypy/interpreter/pyopcode.py`_). This
saves us from adding extra modules to PyPy. The import code is run at
startup time, and we are allowed to use the CPython builtin import
function.
@@ -173,8 +174,6 @@
enables the code generator to emit efficient machine level replacements
for pure integer objects, for instance.
-.. _`pyopcode.py`: http://codespeak.net/svn/pypy/dist/pypy/interpreter/pyopcode.py
-
Restricted Python
=================
Modified: pypy/branch/stringbuilder2/pypy/doc/config/objspace.std.withcelldict.txt
==============================================================================
--- pypy/branch/stringbuilder2/pypy/doc/config/objspace.std.withcelldict.txt (original)
+++ pypy/branch/stringbuilder2/pypy/doc/config/objspace.std.withcelldict.txt Mon Jan 25 15:25:48 2010
@@ -1,2 +1,2 @@
-Enable cell-dicts. This makes global lookups nearly as fast as the lookup of a
-local.
+Enable cell-dicts. This optimization is not helpful without the JIT. In the
+presence of the JIT, it greatly helps looking up globals.
Modified: pypy/branch/stringbuilder2/pypy/doc/confrest.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/doc/confrest.py (original)
+++ pypy/branch/stringbuilder2/pypy/doc/confrest.py Mon Jan 25 15:25:48 2010
@@ -5,6 +5,17 @@
html = py.xml.html
class PyPyPage(Page):
+ googlefragment = """
+<script type="text/javascript">
+var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
+document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
+</script>
+<script type="text/javascript">
+try {
+var pageTracker = _gat._getTracker("UA-7778406-2");
+pageTracker._trackPageview();
+} catch(err) {}</script>
+"""
def fill_menubar(self):
self.menubar = html.div(
html.a("home",
@@ -31,6 +42,14 @@
def get_doclink(self, target):
return relpath(self.targetpath.strpath,
self.project.docpath.join(target).strpath)
+
+ def unicode(self, doctype=True):
+ page = self._root.unicode()
+ page = page.replace("</body>", self.googlefragment + "</body>")
+ if doctype:
+ return self.doctype + page
+ else:
+ return page
class Project(Project):
Modified: pypy/branch/stringbuilder2/pypy/doc/getting-started.txt
==============================================================================
--- pypy/branch/stringbuilder2/pypy/doc/getting-started.txt (original)
+++ pypy/branch/stringbuilder2/pypy/doc/getting-started.txt Mon Jan 25 15:25:48 2010
@@ -35,22 +35,31 @@
Before you can play with PyPy, you will need to obtain a copy
of the sources. This can be done either by `downloading them
from the download page`_ or by checking them out from the
-repository using subversion. We suggest using subversion as it
-offers access to the most recent versions.
+repository using subversion. We suggest using subversion if one
+wants to access the current development.
.. _`downloading them from the download page`: download.html
If you choose to use subversion, you must issue the following command on your
command line, DOS box, or terminal::
- svn co http://codespeak.net/svn/pypy/dist pypy-dist
+ svn co http://codespeak.net/svn/pypy/trunk pypy-trunk
+
+This will check out the subversion head and place it into a directory
+named ``pypy-trunk``, and will get you the PyPy source in
+``pypy-trunk/pypy`` and documentation files in ``pypy-trunk/pypy/doc``.
+We try to ensure that the head is always stable, but it might
+occasionally be broken. You may want to check out `our nightly tests:`_
+find a revision (5-digit number) that passed at least the
+``{own}`` and ``{applevel}`` tests (corresponding to a ``+`` sign on the
+line ``success``) and then check out using::
+
+ svn co -rXXXXX http://codespeak.net/svn/pypy/trunk pypy-trunk
+
+where XXXXX is the revision number.
+
+.. _`our nightly tests:`: http://codespeak.net:8099/summary?branch=<trunk>
-This will check out the most recent stable release from subversion and
-place it into a directory named ``pypy-dist``, and will get you the PyPy
-source in ``pypy-dist/pypy`` and documentation files in
-``pypy-dist/pypy/doc``. If you would prefer to check out the "cutting edge"
-version of PyPy - which may not always be stable! - then check out
-from ``http://codespeak.net/svn/pypy/trunk`` intead.
Where to go from here
----------------------
Modified: pypy/branch/stringbuilder2/pypy/doc/jit/pyjitpl5.txt
==============================================================================
--- pypy/branch/stringbuilder2/pypy/doc/jit/pyjitpl5.txt (original)
+++ pypy/branch/stringbuilder2/pypy/doc/jit/pyjitpl5.txt Mon Jan 25 15:25:48 2010
@@ -2,7 +2,7 @@
PyJitPl5
==========
-This document describes the fith generation of PyPy's JIT.
+This document describes the fifth generation of PyPy's JIT.
Implementation of the JIT
Modified: pypy/branch/stringbuilder2/pypy/interpreter/argument.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/interpreter/argument.py (original)
+++ pypy/branch/stringbuilder2/pypy/interpreter/argument.py Mon Jan 25 15:25:48 2010
@@ -4,7 +4,7 @@
from pypy.interpreter.error import OperationError
from pypy.rlib.debug import make_sure_not_resized
-from pypy.rlib.jit import purefunction, unroll_safe
+from pypy.rlib import jit
class Signature(object):
@@ -17,7 +17,7 @@
self.varargname = varargname
self.kwargname = kwargname
- @purefunction
+ @jit.purefunction
def find_argname(self, name):
try:
return self.argnames.index(name)
@@ -101,6 +101,11 @@
make_sure_not_resized(self.arguments_w)
if w_stararg is not None or w_starstararg is not None:
self._combine_wrapped(w_stararg, w_starstararg)
+ # if we have a call where * or ** args are used at the callsite
+ # we shouldn't let the JIT see the argument matching
+ self._dont_jit = True
+ else:
+ self._dont_jit = False
def __repr__(self):
""" NOT_RPYTHON """
@@ -188,13 +193,28 @@
### Parsing for function calls ###
- @unroll_safe # XXX not true always, but for now
def _match_signature(self, w_firstarg, scope_w, signature, defaults_w=[],
blindargs=0):
"""Parse args and kwargs according to the signature of a code object,
or raise an ArgErr in case of failure.
Return the number of arguments filled in.
"""
+ if jit.we_are_jitted() and self._dont_jit:
+ return self._match_signature_jit_opaque(w_firstarg, scope_w,
+ signature, defaults_w,
+ blindargs)
+ return self._really_match_signature(w_firstarg, scope_w, signature,
+ defaults_w, blindargs)
+
+ @jit.dont_look_inside
+ def _match_signature_jit_opaque(self, w_firstarg, scope_w, signature,
+ defaults_w, blindargs):
+ return self._really_match_signature(w_firstarg, scope_w, signature,
+ defaults_w, blindargs)
+
+ @jit.unroll_safe
+ def _really_match_signature(self, w_firstarg, scope_w, signature, defaults_w=[],
+ blindargs=0):
#
# args_w = list of the normal actual parameters, wrapped
# kwds_w = real dictionary {'keyword': wrapped parameter}
Modified: pypy/branch/stringbuilder2/pypy/interpreter/baseobjspace.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/interpreter/baseobjspace.py (original)
+++ pypy/branch/stringbuilder2/pypy/interpreter/baseobjspace.py Mon Jan 25 15:25:48 2010
@@ -9,7 +9,7 @@
from pypy.rlib.objectmodel import we_are_translated
from pypy.rlib.debug import make_sure_not_resized
from pypy.rlib.timer import DummyTimer, Timer
-from pypy.rlib.jit import we_are_jitted, dont_look_inside, unroll_safe
+from pypy.rlib import jit
import os, sys
__all__ = ['ObjSpace', 'OperationError', 'Wrappable', 'W_Root']
@@ -239,6 +239,9 @@
config = get_pypy_config(translating=False)
self.config = config
+ self.builtin_modules = {}
+ self.reloading_modules = {}
+
# import extra modules for side-effects
import pypy.interpreter.nestedscope # register *_DEREF bytecodes
@@ -266,16 +269,22 @@
def startup(self):
# To be called before using the space
- # Initialize all builtin modules
+ # Initialize already imported builtin modules
from pypy.interpreter.module import Module
+ w_modules = self.sys.get('modules')
for w_modname in self.unpackiterable(
self.sys.get('builtin_module_names')):
+ try:
+ w_mod = self.getitem(w_modules, w_modname)
+ except OperationError, e:
+ if e.match(self, self.w_KeyError):
+ continue
+ raise
modname = self.str_w(w_modname)
- mod = self.interpclass_w(self.getbuiltinmodule(modname))
+ mod = self.interpclass_w(w_mod)
if isinstance(mod, Module):
- import time
self.timer.start("startup " + modname)
- mod.startup(self)
+ mod.init(self)
self.timer.stop("startup " + modname)
def finish(self):
@@ -283,11 +292,9 @@
if w_exitfunc is not None:
self.call_function(w_exitfunc)
from pypy.interpreter.module import Module
- for w_modname in self.unpackiterable(
- self.sys.get('builtin_module_names')):
- modname = self.str_w(w_modname)
- mod = self.interpclass_w(self.getbuiltinmodule(modname))
- if isinstance(mod, Module):
+ for w_mod in self.builtin_modules.values():
+ mod = self.interpclass_w(w_mod)
+ if isinstance(mod, Module) and mod.startup_called:
mod.shutdown(self)
if self.config.objspace.std.withdictmeasurement:
from pypy.objspace.std.dictmultiobject import report
@@ -339,14 +346,42 @@
w_name = self.wrap(name)
w_mod = self.wrap(Module(self, w_name))
- w_modules = self.sys.get('modules')
- self.setitem(w_modules, w_name, w_mod)
+ self.builtin_modules[name] = w_mod
return name
- def getbuiltinmodule(self, name):
+ def getbuiltinmodule(self, name, force_init=False):
w_name = self.wrap(name)
w_modules = self.sys.get('modules')
- return self.getitem(w_modules, w_name)
+ try:
+ w_mod = self.getitem(w_modules, w_name)
+ except OperationError, e:
+ if not e.match(self, self.w_KeyError):
+ raise
+ else:
+ if not force_init:
+ return w_mod
+
+ # If the module is a builtin but not yet imported,
+ # retrieve it and initialize it
+ try:
+ w_mod = self.builtin_modules[name]
+ except KeyError:
+ raise OperationError(
+ self.w_SystemError,
+ self.wrap("getbuiltinmodule() called "
+ "with non-builtin module %s" % name))
+ else:
+ # Add the module to sys.modules
+ self.setitem(w_modules, w_name, w_mod)
+
+ # And initialize it
+ from pypy.interpreter.module import Module
+ mod = self.interpclass_w(w_mod)
+ if isinstance(mod, Module):
+ self.timer.start("startup " + name)
+ mod.init(self)
+ self.timer.stop("startup " + name)
+ return w_mod
def get_builtinmodule_to_install(self):
"""NOT_RPYTHON"""
@@ -390,26 +425,27 @@
"NOT_RPYTHON: only for initializing the space."
from pypy.module.exceptions import Module
- w_name_exceptions = self.wrap('exceptions')
- self.exceptions_module = Module(self, w_name_exceptions)
+ w_name = self.wrap('exceptions')
+ self.exceptions_module = Module(self, w_name)
+ self.builtin_modules['exceptions'] = self.wrap(self.exceptions_module)
from pypy.module.sys import Module
w_name = self.wrap('sys')
self.sys = Module(self, w_name)
- w_modules = self.sys.get('modules')
- self.setitem(w_modules, w_name, self.wrap(self.sys))
+ self.builtin_modules['sys'] = self.wrap(self.sys)
- self.setitem(w_modules, w_name_exceptions,
- self.wrap(self.exceptions_module))
+ from pypy.module.imp import Module
+ w_name = self.wrap('imp')
+ self.builtin_modules['imp'] = self.wrap(Module(self, w_name))
from pypy.module.__builtin__ import Module
w_name = self.wrap('__builtin__')
self.builtin = Module(self, w_name)
w_builtin = self.wrap(self.builtin)
- self.setitem(w_modules, w_name, w_builtin)
+ self.builtin_modules['__builtin__'] = self.wrap(w_builtin)
self.setitem(self.builtin.w_dict, self.wrap('__builtins__'), w_builtin)
- bootstrap_modules = ['sys', '__builtin__', 'exceptions']
+ bootstrap_modules = ['sys', 'imp', '__builtin__', 'exceptions']
installed_builtin_modules = bootstrap_modules[:]
self.export_builtin_exceptions()
@@ -480,12 +516,11 @@
def setup_builtin_modules(self):
"NOT_RPYTHON: only for initializing the space."
- from pypy.interpreter.module import Module
- for w_modname in self.unpackiterable(self.sys.get('builtin_module_names')):
- modname = self.unwrap(w_modname)
- mod = self.getbuiltinmodule(modname)
- if isinstance(mod, Module):
- mod.setup_after_space_initialization()
+ self.getbuiltinmodule('sys')
+ self.getbuiltinmodule('imp')
+ self.getbuiltinmodule('__builtin__')
+ for mod in self.builtin_modules.values():
+ mod.setup_after_space_initialization()
def initialize(self):
"""NOT_RPYTHON: Abstract method that should put some minimal
@@ -496,6 +531,7 @@
def leave_cache_building_mode(self, val):
"hook for the flow object space"
+ @jit.loop_invariant
def getexecutioncontext(self):
"Return what we consider to be the active execution context."
# Important: the annotator must not see a prebuilt ExecutionContext:
@@ -700,7 +736,7 @@
"""
return self.unpackiterable(w_iterable, expected_length)
- @unroll_safe
+ @jit.unroll_safe
def exception_match(self, w_exc_type, w_check_class):
"""Checks if the given exception type matches 'w_check_class'."""
if self.is_w(w_exc_type, w_check_class):
@@ -756,8 +792,7 @@
def call_valuestack(self, w_func, nargs, frame):
from pypy.interpreter.function import Function, Method, is_builtin_code
- if (not we_are_jitted() and frame.is_being_profiled and
- is_builtin_code(w_func)):
+ if frame.is_being_profiled and is_builtin_code(w_func):
# XXX: this code is copied&pasted :-( from the slow path below
# call_valuestack().
args = frame.make_arguments(nargs)
@@ -784,7 +819,6 @@
args = frame.make_arguments(nargs)
return self.call_args(w_func, args)
- @dont_look_inside
def call_args_and_c_profile(self, frame, w_func, args):
ec = self.getexecutioncontext()
ec.c_call_trace(frame, w_func)
Modified: pypy/branch/stringbuilder2/pypy/interpreter/error.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/interpreter/error.py (original)
+++ pypy/branch/stringbuilder2/pypy/interpreter/error.py Mon Jan 25 15:25:48 2010
@@ -203,8 +203,8 @@
w_instclass = space.exception_getclass(w_inst)
if not space.exception_is_valid_class_w(w_instclass):
instclassname = w_instclass.getname(space, '?')
- msg = ("exceptions must be classes, or instances,"
- "or strings (deprecated) not %s" % (instclassname,))
+ msg = ("exceptions must be classes, or instances, "
+ "or strings (deprecated), not %s" % (instclassname,))
raise OperationError(space.w_TypeError, space.wrap(msg))
if not space.is_w(w_value, space.w_None):
Modified: pypy/branch/stringbuilder2/pypy/interpreter/executioncontext.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/interpreter/executioncontext.py (original)
+++ pypy/branch/stringbuilder2/pypy/interpreter/executioncontext.py Mon Jan 25 15:25:48 2010
@@ -3,7 +3,6 @@
from pypy.interpreter.error import OperationError
from pypy.rlib.rarithmetic import LONG_BIT
from pypy.rlib.unroll import unrolling_iterable
-from pypy.rlib.jit import we_are_jitted
from pypy.rlib import jit
def app_profile_call(space, w_callable, frame, event, w_arg):
@@ -15,181 +14,61 @@
"""An ExecutionContext holds the state of an execution thread
in the Python interpreter."""
+ # XXX JIT: when tracing (but not when blackholing!), the following
+ # XXX fields should be known to a constant None or False:
+ # XXX self.w_tracefunc, self.profilefunc
+ # XXX frame.is_being_profiled
+
def __init__(self, space):
self.space = space
- self._init_frame_chain()
+ self.topframeref = jit.vref_None
+ self.framestackdepth = 0
# tracing: space.frame_trace_action.fire() must be called to ensure
# that tracing occurs whenever self.w_tracefunc or self.is_tracing
# is modified.
- self.w_tracefunc = None
+ self.w_tracefunc = None # if not None, no JIT
self.is_tracing = 0
self.compiler = space.createcompiler()
- self.profilefunc = None
+ self.profilefunc = None # if not None, no JIT
self.w_profilefuncarg = None
+ def gettopframe(self):
+ return self.topframeref()
+
def gettopframe_nohidden(self):
- frame = self.gettopframe()
- # I guess this should just use getnextframe_nohidden XXX
+ frame = self.topframeref()
while frame and frame.hide():
- frame = frame.f_back()
+ frame = frame.f_backref()
return frame
@staticmethod
def getnextframe_nohidden(frame):
- frame = frame.f_back()
+ frame = frame.f_backref()
while frame and frame.hide():
- frame = frame.f_back()
+ frame = frame.f_backref()
return frame
def enter(self, frame):
if self.framestackdepth > self.space.sys.recursionlimit:
raise OperationError(self.space.w_RuntimeError,
self.space.wrap("maximum recursion depth exceeded"))
- self._chain(frame)
+ self.framestackdepth += 1
+ frame.f_backref = self.topframeref
+ self.topframeref = jit.virtual_ref(frame)
def leave(self, frame):
- if self.profilefunc:
- self._trace(frame, 'leaveframe', self.space.w_None)
+ try:
+ if self.profilefunc:
+ self._trace(frame, 'leaveframe', self.space.w_None)
+ finally:
+ self.topframeref = frame.f_backref
+ self.framestackdepth -= 1
+ jit.virtual_ref_finish(frame)
- self._unchain(frame)
-
if self.w_tracefunc is not None and not frame.hide():
self.space.frame_trace_action.fire()
# ________________________________________________________________
- # the methods below are used for chaining frames in JIT-friendly way
- # part of that stuff is obscure
-
- @jit.unroll_safe
- def gettopframe(self):
- frame = self.some_frame
- if frame is not None:
- while frame.f_forward is not None:
- frame = frame.f_forward
- return frame
-
- def _init_frame_chain(self):
- # 'some_frame' points to any frame from this thread's frame stack
- # (although in general it should point to the top one).
- # XXX not true: some_frame must point to a frame from which we can
- # reach the top frame by following the chain of f_forward
- self.some_frame = None
- self.framestackdepth = 0
-
- @staticmethod
- def _init_chaining_attributes(frame):
- """
- explanation of the f_back handling:
- -----------------------------------
-
- in the non-JIT case, the frames simply form a doubly linked list via the
- attributes f_back_some and f_forward.
-
- When the JIT is used, things become more complex, as functions can be
- inlined into each other. In this case a frame chain can look like this:
-
- +---------------+
- | real_frame |
- +---------------+
- |
- | f_back_some
- |
- |
- | +--------------+
- | | virtual frame|
- | +--------------+
- | ^
- | | f_forward
- | +--------------+
- | | virtual frame|
- | +--------------+
- | ^
- | |
- v | f_forward
- +---------------+
- | real_frame |
- +---------------+
- |
- |
- v
- ...
-
- This ensures that the virtual frames don't escape via the f_back of the
- real frames. For the same reason, the executioncontext's some_frame
- attribute should only point to real frames.
-
- All places where a frame can become accessed from applevel-code (like
- sys._getframe and traceback catching) need to call force_f_back to ensure
- that the intermediate virtual frames are forced to be real ones.
-
- """
- frame.f_back_some = None
- frame.f_forward = None
- frame.f_back_forced = False
-
- def _chain(self, frame):
- self.framestackdepth += 1
- #
- frame.f_back_some = self.some_frame
- if self._we_are_jitted():
- curtopframe = self.gettopframe()
- assert curtopframe is not None
- curtopframe.f_forward = frame
- else:
- self.some_frame = frame
-
- def _unchain(self, frame):
- #assert frame is self.gettopframe() --- slowish
- if self.some_frame is frame:
- self.some_frame = frame.f_back_some
- else:
- f_back = frame.f_back()
- if f_back is not None:
- f_back.f_forward = None
-
- self.framestackdepth -= 1
-
- @staticmethod
- def _jit_rechain_frame(ec, frame):
- # this method is called after the jit has seen enter (and thus _chain)
- # of a frame, but then does not actually inline it. This method thus
- # needs to make sure that the state is as if the _chain method had been
- # executed outside of the jit. Note that this makes it important that
- # _unchain does not call we_are_jitted
- frame.f_back().f_forward = None
- ec.some_frame = frame
-
- @staticmethod
- @jit.unroll_safe
- def _extract_back_from_frame(frame):
- back_some = frame.f_back_some
- if frame.f_back_forced:
- # don't check back_some.f_forward in this case
- return back_some
- if back_some is None:
- return None
- while True:
- f_forward = back_some.f_forward
- if f_forward is frame or f_forward is None:
- return back_some
- back_some = f_forward
-
- @staticmethod
- def _force_back_of_frame(frame):
- orig_frame = frame
- while frame is not None and not frame.f_back_forced:
- frame.f_back_some = f_back = ExecutionContext._extract_back_from_frame(frame)
- frame.f_back_forced = True
- # now that we force the whole chain, we also have to set the
- # forward links to None
- frame.f_forward = None
- frame = f_back
- return orig_frame.f_back_some
-
- _we_are_jitted = staticmethod(we_are_jitted) # indirection for testing
-
- # the methods above are used for chaining frames in JIT-friendly way
- # ________________________________________________________________
class Subcontext(object):
@@ -204,7 +83,7 @@
self.is_tracing = 0
def enter(self, ec):
- ec.some_frame = self.topframe
+ ec.topframeref = jit.non_virtual_ref(self.topframe)
ec.framestackdepth = self.framestackdepth
ec.w_tracefunc = self.w_tracefunc
ec.profilefunc = self.profilefunc
@@ -247,29 +126,11 @@
while index > 0:
index -= 1
lst[index] = f
- f = f.f_back()
+ f = f.f_backref()
assert f is None
return lst
# coroutine: I think this is all, folks!
-
- def get_builtin(self):
- frame = self.gettopframe_nohidden()
- if frame is not None:
- return frame.builtin
- else:
- return self.space.builtin
-
- # XXX this one should probably be dropped in favor of a module
- def make_standard_w_globals(self):
- "Create a new empty 'globals' dictionary."
- w_key = self.space.wrap("__builtins__")
- w_value = self.space.wrap(self.get_builtin())
- w_globals = self.space.newdict()
- space.setitem(w_globals, w_key, w_value)
- return w_globals
-
- @jit.dont_look_inside
def c_call_trace(self, frame, w_func):
"Profile the call of a builtin function"
if self.profilefunc is None:
@@ -277,7 +138,6 @@
else:
self._trace(frame, 'c_call', w_func)
- @jit.dont_look_inside
def c_return_trace(self, frame, w_retval):
"Profile the return from a builtin function"
if self.profilefunc is None:
@@ -285,7 +145,6 @@
else:
self._trace(frame, 'c_return', w_retval)
- @jit.dont_look_inside
def c_exception_trace(self, frame, w_exc):
"Profile function called upon OperationError."
if self.profilefunc is None:
@@ -293,7 +152,6 @@
else:
self._trace(frame, 'c_exception', w_exc)
- @jit.dont_look_inside
def call_trace(self, frame):
"Trace the call of a function"
if self.w_tracefunc is not None or self.profilefunc is not None:
@@ -301,7 +159,6 @@
if self.profilefunc:
frame.is_being_profiled = True
- @jit.dont_look_inside
def return_trace(self, frame, w_retval):
"Trace the return from a function"
if self.w_tracefunc is not None:
@@ -320,7 +177,14 @@
actionflag.action_dispatcher(self, frame) # slow path
bytecode_trace._always_inline_ = True
- @jit.dont_look_inside
+ def bytecode_trace_after_exception(self, frame):
+ "Like bytecode_trace(), but without increasing the ticker."
+ actionflag = self.space.actionflag
+ ticker = actionflag.get()
+ if ticker & actionflag.interesting_bits: # fast check
+ actionflag.action_dispatcher(self, frame) # slow path
+ bytecode_trace_after_exception._always_inline_ = True
+
def exception_trace(self, frame, operationerr):
"Trace function called upon OperationError."
operationerr.record_interpreter_traceback()
@@ -343,6 +207,7 @@
if self.space.is_w(w_func, self.space.w_None):
self.w_tracefunc = None
else:
+ self.force_all_frames()
self.w_tracefunc = w_func
self.space.frame_trace_action.fire()
@@ -355,16 +220,28 @@
self.setllprofile(app_profile_call, w_func)
def setllprofile(self, func, w_arg):
- self.profilefunc = func
if func is not None:
if w_arg is None:
raise ValueError("Cannot call setllprofile with real None")
- frame = self.gettopframe_nohidden()
- while frame:
- frame.is_being_profiled = True
- frame = self.getnextframe_nohidden(frame)
+ self.force_all_frames(is_being_profiled=True)
+ self.profilefunc = func
self.w_profilefuncarg = w_arg
+ def force_all_frames(self, is_being_profiled=False):
+ # "Force" all frames in the sense of the jit, and optionally
+ # set the flag 'is_being_profiled' on them. A forced frame is
+ # one out of which the jit will exit: if it is running so far,
+ # in a piece of assembler currently running a CALL_MAY_FORCE,
+ # then being forced means that it will fail the following
+ # GUARD_NOT_FORCED operation, and so fall back to interpreted
+ # execution. (We get this effect simply by reading the f_back
+ # field of all frames, during the loop below.)
+ frame = self.gettopframe_nohidden()
+ while frame:
+ if is_being_profiled:
+ frame.is_being_profiled = True
+ frame = self.getnextframe_nohidden(frame)
+
def call_tracing(self, w_func, w_args):
is_tracing = self.is_tracing
self.is_tracing = 0
@@ -415,9 +292,8 @@
'c_return', 'c_exception']:
return
- last_exception = None
+ last_exception = frame.last_exception
if event == 'leaveframe':
- last_exception = frame.last_exception
event = 'return'
assert self.is_tracing == 0
@@ -573,7 +449,7 @@
def fire_after_thread_switch(self):
"""Bit of a hack: fire() the action but only the next time the GIL
- is released and re-acquired (i.e. after a portential thread switch).
+ is released and re-acquired (i.e. after a potential thread switch).
Don't call this if threads are not enabled.
"""
from pypy.module.thread.gil import spacestate
Modified: pypy/branch/stringbuilder2/pypy/interpreter/function.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/interpreter/function.py (original)
+++ pypy/branch/stringbuilder2/pypy/interpreter/function.py Mon Jan 25 15:25:48 2010
@@ -553,6 +553,7 @@
class StaticMethod(Wrappable):
"""The staticmethod objects."""
+ _immutable_ = True
def __init__(self, w_function):
self.w_function = w_function
@@ -566,6 +567,7 @@
class ClassMethod(Wrappable):
"""The classmethod objects."""
+ _immutable_ = True
def __init__(self, w_function):
self.w_function = w_function
Modified: pypy/branch/stringbuilder2/pypy/interpreter/gateway.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/interpreter/gateway.py (original)
+++ pypy/branch/stringbuilder2/pypy/interpreter/gateway.py Mon Jan 25 15:25:48 2010
@@ -386,6 +386,15 @@
else:
return typ.__name__ + '_w'
+
+def unwrap_spec(*spec):
+ """A decorator which attaches the unwrap_spec attribute."""
+ def decorator(func):
+ func.unwrap_spec = spec
+ return func
+ return decorator
+
+
class BuiltinCode(eval.Code):
"The code object implementing a built-in (interpreter-level) hook."
_immutable_ = True
@@ -1075,6 +1084,11 @@
"""
if not isinstance(source, str):
source = str(py.code.Source(source).strip())
+ while source.startswith('@py.test.mark.'):
+ # these decorators are known to return the same function
+ # object, we may ignore them
+ assert '\n' in source
+ source = source[source.find('\n') + 1:]
assert source.startswith("def "), "can only transform functions"
source = source[4:]
p = source.find('(')
Modified: pypy/branch/stringbuilder2/pypy/interpreter/generator.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/interpreter/generator.py (original)
+++ pypy/branch/stringbuilder2/pypy/interpreter/generator.py Mon Jan 25 15:25:48 2010
@@ -2,6 +2,7 @@
from pypy.interpreter.baseobjspace import Wrappable
from pypy.interpreter.gateway import NoneNotWrapped
from pypy.rlib.rarithmetic import intmask
+from pypy.rlib import jit
from pypy.interpreter.pyopcode import LoopBlock
@@ -64,7 +65,7 @@
else:
return w_result # YIELDed
finally:
- self.frame.f_back_some = None
+ self.frame.f_backref = jit.vref_None
self.running = False
def descr_throw(self, w_type, w_val=None, w_tb=None):
Modified: pypy/branch/stringbuilder2/pypy/interpreter/mixedmodule.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/interpreter/mixedmodule.py (original)
+++ pypy/branch/stringbuilder2/pypy/interpreter/mixedmodule.py Mon Jan 25 15:25:48 2010
@@ -13,7 +13,8 @@
applevel_name = None
expose__file__attribute = True
-
+ w_initialdict = None
+
def __init__(self, space, w_name):
""" NOT_RPYTHON """
Module.__init__(self, space, w_name)
@@ -21,6 +22,13 @@
self.__class__.buildloaders()
self.loaders = self.loaders.copy() # copy from the class to the inst
+ def init(self, space):
+ """This is called each time the module is imported or reloaded
+ """
+ if self.w_initialdict is not None:
+ space.call_method(self.w_dict, 'update', self.w_initialdict)
+ Module.init(self, space)
+
def get_applevel_name(cls):
""" NOT_RPYTHON """
if cls.applevel_name is not None:
@@ -82,11 +90,13 @@
for name in self.loaders:
w_value = self.get(name)
space.setitem(self.w_dict, space.new_interned_str(name), w_value)
- self.lazy = False
+ self.lazy = False
+ self.w_initialdict = space.call_method(self.w_dict, 'items')
return self.w_dict
def _freeze_(self):
self.getdict()
+ self.startup_called = False
# hint for the annotator: Modules can hold state, so they are
# not constant
return False
Modified: pypy/branch/stringbuilder2/pypy/interpreter/module.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/interpreter/module.py (original)
+++ pypy/branch/stringbuilder2/pypy/interpreter/module.py Mon Jan 25 15:25:48 2010
@@ -15,22 +15,30 @@
self.w_dict = w_dict
self.w_name = w_name
if w_name is not None:
- space.setitem(w_dict, space.new_interned_str('__name__'), w_name)
+ space.setitem(w_dict, space.new_interned_str('__name__'), w_name)
+ self.startup_called = False
def setup_after_space_initialization(self):
"""NOT_RPYTHON: to allow built-in modules to do some more setup
after the space is fully initialized."""
+ def init(self, space):
+ """This is called each time the module is imported or reloaded
+ """
+ if not self.startup_called:
+ self.startup_called = True
+ self.startup(space)
+
def startup(self, space):
- """This is called at runtime before the space gets uses to allow
- the module to do initialization at runtime.
+ """This is called at runtime on import to allow the module to
+ do initialization when it is imported for the first time.
"""
def shutdown(self, space):
"""This is called when the space is shut down, just after
- sys.exitfunc().
+ sys.exitfunc(), if the module has been imported.
"""
-
+
def getdict(self):
return self.w_dict
Modified: pypy/branch/stringbuilder2/pypy/interpreter/pycode.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/interpreter/pycode.py (original)
+++ pypy/branch/stringbuilder2/pypy/interpreter/pycode.py Mon Jan 25 15:25:48 2010
@@ -27,7 +27,7 @@
# Magic numbers for the bytecode version in code objects.
-# See comments in pypy/module/__builtin__/importing.
+# See comments in pypy/module/imp/importing.
cpython_magic, = struct.unpack("<i", imp.get_magic()) # host magic number
default_magic = (62131+2) | 0x0a0d0000 # this PyPy's magic
# (62131=CPython 2.5.1)
@@ -117,9 +117,6 @@
self._compute_flatcall()
- if self.space.config.objspace.std.withcelldict:
- from pypy.objspace.std.celldict import init_code
- init_code(self)
def _init_flags(self):
co_code = self.co_code
Modified: pypy/branch/stringbuilder2/pypy/interpreter/pyframe.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/interpreter/pyframe.py (original)
+++ pypy/branch/stringbuilder2/pypy/interpreter/pyframe.py Mon Jan 25 15:25:48 2010
@@ -9,7 +9,7 @@
from pypy.interpreter import pytraceback
import opcode
from pypy.rlib.objectmodel import we_are_translated, instantiate
-from pypy.rlib.jit import we_are_jitted, hint
+from pypy.rlib.jit import hint
from pypy.rlib.debug import make_sure_not_resized
from pypy.rlib import jit
@@ -34,13 +34,13 @@
* 'builtin' is the attached built-in module
* 'valuestack_w', 'blockstack', control the interpretation
"""
-
__metaclass__ = extendabletype
frame_finished_execution = False
last_instr = -1
last_exception = None
+ f_backref = jit.vref_None
w_f_trace = None
# For tracing
instr_lb = 0
@@ -64,7 +64,6 @@
self.fastlocals_w = [None]*self.numlocals
make_sure_not_resized(self.fastlocals_w)
self.f_lineno = code.co_firstlineno
- ExecutionContext._init_chaining_attributes(self)
def append_block(self, block):
block.previous = self.lastblock
@@ -142,8 +141,7 @@
executioncontext = self.space.getexecutioncontext()
executioncontext.enter(self)
try:
- if not we_are_jitted():
- executioncontext.call_trace(self)
+ executioncontext.call_trace(self)
# Execution starts just after the last_instr. Initially,
# last_instr is -1. After a generator suspends it points to
# the YIELD_VALUE instruction.
@@ -154,11 +152,12 @@
rstack.resume_point("execute_frame", self, executioncontext,
returns=w_exitvalue)
except Exception:
- if not we_are_jitted():
- executioncontext.return_trace(self, self.space.w_None)
+ executioncontext.return_trace(self, self.space.w_None)
raise
- if not we_are_jitted():
- executioncontext.return_trace(self, w_exitvalue)
+ executioncontext.return_trace(self, w_exitvalue)
+ # clean up the exception, might be useful for not
+ # allocating exception objects in some cases
+ self.last_exception = None
finally:
executioncontext.leave(self)
return w_exitvalue
@@ -308,7 +307,7 @@
w_tb = w(self.last_exception.application_traceback)
tup_state = [
- w(self.f_back()),
+ w(self.f_backref()),
w(self.get_builtin()),
w(self.pycode),
w_valuestack,
@@ -360,8 +359,8 @@
# do not use the instance's __init__ but the base's, because we set
# everything like cells from here
PyFrame.__init__(self, space, pycode, w_globals, closure)
- new_frame.f_back_some = space.interp_w(PyFrame, w_f_back, can_be_None=True)
- new_frame.f_back_forced = True
+ f_back = space.interp_w(PyFrame, w_f_back, can_be_None=True)
+ new_frame.f_backref = jit.non_virtual_ref(f_back)
new_frame.builtin = space.interp_w(Module, w_builtin)
new_frame.set_blocklist([unpickle_block(space, w_blk)
@@ -392,6 +391,7 @@
new_frame.instr_prev = space.int_w(w_instr_prev)
self._setcellvars(cellvars)
+ # XXX what if the frame is in another thread??
space.frame_trace_action.fire()
def hide(self):
@@ -431,12 +431,6 @@
def _setcellvars(self, cellvars):
pass
- def f_back(self):
- return ExecutionContext._extract_back_from_frame(self)
-
- def force_f_back(self):
- return ExecutionContext._force_back_of_frame(self)
-
### line numbers ###
# for f*_f_* unwrapping through unwrap_spec in typedef.py
@@ -584,7 +578,7 @@
return self.get_builtin().getdict()
def fget_f_back(space, self):
- return self.space.wrap(self.f_back())
+ return self.space.wrap(self.f_backref())
def fget_f_lasti(space, self):
return self.space.wrap(self.last_instr)
@@ -605,27 +599,27 @@
def fget_f_exc_type(space, self):
if self.last_exception is not None:
- f = self.f_back()
+ f = self.f_backref()
while f is not None and f.last_exception is None:
- f = f.f_back()
+ f = f.f_backref()
if f is not None:
return f.last_exception.w_type
return space.w_None
def fget_f_exc_value(space, self):
if self.last_exception is not None:
- f = self.f_back()
+ f = self.f_backref()
while f is not None and f.last_exception is None:
- f = f.f_back()
+ f = f.f_backref()
if f is not None:
return f.last_exception.w_value
return space.w_None
def fget_f_exc_traceback(space, self):
if self.last_exception is not None:
- f = self.f_back()
+ f = self.f_backref()
while f is not None and f.last_exception is None:
- f = f.f_back()
+ f = f.f_backref()
if f is not None:
return space.wrap(f.last_exception.application_traceback)
return space.w_None
Modified: pypy/branch/stringbuilder2/pypy/interpreter/pyopcode.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/interpreter/pyopcode.py (original)
+++ pypy/branch/stringbuilder2/pypy/interpreter/pyopcode.py Mon Jan 25 15:25:48 2010
@@ -130,7 +130,7 @@
def handle_operation_error(self, ec, operr, attach_tb=True):
if attach_tb:
- if not jit.we_are_jitted():
+ if 1:
# xxx this is a hack. It allows bytecode_trace() to
# call a signal handler which raises, and catch the
# raised exception immediately. See test_alarm_raise in
@@ -146,15 +146,14 @@
trace = self.w_f_trace
self.w_f_trace = None
try:
- ec.bytecode_trace(self)
+ ec.bytecode_trace_after_exception(self)
finally:
self.w_f_trace = trace
except OperationError, e:
operr = e
pytraceback.record_application_traceback(
self.space, operr, self, self.last_instr)
- if not jit.we_are_jitted():
- ec.exception_trace(self, operr)
+ ec.exception_trace(self, operr)
block = self.unrollstack(SApplicationException.kind)
if block is None:
@@ -913,13 +912,10 @@
arguments = f.popvalues(n_arguments)
args = f.argument_factory(arguments, keywords, keywords_w, w_star, w_starstar)
w_function = f.popvalue()
- if jit.we_are_jitted():
- w_result = f.space.call_args(w_function, args)
+ if f.is_being_profiled and is_builtin_code(w_function):
+ w_result = f.space.call_args_and_c_profile(f, w_function, args)
else:
- if f.is_being_profiled and is_builtin_code(w_function):
- w_result = f.space.call_args_and_c_profile(f, w_function, args)
- else:
- w_result = f.space.call_args(w_function, args)
+ w_result = f.space.call_args(w_function, args)
rstack.resume_point("call_function", f, returns=w_result)
f.pushvalue(w_result)
Modified: pypy/branch/stringbuilder2/pypy/interpreter/pytraceback.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/interpreter/pytraceback.py (original)
+++ pypy/branch/stringbuilder2/pypy/interpreter/pytraceback.py Mon Jan 25 15:25:48 2010
@@ -49,7 +49,6 @@
self.next = space.interp_w(PyTraceback, w_next, can_be_None=True)
def record_application_traceback(space, operror, frame, last_instruction):
- frame.force_f_back()
if frame.pycode.hidden_applevel:
return
tb = operror.application_traceback
Modified: pypy/branch/stringbuilder2/pypy/interpreter/test/test_executioncontext.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/interpreter/test/test_executioncontext.py (original)
+++ pypy/branch/stringbuilder2/pypy/interpreter/test/test_executioncontext.py Mon Jan 25 15:25:48 2010
@@ -1,6 +1,5 @@
import py
from pypy.interpreter import executioncontext
-from pypy.interpreter.executioncontext import ExecutionContext
from pypy.conftest import gettestobjspace
class Finished(Exception):
@@ -221,541 +220,25 @@
events = space.unwrap(w_events)
assert [i[0] for i in events] == ['c_call', 'c_return', 'c_call']
-
-
-class TestFrameChaining(object):
- class EC(ExecutionContext):
- _some_frame = None
- def __init__(self, jitted=False):
- self.jitted = jitted
- self.virtualizable = None
- self.framestackdepth = 0
- self._init_frame_chain()
-
- def _we_are_jitted(self):
- return self.jitted
-
- def _get_some_frame(self):
- if self._some_frame:
- self._some_frame.look_at()
- return self._some_frame
- def _set_some_frame(self, frame):
- if frame is not None:
- frame.force()
- self._some_frame = frame
- some_frame = property(_get_some_frame, _set_some_frame)
-
- class Frame(object):
- _f_back_some = None
- _f_forward = None
-
- def __init__(self, ec, virtual_with_base_frame=None):
- self.ec = ec
- self.virtual_with_base_frame = virtual_with_base_frame
- self.escaped = not virtual_with_base_frame
- ExecutionContext._init_chaining_attributes(self)
-
- def f_back(self):
- return ExecutionContext._extract_back_from_frame(self)
-
- def force_f_back(self):
- return ExecutionContext._force_back_of_frame(self)
-
- def force(self):
- if not self.escaped:
- self.virtual_with_base_frame = None
- self.escaped = True
- if self._f_back_some:
- self._f_back_some.force()
- if self._f_forward:
- self._f_back_some.force()
-
- def look_at(self):
- if (not self.ec.jitted or
- self.ec.virtualizable is not self.virtual_with_base_frame):
- self.force()
-
- def store_ref_to(self, other):
- if (other.virtual_with_base_frame is not self and
- other.virtual_with_base_frame is not self.virtual_with_base_frame):
- other.force()
-
- def _get_f_back_some(self):
- self.look_at()
- return self._f_back_some
- def _set_f_back_some(self, frame):
- self.look_at()
- if frame:
- frame.look_at()
- self.store_ref_to(frame)
- self._f_back_some = frame
- f_back_some = property(_get_f_back_some, _set_f_back_some)
-
- def _get_f_forward(self):
- self.look_at()
- return self._f_forward
- def _set_f_forward(self, frame):
- self.look_at()
- if frame:
- frame.look_at()
- self.store_ref_to(frame)
- self._f_forward = frame
- f_forward = property(_get_f_forward, _set_f_forward)
-
- def test_f_back_no_jit(self):
- ec = self.EC()
- frame = self.Frame(ec)
- frame2 = self.Frame(ec)
- frame2.f_back_some = frame
-
- frame3 = self.Frame(ec)
- frame3.f_back_some = frame2
-
- assert frame3.f_back() is frame2
- assert frame2.f_back() is frame
- assert frame.f_back() is None
-
- def test_f_back_jit(self):
- ec = self.EC()
- frame = self.Frame(ec) # real frame
- frame2 = self.Frame(ec) # virtual frame
- frame2.f_back_some = frame
- frame.f_forward = frame2
-
- frame3 = self.Frame(ec) # virtual frame
- frame3.f_back_some = frame
- frame2.f_forward = frame3
-
- assert frame3.f_back() is frame2
- assert frame2.f_back() is frame
- assert frame.f_back() is None
-
- frame4 = self.Frame(ec) # real frame again
- frame4.f_back_some = frame
- assert frame4.f_back() is frame3
-
- def test_gettopframe_no_jit(self):
- ec = self.EC()
- frame = self.Frame(ec)
- ec.some_frame = frame
- assert ec.gettopframe() is frame
-
- def test_gettopframe_jit(self):
- ec = self.EC()
- frame = self.Frame(ec) # real frame
- ec.some_frame = frame
- assert ec.gettopframe() is frame
-
- frame2 = self.Frame(ec) # virtual frame
- frame2.f_back_some = frame
- frame.f_forward = frame2
- assert ec.gettopframe() is frame2
-
- frame3 = self.Frame(ec) # virtual frame
- frame3.f_back_some = frame
- frame2.f_forward = frame3
- assert ec.gettopframe() is frame3
-
- frame4 = self.Frame(ec) # real frame again
- frame4.f_back_some = frame
- ec.some_frame = frame4
- assert ec.gettopframe() is frame4
-
- def test_frame_chain(self):
-
- ec = self.EC()
-
- assert ec.some_frame is None
- assert ec.framestackdepth == 0
-
- frame = self.Frame(ec)
- ec._chain(frame)
- assert ec.some_frame is frame
- assert ec.framestackdepth == 1
- assert frame.f_back_some is None
- assert frame.f_forward is None
- assert ec.gettopframe() is frame
- assert ec._extract_back_from_frame(frame) is None
-
- frame2 = self.Frame(ec)
- ec._chain(frame2)
- assert ec.some_frame is frame2
- assert ec.framestackdepth == 2
- assert frame2.f_back_some is frame
- assert frame.f_forward is None
- assert frame2.f_forward is None
- assert ec.gettopframe() is frame2
- assert ec._extract_back_from_frame(frame2) is frame
- assert ec._extract_back_from_frame(frame) is None
-
- frame3 = self.Frame(ec)
- ec._chain(frame3)
- assert ec.some_frame is frame3
- assert frame3.f_back_some is frame2
- assert frame2.f_forward is None
- assert ec.gettopframe() is frame3
- assert ec._extract_back_from_frame(frame3) is frame2
- assert ec._extract_back_from_frame(frame2) is frame
- assert ec._extract_back_from_frame(frame) is None
-
- assert frame3.f_back() is frame2
- ec._unchain(frame3)
- assert ec.some_frame is frame2
- assert ec.framestackdepth == 2
- assert frame2.f_forward is None
- assert frame3.f_back_some is frame2
- assert ec.gettopframe() is frame2
- assert ec._extract_back_from_frame(frame2) is frame
- assert ec._extract_back_from_frame(frame) is None
-
- assert frame2.f_back() is frame
- ec._unchain(frame2)
- assert ec.some_frame is frame
- assert ec.framestackdepth == 1
- assert frame.f_forward is None
- assert frame2.f_back_some is frame
- assert ec.gettopframe() is frame
- assert ec._extract_back_from_frame(frame) is None
-
- assert frame.f_back() is None
- ec._unchain(frame)
- assert ec.some_frame is None
- assert ec.framestackdepth == 0
- assert frame.f_back_some is None
- assert ec.gettopframe() is None
-
- def test_frame_chain_forced(self):
-
- ec = self.EC()
-
- frame = self.Frame(ec)
- ec._chain(frame)
- assert ec.gettopframe() is frame
- assert ec._extract_back_from_frame(frame) is None
-
- frame2 = self.Frame(ec)
- ec._chain(frame2)
- assert ec.some_frame is frame2
- assert ec.framestackdepth == 2
- assert frame2.f_back_some is frame
- assert frame.f_forward is None
- assert frame2.f_forward is None
- res = frame2.force_f_back()
- assert res is frame
- assert frame.f_back_forced
- assert ec.gettopframe() is frame2
- assert ec._extract_back_from_frame(frame2) is frame
- assert ec._extract_back_from_frame(frame) is None
-
- frame3 = self.Frame(ec)
- ec._chain(frame3)
- assert ec.gettopframe() is frame3
- assert ec._extract_back_from_frame(frame3) is frame2
- assert ec._extract_back_from_frame(frame2) is frame
- assert ec._extract_back_from_frame(frame) is None
-
- assert frame3.f_back() is frame2
- ec._unchain(frame3)
- assert ec.some_frame is frame2
- assert frame3.f_back_some is frame2
- assert ec.gettopframe() is frame2
- assert ec._extract_back_from_frame(frame2) is frame
- assert ec._extract_back_from_frame(frame) is None
-
- assert frame2.f_back() is frame
- ec._unchain(frame2)
- assert frame2.f_back_some is frame
- assert ec.gettopframe() is frame
- assert ec._extract_back_from_frame(frame) is None
-
- assert frame.f_back() is None
- ec._unchain(frame)
- assert ec.some_frame is None
- assert frame.f_back_some is None
-
- assert frame2.f_back() is frame
- assert frame.f_back() is None
- assert ec.gettopframe() is None
-
-
- def test_frame_chain_jitted(self):
-
- ec = self.EC()
-
- assert ec.some_frame is None
- assert ec.framestackdepth == 0
- assert ec.gettopframe() is None
-
- frame = self.Frame(ec)
- ec._chain(frame)
- assert ec.some_frame is frame
- assert ec.framestackdepth == 1
- assert frame.f_back_some is None
- assert frame.f_forward is None
- assert ec.gettopframe() is frame
- assert ec._extract_back_from_frame(frame) is None
-
- ec.jitted = True
- ec.virtualizable = frame
- frame2 = self.Frame(ec, frame)
- ec._chain(frame2)
- assert ec.some_frame is frame
- assert ec.framestackdepth == 2
- assert frame2.f_back_some is frame
- assert frame.f_forward is frame2
- assert frame2.f_forward is None
- assert ec.gettopframe() is frame2
- assert ec._extract_back_from_frame(frame2) is frame
- assert ec._extract_back_from_frame(frame) is None
-
- # recursive enter/leave seen by the jit
- frame3 = self.Frame(ec, frame)
- ec._chain(frame3)
- assert ec.some_frame is frame
- assert frame3.f_back_some is frame
- assert frame2.f_forward is frame3
- assert ec.gettopframe() is frame3
- assert ec._extract_back_from_frame(frame3) is frame2
- assert ec._extract_back_from_frame(frame2) is frame
- assert ec._extract_back_from_frame(frame) is None
-
- assert frame3.f_back() is frame2
- ec._unchain(frame3)
- assert ec.some_frame is frame
- assert ec.framestackdepth == 2
- assert frame2.f_forward is None
- assert frame3.f_back_some is frame
- assert not frame3.escaped
- assert not frame2.escaped
- assert ec.gettopframe() is frame2
- assert ec._extract_back_from_frame(frame2) is frame
- assert ec._extract_back_from_frame(frame) is None
-
- # recursive enter/leave not seen by the jit
- ec.jitted = False
- ec.virtualizable = None
- ec._chain(frame3)
- assert not frame2.escaped
- assert ec.some_frame is frame3
- assert frame3.f_back_some is frame
- assert frame2.f_forward is None
- assert frame3.escaped
- assert ec.gettopframe() is frame3
- assert ec._extract_back_from_frame(frame3) is frame2
- assert ec._extract_back_from_frame(frame2) is frame
- assert ec._extract_back_from_frame(frame) is None
-
- assert frame3.f_back() is frame2
- ec._unchain(frame3)
- assert ec.some_frame is frame
- assert ec.framestackdepth == 2
- assert frame2.f_forward is None
- assert frame3.f_back_some is frame
- assert ec.gettopframe() is frame2
- assert ec._extract_back_from_frame(frame2) is frame
- assert ec._extract_back_from_frame(frame) is None
-
- ec.jitted = True
- ec.virtualizable = frame
-
- assert frame2.f_back() is frame
- ec._unchain(frame2)
- assert ec.some_frame is frame
- assert ec.framestackdepth == 1
- assert frame.f_forward is None
- assert frame2.f_back_some is frame
- assert ec.gettopframe() is frame
- assert ec._extract_back_from_frame(frame) is None
-
- ec.jitted = False
- assert frame.f_back() is None
- ec._unchain(frame)
- assert ec.some_frame is None
- assert ec.framestackdepth == 0
- assert frame.f_back_some is None
- assert ec.gettopframe() is None
-
- @py.test.mark.xfail
- def test_frame_chain_jitted_forced(self):
-
- ec = self.EC()
-
- assert ec.some_frame is None
- assert ec.framestackdepth == 0
-
- frame = self.Frame(ec)
- ec._chain(frame)
+ def test_profile_and_exception(self):
+ space = self.space
+ w_res = space.appexec([], """():
+ l = []
- ec.jitted = True
- frame2 = self.Frame(ec)
- ec._chain(frame2)
-
- # recursive enter/leave seen by the jit
- frame3 = self.Frame(ec)
- ec._chain(frame3)
- assert ec.gettopframe() is frame3
- res = frame3.force_f_back()
- assert res is frame2
- assert ec.gettopframe() is frame3
-
- assert frame3.f_back() is frame2
- ec._unchain(frame3)
-
- assert frame2.f_back() is frame
- ec._unchain(frame2)
- ec.jitted = False
- assert frame.f_back() is None
- ec._unchain(frame)
-
- assert frame3.f_back() is frame2
- assert frame2.f_back() is frame
- assert frame.f_back() is None
+ def profile(*args):
+ l.append(sys.exc_info()[0])
- def enter_two_jitted_levels(self):
- ec = self.EC()
-
- assert ec.some_frame is None
- assert ec.framestackdepth == 0
+ import sys
+ try:
+ sys.setprofile(profile)
+ try:
+ x
+ except:
+ expected = sys.exc_info()[0]
+ assert expected is NameError
+ for i in l:
+ assert expected is l[0]
+ finally:
+ sys.setprofile(None)
+ """)
- frame = self.Frame(ec)
- ec._chain(frame)
-
- ec.jitted = True
- ec.virtualizable = frame
- frame2 = self.Frame(ec, frame)
- ec._chain(frame2)
- assert not frame2.escaped
- return ec, frame, frame2
-
- def leave_two_jitted_levels(self, ec, frame, frame2):
- assert frame2.f_back() is frame
- ec._unchain(frame2)
- ec.jitted = False
- assert frame.f_back() is None
- ec._unchain(frame)
-
-
- def test_check_escaping_all_inlined(self):
- ec, frame, frame2 = self.enter_two_jitted_levels()
-
- # recursive enter/leave seen by the jit
- frame3 = self.Frame(ec, frame)
- ec._chain(frame3)
- assert not frame2.escaped
- assert not frame3.escaped
-
- assert frame3.f_back() is frame2
- ec._unchain(frame3)
- assert not frame2.escaped
- self.leave_two_jitted_levels(ec, frame, frame2)
-
-
- def test_check_escaping_not_all_inlined_enter_leave_not_seen(self):
- ec, frame, frame2 = self.enter_two_jitted_levels()
-
- ec.jitted = False
- # recursive enter/leave not seen by the jit
- frame3 = self.Frame(ec)
- ec._chain(frame3)
-
- assert not frame2.escaped
- assert frame3.escaped
-
- ec._unchain(frame3)
- ec.jitted = True
- assert not frame2.escaped
-
- self.leave_two_jitted_levels(ec, frame, frame2)
-
- def test_check_escaping_not_all_inlined_enter_leave_seen(self):
- ec, frame, frame2 = self.enter_two_jitted_levels()
-
- # recursive enter/leave seen by the jit
- frame3 = self.Frame(ec, frame)
- ec._chain(frame3)
- ExecutionContext._jit_rechain_frame(ec, frame3)
- ec.jitted = False
- frame3.look_at()
- assert not frame2.escaped
- assert frame3.escaped
-
- ec.jitted = True
- assert frame3.f_back() is frame2
- ec._unchain(frame3)
- assert not frame2.escaped
-
- self.leave_two_jitted_levels(ec, frame, frame2)
-
-
- def test_check_escaping_multi_non_jitted_levels(self):
- ec, frame, frame2 = self.enter_two_jitted_levels()
-
- # recursive enter/leave seen by the jit
- frame3 = self.Frame(ec, frame)
- ec._chain(frame3)
- ExecutionContext._jit_rechain_frame(ec, frame3)
- ec.jitted = False
-
- assert frame3.escaped
- assert not frame2.escaped
- assert frame3.escaped
-
- frame4 = self.Frame(ec)
- ec._chain(frame4)
- assert ec.framestackdepth == 4
-
- ec._unchain(frame4)
- assert frame3.escaped
- assert not frame2.escaped
-
- ec.jitted = True
- assert frame3.f_back() is frame2
- ec._unchain(frame3)
- assert not frame2.escaped
-
- self.leave_two_jitted_levels(ec, frame, frame2)
-
- def test_check_escaping_jitted_with_two_different_virtualizables(self):
- ec, frame, frame2 = self.enter_two_jitted_levels()
-
- frame3 = self.Frame(ec, frame)
- ec._chain(frame3)
- # frame3 is not inlined, but contains a loop itself, for which code has
- # been generated
- ExecutionContext._jit_rechain_frame(ec, frame3)
- ec.virtualizable = frame3
-
- frame3.look_at()
- assert not frame2.escaped
- assert frame3.escaped
-
- frame4 = self.Frame(ec, frame3)
- ec._chain(frame4)
- assert ec.framestackdepth == 4
- assert not frame4.escaped
-
- ec._unchain(frame4)
- assert frame3.escaped
- assert not frame2.escaped
-
- ec.virtualizable = frame
-
- ec._unchain(frame3)
- assert not frame2.escaped
-
- def test_frame_top_is_virtualizable(self):
- ec, frame, frame2 = self.enter_two_jitted_levels()
- frame3 = self.Frame(ec, frame2)
- ec.jitted = False
- ec._chain(frame3)
- ec.gettopframe()
- frame3.force_f_back()
- ec._unchain(frame3)
- assert not frame2.f_forward
- assert ec.gettopframe() is frame2
- ec.jitted = True
- ec._unchain(frame2)
- assert not frame.f_forward
- assert ec.gettopframe() is frame
- ec._unchain(frame)
- assert ec.gettopframe() is None
Modified: pypy/branch/stringbuilder2/pypy/interpreter/test/test_gateway.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/interpreter/test/test_gateway.py (original)
+++ pypy/branch/stringbuilder2/pypy/interpreter/test/test_gateway.py Mon Jan 25 15:25:48 2010
@@ -520,6 +520,16 @@
w_res = space.call_obj_args(w_g, w_self, args3)
assert space.is_true(space.eq(w_res, space.wrap(('g', 'self', 3))))
+ def test_unwrap_spec_decorator(self):
+ space = self.space
+ @gateway.unwrap_spec(gateway.ObjSpace, gateway.W_Root, int)
+ def g(space, w_thing, i):
+ return space.newtuple([w_thing, space.wrap(i)])
+ w_g = space.wrap(gateway.interp2app_temp(g))
+ args = argument.Arguments(space, [space.wrap(-1), space.wrap(0)])
+ w_res = space.call_args(w_g, args)
+ assert space.eq_w(w_res, space.wrap((-1, 0)))
+
class TestPassThroughArguments:
Modified: pypy/branch/stringbuilder2/pypy/interpreter/test/test_module.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/interpreter/test/test_module.py (original)
+++ pypy/branch/stringbuilder2/pypy/interpreter/test/test_module.py Mon Jan 25 15:25:48 2010
@@ -58,7 +58,7 @@
r = repr(_pypy_interact)
assert (r.startswith("<module '_pypy_interact' from ") and
('pypy/lib/_pypy_interact.py' in r or
- 'pypy\\lib\\_pypy_interact.py' in r.lower()) and
+ r'pypy\\lib\\_pypy_interact.py' in r.lower()) and
r.endswith('>'))
nofile = type(_pypy_interact)('nofile', 'foo')
assert repr(nofile) == "<module 'nofile' from ?>"
Modified: pypy/branch/stringbuilder2/pypy/interpreter/test/test_zzpickle_and_slow.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/interpreter/test/test_zzpickle_and_slow.py (original)
+++ pypy/branch/stringbuilder2/pypy/interpreter/test/test_zzpickle_and_slow.py Mon Jan 25 15:25:48 2010
@@ -2,6 +2,7 @@
from pypy import conftest
from pypy.conftest import gettestobjspace
from pypy.interpreter import gateway
+from pypy.rlib.jit import non_virtual_ref, vref_None
class AppTestSlow:
def setup_class(cls):
@@ -30,21 +31,18 @@
from pypy.interpreter import pytraceback
def hide_top_frame(space, w_frame):
w_last = None
- while w_frame.f_back():
- # should have been forced by traceback capturing
- assert w_frame.f_back_forced
+ while w_frame.f_backref():
w_last = w_frame
- w_frame = w_frame.f_back()
+ w_frame = w_frame.f_backref()
assert w_last
- w_saved = w_last.f_back()
- w_last.f_back_some = None
+ w_saved = w_last.f_backref()
+ w_last.f_backref = vref_None
return w_saved
def restore_top_frame(space, w_frame, w_saved):
- while w_frame.f_back():
- assert w_frame.f_back_forced
- w_frame = w_frame.f_back()
- w_frame.f_back_some = w_saved
+ while w_frame.f_backref():
+ w_frame = w_frame.f_backref()
+ w_frame.f_backref = non_virtual_ref(w_saved)
def read_exc_type(space, w_frame):
if w_frame.last_exception is None:
Modified: pypy/branch/stringbuilder2/pypy/jit/backend/llgraph/llimpl.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/jit/backend/llgraph/llimpl.py (original)
+++ pypy/branch/stringbuilder2/pypy/jit/backend/llgraph/llimpl.py Mon Jan 25 15:25:48 2010
@@ -125,6 +125,7 @@
'getarrayitem_gc_pure' : (('ref', 'int'), 'intorptr'),
'arraylen_gc' : (('ref',), 'int'),
'call' : (('ref', 'varargs'), 'intorptr'),
+ 'call_assembler' : (('ref', 'varargs'), 'intorptr'),
'call_pure' : (('ref', 'varargs'), 'intorptr'),
'cond_call_gc_wb' : (('int', 'int', 'ptr', 'varargs'), None),
'oosend' : (('varargs',), 'intorptr'),
@@ -152,7 +153,9 @@
'debug_merge_point': (('ref',), None),
'force_token' : ((), 'int'),
'call_may_force' : (('int', 'varargs'), 'intorptr'),
- 'guard_not_forced': ((), None)
+ 'guard_not_forced': ((), None),
+ 'virtual_ref' : (('ref', 'int'), 'ref'),
+ 'virtual_ref_finish': (('ref', 'ref'), None),
#'getitem' : (('void', 'ref', 'int'), 'int'),
#'setitem' : (('void', 'ref', 'int', 'int'), None),
#'newlist' : (('void', 'varargs'), 'ref'),
@@ -314,6 +317,11 @@
assert isinstance(type, str) and len(type) == 1
op.descr = Descr(ofs, type)
+def compile_add_loop_token(loop, descr):
+ loop = _from_opaque(loop)
+ op = loop.operations[-1]
+ op.descr = descr
+
def compile_add_var(loop, intvar):
loop = _from_opaque(loop)
op = loop.operations[-1]
@@ -389,8 +397,9 @@
class Frame(object):
OPHANDLERS = [None] * (rop._LAST+1)
- def __init__(self, memocast):
+ def __init__(self, memocast, cpu):
self.verbose = False
+ self.cpu = cpu
self.memocast = memocast
self.opindex = 1
self._forced = False
@@ -807,12 +816,53 @@
finally:
self._may_force = -1
+ def op_call_assembler(self, loop_token, *args):
+ global _last_exception
+ assert not self._forced
+ self._may_force = self.opindex
+ try:
+ inpargs = _from_opaque(loop_token._llgraph_compiled_version).inputargs
+ for i, inparg in enumerate(inpargs):
+ TYPE = inparg.concretetype
+ if TYPE is lltype.Signed:
+ set_future_value_int(i, args[i])
+ elif isinstance(TYPE, lltype.Ptr):
+ set_future_value_ref(i, args[i])
+ elif TYPE is lltype.Float:
+ set_future_value_float(i, args[i])
+ else:
+ raise Exception("Nonsense type %s" % TYPE)
+
+ failindex = self.cpu._execute_token(loop_token)
+ try:
+ if self.cpu.index_of_virtualizable != -1:
+ return self.cpu.assembler_helper_ptr(failindex,
+ args[self.cpu.index_of_virtualizable])
+ else:
+ return self.cpu.assembler_helper_ptr(failindex,
+ lltype.nullptr(llmemory.GCREF.TO))
+ except LLException, lle:
+ assert _last_exception is None, "exception left behind"
+ _last_exception = lle
+ # fish op
+ op = self.loop.operations[self.opindex]
+ if op.result is not None:
+ return 0
+ finally:
+ self._may_force = -1
+
def op_guard_not_forced(self, descr):
forced = self._forced
self._forced = False
if forced:
raise GuardFailed
+ def op_virtual_ref(self, _, virtual, index):
+ return virtual
+
+ def op_virtual_ref_finish(self, _, vref, virtual):
+ pass
+
class OOFrame(Frame):
@@ -961,11 +1011,11 @@
return x
-def new_frame(memocast, is_oo):
+def new_frame(memocast, is_oo, cpu):
if is_oo:
- frame = OOFrame(memocast)
+ frame = OOFrame(memocast, cpu)
else:
- frame = Frame(memocast)
+ frame = Frame(memocast, cpu)
return _to_opaque(frame)
_future_values = []
@@ -1059,7 +1109,7 @@
else:
# for tests, a random emulated ll_inst will do
if Class not in _pseudo_exceptions:
- ll_inst = lltype.malloc(rclass.OBJECT)
+ ll_inst = lltype.malloc(rclass.OBJECT, zero=True)
ll_inst.typeptr = lltype.malloc(rclass.OBJECT_VTABLE,
immortal=True)
_pseudo_exceptions[Class] = LLException(ll_inst.typeptr, ll_inst)
@@ -1086,7 +1136,8 @@
assert frame._may_force >= 0
call_op = frame.loop.operations[frame._may_force]
guard_op = frame.loop.operations[frame._may_force+1]
- assert call_op.opnum == rop.CALL_MAY_FORCE
+ opnum = call_op.opnum
+ assert opnum == rop.CALL_MAY_FORCE or opnum == rop.CALL_ASSEMBLER
frame._populate_fail_args(guard_op, skip=call_op.result)
return frame.fail_index
@@ -1201,7 +1252,7 @@
def do_new(size):
TYPE = symbolic.Size2Type[size]
- x = lltype.malloc(TYPE)
+ x = lltype.malloc(TYPE, zero=True)
return cast_to_ptr(x)
def do_new_array(arraynum, count):
Modified: pypy/branch/stringbuilder2/pypy/jit/backend/llgraph/runner.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/jit/backend/llgraph/runner.py (original)
+++ pypy/branch/stringbuilder2/pypy/jit/backend/llgraph/runner.py Mon Jan 25 15:25:48 2010
@@ -74,7 +74,8 @@
class BaseCPU(model.AbstractCPU):
supports_floats = True
- def __init__(self, rtyper, stats=None, opts=None, translate_support_code=False,
+ def __init__(self, rtyper, stats=None, opts=None,
+ translate_support_code=False,
annmixlevel=None, gcdescr=None):
assert type(opts) is not bool
model.AbstractCPU.__init__(self)
@@ -147,6 +148,8 @@
descr = op.descr
if isinstance(descr, Descr):
llimpl.compile_add_descr(c, descr.ofs, descr.typeinfo)
+ if isinstance(descr, history.LoopToken):
+ llimpl.compile_add_loop_token(c, descr)
if self.is_oo and isinstance(descr, (OODescr, MethDescr)):
# hack hack, not rpython
c._obj.externalobj.operations[-1].descr = descr
@@ -207,18 +210,22 @@
else:
assert False, "unknown operation"
- def execute_token(self, loop_token):
- """Calls the assembler generated for the given loop.
- Returns the ResOperation that failed, of type rop.FAIL.
- """
+ def _execute_token(self, loop_token):
compiled_version = loop_token._llgraph_compiled_version
- frame = llimpl.new_frame(self.memo_cast, self.is_oo)
+ frame = llimpl.new_frame(self.memo_cast, self.is_oo, self)
# setup the frame
llimpl.frame_clear(frame, compiled_version)
# run the loop
fail_index = llimpl.frame_execute(frame)
# we hit a FAIL operation.
self.latest_frame = frame
+ return fail_index
+
+ def execute_token(self, loop_token):
+ """Calls the assembler generated for the given loop.
+ Returns the ResOperation that failed, of type rop.FAIL.
+ """
+ fail_index = self._execute_token(loop_token)
return self.get_fail_descr_from_number(fail_index)
def set_future_value_int(self, index, intvalue):
Modified: pypy/branch/stringbuilder2/pypy/jit/backend/llgraph/test/test_llgraph.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/jit/backend/llgraph/test/test_llgraph.py (original)
+++ pypy/branch/stringbuilder2/pypy/jit/backend/llgraph/test/test_llgraph.py Mon Jan 25 15:25:48 2010
@@ -7,7 +7,8 @@
TreeLoop
from pypy.jit.metainterp.resoperation import ResOperation, rop
from pypy.jit.metainterp.executor import execute
-from pypy.jit.backend.test.runner_test import LLtypeBackendTest
+from pypy.jit.backend.test.runner_test import LLtypeBackendTest, \
+ BaseAssemblerCallTests
class TestLLTypeLLGraph(LLtypeBackendTest):
# for individual tests see:
Modified: pypy/branch/stringbuilder2/pypy/jit/backend/llsupport/gc.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/jit/backend/llsupport/gc.py (original)
+++ pypy/branch/stringbuilder2/pypy/jit/backend/llsupport/gc.py Mon Jan 25 15:25:48 2010
@@ -41,7 +41,7 @@
GcLLDescription.__init__(self, gcdescr, translator)
# grab a pointer to the Boehm 'malloc' function
from pypy.rpython.tool import rffi_platform
- compilation_info = rffi_platform.check_boehm()
+ compilation_info = rffi_platform.configure_boehm()
# Versions 6.x of libgc needs to use GC_local_malloc().
# Versions 7.x of libgc removed this function; GC_malloc() has
Modified: pypy/branch/stringbuilder2/pypy/jit/backend/model.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/jit/backend/model.py (original)
+++ pypy/branch/stringbuilder2/pypy/jit/backend/model.py Mon Jan 25 15:25:48 2010
@@ -1,8 +1,12 @@
-from pypy.jit.metainterp import history
+from pypy.jit.metainterp import history, compile
class AbstractCPU(object):
supports_floats = False
+ # assembler_helper_ptr - a pointer to helper to call after a direct
+ # assembler call
+ portal_calldescr = None
+ done_with_this_frame_int_v = -1
def __init__(self):
self.fail_descr_list = []
@@ -209,6 +213,12 @@
def do_call(self, args, calldescr):
raise NotImplementedError
+ def do_call_assembler(self, args, token):
+ raise NotImplementedError
+
+ def do_call_loopinvariant(self, args, calldescr):
+ return self.do_call(args, calldescr)
+
def do_cond_call_gc_wb(self, args, calldescr):
if args[0].getint() & args[1].getint():
self.do_call(args[2:], calldescr)
@@ -219,10 +229,6 @@
def do_cast_ptr_to_int(self, ptrbox):
raise NotImplementedError
- def do_force_token(self):
- # this should not be implemented at all by the backends
- raise NotImplementedError
-
def do_call_may_force(self, args, calldescr):
return self.do_call(args, calldescr)
Modified: pypy/branch/stringbuilder2/pypy/jit/backend/test/runner_test.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/jit/backend/test/runner_test.py (original)
+++ pypy/branch/stringbuilder2/pypy/jit/backend/test/runner_test.py Mon Jan 25 15:25:48 2010
@@ -1,5 +1,5 @@
-import py, sys, random
+import py, sys, random, os
from pypy.jit.metainterp.history import (AbstractFailDescr,
BasicFailDescr,
BoxInt, Box, BoxPtr,
@@ -15,6 +15,7 @@
from pypy.jit.metainterp.test.oparser import parse
from pypy.rpython.annlowlevel import llhelper
from pypy.rpython.llinterp import LLException
+from pypy.jit.metainterp.test.oparser import parse
class Runner(object):
@@ -464,6 +465,30 @@
[funcbox] + args,
'float', descr=calldescr)
assert abs(res.value - 4.6) < 0.0001
+
+ def test_call_stack_alignment(self):
+ # test stack alignment issues, notably for Mac OS/X.
+ # also test the ordering of the arguments.
+
+ def func_ints(*ints):
+ s = str(ints) + '\n'
+ os.write(1, s) # don't remove -- crash if the stack is misaligned
+ return sum([(10+i)*(5+j) for i, j in enumerate(ints)])
+
+ for nb_args in range(0, 35):
+ cpu = self.cpu
+ TP = lltype.Signed
+ #
+ FPTR = self.Ptr(self.FuncType([TP] * nb_args, TP))
+ func_ptr = llhelper(FPTR, func_ints)
+ FUNC = deref(FPTR)
+ calldescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT)
+ funcbox = self.get_funcbox(cpu, func_ptr)
+ args = [280-24*i for i in range(nb_args)]
+ res = self.execute_operation(rop.CALL,
+ [funcbox] + map(BoxInt, args),
+ 'int', descr=calldescr)
+ assert res.value == func_ints(*args)
def test_field_basic(self):
t_box, T_box = self.alloc_instance(self.T)
@@ -779,6 +804,19 @@
r = self.execute_operation(rop.SAME_AS, [BoxFloat(5.5)], 'float')
assert r.value == 5.5
+ def test_virtual_ref(self):
+ # if VIRTUAL_REF reaches the backend, it should just be a SAME_AS
+ u_box = self.alloc_unicode(u"hello\u1234")
+ r = self.execute_operation(rop.VIRTUAL_REF, [u_box, ConstInt(2)],
+ 'ref')
+ assert r.value == u_box.value
+
+ def test_virtual_ref_finish(self):
+ # if VIRTUAL_REF_FINISH reaches the backend, it is a no-op
+ self.execute_operation(rop.VIRTUAL_REF_FINISH,
+ [BoxInt(123), BoxInt(234)],
+ 'void')
+
def test_jump(self):
# this test generates small loops where the JUMP passes many
# arguments of various types, shuffling them around.
@@ -1572,6 +1610,87 @@
lltype.free(x, flavor='raw')
+ def test_assembler_call(self):
+ called = []
+ def assembler_helper(failindex, virtualizable):
+ assert self.cpu.get_latest_value_int(0) == 10
+ called.append(failindex)
+ return 4 + 9
+ self.cpu.index_of_virtualizable = -1
+ self.cpu.assembler_helper_ptr = llhelper(lltype.Ptr(lltype.FuncType
+ ([lltype.Signed, llmemory.GCREF], lltype.Signed)), assembler_helper)
+
+ ops = '''
+ [i0, i1]
+ i2 = int_add(i0, i1)
+ finish(i2)'''
+ loop = parse(ops)
+ looptoken = LoopToken()
+ self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
+ ARGS = [lltype.Signed, lltype.Signed]
+ RES = lltype.Signed
+ self.cpu.portal_calldescr = self.cpu.calldescrof(
+ lltype.Ptr(lltype.FuncType(ARGS, RES)), ARGS, RES)
+ self.cpu.set_future_value_int(0, 1)
+ self.cpu.set_future_value_int(1, 2)
+ res = self.cpu.execute_token(looptoken)
+ assert self.cpu.get_latest_value_int(0) == 3
+ ops = '''
+ [i4, i5]
+ i6 = int_add(i4, 1)
+ i3 = call_assembler(i6, i5, descr=looptoken)
+ guard_not_forced()[]
+ finish(i3)
+ '''
+ loop = parse(ops, namespace=locals())
+ othertoken = LoopToken()
+ self.cpu.compile_loop(loop.inputargs, loop.operations, othertoken)
+ self.cpu.set_future_value_int(0, 4)
+ self.cpu.set_future_value_int(1, 5)
+ res = self.cpu.execute_token(othertoken)
+ assert self.cpu.get_latest_value_int(0) == 13
+ assert called
+
+ def test_assembler_call_float(self):
+ called = []
+ def assembler_helper(failindex, virtualizable):
+ assert self.cpu.get_latest_value_float(0) == 1.2 + 3.2
+ called.append(failindex)
+ return 13.5
+ self.cpu.index_of_virtualizable = -1
+ self.cpu.assembler_helper_ptr = llhelper(lltype.Ptr(lltype.FuncType
+ ([lltype.Signed, llmemory.GCREF], lltype.Float)), assembler_helper)
+ ARGS = [lltype.Float, lltype.Float]
+ RES = lltype.Float
+ self.cpu.portal_calldescr = self.cpu.calldescrof(
+ lltype.Ptr(lltype.FuncType(ARGS, RES)), ARGS, RES)
+
+ ops = '''
+ [f0, f1]
+ f2 = float_add(f0, f1)
+ finish(f2)'''
+ loop = parse(ops)
+ looptoken = LoopToken()
+ self.cpu.compile_loop(loop.inputargs, loop.operations, looptoken)
+ self.cpu.set_future_value_float(0, 1.2)
+ self.cpu.set_future_value_float(1, 2.3)
+ res = self.cpu.execute_token(looptoken)
+ assert self.cpu.get_latest_value_float(0) == 1.2 + 2.3
+ ops = '''
+ [f4, f5]
+ f3 = call_assembler(f4, f5, descr=looptoken)
+ guard_not_forced()[]
+ finish(f3)
+ '''
+ loop = parse(ops, namespace=locals())
+ othertoken = LoopToken()
+ self.cpu.compile_loop(loop.inputargs, loop.operations, othertoken)
+ self.cpu.set_future_value_float(0, 1.2)
+ self.cpu.set_future_value_float(1, 3.2)
+ res = self.cpu.execute_token(othertoken)
+ assert self.cpu.get_latest_value_float(0) == 13.5
+ assert called
+
class OOtypeBackendTest(BaseBackendTest):
type_system = 'ootype'
@@ -1609,3 +1728,4 @@
def alloc_unicode(self, unicode):
py.test.skip("implement me")
+
Modified: pypy/branch/stringbuilder2/pypy/jit/backend/test/support.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/jit/backend/test/support.py (original)
+++ pypy/branch/stringbuilder2/pypy/jit/backend/test/support.py Mon Jan 25 15:25:48 2010
@@ -100,6 +100,9 @@
def check_aborted_count(self, *args, **kwds):
pass
+ def check_aborted_count_at_least(self, *args, **kwds):
+ pass
+
def interp_operations(self, *args, **kwds):
py.test.skip("interp_operations test skipped")
@@ -117,6 +120,7 @@
def _get_TranslationContext(self):
t = TranslationContext()
t.config.translation.gc = 'boehm'
+ t.config.translation.list_comprehension_operations = True
return t
def _compile_and_run(self, t, entry_point, entry_point_graph, args):
Modified: pypy/branch/stringbuilder2/pypy/jit/backend/test/test_random.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/jit/backend/test/test_random.py (original)
+++ pypy/branch/stringbuilder2/pypy/jit/backend/test/test_random.py Mon Jan 25 15:25:48 2010
@@ -431,10 +431,11 @@
for _op in [rop.FLOAT_NEG,
rop.FLOAT_ABS,
- rop.FLOAT_IS_TRUE,
]:
OPERATIONS.append(UnaryFloatOperation(_op))
+OPERATIONS.append(UnaryFloatOperation(rop.FLOAT_IS_TRUE, boolres=True))
+
OPERATIONS.append(CastFloatToIntOperation(rop.CAST_FLOAT_TO_INT))
OPERATIONS.append(CastIntToFloatOperation(rop.CAST_INT_TO_FLOAT))
Modified: pypy/branch/stringbuilder2/pypy/jit/backend/x86/assembler.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/jit/backend/x86/assembler.py (original)
+++ pypy/branch/stringbuilder2/pypy/jit/backend/x86/assembler.py Mon Jan 25 15:25:48 2010
@@ -2,7 +2,8 @@
import ctypes
from pypy.jit.backend.llsupport import symbolic
from pypy.jit.metainterp.history import Const, Box, BoxInt, BoxPtr, BoxFloat
-from pypy.jit.metainterp.history import AbstractFailDescr, INT, REF, FLOAT
+from pypy.jit.metainterp.history import AbstractFailDescr, INT, REF, FLOAT,\
+ LoopToken
from pypy.rpython.lltypesystem import lltype, rffi, ll2ctypes, rstr, llmemory
from pypy.rpython.lltypesystem.rclass import OBJECT
from pypy.rpython.lltypesystem.lloperation import llop
@@ -17,6 +18,7 @@
from pypy.jit.metainterp.resoperation import rop
from pypy.jit.backend.x86.support import values_array
from pypy.rlib.debug import debug_print
+from pypy.rlib import rgc
# our calling convention - we pass first 6 args in registers
# and the rest stays on the stack
@@ -27,7 +29,6 @@
else:
CALL_ALIGN = 1
-
def align_stack_words(words):
return (words + CALL_ALIGN - 1) & ~(CALL_ALIGN-1)
@@ -75,6 +76,7 @@
mc = None
mc2 = None
mc_size = MachineCodeBlockWrapper.MC_DEFAULT_SIZE
+ _float_constants = None
def __init__(self, cpu, translate_support_code=False,
failargs_limit=1000):
@@ -85,6 +87,7 @@
self.malloc_array_func_addr = 0
self.malloc_str_func_addr = 0
self.malloc_unicode_func_addr = 0
+ self.assembler_helper_adr = 0
self.fail_boxes_int = values_array(lltype.Signed, failargs_limit)
self.fail_boxes_ptr = values_array(llmemory.GCREF, failargs_limit)
self.fail_boxes_float = values_array(lltype.Float, failargs_limit)
@@ -117,6 +120,14 @@
ll_new_unicode = gc_ll_descr.get_funcptr_for_newunicode()
self.malloc_unicode_func_addr = rffi.cast(lltype.Signed,
ll_new_unicode)
+ if we_are_translated():
+ self.assembler_helper_adr = self.cpu.cast_ptr_to_int(
+ self.cpu.assembler_helper_ptr)
+ else:
+ if getattr(self.cpu, 'assembler_helper_ptr', None):
+ self.assembler_helper_adr = self.cpu.cast_ptr_to_int(
+ self.cpu.assembler_helper_ptr)
+
# done
# we generate the loop body in 'mc'
# 'mc2' is for guard recovery code
@@ -153,6 +164,7 @@
"""adds the following attributes to looptoken:
_x86_loop_code (an integer giving an address)
_x86_bootstrap_code (an integer giving an address)
+ _x86_direct_bootstrap_code
_x86_frame_depth
_x86_param_depth
_x86_arglocs
@@ -161,15 +173,29 @@
regalloc = RegAlloc(self, self.cpu.translate_support_code)
arglocs = regalloc.prepare_loop(inputargs, operations, looptoken)
looptoken._x86_arglocs = arglocs
+ needed_mem = len(arglocs[0]) * 16 + 16
+ if needed_mem >= self.mc.bytes_free():
+ self.mc.make_new_mc()
looptoken._x86_bootstrap_code = self.mc.tell()
adr_stackadjust = self._assemble_bootstrap_code(inputargs, arglocs)
- looptoken._x86_loop_code = self.mc.tell()
+ curadr = self.mc.tell()
+ looptoken._x86_loop_code = curadr
looptoken._x86_frame_depth = -1 # temporarily
looptoken._x86_param_depth = -1 # temporarily
frame_depth, param_depth = self._assemble(regalloc, operations)
self._patch_stackadjust(adr_stackadjust, frame_depth+param_depth)
looptoken._x86_frame_depth = frame_depth
looptoken._x86_param_depth = param_depth
+ # we need to make sure here that we don't overload an mc badly.
+ # a safe estimate is that we need at most 16 bytes per arg
+ needed_mem = len(arglocs[0]) * 16 + 16
+ if needed_mem >= self.mc.bytes_free():
+ self.mc.make_new_mc()
+ looptoken._x86_direct_bootstrap_code = self.mc.tell()
+ self._assemble_bootstrap_direct_call(arglocs, curadr,
+ frame_depth+param_depth)
+ debug_print("Loop #", looptoken.number, "has address",
+ looptoken._x86_loop_code, "to", self.mc.tell())
def assemble_bridge(self, faildescr, inputargs, operations):
self.make_sure_mc_exists()
@@ -192,6 +218,9 @@
faildescr._x86_bridge_param_depth = param_depth
# patch the jump from original guard
self.patch_jump(faildescr, adr_bridge)
+ debug_print("Bridge out of guard",
+ self.cpu.get_fail_descr_number(faildescr),
+ "has address", adr_bridge, "to", self.mc.tell())
def patch_jump(self, faildescr, adr_new_target):
adr_jump_offset = faildescr._x86_adr_jump_offset
@@ -224,17 +253,17 @@
def _patch_stackadjust(self, adr_lea, reserved_depth):
# patch stack adjustment LEA
- # possibly align, e.g. for Mac OS X
mc = codebuf.InMemoryCodeBuilder(adr_lea, adr_lea + 4)
# Compute the correct offset for the instruction LEA ESP, [EBP-4*words].
# Given that [EBP] is where we saved EBP, i.e. in the last word
# of our fixed frame, then the 'words' value is:
words = (FRAME_FIXED_SIZE - 1) + reserved_depth
- mc.write(packimm32(-WORD * words))
+ # align, e.g. for Mac OS X
+ aligned_words = align_stack_words(words+2)-2 # 2 = EIP+EBP
+ mc.write(packimm32(-WORD * aligned_words))
mc.done()
- def _assemble_bootstrap_code(self, inputargs, arglocs):
- nonfloatlocs, floatlocs = arglocs
+ def _call_header(self):
self.mc.PUSH(ebp)
self.mc.MOV(ebp, esp)
self.mc.PUSH(ebx)
@@ -242,7 +271,41 @@
self.mc.PUSH(edi)
# NB. the shape of the frame is hard-coded in get_basic_shape() too.
# Also, make sure this is consistent with FRAME_FIXED_SIZE.
- adr_stackadjust = self._patchable_stackadjust()
+ return self._patchable_stackadjust()
+
+ def _assemble_bootstrap_direct_call(self, arglocs, jmpadr, stackdepth):
+ # XXX pushing ebx esi and edi is a bit pointless, since we store
+ # all regsiters anyway, for the case of guard_not_forced
+ # XXX this can be improved greatly. Right now it'll behave like
+ # a normal call
+ nonfloatlocs, floatlocs = arglocs
+ # XXX not to repeat the logic, a bit around
+ adr_stackadjust = self._call_header()
+ self._patch_stackadjust(adr_stackadjust, stackdepth)
+ for i in range(len(nonfloatlocs)):
+ loc = nonfloatlocs[i]
+ if isinstance(loc, REG):
+ self.mc.MOV(loc, mem(ebp, (2 + i) * WORD))
+ loc = floatlocs[i]
+ if isinstance(loc, XMMREG):
+ self.mc.MOVSD(loc, mem64(ebp, (1 + i) * 2 * WORD))
+ tmp = eax
+ xmmtmp = xmm0
+ for i in range(len(nonfloatlocs)):
+ loc = nonfloatlocs[i]
+ if loc is not None and not isinstance(loc, REG):
+ self.mc.MOV(tmp, mem(ebp, (2 + i) * WORD))
+ self.mc.MOV(loc, tmp)
+ loc = floatlocs[i]
+ if loc is not None and not isinstance(loc, XMMREG):
+ self.mc.MOVSD(xmmtmp, mem64(ebp, (1 + i) * 2 * WORD))
+ self.mc.MOVSD(loc, xmmtmp)
+ self.mc.JMP(rel32(jmpadr))
+ return adr_stackadjust
+
+ def _assemble_bootstrap_code(self, inputargs, arglocs):
+ nonfloatlocs, floatlocs = arglocs
+ adr_stackadjust = self._call_header()
tmp = X86RegisterManager.all_regs[0]
xmmtmp = X86XMMRegisterManager.all_regs[0]
for i in range(len(nonfloatlocs)):
@@ -366,19 +429,18 @@
def genop_cmp(self, op, arglocs, result_loc):
if isinstance(op.args[0], Const):
self.mc.CMP(arglocs[1], arglocs[0])
- self.mc.MOV(result_loc, imm8(0))
getattr(self.mc, 'SET' + rev_cond)(lower_byte(result_loc))
else:
self.mc.CMP(arglocs[0], arglocs[1])
- self.mc.MOV(result_loc, imm8(0))
getattr(self.mc, 'SET' + cond)(lower_byte(result_loc))
+ self.mc.MOVZX(result_loc, lower_byte(result_loc))
return genop_cmp
def _cmpop_float(cond):
def genop_cmp(self, op, arglocs, result_loc):
self.mc.UCOMISD(arglocs[0], arglocs[1])
- self.mc.MOV(result_loc, imm8(0))
getattr(self.mc, 'SET' + cond)(lower_byte(result_loc))
+ self.mc.MOVZX(result_loc, lower_byte(result_loc))
return genop_cmp
def _cmpop_guard(cond, rev_cond, false_cond, false_rev_cond):
@@ -402,38 +464,47 @@
return self.implement_guard(addr, getattr(self.mc, name))
return genop_cmp_guard
-## XXX redo me
-## def align_stack_for_call(self, nargs):
-## # xxx do something when we don't use push anymore for calls
-## extra_on_stack = align_stack_words(nargs)
-## for i in range(extra_on_stack-nargs):
-## self.mc.PUSH(imm(0)) --- or just use a single SUB(esp, imm)
-## return extra_on_stack
-
- def _emit_call(self, x, arglocs, start=0, tmp=eax):
+ def _cmpop_guard_float(cond, false_cond):
+ def genop_cmp_guard_float(self, op, guard_op, addr, arglocs,
+ result_loc):
+ guard_opnum = guard_op.opnum
+ self.mc.UCOMISD(arglocs[0], arglocs[1])
+ if guard_opnum == rop.GUARD_FALSE:
+ name = 'J' + cond
+ return self.implement_guard(addr, getattr(self.mc, name))
+ else:
+ name = 'J' + false_cond
+ return self.implement_guard(addr, getattr(self.mc, name))
+ return genop_cmp_guard_float
+
+ @specialize.arg(5)
+ def _emit_call(self, x, arglocs, start=0, tmp=eax, force_mc=False,
+ mc=None):
+ if not force_mc:
+ mc = self.mc
p = 0
n = len(arglocs)
for i in range(start, n):
loc = arglocs[i]
if isinstance(loc, REG):
if isinstance(loc, XMMREG):
- self.mc.MOVSD(mem64(esp, p), loc)
+ mc.MOVSD(mem64(esp, p), loc)
else:
- self.mc.MOV(mem(esp, p), loc)
+ mc.MOV(mem(esp, p), loc)
p += round_up_to_4(loc.width)
p = 0
for i in range(start, n):
loc = arglocs[i]
if not isinstance(loc, REG):
if isinstance(loc, MODRM64):
- self.mc.MOVSD(xmm0, loc)
- self.mc.MOVSD(mem64(esp, p), xmm0)
+ mc.MOVSD(xmm0, loc)
+ mc.MOVSD(mem64(esp, p), xmm0)
else:
- self.mc.MOV(tmp, loc)
- self.mc.MOV(mem(esp, p), tmp)
+ mc.MOV(tmp, loc)
+ mc.MOV(mem(esp, p), tmp)
p += round_up_to_4(loc.width)
self._regalloc.reserve_param(p//WORD)
- self.mc.CALL(x)
+ mc.CALL(x)
self.mark_gc_roots()
def call(self, addr, args, res):
@@ -460,11 +531,11 @@
genop_int_lt = _cmpop("L", "G")
genop_int_le = _cmpop("LE", "GE")
genop_int_eq = _cmpop("E", "E")
- genop_oois = genop_int_eq
genop_int_ne = _cmpop("NE", "NE")
- genop_ooisnot = genop_int_ne
genop_int_gt = _cmpop("G", "L")
genop_int_ge = _cmpop("GE", "LE")
+ genop_oois = genop_int_eq
+ genop_ooisnot = genop_int_ne
genop_float_lt = _cmpop_float('B')
genop_float_le = _cmpop_float('BE')
@@ -484,12 +555,21 @@
genop_guard_int_ne = _cmpop_guard("NE", "NE", "E", "E")
genop_guard_int_gt = _cmpop_guard("G", "L", "LE", "GE")
genop_guard_int_ge = _cmpop_guard("GE", "LE", "L", "G")
+ genop_guard_oois = genop_guard_int_eq
+ genop_guard_ooisnot = genop_guard_int_ne
genop_guard_uint_gt = _cmpop_guard("A", "B", "BE", "AE")
genop_guard_uint_lt = _cmpop_guard("B", "A", "AE", "BE")
genop_guard_uint_le = _cmpop_guard("BE", "AE", "A", "B")
genop_guard_uint_ge = _cmpop_guard("AE", "BE", "B", "A")
+ genop_guard_float_lt = _cmpop_guard_float("B", "AE")
+ genop_guard_float_le = _cmpop_guard_float("BE", "A")
+ genop_guard_float_eq = _cmpop_guard_float("E", "NE")
+ genop_guard_float_ne = _cmpop_guard_float("NE", "E")
+ genop_guard_float_gt = _cmpop_guard_float("A", "BE")
+ genop_guard_float_ge = _cmpop_guard_float("AE", "B")
+
def genop_float_neg(self, op, arglocs, resloc):
# Following what gcc does: res = x ^ 0x8000000000000000
self.mc.XORPD(arglocs[0], self.loc_float_const_neg)
@@ -498,6 +578,16 @@
# Following what gcc does: res = x & 0x7FFFFFFFFFFFFFFF
self.mc.ANDPD(arglocs[0], self.loc_float_const_abs)
+ def genop_guard_float_is_true(self, op, guard_op, addr, arglocs, resloc):
+ guard_opnum = guard_op.opnum
+ loc0, loc1 = arglocs
+ self.mc.XORPD(loc0, loc0)
+ self.mc.UCOMISD(loc0, loc1)
+ if guard_opnum == rop.GUARD_TRUE:
+ return self.implement_guard(addr, self.mc.JZ)
+ else:
+ return self.implement_guard(addr, self.mc.JNZ)
+
def genop_float_is_true(self, op, arglocs, resloc):
loc0, loc1 = arglocs
self.mc.XORPD(loc0, loc0)
@@ -511,9 +601,6 @@
def genop_cast_int_to_float(self, op, arglocs, resloc):
self.mc.CVTSI2SD(resloc, arglocs[0])
- def genop_bool_not(self, op, arglocs, resloc):
- self.mc.XOR(arglocs[0], imm8(1))
-
def genop_int_lshift(self, op, arglocs, resloc):
loc, loc2 = arglocs
if loc2 is ecx:
@@ -534,8 +621,7 @@
def genop_guard_int_is_true(self, op, guard_op, addr, arglocs, resloc):
guard_opnum = guard_op.opnum
- loc = arglocs[0]
- self.mc.TEST(loc, loc)
+ self.mc.CMP(arglocs[0], imm8(0))
if guard_opnum == rop.GUARD_TRUE:
return self.implement_guard(addr, self.mc.JZ)
else:
@@ -543,12 +629,24 @@
def genop_int_is_true(self, op, arglocs, resloc):
self.mc.CMP(arglocs[0], imm8(0))
- self.mc.MOV(resloc, imm8(0))
self.mc.SETNE(lower_byte(resloc))
+ self.mc.MOVZX(resloc, lower_byte(resloc))
+
+ def genop_guard_bool_not(self, op, guard_op, addr, arglocs, resloc):
+ guard_opnum = guard_op.opnum
+ self.mc.CMP(arglocs[0], imm8(0))
+ if guard_opnum == rop.GUARD_TRUE:
+ return self.implement_guard(addr, self.mc.JNZ)
+ else:
+ return self.implement_guard(addr, self.mc.JZ)
+
+ def genop_bool_not(self, op, arglocs, resloc):
+ self.mc.XOR(arglocs[0], imm8(1))
def genop_same_as(self, op, arglocs, resloc):
self.mov(arglocs[0], resloc)
genop_cast_ptr_to_int = genop_same_as
+ genop_virtual_ref = genop_same_as
def genop_int_mod(self, op, arglocs, resloc):
self.mc.CDQ()
@@ -955,6 +1053,7 @@
boxes.append(box)
return boxes
+ @rgc.no_collect
def grab_frame_values(self, bytecode, frame_addr, allregisters):
# no malloc allowed here!!
self.fail_ebp = allregisters[16 + ebp.op]
@@ -1019,6 +1118,7 @@
def setup_failure_recovery(self):
+ @rgc.no_collect
def failure_recovery_func(registers):
# 'registers' is a pointer to a structure containing the
# original value of the registers, optionally the original
@@ -1153,7 +1253,7 @@
tmp = ecx
else:
tmp = eax
-
+
self._emit_call(x, arglocs, 2, tmp=tmp)
if isinstance(resloc, MODRM64):
@@ -1174,6 +1274,38 @@
self.mc.CMP(mem(ebp, FORCE_INDEX_OFS), imm(0))
return self.implement_guard(addr, self.mc.JL)
+ def genop_guard_call_assembler(self, op, guard_op, addr,
+ arglocs, result_loc):
+ faildescr = guard_op.descr
+ fail_index = self.cpu.get_fail_descr_number(faildescr)
+ self.mc.MOV(mem(ebp, FORCE_INDEX_OFS), imm(fail_index))
+ descr = op.descr
+ assert isinstance(descr, LoopToken)
+ assert len(arglocs) - 2 == len(descr._x86_arglocs[0])
+ self._emit_call(rel32(descr._x86_direct_bootstrap_code), arglocs, 2,
+ tmp=eax)
+ mc = self.mc._mc
+ mc.CMP(eax, imm(self.cpu.done_with_this_frame_int_v))
+ mc.write(constlistofchars('\x74\x00')) # JE below
+ je_location = mc.get_relative_pos()
+ self._emit_call(rel32(self.assembler_helper_adr), [eax, arglocs[1]], 0,
+ tmp=ecx, force_mc=True, mc=mc)
+ mc.write(constlistofchars('\xEB\x00')) # JMP below
+ jmp_location = mc.get_relative_pos()
+ offset = jmp_location - je_location
+ assert 0 < offset <= 127
+ mc.overwrite(je_location - 1, [chr(offset)])
+ mc.MOV(eax, heap(self.fail_boxes_int.get_addr_for_num(0)))
+ offset = mc.get_relative_pos() - jmp_location
+ assert 0 < offset <= 127
+ mc.overwrite(jmp_location - 1, [chr(offset)])
+ if isinstance(result_loc, MODRM64):
+ self.mc.FSTP(result_loc)
+ else:
+ assert result_loc is eax or result_loc is None
+ self.mc.CMP(mem(ebp, FORCE_INDEX_OFS), imm(0))
+ return self.implement_guard(addr, self.mc.JL)
+
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
@@ -1218,7 +1350,7 @@
def not_implemented_op_guard(self, op, guard_op,
failaddr, arglocs, resloc):
- msg = "not implemented operation (guard): %s" % guard_op.getopname()
+ msg = "not implemented operation (guard): %s" % op.getopname()
print msg
raise NotImplementedError(msg)
Modified: pypy/branch/stringbuilder2/pypy/jit/backend/x86/regalloc.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/jit/backend/x86/regalloc.py (original)
+++ pypy/branch/stringbuilder2/pypy/jit/backend/x86/regalloc.py Mon Jan 25 15:25:48 2010
@@ -52,7 +52,28 @@
print "convert_to_imm: got a %s" % c
raise AssertionError
-BASE_CONSTANT_SIZE = 1000
+
+class FloatConstants(object):
+ BASE_CONSTANT_SIZE = 1000
+
+ def __init__(self):
+ self.cur_array_free = 0
+
+ def _get_new_array(self):
+ n = self.BASE_CONSTANT_SIZE
+ self.cur_array = lltype.malloc(rffi.CArray(lltype.Float), n,
+ flavor='raw')
+ self.cur_array_free = n
+ _get_new_array._dont_inline_ = True
+
+ def record_float(self, floatval):
+ if self.cur_array_free == 0:
+ self._get_new_array()
+ arr = self.cur_array
+ n = self.cur_array_free - 1
+ arr[n] = floatval
+ self.cur_array_free = n
+ return rffi.cast(lltype.Signed, arr) + n * 8
class X86XMMRegisterManager(RegisterManager):
@@ -63,29 +84,19 @@
save_around_call_regs = all_regs
reg_width = 2
- def new_const_array(self):
- return lltype.malloc(rffi.CArray(lltype.Float), BASE_CONSTANT_SIZE,
- flavor='raw')
-
def __init__(self, longevity, frame_manager=None, assembler=None):
RegisterManager.__init__(self, longevity, frame_manager=frame_manager,
assembler=assembler)
- self.constant_arrays = [self.new_const_array()]
- self.constant_array_counter = 0
+ if assembler is None:
+ self.float_constants = FloatConstants()
+ else:
+ if assembler._float_constants is None:
+ assembler._float_constants = FloatConstants()
+ self.float_constants = assembler._float_constants
def convert_to_imm(self, c):
- if self.constant_array_counter >= BASE_CONSTANT_SIZE:
- self.constant_arrays.append(self.new_const_array())
- self.constant_array_counter = 0
- res = self.constant_array_counter
- self.constant_array_counter += 1
- arr = self.constant_arrays[-1]
- arr[res] = c.getfloat()
- return self.get_addr_of_const_float(-1, res)
-
- def get_addr_of_const_float(self, num_arr, num_pos):
- arr = self.constant_arrays[num_arr]
- return heap64(rffi.cast(lltype.Signed, arr) + num_pos * WORD * 2)
+ adr = self.float_constants.record_float(c.getfloat())
+ return heap64(adr)
def after_call(self, v):
# the result is stored in st0, but we don't have this around,
@@ -307,7 +318,7 @@
self.assembler.regalloc_perform_discard(op, arglocs)
def can_merge_with_next_guard(self, op, i, operations):
- if op.opnum == rop.CALL_MAY_FORCE:
+ if op.opnum == rop.CALL_MAY_FORCE or op.opnum == rop.CALL_ASSEMBLER:
assert operations[i + 1].opnum == rop.GUARD_NOT_FORCED
return True
if not op.is_comparison():
@@ -334,10 +345,10 @@
self.possibly_free_vars(op.args)
continue
if self.can_merge_with_next_guard(op, i, operations):
- oplist[op.opnum](self, op, operations[i + 1])
+ oplist_with_guard[op.opnum](self, op, operations[i + 1])
i += 1
else:
- oplist[op.opnum](self, op, None)
+ oplist[op.opnum](self, op)
if op.result is not None:
self.possibly_free_var(op.result)
self.rm._check_invariants()
@@ -386,7 +397,7 @@
return self.xrm.loc(v)
return self.rm.loc(v)
- def _consider_guard(self, op, ignored):
+ def _consider_guard(self, op):
loc = self.rm.make_sure_var_in_reg(op.args[0])
self.perform_guard(op, [loc], None)
self.rm.possibly_free_var(op.args[0])
@@ -396,7 +407,7 @@
consider_guard_nonnull = _consider_guard
consider_guard_isnull = _consider_guard
- def consider_finish(self, op, ignored):
+ def consider_finish(self, op):
locs = [self.loc(v) for v in op.args]
locs_are_ref = [v.type == REF for v in op.args]
fail_index = self.assembler.cpu.get_fail_descr_number(op.descr)
@@ -404,10 +415,10 @@
self.exc, locs_are_ref)
self.possibly_free_vars(op.args)
- def consider_guard_no_exception(self, op, ignored):
+ def consider_guard_no_exception(self, op):
self.perform_guard(op, [], None)
- def consider_guard_exception(self, op, ignored):
+ def consider_guard_exception(self, op):
loc = self.rm.make_sure_var_in_reg(op.args[0])
box = TempBox()
loc1 = self.rm.force_allocate_reg(box, op.args)
@@ -423,13 +434,13 @@
consider_guard_no_overflow = consider_guard_no_exception
consider_guard_overflow = consider_guard_no_exception
- def consider_guard_value(self, op, ignored):
+ def consider_guard_value(self, op):
x = self.make_sure_var_in_reg(op.args[0])
y = self.loc(op.args[1])
self.perform_guard(op, [x, y], None)
self.possibly_free_vars(op.args)
- def consider_guard_class(self, op, ignored):
+ def consider_guard_class(self, op):
assert isinstance(op.args[0], Box)
x = self.rm.make_sure_var_in_reg(op.args[0])
y = self.loc(op.args[1])
@@ -438,15 +449,15 @@
consider_guard_nonnull_class = consider_guard_class
- def _consider_binop_part(self, op, ignored):
+ def _consider_binop_part(self, op):
x = op.args[0]
argloc = self.loc(op.args[1])
loc = self.rm.force_result_in_reg(op.result, x, op.args)
self.rm.possibly_free_var(op.args[1])
return loc, argloc
- def _consider_binop(self, op, ignored):
- loc, argloc = self._consider_binop_part(op, ignored)
+ def _consider_binop(self, op):
+ loc, argloc = self._consider_binop_part(op)
self.Perform(op, [loc, argloc], loc)
consider_int_add = _consider_binop
@@ -460,14 +471,13 @@
consider_int_sub_ovf = _consider_binop
consider_int_add_ovf = _consider_binop
- def consider_int_neg(self, op, ignored):
+ def consider_int_neg(self, op):
res = self.rm.force_result_in_reg(op.result, op.args[0])
self.Perform(op, [res], res)
consider_int_invert = consider_int_neg
- consider_bool_not = consider_int_neg
- def consider_int_lshift(self, op, ignored):
+ def consider_int_lshift(self, op):
if isinstance(op.args[1], Const):
loc2 = self.rm.convert_to_imm(op.args[1])
else:
@@ -493,11 +503,11 @@
self.rm.possibly_free_vars(op.args)
self.rm.possibly_free_var(tmpvar)
- def consider_int_mod(self, op, ignored):
+ def consider_int_mod(self, op):
self._consider_int_div_or_mod(op, edx, eax)
self.Perform(op, [eax, ecx], edx)
- def consider_int_floordiv(self, op, ignored):
+ def consider_int_floordiv(self, op):
self._consider_int_div_or_mod(op, eax, edx)
self.Perform(op, [eax, ecx], eax)
@@ -531,7 +541,7 @@
consider_oois = _consider_compop
consider_ooisnot = _consider_compop
- def _consider_float_op(self, op, ignored):
+ def _consider_float_op(self, op):
loc1 = self.xrm.loc(op.args[1])
loc0 = self.xrm.force_result_in_reg(op.result, op.args[0], op.args)
self.Perform(op, [loc0, loc1], loc0)
@@ -542,15 +552,17 @@
consider_float_mul = _consider_float_op
consider_float_truediv = _consider_float_op
- def _consider_float_cmp(self, op, ignored):
- assert ignored is None
- # XXX so far we don't have guards here, but we want them
+ def _consider_float_cmp(self, op, guard_op):
loc0 = self.xrm.make_sure_var_in_reg(op.args[0], op.args,
imm_fine=False)
loc1 = self.xrm.loc(op.args[1])
- res = self.rm.force_allocate_reg(op.result, need_lower_byte=True)
- self.Perform(op, [loc0, loc1], res)
- self.xrm.possibly_free_vars(op.args)
+ arglocs = [loc0, loc1]
+ self.xrm.possibly_free_vars(op.args)
+ if guard_op is None:
+ res = self.rm.force_allocate_reg(op.result, need_lower_byte=True)
+ self.Perform(op, arglocs, res)
+ else:
+ self.perform_with_guard(op, guard_op, arglocs, None)
consider_float_lt = _consider_float_cmp
consider_float_le = _consider_float_cmp
@@ -559,32 +571,37 @@
consider_float_gt = _consider_float_cmp
consider_float_ge = _consider_float_cmp
- def consider_float_neg(self, op, ignored):
+ def consider_float_neg(self, op):
loc0 = self.xrm.force_result_in_reg(op.result, op.args[0])
self.Perform(op, [loc0], loc0)
self.xrm.possibly_free_var(op.args[0])
- def consider_float_abs(self, op, ignored):
+ def consider_float_abs(self, op):
loc0 = self.xrm.force_result_in_reg(op.result, op.args[0])
self.Perform(op, [loc0], loc0)
self.xrm.possibly_free_var(op.args[0])
- def consider_float_is_true(self, op, ignored):
+ def consider_float_is_true(self, op, guard_op):
+ # doesn't need arg to be in a register
tmpbox0 = TempBox()
loc0 = self.xrm.force_allocate_reg(tmpbox0)
loc1 = self.xrm.loc(op.args[0])
- loc2 = self.rm.force_allocate_reg(op.result, need_lower_byte=True)
- self.Perform(op, [loc0, loc1], loc2)
+ arglocs = [loc0, loc1]
self.xrm.possibly_free_var(op.args[0])
self.xrm.possibly_free_var(tmpbox0)
+ if guard_op is not None:
+ self.perform_with_guard(op, guard_op, arglocs, None)
+ else:
+ loc2 = self.rm.force_allocate_reg(op.result, need_lower_byte=True)
+ self.Perform(op, arglocs, loc2)
- def consider_cast_float_to_int(self, op, ignored):
+ def consider_cast_float_to_int(self, op):
loc0 = self.xrm.make_sure_var_in_reg(op.args[0], imm_fine=False)
loc1 = self.rm.force_allocate_reg(op.result)
self.Perform(op, [loc0], loc1)
self.xrm.possibly_free_var(op.args[0])
- def consider_cast_int_to_float(self, op, ignored):
+ def consider_cast_int_to_float(self, op):
loc0 = self.rm.loc(op.args[0])
loc1 = self.xrm.force_allocate_reg(op.result)
self.Perform(op, [loc0], loc1)
@@ -614,7 +631,7 @@
self._call(op, [imm(size)] + [self.loc(arg) for arg in op.args],
guard_not_forced_op=guard_not_forced_op)
- def consider_call(self, op, ignored):
+ def consider_call(self, op):
self._consider_call(op)
consider_call_pure = consider_call
@@ -622,7 +639,21 @@
assert guard_op is not None
self._consider_call(op, guard_op)
- def consider_cond_call_gc_wb(self, op, ignored):
+ def consider_call_assembler(self, op, guard_op):
+ descr = op.descr
+ portal_calldescr = self.assembler.cpu.portal_calldescr
+ size = portal_calldescr.get_result_size(self.translate_support_code)
+ vable_index = self.assembler.cpu.index_of_virtualizable
+ if vable_index != -1:
+ self.rm._sync_var(op.args[vable_index])
+ vable = self.fm.loc(op.args[vable_index], 1)
+ else:
+ vable = imm(0)
+ self._call(op, [imm(size), vable] +
+ [self.loc(arg) for arg in op.args],
+ guard_not_forced_op=guard_op)
+
+ def consider_cond_call_gc_wb(self, op):
assert op.result is None
arglocs = [self.loc(arg) for arg in op.args]
# add eax, ecx and edx as extra "arguments" to ensure they are
@@ -664,7 +695,7 @@
gc_ll_descr.get_malloc_fixedsize_slowpath_addr(),
)
- def consider_new(self, op, ignored):
+ def consider_new(self, op):
gc_ll_descr = self.assembler.cpu.gc_ll_descr
if gc_ll_descr.can_inline_malloc(op.descr):
self._fastpath_malloc(op, op.descr)
@@ -673,7 +704,7 @@
arglocs = [imm(x) for x in args]
return self._call(op, arglocs)
- def consider_new_with_vtable(self, op, ignored):
+ def consider_new_with_vtable(self, op):
classint = op.args[0].getint()
descrsize = self.assembler.cpu.class_sizes[classint]
if self.assembler.cpu.gc_ll_descr.can_inline_malloc(descrsize):
@@ -686,7 +717,7 @@
arglocs.append(self.loc(op.args[0]))
return self._call(op, arglocs)
- def consider_newstr(self, op, ignored):
+ def consider_newstr(self, op):
gc_ll_descr = self.assembler.cpu.gc_ll_descr
if gc_ll_descr.get_funcptr_for_newstr is not None:
# framework GC
@@ -698,7 +729,7 @@
return self._malloc_varsize(ofs_items, ofs, 0, op.args[0],
op.result)
- def consider_newunicode(self, op, ignored):
+ def consider_newunicode(self, op):
gc_ll_descr = self.assembler.cpu.gc_ll_descr
if gc_ll_descr.get_funcptr_for_newunicode is not None:
# framework GC
@@ -736,7 +767,7 @@
self.PerformDiscard(ResOperation(rop.SETFIELD_GC, [], None),
[eax, imm(ofs_length), imm(WORD), loc])
- def consider_new_array(self, op, ignored):
+ def consider_new_array(self, op):
gc_ll_descr = self.assembler.cpu.gc_ll_descr
if gc_ll_descr.get_funcptr_for_newarray is not None:
# framework GC
@@ -767,7 +798,7 @@
ptr = fielddescr.is_pointer_field()
return imm(ofs), imm(size), ptr
- def consider_setfield_gc(self, op, ignored):
+ def consider_setfield_gc(self, op):
ofs_loc, size_loc, ptr = self._unpack_fielddescr(op.descr)
assert isinstance(size_loc, IMM32)
if size_loc.value == 1:
@@ -782,7 +813,7 @@
consider_setfield_raw = consider_setfield_gc
- def consider_strsetitem(self, op, ignored):
+ def consider_strsetitem(self, op):
base_loc = self.rm.make_sure_var_in_reg(op.args[0], op.args)
ofs_loc = self.rm.make_sure_var_in_reg(op.args[1], op.args)
value_loc = self.rm.make_sure_var_in_reg(op.args[2], op.args,
@@ -792,7 +823,7 @@
consider_unicodesetitem = consider_strsetitem
- def consider_setarrayitem_gc(self, op, ignored):
+ def consider_setarrayitem_gc(self, op):
scale, ofs, ptr = self._unpack_arraydescr(op.descr)
base_loc = self.rm.make_sure_var_in_reg(op.args[0], op.args)
if scale == 0:
@@ -808,7 +839,7 @@
consider_setarrayitem_raw = consider_setarrayitem_gc
- def consider_getfield_gc(self, op, ignored):
+ def consider_getfield_gc(self, op):
ofs_loc, size_loc, _ = self._unpack_fielddescr(op.descr)
base_loc = self.rm.make_sure_var_in_reg(op.args[0], op.args)
self.rm.possibly_free_vars(op.args)
@@ -819,7 +850,7 @@
consider_getfield_raw_pure = consider_getfield_gc
consider_getfield_gc_pure = consider_getfield_gc
- def consider_getarrayitem_gc(self, op, ignored):
+ def consider_getarrayitem_gc(self, op):
scale, ofs, _ = self._unpack_arraydescr(op.descr)
base_loc = self.rm.make_sure_var_in_reg(op.args[0], op.args)
ofs_loc = self.rm.make_sure_var_in_reg(op.args[1], op.args)
@@ -829,29 +860,34 @@
consider_getarrayitem_gc_pure = consider_getarrayitem_gc
-
- def _consider_nullity(self, op, guard_op):
- # doesn't need a register in arg
+ def consider_int_is_true(self, op, guard_op):
+ # doesn't need arg to be in a register
+ argloc = self.loc(op.args[0])
+ self.rm.possibly_free_var(op.args[0])
if guard_op is not None:
- argloc = self.rm.make_sure_var_in_reg(op.args[0])
- self.rm.possibly_free_var(op.args[0])
self.perform_with_guard(op, guard_op, [argloc], None)
else:
- argloc = self.loc(op.args[0])
- self.rm.possibly_free_var(op.args[0])
resloc = self.rm.force_allocate_reg(op.result, need_lower_byte=True)
self.Perform(op, [argloc], resloc)
- consider_int_is_true = _consider_nullity
+ def consider_bool_not(self, op, guard_op):
+ if guard_op is not None:
+ # doesn't need arg to be in a register
+ argloc = self.loc(op.args[0])
+ self.rm.possibly_free_var(op.args[0])
+ self.perform_with_guard(op, guard_op, [argloc], None)
+ else:
+ self.consider_int_neg(op)
- def consider_same_as(self, op, ignored):
+ def consider_same_as(self, op):
argloc = self.loc(op.args[0])
self.possibly_free_var(op.args[0])
resloc = self.force_allocate_reg(op.result)
self.Perform(op, [argloc], resloc)
consider_cast_ptr_to_int = consider_same_as
+ consider_virtual_ref = consider_same_as
- def consider_strlen(self, op, ignored):
+ def consider_strlen(self, op):
base_loc = self.rm.make_sure_var_in_reg(op.args[0], op.args)
self.rm.possibly_free_vars(op.args)
result_loc = self.rm.force_allocate_reg(op.result)
@@ -859,7 +895,7 @@
consider_unicodelen = consider_strlen
- def consider_arraylen_gc(self, op, ignored):
+ def consider_arraylen_gc(self, op):
arraydescr = op.descr
assert isinstance(arraydescr, BaseArrayDescr)
ofs = arraydescr.get_ofs_length(self.translate_support_code)
@@ -868,7 +904,7 @@
result_loc = self.rm.force_allocate_reg(op.result)
self.Perform(op, [base_loc, imm(ofs)], result_loc)
- def consider_strgetitem(self, op, ignored):
+ def consider_strgetitem(self, op):
base_loc = self.rm.make_sure_var_in_reg(op.args[0], op.args)
ofs_loc = self.rm.make_sure_var_in_reg(op.args[1], op.args)
self.rm.possibly_free_vars(op.args)
@@ -877,7 +913,7 @@
consider_unicodegetitem = consider_strgetitem
- def consider_jump(self, op, ignored):
+ def consider_jump(self, op):
assembler = self.assembler
assert self.jump_target_descr is None
descr = op.descr
@@ -905,9 +941,12 @@
self.possibly_free_vars(op.args)
assembler.closing_jump(self.jump_target_descr)
- def consider_debug_merge_point(self, op, ignored):
+ def consider_debug_merge_point(self, op):
pass
+ def consider_virtual_ref_finish(self, op):
+ self.possibly_free_vars(op.args)
+
def get_mark_gc_roots(self, gcrootmap):
shape = gcrootmap.get_basic_shape()
for v, val in self.fm.frame_bindings.items():
@@ -926,22 +965,37 @@
assert reg is eax # ok to ignore this one
return gcrootmap.compress_callshape(shape)
- def consider_force_token(self, op, ignored):
+ def consider_force_token(self, op):
loc = self.rm.force_allocate_reg(op.result)
self.Perform(op, [], loc)
- def not_implemented_op(self, op, ignored):
+ def not_implemented_op(self, op):
msg = "[regalloc] Not implemented operation: %s" % op.getopname()
print msg
raise NotImplementedError(msg)
+ def not_implemented_op_with_guard(self, op, guard_op):
+ msg = "[regalloc] Not implemented operation with guard: %s" % (
+ op.getopname(),)
+ print msg
+ raise NotImplementedError(msg)
+
oplist = [RegAlloc.not_implemented_op] * rop._LAST
+oplist_with_guard = [RegAlloc.not_implemented_op_with_guard] * rop._LAST
+
+def add_none_argument(fn):
+ return lambda self, op: fn(self, op, None)
for name, value in RegAlloc.__dict__.iteritems():
if name.startswith('consider_'):
name = name[len('consider_'):]
num = getattr(rop, name.upper())
- oplist[num] = value
+ if (ResOperation(num, [], None).is_comparison()
+ or num == rop.CALL_MAY_FORCE or num == rop.CALL_ASSEMBLER):
+ oplist_with_guard[num] = value
+ oplist[num] = add_none_argument(value)
+ else:
+ oplist[num] = value
def get_ebp_ofs(position):
# Argument is a frame position (0, 1, 2...).
Modified: pypy/branch/stringbuilder2/pypy/jit/backend/x86/runner.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/jit/backend/x86/runner.py (original)
+++ pypy/branch/stringbuilder2/pypy/jit/backend/x86/runner.py Mon Jan 25 15:25:48 2010
@@ -18,8 +18,8 @@
def __init__(self, rtyper, stats, opts=None, translate_support_code=False,
gcdescr=None):
- AbstractLLCPU.__init__(self, rtyper, stats, opts, translate_support_code,
- gcdescr)
+ AbstractLLCPU.__init__(self, rtyper, stats, opts,
+ translate_support_code, gcdescr)
def setup(self):
if self.opts is not None:
Modified: pypy/branch/stringbuilder2/pypy/jit/backend/x86/test/test_gc_integration.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/jit/backend/x86/test/test_gc_integration.py (original)
+++ pypy/branch/stringbuilder2/pypy/jit/backend/x86/test/test_gc_integration.py Mon Jan 25 15:25:48 2010
@@ -78,7 +78,7 @@
box = boxes[0]
regalloc.position = 0
regalloc.consider_call(ResOperation(rop.CALL, [box], BoxInt(),
- calldescr), None)
+ calldescr))
assert len(regalloc.assembler.movs) == 3
#
mark = regalloc.get_mark_gc_roots(cpu.gc_ll_descr.gcrootmap)
Modified: pypy/branch/stringbuilder2/pypy/jit/backend/x86/test/test_recursive.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/jit/backend/x86/test/test_recursive.py (original)
+++ pypy/branch/stringbuilder2/pypy/jit/backend/x86/test/test_recursive.py Mon Jan 25 15:25:48 2010
@@ -3,4 +3,6 @@
from pypy.jit.backend.x86.test.test_basic import Jit386Mixin
class TestRecursive(Jit386Mixin, RecursiveTests):
+ # for the individual tests see
+ # ====> ../../../metainterp/test/test_recursive.py
pass
Modified: pypy/branch/stringbuilder2/pypy/jit/backend/x86/test/test_regalloc.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/jit/backend/x86/test/test_regalloc.py (original)
+++ pypy/branch/stringbuilder2/pypy/jit/backend/x86/test/test_regalloc.py Mon Jan 25 15:25:48 2010
@@ -9,7 +9,7 @@
from pypy.jit.backend.llsupport.descr import GcCache
from pypy.jit.backend.x86.runner import CPU
from pypy.jit.backend.x86.regalloc import RegAlloc, WORD, X86RegisterManager,\
- BASE_CONSTANT_SIZE
+ FloatConstants
from pypy.jit.metainterp.test.oparser import parse
from pypy.rpython.lltypesystem import lltype, llmemory, rffi
from pypy.rpython.annlowlevel import llhelper
@@ -28,6 +28,7 @@
class MockAssembler(object):
gcrefs = None
+ _float_constants = None
def __init__(self, cpu=None, gc_ll_descr=None):
self.movs = []
@@ -503,6 +504,7 @@
def test_float_overflow_const_list(self):
ops = ['[f0]']
+ BASE_CONSTANT_SIZE = FloatConstants.BASE_CONSTANT_SIZE
for i in range(BASE_CONSTANT_SIZE * 2):
ops.append('f%d = float_add(f%d, 3.5)' % (i + 1, i))
ops.append('finish(f%d)' % (BASE_CONSTANT_SIZE * 2))
Modified: pypy/branch/stringbuilder2/pypy/jit/backend/x86/test/test_runner.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/jit/backend/x86/test/test_runner.py (original)
+++ pypy/branch/stringbuilder2/pypy/jit/backend/x86/test/test_runner.py Mon Jan 25 15:25:48 2010
@@ -25,8 +25,8 @@
# for the individual tests see
# ====> ../../test/runner_test.py
- def setup_class(cls):
- cls.cpu = CPU(rtyper=None, stats=FakeStats())
+ def setup_method(self, meth):
+ self.cpu = CPU(rtyper=None, stats=FakeStats())
def test_execute_ptr_operation(self):
cpu = self.cpu
@@ -72,45 +72,41 @@
func = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_int)(f)
addr = ctypes.cast(func, ctypes.c_void_p).value
- try:
- saved_addr = self.cpu.assembler.malloc_func_addr
- self.cpu.assembler.malloc_func_addr = addr
- ofs = symbolic.get_field_token(rstr.STR, 'chars', False)[0]
-
- res = self.execute_operation(rop.NEWSTR, [ConstInt(7)], 'ref')
- assert allocs[0] == 7 + ofs + WORD
- resbuf = self._resbuf(res)
- assert resbuf[ofs/WORD] == 7
-
- # ------------------------------------------------------------
-
- res = self.execute_operation(rop.NEWSTR, [BoxInt(7)], 'ref')
- assert allocs[0] == 7 + ofs + WORD
- resbuf = self._resbuf(res)
- assert resbuf[ofs/WORD] == 7
-
- # ------------------------------------------------------------
-
- TP = lltype.GcArray(lltype.Signed)
- ofs = symbolic.get_field_token(TP, 'length', False)[0]
- descr = self.cpu.arraydescrof(TP)
-
- res = self.execute_operation(rop.NEW_ARRAY, [ConstInt(10)],
- 'ref', descr)
- assert allocs[0] == 10*WORD + ofs + WORD
- resbuf = self._resbuf(res)
- assert resbuf[ofs/WORD] == 10
-
- # ------------------------------------------------------------
-
- res = self.execute_operation(rop.NEW_ARRAY, [BoxInt(10)],
- 'ref', descr)
- assert allocs[0] == 10*WORD + ofs + WORD
- resbuf = self._resbuf(res)
- assert resbuf[ofs/WORD] == 10
-
- finally:
- self.cpu.assembler.malloc_func_addr = saved_addr
+ self.cpu.assembler.make_sure_mc_exists()
+ self.cpu.assembler.malloc_func_addr = addr
+ ofs = symbolic.get_field_token(rstr.STR, 'chars', False)[0]
+
+ res = self.execute_operation(rop.NEWSTR, [ConstInt(7)], 'ref')
+ assert allocs[0] == 7 + ofs + WORD
+ resbuf = self._resbuf(res)
+ assert resbuf[ofs/WORD] == 7
+
+ # ------------------------------------------------------------
+
+ res = self.execute_operation(rop.NEWSTR, [BoxInt(7)], 'ref')
+ assert allocs[0] == 7 + ofs + WORD
+ resbuf = self._resbuf(res)
+ assert resbuf[ofs/WORD] == 7
+
+ # ------------------------------------------------------------
+
+ TP = lltype.GcArray(lltype.Signed)
+ ofs = symbolic.get_field_token(TP, 'length', False)[0]
+ descr = self.cpu.arraydescrof(TP)
+
+ res = self.execute_operation(rop.NEW_ARRAY, [ConstInt(10)],
+ 'ref', descr)
+ assert allocs[0] == 10*WORD + ofs + WORD
+ resbuf = self._resbuf(res)
+ assert resbuf[ofs/WORD] == 10
+
+ # ------------------------------------------------------------
+
+ res = self.execute_operation(rop.NEW_ARRAY, [BoxInt(10)],
+ 'ref', descr)
+ assert allocs[0] == 10*WORD + ofs + WORD
+ resbuf = self._resbuf(res)
+ assert resbuf[ofs/WORD] == 10
def test_stringitems(self):
from pypy.rpython.lltypesystem.rstr import STR
@@ -317,9 +313,9 @@
class TestX86OverflowMC(TestX86):
- def setup_class(cls):
- cls.cpu = CPU(rtyper=None, stats=FakeStats())
- cls.cpu.assembler.mc_size = 1024
+ def setup_method(self, meth):
+ self.cpu = CPU(rtyper=None, stats=FakeStats())
+ self.cpu.assembler.mc_size = 1024
def test_overflow_mc(self):
ops = []
@@ -332,6 +328,7 @@
ops.append(ResOperation(rop.FINISH, [v], None,
descr=BasicFailDescr()))
looptoken = LoopToken()
+ self.cpu.assembler.make_sure_mc_exists()
old_mc_mc = self.cpu.assembler.mc._mc
self.cpu.compile_loop([base_v], ops, looptoken)
assert self.cpu.assembler.mc._mc != old_mc_mc # overflowed
Modified: pypy/branch/stringbuilder2/pypy/jit/backend/x86/test/test_tlc.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/jit/backend/x86/test/test_tlc.py (original)
+++ pypy/branch/stringbuilder2/pypy/jit/backend/x86/test/test_tlc.py Mon Jan 25 15:25:48 2010
@@ -1,6 +1,5 @@
import py
-py.test.skip("Widening to trash error")
from pypy.jit.backend.x86.test.test_basic import Jit386Mixin
from pypy.jit.metainterp.test.test_tlc import TLCTests
from pypy.jit.tl import tlc
@@ -10,6 +9,7 @@
# ====> ../../test/test_tlc.py
def test_accumulator(self):
+ py.test.skip("investigate, maybe")
path = py.path.local(tlc.__file__).dirpath('accumulator.tlc.src')
code = path.read()
res = self.exec_code(code, 20)
@@ -18,6 +18,7 @@
assert res == 10
def test_fib(self):
+ py.test.skip("investigate, maybe")
path = py.path.local(tlc.__file__).dirpath('fibo.tlc.src')
code = path.read()
res = self.exec_code(code, 7)
Modified: pypy/branch/stringbuilder2/pypy/jit/backend/x86/test/test_ztranslation.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/jit/backend/x86/test/test_ztranslation.py (original)
+++ pypy/branch/stringbuilder2/pypy/jit/backend/x86/test/test_ztranslation.py Mon Jan 25 15:25:48 2010
@@ -4,6 +4,7 @@
from pypy.jit.metainterp.jitprof import Profiler
from pypy.jit.backend.x86.runner import CPU386
from pypy.jit.backend.test.support import CCompiledMixin
+from pypy.jit.metainterp.policy import StopAtXPolicy
class TestTranslationX86(CCompiledMixin):
CPUClass = CPU386
@@ -94,3 +95,52 @@
return total * 10
res = self.meta_interp(main, [40])
assert res == main(40)
+
+ def test_direct_assembler_call_translates(self):
+ class Thing(object):
+ def __init__(self, val):
+ self.val = val
+
+ class Frame(object):
+ _virtualizable2_ = ['thing']
+
+ driver = JitDriver(greens = ['codeno'], reds = ['frame', 'i'],
+ virtualizables = ['frame'],
+ get_printable_location = lambda codeno : str(codeno),
+ can_inline = lambda codeno : False)
+ class SomewhereElse(object):
+ pass
+
+ somewhere_else = SomewhereElse()
+
+ def change(newthing):
+ somewhere_else.frame.thing = newthing
+
+ def main(codeno):
+ frame = Frame()
+ somewhere_else.frame = frame
+ frame.thing = Thing(0)
+ portal(codeno, frame)
+ return frame.thing.val
+
+ def portal(codeno, frame):
+ i = 0
+ while i < 10:
+ driver.can_enter_jit(frame=frame, codeno=codeno, i=i)
+ driver.jit_merge_point(frame=frame, codeno=codeno, i=i)
+ nextval = frame.thing.val
+ if codeno == 0:
+ subframe = Frame()
+ subframe.thing = Thing(nextval)
+ nextval = portal(1, subframe)
+ elif frame.thing.val > 40:
+ change(Thing(13))
+ nextval = 13
+ frame.thing = Thing(nextval + 1)
+ i += 1
+ return frame.thing.val
+
+ res = self.meta_interp(main, [0], inline=True,
+ policy=StopAtXPolicy(change))
+ assert res == main(0)
+
Modified: pypy/branch/stringbuilder2/pypy/jit/metainterp/codewriter.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/jit/metainterp/codewriter.py (original)
+++ pypy/branch/stringbuilder2/pypy/jit/metainterp/codewriter.py Mon Jan 25 15:25:48 2010
@@ -11,7 +11,7 @@
from pypy.tool.udir import udir
from pypy.translator.simplify import get_funcobj, get_functype
from pypy.translator.backendopt.canraise import RaiseAnalyzer
-from pypy.translator.backendopt.writeanalyze import WriteAnalyzer
+from pypy.translator.backendopt.writeanalyze import ReadWriteAnalyzer
from pypy.jit.metainterp.typesystem import deref, arrayItem, fieldType
from pypy.jit.metainterp.effectinfo import effectinfo_from_writeanalyze
from pypy.jit.metainterp.effectinfo import VirtualizableAnalyzer
@@ -86,12 +86,22 @@
if leave_graph is not None:
todo.append(leave_graph)
self.candidate_graphs = seen = set(todo)
+
+ def callers():
+ graph = top_graph
+ print graph
+ while graph in coming_from:
+ graph = coming_from[graph]
+ print '<-', graph
+ coming_from = {}
+
while todo:
top_graph = todo.pop()
for _, op in top_graph.iterblockops():
if op.opname not in ("direct_call", "indirect_call", "oosend"):
continue
kind = self.guess_call_kind(op, is_candidate)
+ # use callers() to view the calling chain in pdb
if kind != "regular":
continue
for graph in self.graphs_from(op, is_candidate):
@@ -100,6 +110,7 @@
assert is_candidate(graph)
todo.append(graph)
seen.add(graph)
+ coming_from[graph] = top_graph
return self.candidate_graphs
def graphs_from(self, op, is_candidate=None):
@@ -185,7 +196,7 @@
self.portal_runner_ptr = portal_runner_ptr
translator = self.rtyper.annotator.translator
self.raise_analyzer = RaiseAnalyzer(translator)
- self.write_analyzer = WriteAnalyzer(translator)
+ self.readwrite_analyzer = ReadWriteAnalyzer(translator)
self.virtualizable_analyzer = VirtualizableAnalyzer(translator)
def make_portal_bytecode(self, graph):
@@ -326,7 +337,7 @@
# ok
if consider_effects_of is not None:
effectinfo = effectinfo_from_writeanalyze(
- self.write_analyzer.analyze(consider_effects_of),
+ self.readwrite_analyzer.analyze(consider_effects_of),
self.cpu,
self.virtualizable_analyzer.analyze(consider_effects_of))
calldescr = self.cpu.calldescrof(FUNC, tuple(NON_VOID_ARGS), RESULT, effectinfo)
@@ -417,7 +428,6 @@
"""Generate a constant of the given value.
Returns its index in the list self.positions[].
"""
- if constvalue is _we_are_jitted: constvalue = True
const = Const._new(constvalue, self.cpu)
return self.get_position(const)
@@ -496,9 +506,22 @@
linkfalse, linktrue = block.exits
if linkfalse.llexitcase == True:
linkfalse, linktrue = linktrue, linkfalse
+ vpos = self.var_position(block.exitswitch)
+ #
+ # constant-fold an exitswitch
+ cv = self.get_constant_value(vpos)
+ if cv is not None:
+ if cv.value:
+ link = linktrue
+ else:
+ link = linkfalse
+ self.emit(*self.insert_renaming(link))
+ self.make_bytecode_block(link.target)
+ return
+ #
self.emit("goto_if_not",
tlabel(linkfalse),
- self.var_position(block.exitswitch))
+ vpos)
self.minimize_variables(argument_only=True, exitswitch=False)
truerenaming = self.insert_renaming(linktrue)
falserenaming = self.insert_renaming(linkfalse)
@@ -818,15 +841,21 @@
self.serialize_op_same_as(op)
def serialize_op_int_is_true(self, op):
- if isinstance(op.args[0], Constant):
- if op.args[0].value is objectmodel.malloc_zero_filled:
+ vpos = self.var_position(op.args[0])
+ cv = self.get_constant_value(vpos)
+ if cv is not None:
+ if cv.value is objectmodel.malloc_zero_filled:
# always True for now
warmrunnerdesc = self.codewriter.metainterp_sd.warmrunnerdesc
if warmrunnerdesc is not None:
assert warmrunnerdesc.gcdescr.malloc_zero_filled
self.var_positions[op.result] = self.var_position(Constant(1))
return
- self.emit('int_is_true', self.var_position(op.args[0]))
+ if cv.value is _we_are_jitted:
+ # always True
+ self.var_positions[op.result] = self.var_position(Constant(1))
+ return
+ self.emit('int_is_true', vpos)
self.register_var(op.result)
serialize_op_uint_is_true = serialize_op_int_is_true
@@ -1158,16 +1187,17 @@
self.var_position(op.args[3]))
def serialize_op_jit_marker(self, op):
- if op.args[0].value == 'jit_merge_point':
- assert self.portal, "jit_merge_point in non-main graph!"
- self.emit('jit_merge_point')
- assert ([self.var_position(i) for i in op.args[2:]] ==
- range(0, 2*(len(op.args) - 2), 2))
- #for i in range(2, len(op.args)):
- # arg = op.args[i]
- # self._eventualy_builtin(arg)
- elif op.args[0].value == 'can_enter_jit':
- self.emit('can_enter_jit')
+ key = op.args[0].value
+ getattr(self, 'handle_jit_marker__%s' % key)(op)
+
+ def handle_jit_marker__jit_merge_point(self, op):
+ assert self.portal, "jit_merge_point in non-main graph!"
+ self.emit('jit_merge_point')
+ assert ([self.var_position(i) for i in op.args[2:]] ==
+ range(0, 2*(len(op.args) - 2), 2))
+
+ def handle_jit_marker__can_enter_jit(self, op):
+ self.emit('can_enter_jit')
def serialize_op_direct_call(self, op):
kind = self.codewriter.guess_call_kind(op)
@@ -1205,21 +1235,26 @@
calldescr, non_void_args = self.codewriter.getcalldescr(
op.args[0], args, op.result, consider_effects_of=op)
pure = False
+ loopinvariant = False
if op.opname == "direct_call":
func = getattr(get_funcobj(op.args[0].value), '_callable', None)
pure = getattr(func, "_pure_function_", False)
+ loopinvariant = getattr(func, "_jit_loop_invariant_", False)
all_promoted_args = getattr(func,
"_pure_function_with_all_promoted_args_", False)
if pure and not all_promoted_args:
effectinfo = calldescr.get_extra_info()
assert (effectinfo is not None and
- not effectinfo.promotes_virtualizables)
+ not effectinfo.forces_virtual_or_virtualizable)
try:
canraise = self.codewriter.raise_analyzer.can_raise(op)
except lltype.DelayedPointer:
canraise = True # if we need to look into the delayed ptr that is
# the portal, then it's certainly going to raise
- if pure:
+ if loopinvariant:
+ self.emit("residual_call_loopinvariant")
+ assert not non_void_args, "arguments not supported for loop-invariant function!"
+ elif pure:
# XXX check what to do about exceptions (also MemoryError?)
self.emit('residual_call_pure')
elif canraise:
@@ -1279,6 +1314,9 @@
return self._do_builtin_call(op, oopspec_name, args)
def _do_builtin_call(self, op, oopspec_name, args):
+ if oopspec_name.startswith('virtual_ref'):
+ self.handle_virtual_ref_call(op, oopspec_name, args)
+ return
argtypes = [v.concretetype for v in args]
resulttype = op.result.concretetype
c_func, TP = support.builtin_func_for_spec(self.codewriter.rtyper,
@@ -1299,6 +1337,15 @@
self.emit_varargs([c_func] + non_void_args)
self.register_var(op.result)
+ def handle_virtual_ref_call(self, op, oopspec_name, args):
+ self.emit(oopspec_name) # 'virtual_ref' or 'virtual_ref_finish'
+ self.emit(self.var_position(args[0]))
+ self.register_var(op.result)
+ #
+ vrefinfo = self.codewriter.metainterp_sd.virtualref_info
+ self.codewriter.register_known_gctype(vrefinfo.jit_virtual_ref_vtable,
+ vrefinfo.JIT_VIRTUAL_REF)
+
def _array_of_voids(self, ARRAY):
if isinstance(ARRAY, ootype.Array):
return ARRAY.ITEM == ootype.Void
@@ -1557,12 +1604,15 @@
log.WARNING("found debug_assert in %r; should have be removed" %
(self.graph,))
- def serialize_op_promote_virtualizable(self, op):
+ def serialize_op_jit_force_virtualizable(self, op):
vinfo = self.codewriter.metainterp_sd.virtualizable_info
assert vinfo is not None
assert vinfo.is_vtypeptr(op.args[0].concretetype)
self.vable_flags[op.args[0]] = op.args[2].value
+ def serialize_op_jit_force_virtual(self, op):
+ self._do_builtin_call(op, 'jit_force_virtual', op.args)
+
serialize_op_oostring = handle_builtin_call
serialize_op_oounicode = handle_builtin_call
serialize_op_gc_identityhash = handle_builtin_call
@@ -1596,6 +1646,14 @@
raise VirtualizableArrayField(self.graph)
raise
+ def get_constant_value(self, vpos):
+ """Reverse of var_position(). Returns either None or a Constant."""
+ if vpos & 1:
+ value = self.constants[vpos // 2].value
+ return Constant(value)
+ else:
+ return None
+
def emit(self, *stuff):
self.assembler.extend(stuff)
Modified: pypy/branch/stringbuilder2/pypy/jit/metainterp/compile.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/jit/metainterp/compile.py (original)
+++ pypy/branch/stringbuilder2/pypy/jit/metainterp/compile.py Mon Jan 25 15:25:48 2010
@@ -54,9 +54,11 @@
for box in loop.inputargs:
assert isinstance(box, Box)
if start > 0:
- loop.operations = history.operations[start:]
+ ops = history.operations[start:]
else:
- loop.operations = history.operations
+ ops = history.operations
+ # make a copy, because optimize_loop can mutate the ops and descrs
+ loop.operations = [op.clone() for op in ops]
metainterp_sd = metainterp.staticdata
loop_token = make_loop_token(len(loop.inputargs))
loop.token = loop_token
@@ -203,10 +205,18 @@
class ResumeDescr(AbstractFailDescr):
def __init__(self, original_greenkey):
self.original_greenkey = original_greenkey
+ def _clone_if_mutable(self):
+ raise NotImplementedError
class ResumeGuardDescr(ResumeDescr):
counter = 0
- # this class also gets attributes stored by resume.py code
+ # this class also gets the following attributes stored by resume.py code
+ rd_snapshot = None
+ rd_frame_info_list = None
+ rd_numb = None
+ rd_consts = None
+ rd_virtuals = None
+ rd_pendingfields = None
def __init__(self, metainterp_sd, original_greenkey):
ResumeDescr.__init__(self, original_greenkey)
@@ -231,29 +241,67 @@
new_loop.operations)
+ def _clone_if_mutable(self):
+ res = self.__class__(self.metainterp_sd, self.original_greenkey)
+ # XXX a bit ugly to have to list them all here
+ res.rd_snapshot = self.rd_snapshot
+ res.rd_frame_info_list = self.rd_frame_info_list
+ res.rd_numb = self.rd_numb
+ res.rd_consts = self.rd_consts
+ res.rd_virtuals = self.rd_virtuals
+ res.rd_pendingfields = self.rd_pendingfields
+ return res
+
class ResumeGuardForcedDescr(ResumeGuardDescr):
def handle_fail(self, metainterp_sd):
from pypy.jit.metainterp.pyjitpl import MetaInterp
metainterp = MetaInterp(metainterp_sd)
token = metainterp_sd.cpu.get_latest_force_token()
- data = self.fetch_data(token)
- if data is None:
- data = []
- metainterp._already_allocated_resume_virtuals = data
+ all_virtuals = self.fetch_data(token)
+ if all_virtuals is None:
+ all_virtuals = []
+ metainterp._already_allocated_resume_virtuals = all_virtuals
self.counter = -2 # never compile
return metainterp.handle_guard_failure(self)
- def force_virtualizable(self, vinfo, virtualizable, force_token):
+ @staticmethod
+ def force_now(cpu, token):
+ # Called during a residual call from the assembler, if the code
+ # actually needs to force one of the virtualrefs or the virtualizable.
+ # Implemented by forcing *all* virtualrefs and the virtualizable.
+ faildescr = cpu.force(token)
+ assert isinstance(faildescr, ResumeGuardForcedDescr)
+ faildescr.handle_async_forcing(token)
+
+ def handle_async_forcing(self, force_token):
from pypy.jit.metainterp.pyjitpl import MetaInterp
from pypy.jit.metainterp.resume import force_from_resumedata
- metainterp = MetaInterp(self.metainterp_sd)
+ # To handle the forcing itself, we create a temporary MetaInterp
+ # as a convenience to move the various data to its proper place.
+ metainterp_sd = self.metainterp_sd
+ metainterp = MetaInterp(metainterp_sd)
metainterp.history = None # blackholing
- liveboxes = metainterp.cpu.make_boxes_from_latest_values(self)
- virtualizable_boxes, data = force_from_resumedata(metainterp,
- liveboxes, self)
- vinfo.write_boxes(virtualizable, virtualizable_boxes)
- self.save_data(force_token, data)
+ liveboxes = metainterp_sd.cpu.make_boxes_from_latest_values(self)
+ #
+ expect_virtualizable = metainterp_sd.virtualizable_info is not None
+ forced_data = force_from_resumedata(metainterp, liveboxes, self,
+ expect_virtualizable)
+ virtualizable_boxes, virtualref_boxes, all_virtuals = forced_data
+ #
+ # Handle virtualref_boxes: mark each JIT_VIRTUAL_REF as forced
+ vrefinfo = metainterp_sd.virtualref_info
+ for i in range(0, len(virtualref_boxes), 2):
+ virtualbox = virtualref_boxes[i]
+ vrefbox = virtualref_boxes[i+1]
+ vrefinfo.forced_single_vref(vrefbox.getref_base(),
+ virtualbox.getref_base())
+ # Handle virtualizable_boxes: store them on the real virtualizable now
+ if expect_virtualizable:
+ metainterp_sd.virtualizable_info.forced_vable(virtualizable_boxes)
+ # Handle all_virtuals: keep them for later blackholing from the
+ # future failure of the GUARD_NOT_FORCED
+ self.save_data(force_token, all_virtuals)
def save_data(self, key, value):
globaldata = self.metainterp_sd.globaldata
@@ -309,13 +357,16 @@
# it does not work -- i.e. none of the existing old_loop_tokens match.
new_loop = create_empty_loop(metainterp)
new_loop.inputargs = metainterp.history.inputargs
- new_loop.operations = metainterp.history.operations
+ # clone ops, as optimize_bridge can mutate the ops
+ new_loop.operations = [op.clone() for op in metainterp.history.operations]
metainterp_sd = metainterp.staticdata
try:
target_loop_token = metainterp_sd.state.optimize_bridge(metainterp_sd,
old_loop_tokens,
new_loop)
except InvalidLoop:
+ # XXX I am fairly convinced that optimize_bridge cannot actually raise
+ # InvalidLoop
return None
# Did it work?
if target_loop_token is not None:
Modified: pypy/branch/stringbuilder2/pypy/jit/metainterp/effectinfo.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/jit/metainterp/effectinfo.py (original)
+++ pypy/branch/stringbuilder2/pypy/jit/metainterp/effectinfo.py Mon Jan 25 15:25:48 2010
@@ -7,44 +7,62 @@
class EffectInfo(object):
_cache = {}
- def __new__(cls, write_descrs_fields, write_descrs_arrays,
- promotes_virtualizables=False):
- key = (frozenset(write_descrs_fields), frozenset(write_descrs_arrays),
- promotes_virtualizables)
+ def __new__(cls, readonly_descrs_fields,
+ write_descrs_fields, write_descrs_arrays,
+ forces_virtual_or_virtualizable=False):
+ key = (frozenset(readonly_descrs_fields),
+ frozenset(write_descrs_fields),
+ frozenset(write_descrs_arrays),
+ forces_virtual_or_virtualizable)
if key in cls._cache:
return cls._cache[key]
result = object.__new__(cls)
+ result.readonly_descrs_fields = readonly_descrs_fields
result.write_descrs_fields = write_descrs_fields
result.write_descrs_arrays = write_descrs_arrays
- result.promotes_virtualizables = promotes_virtualizables
+ result.forces_virtual_or_virtualizable= forces_virtual_or_virtualizable
cls._cache[key] = result
return result
-def effectinfo_from_writeanalyze(effects, cpu, promotes_virtualizables=False):
+def effectinfo_from_writeanalyze(effects, cpu,
+ forces_virtual_or_virtualizable=False):
from pypy.translator.backendopt.writeanalyze import top_set
if effects is top_set:
return None
+ readonly_descrs_fields = []
+ # readonly_descrs_arrays = [] --- not enabled for now
write_descrs_fields = []
write_descrs_arrays = []
+
+ def add_struct(descrs_fields, (_, T, fieldname)):
+ T = deref(T)
+ if consider_struct(T, fieldname):
+ descr = cpu.fielddescrof(T, fieldname)
+ descrs_fields.append(descr)
+
+ def add_array(descrs_arrays, (_, T)):
+ ARRAY = deref(T)
+ if consider_array(ARRAY):
+ descr = cpu.arraydescrof(ARRAY)
+ descrs_arrays.append(descr)
+
for tup in effects:
if tup[0] == "struct":
- _, T, fieldname = tup
- T = deref(T)
- if not consider_struct(T, fieldname):
- continue
- descr = cpu.fielddescrof(T, fieldname)
- write_descrs_fields.append(descr)
+ add_struct(write_descrs_fields, tup)
+ elif tup[0] == "readstruct":
+ tupw = ("struct",) + tup[1:]
+ if tupw not in effects:
+ add_struct(readonly_descrs_fields, tup)
elif tup[0] == "array":
- _, T = tup
- ARRAY = deref(T)
- if not consider_array(ARRAY):
- continue
- descr = cpu.arraydescrof(ARRAY)
- write_descrs_arrays.append(descr)
+ add_array(write_descrs_arrays, tup)
+ elif tup[0] == "readarray":
+ pass
else:
assert 0
- return EffectInfo(write_descrs_fields, write_descrs_arrays,
- promotes_virtualizables)
+ return EffectInfo(readonly_descrs_fields,
+ write_descrs_fields,
+ write_descrs_arrays,
+ forces_virtual_or_virtualizable)
def consider_struct(TYPE, fieldname):
if fieldType(TYPE, fieldname) is lltype.Void:
@@ -73,4 +91,5 @@
class VirtualizableAnalyzer(BoolGraphAnalyzer):
def analyze_simple_operation(self, op):
- return op.opname == 'promote_virtualizable'
+ return op.opname in ('jit_force_virtualizable',
+ 'jit_force_virtual')
Modified: pypy/branch/stringbuilder2/pypy/jit/metainterp/executor.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/jit/metainterp/executor.py (original)
+++ pypy/branch/stringbuilder2/pypy/jit/metainterp/executor.py Mon Jan 25 15:25:48 2010
@@ -6,7 +6,7 @@
from pypy.rpython.ootypesystem import ootype
from pypy.rpython.lltypesystem.lloperation import llop
from pypy.rlib.rarithmetic import ovfcheck, r_uint, intmask
-from pypy.jit.metainterp.history import BoxInt, ConstInt, check_descr
+from pypy.jit.metainterp.history import BoxInt, BoxPtr, ConstInt, check_descr
from pypy.jit.metainterp.history import INT, REF, ConstFloat
from pypy.jit.metainterp import resoperation
from pypy.jit.metainterp.resoperation import rop
@@ -220,6 +220,15 @@
# ____________________________________________________________
+def do_force_token(cpu):
+ raise NotImplementedError
+
+def do_virtual_ref(cpu, box1, box2):
+ raise NotImplementedError
+
+def do_virtual_ref_finish(cpu, box1, box2):
+ raise NotImplementedError
+
def do_debug_merge_point(cpu, box1):
from pypy.jit.metainterp.warmspot import get_stats
loc = box1._get_str()
Modified: pypy/branch/stringbuilder2/pypy/jit/metainterp/history.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/jit/metainterp/history.py (original)
+++ pypy/branch/stringbuilder2/pypy/jit/metainterp/history.py Mon Jan 25 15:25:48 2010
@@ -122,6 +122,9 @@
def repr_of_descr(self):
return '%r' % (self,)
+ def _clone_if_mutable(self):
+ return self
+
class AbstractFailDescr(AbstractDescr):
index = -1
@@ -802,15 +805,30 @@
class History(object):
- def __init__(self, cpu):
- self.cpu = cpu
+ def __init__(self):
self.inputargs = None
self.operations = []
+
def record(self, opnum, argboxes, resbox, descr=None):
op = ResOperation(opnum, argboxes, resbox, descr)
self.operations.append(op)
return op
+ def substitute_operation(self, position, opnum, argboxes, descr=None):
+ resbox = self.operations[position].result
+ op = ResOperation(opnum, argboxes, resbox, descr)
+ self.operations[position] = op
+
+ def slice_history_at(self, position):
+ """ a strange function that does this:
+ history : operation_at_position : rest
+ it'll kill operation_at_position, store everything before that
+ in history.operations and return rest
+ """
+ rest = self.operations[position + 1:]
+ del self.operations[position:]
+ return rest
+
# ____________________________________________________________
@@ -926,10 +944,6 @@
loops.append(loop)
display_loops(loops, errmsg, extraloops)
-
-class CrashInJIT(Exception):
- pass
-
# ----------------------------------------------------------------
class Options:
Modified: pypy/branch/stringbuilder2/pypy/jit/metainterp/jitprof.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/jit/metainterp/jitprof.py (original)
+++ pypy/branch/stringbuilder2/pypy/jit/metainterp/jitprof.py Mon Jan 25 15:25:48 2010
@@ -20,6 +20,7 @@
OPT_FORCINGS
ABORT_TOO_LONG
ABORT_BRIDGE
+ABORT_ESCAPE
NVIRTUALS
NVHOLES
NVREUSED
@@ -176,8 +177,9 @@
self._print_intline("opt ops", cnt[OPT_OPS])
self._print_intline("opt guards", cnt[OPT_GUARDS])
self._print_intline("forcings", cnt[OPT_FORCINGS])
- self._print_intline("trace too long", cnt[ABORT_TOO_LONG])
- self._print_intline("bridge abort", cnt[ABORT_BRIDGE])
+ self._print_intline("abort: trace too long", cnt[ABORT_TOO_LONG])
+ self._print_intline("abort: compiling", cnt[ABORT_BRIDGE])
+ self._print_intline("abort: vable escape", cnt[ABORT_ESCAPE])
self._print_intline("nvirtuals", cnt[NVIRTUALS])
self._print_intline("nvholes", cnt[NVHOLES])
self._print_intline("nvreused", cnt[NVREUSED])
Modified: pypy/branch/stringbuilder2/pypy/jit/metainterp/optimizeopt.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/jit/metainterp/optimizeopt.py (original)
+++ pypy/branch/stringbuilder2/pypy/jit/metainterp/optimizeopt.py Mon Jan 25 15:25:48 2010
@@ -11,7 +11,7 @@
from pypy.jit.metainterp.specnode import VirtualStructSpecNode
from pypy.jit.metainterp.optimizeutil import _findall, sort_descrs
from pypy.jit.metainterp.optimizeutil import descrlist_dict
-from pypy.jit.metainterp.optimizeutil import InvalidLoop
+from pypy.jit.metainterp.optimizeutil import InvalidLoop, args_dict
from pypy.jit.metainterp import resume, compile
from pypy.jit.metainterp.typesystem import llhelper, oohelper
from pypy.rlib.objectmodel import we_are_translated
@@ -161,18 +161,18 @@
return self.box
def make_virtual_info(self, modifier, fieldnums):
- vinfo = self._cached_vinfo
- if vinfo is not None and resume.tagged_list_eq(
- vinfo.fieldnums, fieldnums):
+ vinfo = self._cached_vinfo
+ if vinfo is not None and vinfo.equals(fieldnums):
return vinfo
vinfo = self._make_virtual(modifier)
- vinfo.fieldnums = fieldnums
+ vinfo.set_content(fieldnums)
self._cached_vinfo = vinfo
return vinfo
def _make_virtual(self, modifier):
raise NotImplementedError("abstract base")
+
def get_fielddescrlist_cache(cpu):
if not hasattr(cpu, '_optimizeopt_fielddescrlist_cache'):
result = descrlist_dict()
@@ -207,6 +207,8 @@
iteritems = list(iteritems)
iteritems.sort(key = lambda (x,y): x.sort_key())
for ofs, value in iteritems:
+ if value.is_null():
+ continue
subbox = value.force_box()
op = ResOperation(rop.SETFIELD_GC, [box, subbox], None,
descr=ofs)
@@ -234,7 +236,6 @@
def get_args_for_fail(self, modifier):
if self.box is None and not modifier.already_seen_virtual(self.keybox):
- # modifier.already_seen_virtual()
# checks for recursion: it is False unless
# we have already seen the very same keybox
lst = self._get_field_descr_list()
@@ -294,6 +295,8 @@
for index in range(len(self._items)):
subvalue = self._items[index]
if subvalue is not self.constvalue:
+ if subvalue.is_null():
+ continue
subbox = subvalue.force_box()
op = ResOperation(rop.SETARRAYITEM_GC,
[box, ConstInt(index), subbox], None,
@@ -302,11 +305,9 @@
def get_args_for_fail(self, modifier):
if self.box is None and not modifier.already_seen_virtual(self.keybox):
- # modifier.already_seen_virtual()
# checks for recursion: it is False unless
# we have already seen the very same keybox
itemboxes = []
- const = self.optimizer.new_const_item(self.arraydescr)
for itemvalue in self._items:
itemboxes.append(itemvalue.get_key_box())
modifier.register_virtual_fields(self.keybox, itemboxes)
@@ -387,6 +388,8 @@
self.resumedata_memo = resume.ResumeDataLoopMemo(metainterp_sd)
self.heap_op_optimizer = HeapOpOptimizer(self)
self.bool_boxes = {}
+ self.loop_invariant_results = {}
+ self.pure_operations = args_dict()
def forget_numberings(self, virtualbox):
self.metainterp_sd.profiler.count(jitprof.OPT_FORCINGS)
@@ -513,17 +516,16 @@
# accumulate counters
self.resumedata_memo.update_counters(self.metainterp_sd.profiler)
- def emit_operation(self, op, must_clone=True):
+ def emit_operation(self, op):
self.heap_op_optimizer.emitting_operation(op)
+ self._emit_operation(op)
+
+ def _emit_operation(self, op):
for i in range(len(op.args)):
arg = op.args[i]
if arg in self.values:
box = self.values[arg].force_box()
- if box is not arg:
- if must_clone:
- op = op.clone()
- must_clone = False
- op.args[i] = box
+ op.args[i] = box
self.metainterp_sd.profiler.count(jitprof.OPT_OPS)
if op.is_guard():
self.metainterp_sd.profiler.count(jitprof.OPT_GUARDS)
@@ -535,10 +537,11 @@
self.newoperations.append(op)
def store_final_boxes_in_guard(self, op):
+ pendingfields = self.heap_op_optimizer.force_lazy_setfields_for_guard()
descr = op.descr
assert isinstance(descr, compile.ResumeGuardDescr)
modifier = resume.ResumeDataVirtualAdder(descr, self.resumedata_memo)
- newboxes = modifier.finish(self.values)
+ newboxes = modifier.finish(self.values, pendingfields)
if len(newboxes) > self.metainterp_sd.options.failargs_limit: # XXX be careful here
raise compile.GiveUp
descr.store_final_boxes(op, newboxes)
@@ -569,6 +572,23 @@
resbox = execute_nonspec(self.cpu, op.opnum, argboxes, op.descr)
self.make_constant(op.result, resbox.constbox())
return
+
+ if op.descr is None:
+ # did we do the exact same operation already?
+ args = op.args[:]
+ for i in range(len(args)):
+ arg = args[i]
+ if arg in self.values:
+ args[i] = self.values[arg].get_key_box()
+ args.append(ConstInt(op.opnum))
+ oldop = self.pure_operations.get(args, None)
+ if oldop is not None:
+ assert oldop.opnum == op.opnum
+ self.make_equal_to(op.result, self.getvalue(oldop.result))
+ return
+ else:
+ self.pure_operations[args] = op
+
# otherwise, the operation remains
self.emit_operation(op)
@@ -582,9 +602,8 @@
for i in range(len(specnodes)):
value = self.getvalue(op.args[i])
specnodes[i].teardown_virtual_node(self, value, exitargs)
- op2 = op.clone()
- op2.args = exitargs[:]
- self.emit_operation(op2, must_clone=False)
+ op.args = exitargs[:]
+ self.emit_operation(op)
def optimize_guard(self, op, constbox, emit_operation=True):
value = self.getvalue(op.args[0])
@@ -699,7 +718,7 @@
elif value.is_null():
self.make_constant_int(op.result, not expect_nonnull)
else:
- self.emit_operation(op)
+ self.optimize_default(op)
def optimize_INT_IS_TRUE(self, op):
self._optimize_nullness(op, op.args[0], True)
@@ -736,6 +755,49 @@
def optimize_OOIS(self, op):
self._optimize_oois_ooisnot(op, False)
+ def optimize_VIRTUAL_REF(self, op):
+ indexbox = op.args[1]
+ #
+ # get some constants
+ vrefinfo = self.metainterp_sd.virtualref_info
+ c_cls = vrefinfo.jit_virtual_ref_const_class
+ descr_virtual_token = vrefinfo.descr_virtual_token
+ descr_virtualref_index = vrefinfo.descr_virtualref_index
+ #
+ # Replace the VIRTUAL_REF operation with a virtual structure of type
+ # 'jit_virtual_ref'. The jit_virtual_ref structure may be forced soon,
+ # but the point is that doing so does not force the original structure.
+ op = ResOperation(rop.NEW_WITH_VTABLE, [c_cls], op.result)
+ vrefvalue = self.make_virtual(c_cls, op.result, op)
+ tokenbox = BoxInt()
+ self.emit_operation(ResOperation(rop.FORCE_TOKEN, [], tokenbox))
+ vrefvalue.setfield(descr_virtual_token, self.getvalue(tokenbox))
+ vrefvalue.setfield(descr_virtualref_index, self.getvalue(indexbox))
+
+ def optimize_VIRTUAL_REF_FINISH(self, op):
+ # Set the 'forced' field of the virtual_ref.
+ # In good cases, this is all virtual, so has no effect.
+ # Otherwise, this forces the real object -- but only now, as
+ # opposed to much earlier. This is important because the object is
+ # typically a PyPy PyFrame, and now is the end of its execution, so
+ # forcing it now does not have catastrophic effects.
+ vrefinfo = self.metainterp_sd.virtualref_info
+ # - set 'forced' to point to the real object
+ op1 = ResOperation(rop.SETFIELD_GC, op.args, None,
+ descr = vrefinfo.descr_forced)
+ self.optimize_SETFIELD_GC(op1)
+ # - set 'virtual_token' to TOKEN_NONE
+ args = [op.args[0], ConstInt(0)]
+ op1 = ResOperation(rop.SETFIELD_GC, args, None,
+ descr = vrefinfo.descr_virtual_token)
+ self.optimize_SETFIELD_GC(op1)
+ # Note that in some cases the virtual in op.args[1] has been forced
+ # already. This is fine. In that case, and *if* a residual
+ # CALL_MAY_FORCE suddenly turns out to access it, then it will
+ # trigger a ResumeGuardForcedDescr.handle_async_forcing() which
+ # will work too (but just be a little pointless, as the structure
+ # was already forced).
+
def optimize_GETFIELD_GC(self, op):
value = self.getvalue(op.args[0])
if value.is_virtual():
@@ -753,11 +815,11 @@
def optimize_SETFIELD_GC(self, op):
value = self.getvalue(op.args[0])
+ fieldvalue = self.getvalue(op.args[1])
if value.is_virtual():
- value.setfield(op.descr, self.getvalue(op.args[1]))
+ value.setfield(op.descr, fieldvalue)
else:
value.ensure_nonnull()
- fieldvalue = self.getvalue(op.args[1])
self.heap_op_optimizer.optimize_SETFIELD_GC(op, value, fieldvalue)
def optimize_NEW_WITH_VTABLE(self, op):
@@ -826,6 +888,23 @@
def optimize_DEBUG_MERGE_POINT(self, op):
self.emit_operation(op)
+ def optimize_CALL_LOOPINVARIANT(self, op):
+ funcvalue = self.getvalue(op.args[0])
+ if not funcvalue.is_constant():
+ self.optimize_default(op)
+ return
+ resvalue = self.loop_invariant_results.get(op.args[0].getint(), None)
+ if resvalue is not None:
+ self.make_equal_to(op.result, resvalue)
+ return
+ # change the op to be a normal call, from the backend's point of view
+ # there is no reason to have a separate operation for this
+ op.opnum = rop.CALL
+ self.optimize_default(op)
+ resvalue = self.getvalue(op.result)
+ self.loop_invariant_results[op.args[0].getint()] = resvalue
+
+
optimize_ops = _findall(Optimizer, 'optimize_')
@@ -839,11 +918,13 @@
class HeapOpOptimizer(object):
def __init__(self, optimizer):
self.optimizer = optimizer
- # cached OptValues for each field descr
+ # cached fields: {descr: {OptValue_instance: OptValue_fieldvalue}}
self.cached_fields = {}
-
- # cached OptValues for each field descr
+ # cached array items: {descr: CachedArrayItems}
self.cached_arrayitems = {}
+ # lazily written setfields (at most one per descr): {descr: op}
+ self.lazy_setfields = {}
+ self.lazy_setfields_descrs = [] # keys (at least) of previous dict
def clean_caches(self):
self.cached_fields.clear()
@@ -851,15 +932,23 @@
def cache_field_value(self, descr, value, fieldvalue, write=False):
if write:
+ # when seeing a setfield, we have to clear the cache for the same
+ # field on any other structure, just in case they are aliasing
+ # each other
d = self.cached_fields[descr] = {}
else:
d = self.cached_fields.setdefault(descr, {})
d[value] = fieldvalue
def read_cached_field(self, descr, value):
+ # XXX self.cached_fields and self.lazy_setfields should probably
+ # be merged somehow
d = self.cached_fields.get(descr, None)
if d is None:
- return None
+ op = self.lazy_setfields.get(descr, None)
+ if op is None:
+ return None
+ return self.optimizer.getvalue(op.args[1])
return d.get(value, None)
def cache_arrayitem_value(self, descr, value, indexvalue, fieldvalue, write=False):
@@ -908,8 +997,6 @@
return None
def emitting_operation(self, op):
- if op.is_always_pure():
- return
if op.has_no_side_effect():
return
if op.is_ovf():
@@ -921,10 +1008,20 @@
opnum == rop.SETARRAYITEM_GC or
opnum == rop.DEBUG_MERGE_POINT):
return
- if opnum == rop.CALL:
- effectinfo = op.descr.get_extra_info()
+ if (opnum == rop.CALL or
+ opnum == rop.CALL_MAY_FORCE or
+ opnum == rop.CALL_ASSEMBLER):
+ if opnum == rop.CALL_ASSEMBLER:
+ effectinfo = None
+ else:
+ effectinfo = op.descr.get_extra_info()
if effectinfo is not None:
+ # XXX we can get the wrong complexity here, if the lists
+ # XXX stored on effectinfo are large
+ for fielddescr in effectinfo.readonly_descrs_fields:
+ self.force_lazy_setfield(fielddescr)
for fielddescr in effectinfo.write_descrs_fields:
+ self.force_lazy_setfield(fielddescr)
try:
del self.cached_fields[fielddescr]
except KeyError:
@@ -935,9 +1032,73 @@
except KeyError:
pass
return
+ self.force_all_lazy_setfields()
+ elif op.is_final() or (not we_are_translated() and
+ op.opnum < 0): # escape() operations
+ self.force_all_lazy_setfields()
self.clean_caches()
+ def force_lazy_setfield(self, descr, before_guard=False):
+ try:
+ op = self.lazy_setfields[descr]
+ except KeyError:
+ return
+ del self.lazy_setfields[descr]
+ self.optimizer._emit_operation(op)
+ #
+ # hackish: reverse the order of the last two operations if it makes
+ # sense to avoid a situation like "int_eq/setfield_gc/guard_true",
+ # which the backend (at least the x86 backend) does not handle well.
+ newoperations = self.optimizer.newoperations
+ if before_guard and len(newoperations) >= 2:
+ lastop = newoperations[-1]
+ prevop = newoperations[-2]
+ # - is_comparison() for cases like "int_eq/setfield_gc/guard_true"
+ # - CALL_MAY_FORCE: "call_may_force/setfield_gc/guard_not_forced"
+ if ((prevop.is_comparison() or prevop.opnum == rop.CALL_MAY_FORCE)
+ and prevop.result not in lastop.args):
+ newoperations[-2] = lastop
+ newoperations[-1] = prevop
+
+ def force_all_lazy_setfields(self):
+ if len(self.lazy_setfields_descrs) > 0:
+ for descr in self.lazy_setfields_descrs:
+ self.force_lazy_setfield(descr)
+ del self.lazy_setfields_descrs[:]
+
+ def force_lazy_setfields_for_guard(self):
+ pendingfields = []
+ for descr in self.lazy_setfields_descrs:
+ try:
+ op = self.lazy_setfields[descr]
+ except KeyError:
+ continue
+ # the only really interesting case that we need to handle in the
+ # guards' resume data is that of a virtual object that is stored
+ # into a field of a non-virtual object.
+ value = self.optimizer.getvalue(op.args[0])
+ assert not value.is_virtual() # it must be a non-virtual
+ fieldvalue = self.optimizer.getvalue(op.args[1])
+ if fieldvalue.is_virtual():
+ # this is the case that we leave to resume.py
+ pendingfields.append((descr, value.box,
+ fieldvalue.get_key_box()))
+ else:
+ self.force_lazy_setfield(descr, before_guard=True)
+ return pendingfields
+
+ def force_lazy_setfield_if_necessary(self, op, value, write=False):
+ try:
+ op1 = self.lazy_setfields[op.descr]
+ except KeyError:
+ if write:
+ self.lazy_setfields_descrs.append(op.descr)
+ else:
+ if self.optimizer.getvalue(op1.args[0]) is not value:
+ self.force_lazy_setfield(op.descr)
+
def optimize_GETFIELD_GC(self, op, value):
+ self.force_lazy_setfield_if_necessary(op, value)
# check if the field was read from another getfield_gc just before
# or has been written to recently
fieldvalue = self.read_cached_field(op.descr, value)
@@ -952,7 +1113,8 @@
self.cache_field_value(op.descr, value, fieldvalue)
def optimize_SETFIELD_GC(self, op, value, fieldvalue):
- self.optimizer.emit_operation(op)
+ self.force_lazy_setfield_if_necessary(op, value, write=True)
+ self.lazy_setfields[op.descr] = op
# remember the result of future reads of the field
self.cache_field_value(op.descr, value, fieldvalue, write=True)
Modified: pypy/branch/stringbuilder2/pypy/jit/metainterp/optimizeutil.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/jit/metainterp/optimizeutil.py (original)
+++ pypy/branch/stringbuilder2/pypy/jit/metainterp/optimizeutil.py Mon Jan 25 15:25:48 2010
@@ -1,7 +1,7 @@
from pypy.rlib.objectmodel import r_dict, compute_identity_hash
from pypy.rlib.rarithmetic import intmask
from pypy.rlib.unroll import unrolling_iterable
-from pypy.jit.metainterp import resoperation
+from pypy.jit.metainterp import resoperation, history
class InvalidLoop(Exception):
"""Raised when the optimize*.py detect that the loop that
@@ -59,3 +59,35 @@
def descrlist_dict():
return r_dict(descrlist_eq, descrlist_hash)
+# ____________________________________________________________
+
+def args_eq(args1, args2):
+ if len(args1) != len(args2):
+ return False
+ for i in range(len(args1)):
+ arg1 = args1[i]
+ arg2 = args2[i]
+ if isinstance(arg1, history.Const):
+ if arg1.__class__ is not arg2.__class__:
+ return False
+ if not arg1.same_constant(arg2):
+ return False
+ else:
+ if not arg1 is arg2:
+ return False
+ return True
+
+def args_hash(args):
+ res = 0x345678
+ for arg in args:
+ if isinstance(arg, history.Const):
+ y = arg._get_hash_()
+ else:
+ y = compute_identity_hash(arg)
+ res = intmask((1000003 * res) ^ y)
+ return res
+
+def args_dict():
+ return r_dict(args_eq, args_hash)
+
+
Modified: pypy/branch/stringbuilder2/pypy/jit/metainterp/policy.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/jit/metainterp/policy.py (original)
+++ pypy/branch/stringbuilder2/pypy/jit/metainterp/policy.py Mon Jan 25 15:25:48 2010
@@ -49,8 +49,6 @@
def look_inside_graph(self, graph):
from pypy.translator.backendopt.support import find_backedges
contains_loop = bool(find_backedges(graph))
- unsupported = contains_unsupported_variable_type(graph,
- self.supports_floats)
try:
func = graph.func
except AttributeError:
@@ -61,7 +59,8 @@
contains_loop = contains_loop and not getattr(
func, '_jit_unroll_safe_', False)
- res = see_function and not unsupported
+ res = see_function and not contains_unsupported_variable_type(graph,
+ self.supports_floats)
if res and contains_loop:
self.unsafe_loopy_graphs.add(graph)
return res and not contains_loop
Modified: pypy/branch/stringbuilder2/pypy/jit/metainterp/pyjitpl.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/jit/metainterp/pyjitpl.py (original)
+++ pypy/branch/stringbuilder2/pypy/jit/metainterp/pyjitpl.py Mon Jan 25 15:25:48 2010
@@ -11,7 +11,7 @@
from pypy.jit.metainterp import codewriter, executor
from pypy.jit.metainterp.logger import Logger
from pypy.jit.metainterp.jitprof import BLACKHOLED_OPS, EmptyProfiler
-from pypy.jit.metainterp.jitprof import GUARDS, RECORDED_OPS
+from pypy.jit.metainterp.jitprof import GUARDS, RECORDED_OPS, ABORT_ESCAPE
from pypy.jit.metainterp.jitprof import ABORT_TOO_LONG, ABORT_BRIDGE
from pypy.rlib.rarithmetic import intmask
from pypy.rlib.objectmodel import specialize
@@ -42,16 +42,10 @@
argtypes = unrolling_iterable(self.argtypes)
def wrapped(self, orgpc):
args = (self, )
- #if DEBUG >= DEBUG_DETAILED:
- # s = '%s:%d\t%s' % (self.jitcode.name, orgpc, name)
- #else:
- s = ''
for argspec in argtypes:
if argspec == "box":
box = self.load_arg()
args += (box, )
- #if DEBUG >= DEBUG_DETAILED:
- # s += '\t' + box.repr_rpython()
elif argspec == "constbox":
args += (self.load_const_arg(), )
elif argspec == "int":
@@ -82,12 +76,7 @@
args += (methdescr, )
else:
assert 0, "unknown argtype declaration: %r" % (argspec,)
- #if DEBUG >= DEBUG_DETAILED:
- # debug_print(s)
val = func(*args)
- #if DEBUG >= DEBUG_DETAILED:
- # reprboxes = ' '.join([box.repr_rpython() for box in self.env])
- # debug_print(' \x1b[34menv=[%s]\x1b[0m' % (reprboxes,))
if val is None:
val = False
return val
@@ -654,6 +643,10 @@
def opimpl_residual_call(self, calldescr, varargs):
return self.do_residual_call(varargs, descr=calldescr, exc=True)
+ @arguments("descr", "varargs")
+ def opimpl_residual_call_loopinvariant(self, calldescr, varargs):
+ return self.execute_varargs(rop.CALL_LOOPINVARIANT, varargs, calldescr, exc=True)
+
@arguments("varargs")
def opimpl_recursion_leave_prep(self, varargs):
warmrunnerstate = self.metainterp.staticdata.state
@@ -667,16 +660,40 @@
return False
return self.perform_call(leave_code, varargs)
- @arguments("descr", "varargs")
- def opimpl_recursive_call(self, calldescr, varargs):
+ @arguments("orgpc", "descr", "varargs")
+ def opimpl_recursive_call(self, pc, calldescr, varargs):
warmrunnerstate = self.metainterp.staticdata.state
- if warmrunnerstate.inlining:
+ token = None
+ if not self.metainterp.is_blackholing() and warmrunnerstate.inlining:
num_green_args = self.metainterp.staticdata.num_green_args
portal_code = self.metainterp.staticdata.portal_code
greenkey = varargs[1:num_green_args + 1]
if warmrunnerstate.can_inline_callable(greenkey):
return self.perform_call(portal_code, varargs[1:], greenkey)
- return self.do_residual_call(varargs, descr=calldescr, exc=True)
+ token = warmrunnerstate.get_assembler_token(greenkey)
+ call_position = 0
+ if token is not None:
+ call_position = len(self.metainterp.history.operations)
+ # guard value for all green args, needed to make sure
+ # that assembler that we call is still correct
+ greenargs = varargs[1:num_green_args + 1]
+ self.generate_guard_value_for_green_args(pc, greenargs)
+ res = self.do_residual_call(varargs, descr=calldescr, exc=True)
+ if not self.metainterp.is_blackholing() and token is not None:
+ # XXX fix the call position, <UGLY!>
+ found = False
+ while True:
+ op = self.metainterp.history.operations[call_position]
+ if op.opnum == rop.CALL or op.opnum == rop.CALL_MAY_FORCE:
+ found = True
+ break
+ call_position += 1
+ assert found
+ # </UGLY!>
+ # this will substitute the residual call with assembler call
+ self.metainterp.direct_assembler_call(pc, varargs, token,
+ call_position)
+ return res
@arguments("descr", "varargs")
def opimpl_residual_call_noexception(self, calldescr, varargs):
@@ -786,7 +803,7 @@
def opimpl_keepalive(self, box):
pass # xxx?
- def generate_merge_point(self, pc, varargs):
+ def generate_guard_value_for_green_args(self, pc, varargs):
num_green_args = self.metainterp.staticdata.num_green_args
for i in range(num_green_args):
varargs[i] = self.implement_guard_value(pc, varargs[i])
@@ -826,7 +843,7 @@
@arguments("orgpc")
def opimpl_jit_merge_point(self, pc):
if not self.metainterp.is_blackholing():
- self.generate_merge_point(pc, self.env)
+ self.generate_guard_value_for_green_args(pc, self.env)
# xxx we may disable the following line in some context later
self.debug_merge_point()
if self.metainterp.seen_can_enter_jit:
@@ -834,8 +851,7 @@
try:
self.metainterp.reached_can_enter_jit(self.env)
except GiveUp:
- self.metainterp.staticdata.profiler.count(ABORT_BRIDGE)
- self.metainterp.switch_to_blackhole()
+ self.metainterp.switch_to_blackhole(ABORT_BRIDGE)
if self.metainterp.is_blackholing():
self.blackhole_reached_merge_point(self.env)
return True
@@ -846,6 +862,7 @@
greenkey = self.env[:num_green_args]
sd = self.metainterp.staticdata
loc = sd.state.get_location_str(greenkey)
+ debug_print(loc)
constloc = self.metainterp.cpu.ts.conststr(loc)
self.metainterp.history.record(rop.DEBUG_MERGE_POINT,
[constloc], None)
@@ -858,9 +875,13 @@
def opimpl_teardown_exception_block(self):
self.exception_target = -1
- @arguments("constbox", "jumptarget")
- def opimpl_goto_if_exception_mismatch(self, vtableref, next_exc_target):
- assert isinstance(self.exception_box, Const) # XXX
+ @arguments("constbox", "jumptarget", "orgpc")
+ def opimpl_goto_if_exception_mismatch(self, vtableref, next_exc_target, pc):
+ # XXX used to be:
+ # assert isinstance(self.exception_box, Const) # XXX
+ # seems this can happen that self.exception_box is not a Const,
+ # but I failed to write a test so far :-(
+ self.exception_box = self.implement_guard_value(pc, self.exception_box)
cpu = self.metainterp.cpu
ts = self.metainterp.cpu.ts
if not ts.subclassOf(cpu, self.exception_box, vtableref):
@@ -886,6 +907,55 @@
return self.metainterp.finishframe_exception(self.exception_box,
self.exc_value_box)
+ @arguments("box")
+ def opimpl_virtual_ref(self, box):
+ # Details on the content of metainterp.virtualref_boxes:
+ #
+ # * it's a list whose items go two by two, containing first the
+ # virtual box (e.g. the PyFrame) and then the vref box (e.g.
+ # the 'virtual_ref(frame)').
+ #
+ # * if we detect that the virtual box escapes during tracing
+ # already (by generating a CALl_MAY_FORCE that marks the flags
+ # in the vref), then we replace the vref in the list with
+ # ConstPtr(NULL).
+ #
+ metainterp = self.metainterp
+ if metainterp.is_blackholing():
+ resbox = box # good enough when blackholing
+ else:
+ vrefinfo = metainterp.staticdata.virtualref_info
+ obj = box.getref_base()
+ vref = vrefinfo.virtual_ref_during_tracing(obj)
+ resbox = history.BoxPtr(vref)
+ cindex = history.ConstInt(len(metainterp.virtualref_boxes) // 2)
+ metainterp.history.record(rop.VIRTUAL_REF, [box, cindex], resbox)
+ # Note: we allocate a JIT_VIRTUAL_REF here
+ # (in virtual_ref_during_tracing()), in order to detect when
+ # the virtual escapes during tracing already. We record it as a
+ # VIRTUAL_REF operation, although the backend sees this operation
+ # as a no-op. The point is that the backend should not really see
+ # it in practice, as optimizeopt.py should either kill it or
+ # replace it with a NEW_WITH_VTABLE followed by SETFIELD_GCs.
+ metainterp.virtualref_boxes.append(box)
+ metainterp.virtualref_boxes.append(resbox)
+ self.make_result_box(resbox)
+
+ @arguments("box")
+ def opimpl_virtual_ref_finish(self, box):
+ # virtual_ref_finish() assumes that we have a stack-like, last-in
+ # first-out order.
+ metainterp = self.metainterp
+ vrefbox = metainterp.virtualref_boxes.pop()
+ lastbox = metainterp.virtualref_boxes.pop()
+ assert box.getref_base() == lastbox.getref_base()
+ if not metainterp.is_blackholing():
+ vrefinfo = metainterp.staticdata.virtualref_info
+ vref = vrefbox.getref_base()
+ if vrefinfo.is_virtual_ref(vref):
+ metainterp.history.record(rop.VIRTUAL_REF_FINISH,
+ [vrefbox, lastbox], None)
+
# ------------------------------
def setup_call(self, argboxes):
@@ -947,7 +1017,7 @@
if metainterp.staticdata.virtualizable_info is not None:
virtualizable_boxes = metainterp.virtualizable_boxes
resume.capture_resumedata(metainterp.framestack, virtualizable_boxes,
- resumedescr)
+ metainterp.virtualref_boxes, resumedescr)
self.metainterp.staticdata.profiler.count_ops(opnum, GUARDS)
# count
metainterp.attach_debug_info(guard_op)
@@ -988,13 +1058,13 @@
def do_residual_call(self, argboxes, descr, exc):
effectinfo = descr.get_extra_info()
- if effectinfo is None or effectinfo.promotes_virtualizables:
+ if effectinfo is None or effectinfo.forces_virtual_or_virtualizable:
# residual calls require attention to keep virtualizables in-sync
- self.metainterp.vable_before_residual_call()
+ self.metainterp.vable_and_vrefs_before_residual_call()
# xxx do something about code duplication
resbox = self.metainterp.execute_and_record_varargs(
rop.CALL_MAY_FORCE, argboxes, descr=descr)
- self.metainterp.vable_after_residual_call()
+ self.metainterp.vable_and_vrefs_after_residual_call()
if resbox is not None:
self.make_result_box(resbox)
self.generate_guard(self.pc, rop.GUARD_NOT_FORCED, None, [])
@@ -1047,6 +1117,9 @@
self._addr2name_values = []
self.__dict__.update(compile.make_done_loop_tokens())
+ # store this information for fastpath of call_assembler
+ d = self.loop_tokens_done_with_this_frame_int[0].finishdescr
+ self.cpu.done_with_this_frame_int_v = self.cpu.get_fail_descr_number(d)
def _freeze_(self):
return True
@@ -1234,8 +1307,7 @@
try:
self.compile_done_with_this_frame(resultbox)
except GiveUp:
- self.staticdata.profiler.count(ABORT_BRIDGE)
- self.switch_to_blackhole()
+ self.switch_to_blackhole(ABORT_BRIDGE)
sd = self.staticdata
if sd.result_type == 'void':
assert resultbox is None
@@ -1272,8 +1344,7 @@
try:
self.compile_exit_frame_with_exception(excvaluebox)
except GiveUp:
- self.staticdata.profiler.count(ABORT_BRIDGE)
- self.switch_to_blackhole()
+ self.switch_to_blackhole(ABORT_BRIDGE)
raise self.staticdata.ExitFrameWithExceptionRef(self.cpu, excvaluebox.getref_base())
def check_recursion_invariant(self):
@@ -1308,7 +1379,7 @@
def create_empty_history(self):
warmrunnerstate = self.staticdata.state
- self.history = history.History(self.cpu)
+ self.history = history.History()
self.staticdata.stats.set_history(self.history)
def _all_constants(self, *boxes):
@@ -1391,7 +1462,8 @@
op.pc = self.framestack[-1].pc
op.name = self.framestack[-1].jitcode.name
- def switch_to_blackhole(self):
+ def switch_to_blackhole(self, reason):
+ self.staticdata.profiler.count(reason)
debug_print('~~~ ABORTING TRACING')
debug_stop('jit-tracing')
debug_start('jit-blackhole')
@@ -1399,15 +1471,15 @@
self.staticdata.stats.aborted()
self.staticdata.profiler.end_tracing()
self.staticdata.profiler.start_blackhole()
+ switch_to_blackhole._dont_inline_ = True
def switch_to_blackhole_if_trace_too_long(self):
if not self.is_blackholing():
warmrunnerstate = self.staticdata.state
if len(self.history.operations) > warmrunnerstate.trace_limit:
- self.staticdata.profiler.count(ABORT_TOO_LONG)
self.greenkey_of_huge_function = self.find_biggest_function()
self.portal_trace_positions = None
- self.switch_to_blackhole()
+ self.switch_to_blackhole(ABORT_TOO_LONG)
def _interpret(self):
# Execute the frames forward until we raise a DoneWithThisFrame,
@@ -1531,6 +1603,7 @@
len(self.virtualizable_boxes)-1,
duplicates)
live_arg_boxes += self.virtualizable_boxes[:-1]
+ assert len(self.virtualref_boxes) == 0, "missing virtual_ref_finish()?"
# Called whenever we reach the 'can_enter_jit' hint.
# First, attempt to make a bridge:
# - if self.resumekey is a ResumeGuardDescr, it starts from a guard
@@ -1560,17 +1633,9 @@
# we cannot reconstruct the beginning of the proper loop
raise GiveUp
- oldops = self.history.operations[:]
# raises in case it works -- which is the common case
self.compile(original_boxes, live_arg_boxes, start)
- # creation of the loop was cancelled! Patch
- # history.operations so that it contains again
- # exactly its old list of operations...
- # xxx maybe we could patch history.operations with
- # Nones after calling self.compile() instead of
- # before... xxx maybe we should just raise GiveUp
- del self.history.operations[:]
- self.history.operations.extend(oldops)
+ # creation of the loop was cancelled!
# Otherwise, no loop found so far, so continue tracing.
start = len(self.history.operations)
@@ -1608,6 +1673,7 @@
greenkey, 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
def compile_bridge(self, live_arg_boxes):
num_green_args = self.staticdata.num_green_args
@@ -1686,6 +1752,7 @@
f = self.newframe(self.staticdata.portal_code)
f.pc = 0
f.env = original_boxes[:]
+ self.virtualref_boxes = []
self.initialize_virtualizable(original_boxes)
return original_boxes
@@ -1694,7 +1761,7 @@
self.in_recursion = -1 # always one portal around
inputargs_and_holes = self.cpu.make_boxes_from_latest_values(resumedescr)
if must_compile:
- self.history = history.History(self.cpu)
+ self.history = history.History()
self.history.inputargs = [box for box in inputargs_and_holes if box]
self.staticdata.profiler.start_tracing()
else:
@@ -1723,9 +1790,18 @@
virtualizable = vinfo.unwrap_virtualizable_box(virtualizable_box)
vinfo.clear_vable_token(virtualizable)
- def vable_before_residual_call(self):
+ def vable_and_vrefs_before_residual_call(self):
if self.is_blackholing():
return
+ #
+ vrefinfo = self.staticdata.virtualref_info
+ for i in range(1, len(self.virtualref_boxes), 2):
+ vrefbox = self.virtualref_boxes[i]
+ vref = vrefbox.getref_base()
+ vrefinfo.tracing_before_residual_call(vref)
+ # the FORCE_TOKEN is already set at runtime in each vref when
+ # it is created, by optimizeopt.py.
+ #
vinfo = self.staticdata.virtualizable_info
if vinfo is not None:
virtualizable_box = self.virtualizable_boxes[-1]
@@ -1738,23 +1814,50 @@
force_token_box],
None, descr=vinfo.vable_token_descr)
- def vable_after_residual_call(self):
+ def vable_and_vrefs_after_residual_call(self):
if self.is_blackholing():
- vable_escapes = True
+ escapes = True
else:
- vable_escapes = False
+ escapes = False
+ #
+ vrefinfo = self.staticdata.virtualref_info
+ for i in range(0, len(self.virtualref_boxes), 2):
+ virtualbox = self.virtualref_boxes[i]
+ vrefbox = self.virtualref_boxes[i+1]
+ vref = vrefbox.getref_base()
+ if vrefinfo.tracing_after_residual_call(vref):
+ # this vref was really a virtual_ref, but it escaped
+ # during this CALL_MAY_FORCE. Mark this fact by
+ # generating a VIRTUAL_REF_FINISH on it and replacing
+ # it by ConstPtr(NULL).
+ self.stop_tracking_virtualref(i)
+ #
vinfo = self.staticdata.virtualizable_info
if vinfo is not None:
virtualizable_box = self.virtualizable_boxes[-1]
virtualizable = vinfo.unwrap_virtualizable_box(virtualizable_box)
if vinfo.tracing_after_residual_call(virtualizable):
- # We just did the residual call, and it shows that the
- # virtualizable escapes.
- self.switch_to_blackhole()
- vable_escapes = True
- if vable_escapes:
+ # the virtualizable escaped during CALL_MAY_FORCE.
+ escapes = True
+ #
+ if escapes:
+ self.switch_to_blackhole(ABORT_ESCAPE)
+ #
+ if escapes:
self.load_fields_from_virtualizable()
+ def stop_tracking_virtualref(self, i):
+ virtualbox = self.virtualref_boxes[i]
+ vrefbox = self.virtualref_boxes[i+1]
+ # record VIRTUAL_REF_FINISH just before the current CALL_MAY_FORCE
+ call_may_force_op = self.history.operations.pop()
+ assert call_may_force_op.opnum == rop.CALL_MAY_FORCE
+ self.history.record(rop.VIRTUAL_REF_FINISH,
+ [vrefbox, virtualbox], None)
+ self.history.operations.append(call_may_force_op)
+ # mark by replacing it with ConstPtr(NULL)
+ self.virtualref_boxes[i+1] = self.cpu.ts.CONST_NULL
+
def handle_exception(self):
etype = self.cpu.get_exception()
evalue = self.cpu.get_exc_value()
@@ -1787,7 +1890,20 @@
vinfo = self.staticdata.virtualizable_info
self.framestack = []
expect_virtualizable = vinfo is not None
- virtualizable_boxes = resume.rebuild_from_resumedata(self, newboxes, resumedescr, expect_virtualizable)
+ virtualizable_boxes, virtualref_boxes = resume.rebuild_from_resumedata(
+ self, newboxes, resumedescr, expect_virtualizable)
+ #
+ # virtual refs: make the vrefs point to the freshly allocated virtuals
+ self.virtualref_boxes = virtualref_boxes
+ vrefinfo = self.staticdata.virtualref_info
+ for i in range(0, len(virtualref_boxes), 2):
+ virtualbox = virtualref_boxes[i]
+ vrefbox = virtualref_boxes[i+1]
+ vrefinfo.continue_tracing(vrefbox.getref_base(),
+ virtualbox.getref_base())
+ #
+ # virtualizable: synchronize the real virtualizable and the local
+ # boxes, in whichever direction is appropriate
if expect_virtualizable:
self.virtualizable_boxes = virtualizable_boxes
if self._already_allocated_resume_virtuals is not None:
@@ -1796,12 +1912,19 @@
self.load_fields_from_virtualizable()
return
# just jumped away from assembler (case 4 in the comment in
- # virtualizable.py) into tracing (case 2); check that vable_rti
- # is and stays NULL.
+ # virtualizable.py) into tracing (case 2); check that vable_token
+ # is and stays 0. Note the call to reset_vable_token() in
+ # warmstate.py.
virtualizable_box = self.virtualizable_boxes[-1]
virtualizable = vinfo.unwrap_virtualizable_box(virtualizable_box)
assert not virtualizable.vable_token
- self.synchronize_virtualizable()
+ if self._already_allocated_resume_virtuals is not None:
+ # resuming from a ResumeGuardForcedDescr: load the new values
+ # currently stored on the virtualizable fields
+ self.load_fields_from_virtualizable()
+ else:
+ # normal case: fill the virtualizable with the local boxes
+ self.synchronize_virtualizable()
def check_synchronized_virtualizable(self):
if not we_are_translated():
@@ -1850,12 +1973,33 @@
abox, ConstInt(j), itembox)
assert i + 1 == len(self.virtualizable_boxes)
+ def gen_load_from_other_virtualizable(self, vbox):
+ vinfo = self.staticdata.virtualizable_info
+ boxes = []
+ assert vinfo is not None
+ for i in range(vinfo.num_static_extra_boxes):
+ descr = vinfo.static_field_descrs[i]
+ boxes.append(self.execute_and_record(rop.GETFIELD_GC, descr, vbox))
+ virtualizable = vinfo.unwrap_virtualizable_box(vbox)
+ for k in range(vinfo.num_arrays):
+ descr = vinfo.array_field_descrs[k]
+ abox = self.execute_and_record(rop.GETFIELD_GC, descr, vbox)
+ descr = vinfo.array_descrs[k]
+ for j in range(vinfo.get_array_length(virtualizable, k)):
+ boxes.append(self.execute_and_record(rop.GETARRAYITEM_GC, descr,
+ abox, ConstInt(j)))
+ return boxes
+
def replace_box(self, oldbox, newbox):
for frame in self.framestack:
boxes = frame.env
for i in range(len(boxes)):
if boxes[i] is oldbox:
boxes[i] = newbox
+ boxes = self.virtualref_boxes
+ for i in range(len(boxes)):
+ if boxes[i] is oldbox:
+ boxes[i] = newbox
if self.staticdata.virtualizable_info is not None:
boxes = self.virtualizable_boxes
for i in range(len(boxes)):
@@ -1886,6 +2030,20 @@
max_key = key
return max_key
+ def direct_assembler_call(self, pc, varargs, token, call_position):
+ """ Generate a direct call to assembler for portal entry point.
+ """
+ assert not self.is_blackholing() # XXX
+ num_green_args = self.staticdata.num_green_args
+ args = varargs[num_green_args + 1:]
+ resbox = self.history.operations[call_position].result
+ rest = self.history.slice_history_at(call_position)
+ if self.staticdata.virtualizable_info is not None:
+ vindex = self.staticdata.virtualizable_info.index_of_virtualizable
+ vbox = args[vindex - num_green_args]
+ args += self.gen_load_from_other_virtualizable(vbox)
+ self.history.record(rop.CALL_ASSEMBLER, args[:], resbox, descr=token)
+ self.history.operations += rest
class GenerateMergePoint(Exception):
def __init__(self, args, target_loop_token):
Modified: pypy/branch/stringbuilder2/pypy/jit/metainterp/resoperation.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/jit/metainterp/resoperation.py (original)
+++ pypy/branch/stringbuilder2/pypy/jit/metainterp/resoperation.py Mon Jan 25 15:25:48 2010
@@ -31,7 +31,11 @@
self.descr = descr
def clone(self):
- op = ResOperation(self.opnum, self.args, self.result, self.descr)
+ descr = self.descr
+ if descr is not None:
+ descr = descr._clone_if_mutable()
+ op = ResOperation(self.opnum, self.args, self.result, descr)
+ op.fail_args = self.fail_args
if not we_are_translated():
op.name = self.name
op.pc = self.pc
@@ -90,7 +94,7 @@
return rop._OVF_FIRST <= self.opnum <= rop._OVF_LAST
def is_comparison(self):
- return rop._COMPARISON_FIRST <= self.opnum <= rop._COMPARISON_LAST
+ return self.is_always_pure() and self.returns_bool_result()
def is_final(self):
return rop._FINAL_FIRST <= self.opnum <= rop._FINAL_LAST
@@ -155,7 +159,6 @@
'CAST_FLOAT_TO_INT/1',
'CAST_INT_TO_FLOAT/1',
#
- '_COMPARISON_FIRST',
'INT_LT/2b',
'INT_LE/2b',
'INT_EQ/2b',
@@ -166,8 +169,7 @@
'UINT_LE/2b',
'UINT_GT/2b',
'UINT_GE/2b',
- '_COMPARISON_LAST',
- 'FLOAT_LT/2b', # maybe these ones should be comparisons too
+ 'FLOAT_LT/2b',
'FLOAT_LE/2b',
'FLOAT_EQ/2b',
'FLOAT_NE/2b',
@@ -205,6 +207,8 @@
'NEW/0d',
'NEW_WITH_VTABLE/1',
'NEW_ARRAY/1d',
+ 'FORCE_TOKEN/0',
+ 'VIRTUAL_REF/2',
'_NOSIDEEFFECT_LAST', # ----- end of no_side_effect operations -----
'SETARRAYITEM_GC/3d',
@@ -221,11 +225,13 @@
'COND_CALL_GC_MALLOC', # [a, b, if_(a<=b)_result, if_(a>b)_call, args...]
# => result (for mallocs)
'DEBUG_MERGE_POINT/1', # debugging only
- 'FORCE_TOKEN/0',
+ 'VIRTUAL_REF_FINISH/2',
'_CANRAISE_FIRST', # ----- start of can_raise operations -----
'CALL',
+ 'CALL_ASSEMBLER',
'CALL_MAY_FORCE',
+ 'CALL_LOOPINVARIANT',
'OOSEND', # ootype operation
'_CANRAISE_LAST', # ----- end of can_raise operations -----
Modified: pypy/branch/stringbuilder2/pypy/jit/metainterp/resume.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/jit/metainterp/resume.py (original)
+++ pypy/branch/stringbuilder2/pypy/jit/metainterp/resume.py Mon Jan 25 15:25:48 2010
@@ -21,15 +21,10 @@
self.boxes = boxes
class FrameInfo(object):
- __slots__ = ('prev', 'jitcode', 'pc', 'exception_target', 'level')
+ __slots__ = ('prev', 'jitcode', 'pc', 'exception_target')
def __init__(self, prev, frame):
self.prev = prev
- if prev is None:
- level = 1
- else:
- level = prev.level + 1
- self.level = level
self.jitcode = frame.jitcode
self.pc = frame.pc
self.exception_target = frame.exception_target
@@ -47,7 +42,8 @@
back.parent_resumedata_snapshot,
back.env[:])
-def capture_resumedata(framestack, virtualizable_boxes, storage):
+def capture_resumedata(framestack, virtualizable_boxes, virtualref_boxes,
+ storage):
n = len(framestack)-1
top = framestack[n]
_ensure_parent_resumedata(framestack, n)
@@ -55,6 +51,7 @@
top)
storage.rd_frame_info_list = frame_info_list
snapshot = Snapshot(top.parent_resumedata_snapshot, top.env[:])
+ snapshot = Snapshot(snapshot, virtualref_boxes[:]) # xxx for now
if virtualizable_boxes is not None:
snapshot = Snapshot(snapshot, virtualizable_boxes[:]) # xxx for now
storage.rd_snapshot = snapshot
@@ -98,8 +95,8 @@
TAGBOX = 2
TAGVIRTUAL = 3
-UNASSIGNED = tag(-2 ** 12 - 1, TAGBOX)
-UNASSIGNEDVIRTUAL = tag(-2 ** 12 - 1, TAGVIRTUAL)
+UNASSIGNED = tag(-1<<13, TAGBOX)
+UNASSIGNEDVIRTUAL = tag(-1<<13, TAGVIRTUAL)
NULLREF = tag(-1, TAGCONST)
@@ -200,6 +197,7 @@
return len(self.cached_boxes)
def assign_number_to_box(self, box, boxes):
+ # returns a negative number
if box in self.cached_boxes:
num = self.cached_boxes[box]
boxes[-num-1] = box
@@ -213,6 +211,7 @@
return len(self.cached_virtuals)
def assign_number_to_virtual(self, box):
+ # returns a negative number
if box in self.cached_virtuals:
num = self.cached_virtuals[box]
else:
@@ -235,8 +234,6 @@
def __init__(self, storage, memo):
self.storage = storage
self.memo = memo
- #self.virtuals = []
- #self.vfieldboxes = []
def make_virtual(self, known_class, fielddescrs):
return VirtualInfo(known_class, fielddescrs)
@@ -257,8 +254,6 @@
if (isinstance(box, Box) and box not in self.liveboxes_from_env
and box not in self.liveboxes):
self.liveboxes[box] = UNASSIGNED
- return True
- return False
def _register_boxes(self, boxes):
for box in boxes:
@@ -273,9 +268,11 @@
_, tagbits = untag(tagged)
return tagbits == TAGVIRTUAL
- def finish(self, values):
+ def finish(self, values, pending_setfields=[]):
# compute the numbering
storage = self.storage
+ # make sure that nobody attached resume data to this guard yet
+ assert storage.rd_numb is None
numb, liveboxes_from_env, v = self.memo.number(values,
storage.rd_snapshot)
self.liveboxes_from_env = liveboxes_from_env
@@ -296,16 +293,29 @@
value = values[box]
value.get_args_for_fail(self)
+ for _, box, fieldbox in pending_setfields:
+ self.register_box(box)
+ self.register_box(fieldbox)
+ value = values[fieldbox]
+ value.get_args_for_fail(self)
+
self._number_virtuals(liveboxes, values, v)
+ self._add_pending_fields(pending_setfields)
storage.rd_consts = self.memo.consts
dump_storage(storage, liveboxes)
return liveboxes[:]
def _number_virtuals(self, liveboxes, values, num_env_virtuals):
+ # !! 'liveboxes' is a list that is extend()ed in-place !!
memo = self.memo
new_liveboxes = [None] * memo.num_cached_boxes()
count = 0
+ # So far, self.liveboxes should contain 'tagged' values that are
+ # either UNASSIGNED, UNASSIGNEDVIRTUAL, or a *non-negative* value
+ # with the TAGVIRTUAL. The following loop removes the UNASSIGNED
+ # and UNASSIGNEDVIRTUAL entries, and replaces them with real
+ # negative values.
for box, tagged in self.liveboxes.iteritems():
i, tagbits = untag(tagged)
if tagbits == TAGBOX:
@@ -320,6 +330,8 @@
assert box not in self.liveboxes_from_env
index = memo.assign_number_to_virtual(box)
self.liveboxes[box] = tag(index, TAGVIRTUAL)
+ else:
+ assert i >= 0
new_liveboxes.reverse()
liveboxes.extend(new_liveboxes)
nholes = len(new_liveboxes) - count
@@ -356,6 +368,16 @@
return True
return False
+ def _add_pending_fields(self, pending_setfields):
+ rd_pendingfields = None
+ if pending_setfields:
+ rd_pendingfields = []
+ for descr, box, fieldbox in pending_setfields:
+ num = self._gettagged(box)
+ fieldnum = self._gettagged(fieldbox)
+ rd_pendingfields.append((descr, num, fieldnum))
+ self.storage.rd_pendingfields = rd_pendingfields
+
def _gettagged(self, box):
if isinstance(box, Const):
return self.memo.getconst(box)
@@ -364,11 +386,16 @@
return self.liveboxes_from_env[box]
return self.liveboxes[box]
+
class AbstractVirtualInfo(object):
def allocate(self, metainterp):
raise NotImplementedError
def setfields(self, metainterp, box, fn_decode_box):
raise NotImplementedError
+ def equals(self, fieldnums):
+ return tagged_list_eq(self.fieldnums, fieldnums)
+ def set_content(self, fieldnums):
+ self.fieldnums = fieldnums
class AbstractVirtualStructInfo(AbstractVirtualInfo):
@@ -439,11 +466,13 @@
debug_print("\t\t", str(untag(i)))
-def rebuild_from_resumedata(metainterp, newboxes, storage, expects_virtualizables):
+def rebuild_from_resumedata(metainterp, newboxes, storage,
+ expects_virtualizables):
resumereader = ResumeDataReader(storage, newboxes, metainterp)
virtualizable_boxes = None
if expects_virtualizables:
virtualizable_boxes = resumereader.consume_boxes()
+ virtualref_boxes = resumereader.consume_boxes()
frameinfo = storage.rd_frame_info_list
while True:
env = resumereader.consume_boxes()
@@ -453,11 +482,16 @@
if frameinfo is None:
break
metainterp.framestack.reverse()
- return virtualizable_boxes
+ return virtualizable_boxes, virtualref_boxes
-def force_from_resumedata(metainterp, newboxes, storage):
+def force_from_resumedata(metainterp, newboxes, storage,
+ expects_virtualizables):
resumereader = ResumeDataReader(storage, newboxes, metainterp)
- return resumereader.consume_boxes(), resumereader.virtuals
+ virtualizable_boxes = None
+ if expects_virtualizables:
+ virtualizable_boxes = resumereader.consume_boxes()
+ virtualref_boxes = resumereader.consume_boxes()
+ return virtualizable_boxes, virtualref_boxes, resumereader.virtuals
class ResumeDataReader(object):
@@ -469,6 +503,7 @@
self.liveboxes = liveboxes
self.cpu = metainterp.cpu
self._prepare_virtuals(metainterp, storage.rd_virtuals)
+ self._prepare_pendingfields(metainterp, storage.rd_pendingfields)
def _prepare_virtuals(self, metainterp, virtuals):
if virtuals:
@@ -487,6 +522,16 @@
vinfo.setfields(metainterp, self.virtuals[i],
self._decode_box)
+ def _prepare_pendingfields(self, metainterp, pendingfields):
+ if pendingfields:
+ if metainterp._already_allocated_resume_virtuals is not None:
+ return
+ for descr, num, fieldnum in pendingfields:
+ box = self._decode_box(num)
+ fieldbox = self._decode_box(fieldnum)
+ metainterp.execute_and_record(rop.SETFIELD_GC,
+ descr, box, fieldbox)
+
def consume_boxes(self):
numb = self.cur_numb
assert numb is not None
Modified: pypy/branch/stringbuilder2/pypy/jit/metainterp/support.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/jit/metainterp/support.py (original)
+++ pypy/branch/stringbuilder2/pypy/jit/metainterp/support.py Mon Jan 25 15:25:48 2010
@@ -3,6 +3,7 @@
from pypy.rpython import rlist
from pypy.rpython.lltypesystem import rstr as ll_rstr, rdict as ll_rdict
from pypy.rpython.lltypesystem import rlist as lltypesystem_rlist
+from pypy.rpython.lltypesystem.lloperation import llop
from pypy.rpython.ootypesystem import rdict as oo_rdict
from pypy.rpython.llinterp import LLInterpreter
from pypy.rpython.extregistry import ExtRegistryEntry
@@ -136,6 +137,9 @@
def _ll_1_gc_identityhash(x):
return lltype.identityhash(x)
+def _ll_1_jit_force_virtual(inst):
+ return llop.jit_force_virtual(lltype.typeOf(inst), inst)
+
class LLtypeHelpers:
Modified: pypy/branch/stringbuilder2/pypy/jit/metainterp/test/test_basic.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/jit/metainterp/test/test_basic.py (original)
+++ pypy/branch/stringbuilder2/pypy/jit/metainterp/test/test_basic.py Mon Jan 25 15:25:48 2010
@@ -1,7 +1,7 @@
import py
import sys
from pypy.rlib.jit import JitDriver, we_are_jitted, hint, dont_look_inside
-from pypy.rlib.jit import OPTIMIZER_FULL, OPTIMIZER_SIMPLE
+from pypy.rlib.jit import OPTIMIZER_FULL, OPTIMIZER_SIMPLE, loop_invariant
from pypy.jit.metainterp.warmspot import ll_meta_interp, get_stats
from pypy.jit.backend.llgraph import runner
from pypy.jit.metainterp import support, codewriter, pyjitpl, history
@@ -52,6 +52,8 @@
assert get_stats().exec_jumps <= maxcount
def check_aborted_count(self, count):
assert get_stats().aborted_count == count
+ def check_aborted_count_at_least(self, count):
+ assert get_stats().aborted_count >= count
def meta_interp(self, *args, **kwds):
kwds['CPUClass'] = self.CPUClass
@@ -84,6 +86,10 @@
metainterp, rtyper = _get_bare_metainterp(f, args, self.CPUClass,
self.type_system,
**kwds)
+ metainterp.staticdata.state = FakeWarmRunnerState()
+ metainterp.staticdata.state.cpu = metainterp.staticdata.cpu
+ if hasattr(self, 'finish_metainterp_for_interp_operations'):
+ self.finish_metainterp_for_interp_operations(metainterp)
portal_graph = rtyper.annotator.translator.graphs[0]
cw = codewriter.CodeWriter(rtyper)
@@ -95,7 +101,6 @@
cw.finish_making_bytecodes()
metainterp.staticdata.portal_code = maingraph
metainterp.staticdata._class_sizes = cw.class_sizes
- metainterp.staticdata.state = FakeWarmRunnerState()
metainterp.staticdata.DoneWithThisFrameInt = DoneWithThisFrame
metainterp.staticdata.DoneWithThisFrameRef = DoneWithThisFrameRef
metainterp.staticdata.DoneWithThisFrameFloat = DoneWithThisFrame
@@ -380,6 +385,26 @@
res = self.meta_interp(f, [55])
assert res == -1
+ def test_confirm_enter_jit(self):
+ def confirm_enter_jit(x, y):
+ return x <= 5
+ myjitdriver = JitDriver(greens = ['x'], reds = ['y'],
+ confirm_enter_jit = confirm_enter_jit)
+ def f(x, y):
+ while y >= 0:
+ myjitdriver.can_enter_jit(x=x, y=y)
+ myjitdriver.jit_merge_point(x=x, y=y)
+ y -= x
+ return y
+ #
+ res = self.meta_interp(f, [10, 84])
+ assert res == -6
+ self.check_loop_count(0)
+ #
+ res = self.meta_interp(f, [3, 19])
+ assert res == -2
+ self.check_loop_count(1)
+
def test_format(self):
def f(n):
return len("<%d>" % n)
@@ -1196,6 +1221,69 @@
res = self.meta_interp(f, [21])
assert res == 42
self.check_loops(guard_nonnull=1, guard_isnull=1)
+
+ def test_loop_invariant(self):
+ myjitdriver = JitDriver(greens = [], reds = ['x', 'res'])
+ class A(object):
+ pass
+ a = A()
+ a.current_a = A()
+ a.current_a.x = 1
+ @loop_invariant
+ def f():
+ return a.current_a
+
+ def g(x):
+ res = 0
+ while x > 0:
+ myjitdriver.can_enter_jit(x=x, res=res)
+ myjitdriver.jit_merge_point(x=x, res=res)
+ res += f().x
+ res += f().x
+ res += f().x
+ x -= 1
+ a.current_a = A()
+ a.current_a.x = 2
+ return res
+ res = self.meta_interp(g, [21])
+ assert res == 3 * 21
+ self.check_loops(call=1)
+
+ def test_bug_optimizeopt_mutates_ops(self):
+ myjitdriver = JitDriver(greens = [], reds = ['x', 'res', 'a', 'const'])
+ class A(object):
+ pass
+ class B(A):
+ pass
+
+ glob = A()
+ glob.a = None
+ def f(x):
+ res = 0
+ a = A()
+ a.x = 0
+ glob.a = A()
+ const = 2
+ while x > 0:
+ myjitdriver.can_enter_jit(x=x, res=res, a=a, const=const)
+ myjitdriver.jit_merge_point(x=x, res=res, a=a, const=const)
+ if type(glob.a) is B:
+ res += 1
+ if a is None:
+ a = A()
+ a.x = x
+ glob.a = B()
+ const = 2
+ else:
+ const = hint(const, promote=True)
+ x -= const
+ res += a.x
+ a = None
+ glob.a = A()
+ const = 1
+ return res
+ res = self.meta_interp(f, [21])
+ assert res == f(21)
class TestOOtype(BasicTests, OOJitMixin):
Modified: pypy/branch/stringbuilder2/pypy/jit/metainterp/test/test_codewriter.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/jit/metainterp/test/test_codewriter.py (original)
+++ pypy/branch/stringbuilder2/pypy/jit/metainterp/test/test_codewriter.py Mon Jan 25 15:25:48 2010
@@ -2,6 +2,7 @@
from pypy.rlib import jit
from pypy.jit.metainterp import support, typesystem
from pypy.jit.metainterp.policy import JitPolicy
+from pypy.jit.metainterp.history import ConstInt
from pypy.jit.metainterp.codewriter import CodeWriter
from pypy.jit.metainterp.test.test_basic import LLJitMixin, OOJitMixin
from pypy.translator.translator import graphof
@@ -78,7 +79,27 @@
supports_floats=True)
funcs = set([graph.func for graph in res])
assert funcs == set([f, h])
-
+
+def test_unroll_safe_and_inline():
+ @jit.unroll_safe
+ def h(x):
+ i = 0
+ while i < x:
+ i += 1
+ return i
+ h._always_inline_ = True
+
+ def g(x):
+ return h(x)
+
+ rtyper = support.annotate(g, [7])
+ cw = CodeWriter(rtyper)
+ jitpolicy = JitPolicy()
+ translator = rtyper.annotator.translator
+ res = cw.find_all_graphs(translator.graphs[0], None, jitpolicy,
+ supports_floats=True)
+ funcs = set([graph.func for graph in res])
+ assert funcs == set([g, h])
def test_find_all_graphs_str_join():
def i(x, y):
@@ -101,6 +122,8 @@
def make_graphs(self, func, values, type_system='lltype'):
class FakeMetaInterpSd:
virtualizable_info = None
+ class options:
+ listops = True
def find_opcode(self, name):
default = len(self.opname_to_index)
return self.opname_to_index.setdefault(name, default)
@@ -283,7 +306,7 @@
assert calldescrs[0][4] is not None
assert not calldescrs[0][4].write_descrs_fields
assert not calldescrs[0][4].write_descrs_arrays
- assert not calldescrs[0][4].promotes_virtualizables
+ assert not calldescrs[0][4].forces_virtual_or_virtualizable
def test_oosend_look_inside_only_one(self):
class A:
@@ -394,7 +417,7 @@
assert cw.list_of_addr2name[0][1].endswith('.A1')
assert cw.list_of_addr2name[1][1] == 'A1.g'
- def test_promote_virtualizable_effectinfo(self):
+ def test_jit_force_virtualizable_effectinfo(self):
class Frame(object):
_virtualizable2_ = ['x']
@@ -430,9 +453,64 @@
effectinfo_g1 = calldescrs[1][4]
effectinfo_g2 = calldescrs[2][4]
effectinfo_h = calldescrs[3][4]
- assert effectinfo_g1.promotes_virtualizables
- assert effectinfo_g2.promotes_virtualizables
- assert not effectinfo_h.promotes_virtualizables
+ assert effectinfo_g1.forces_virtual_or_virtualizable
+ assert effectinfo_g2.forces_virtual_or_virtualizable
+ assert not effectinfo_h.forces_virtual_or_virtualizable
+
+ def make_vrefinfo(self):
+ from pypy.jit.metainterp.virtualref import VirtualRefInfo
+ class FakeWarmRunnerDesc:
+ cpu = self.metainterp_sd.cpu
+ self.metainterp_sd.virtualref_info = VirtualRefInfo(FakeWarmRunnerDesc)
+
+ def test_vref_simple(self):
+ class X:
+ pass
+ def f():
+ return jit.virtual_ref(X())
+ graphs = self.make_graphs(f, [])
+ assert graphs[0].func is f
+ assert graphs[1].func is jit.virtual_ref
+ self.make_vrefinfo()
+ cw = CodeWriter(self.rtyper)
+ cw.candidate_graphs = [graphs[0]]
+ cw._start(self.metainterp_sd, None)
+ jitcode = cw.make_one_bytecode((graphs[0], None), False)
+ assert 'virtual_ref' in jitcode._source
+
+ def test_vref_forced(self):
+ class X:
+ pass
+ def f():
+ vref = jit.virtual_ref(X())
+ return vref()
+ graphs = self.make_graphs(f, [])
+ assert graphs[0].func is f
+ assert graphs[1].func is jit.virtual_ref
+ self.make_vrefinfo()
+ cw = CodeWriter(self.rtyper)
+ cw.candidate_graphs = [graphs[0]]
+ cw._start(self.metainterp_sd, None)
+ jitcode = cw.make_one_bytecode((graphs[0], None), False)
+ assert 'virtual_ref' in jitcode._source
+ # the call vref() becomes a residual call to a helper that contains
+ # itself a copy of the call.
+ assert 'residual_call' in jitcode._source
+
+ def test_we_are_jitted(self):
+ def f():
+ if jit.we_are_jitted():
+ return 55
+ else:
+ return 66
+ graphs = self.make_graphs(f, [])
+ cw = CodeWriter(self.rtyper)
+ cw.candidate_graphs = [graphs[0]]
+ cw._start(self.metainterp_sd, None)
+ jitcode = cw.make_one_bytecode((graphs[0], None), False)
+ assert 'goto_if_not' not in jitcode._source
+ assert ConstInt(55) in jitcode.constants
+ assert ConstInt(66) not in jitcode.constants
class ImmutableFieldsTests:
Modified: pypy/branch/stringbuilder2/pypy/jit/metainterp/test/test_compile.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/jit/metainterp/test/test_compile.py (original)
+++ pypy/branch/stringbuilder2/pypy/jit/metainterp/test/test_compile.py Mon Jan 25 15:25:48 2010
@@ -77,7 +77,7 @@
metainterp = FakeMetaInterp()
metainterp.staticdata = staticdata
metainterp.cpu = cpu
- metainterp.history = History(metainterp.cpu)
+ metainterp.history = History()
metainterp.history.operations = loop.operations[:]
metainterp.history.inputargs = loop.inputargs[:]
#
@@ -94,7 +94,7 @@
metainterp = FakeMetaInterp()
metainterp.staticdata = staticdata
metainterp.cpu = cpu
- metainterp.history = History(metainterp.cpu)
+ metainterp.history = History()
metainterp.history.operations = loop.operations[:]
metainterp.history.inputargs = loop.inputargs[:]
#
Modified: pypy/branch/stringbuilder2/pypy/jit/metainterp/test/test_effectinfo.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/jit/metainterp/test/test_effectinfo.py (original)
+++ pypy/branch/stringbuilder2/pypy/jit/metainterp/test/test_effectinfo.py Mon Jan 25 15:25:48 2010
@@ -3,32 +3,77 @@
from pypy.rpython.ootypesystem import ootype
from pypy.jit.metainterp.effectinfo import effectinfo_from_writeanalyze
+class FakeCPU:
+ def fielddescrof(self, T, fieldname):
+ return ('fielddescr', T, fieldname)
+ def arraydescrof(self, A):
+ return ('arraydescr', A)
+
+def test_include_read_field():
+ S = lltype.GcStruct("S", ("a", lltype.Signed))
+ effects = frozenset([("readstruct", lltype.Ptr(S), "a")])
+ effectinfo = effectinfo_from_writeanalyze(effects, FakeCPU())
+ assert list(effectinfo.readonly_descrs_fields) == [('fielddescr', S, "a")]
+ assert not effectinfo.write_descrs_fields
+ assert not effectinfo.write_descrs_arrays
+
+def test_include_write_field():
+ S = lltype.GcStruct("S", ("a", lltype.Signed))
+ effects = frozenset([("struct", lltype.Ptr(S), "a")])
+ effectinfo = effectinfo_from_writeanalyze(effects, FakeCPU())
+ assert list(effectinfo.write_descrs_fields) == [('fielddescr', S, "a")]
+ assert not effectinfo.readonly_descrs_fields
+ assert not effectinfo.write_descrs_arrays
+
+def test_include_write_array():
+ A = lltype.GcArray(lltype.Signed)
+ effects = frozenset([("array", lltype.Ptr(A))])
+ effectinfo = effectinfo_from_writeanalyze(effects, FakeCPU())
+ assert not effectinfo.readonly_descrs_fields
+ assert not effectinfo.write_descrs_fields
+ assert list(effectinfo.write_descrs_arrays) == [('arraydescr', A)]
+
+def test_dont_include_read_and_write_field():
+ S = lltype.GcStruct("S", ("a", lltype.Signed))
+ effects = frozenset([("readstruct", lltype.Ptr(S), "a"),
+ ("struct", lltype.Ptr(S), "a")])
+ effectinfo = effectinfo_from_writeanalyze(effects, FakeCPU())
+ assert not effectinfo.readonly_descrs_fields
+ assert list(effectinfo.write_descrs_fields) == [('fielddescr', S, "a")]
+ assert not effectinfo.write_descrs_arrays
+
+
def test_filter_out_typeptr():
effects = frozenset([("struct", lltype.Ptr(OBJECT), "typeptr")])
effectinfo = effectinfo_from_writeanalyze(effects, None)
+ assert not effectinfo.readonly_descrs_fields
assert not effectinfo.write_descrs_fields
assert not effectinfo.write_descrs_arrays
def test_filter_out_array_of_void():
effects = frozenset([("array", lltype.Ptr(lltype.GcArray(lltype.Void)))])
effectinfo = effectinfo_from_writeanalyze(effects, None)
+ assert not effectinfo.readonly_descrs_fields
assert not effectinfo.write_descrs_fields
assert not effectinfo.write_descrs_arrays
def test_filter_out_struct_with_void():
effects = frozenset([("struct", lltype.Ptr(lltype.GcStruct("x", ("a", lltype.Void))), "a")])
effectinfo = effectinfo_from_writeanalyze(effects, None)
+ assert not effectinfo.readonly_descrs_fields
assert not effectinfo.write_descrs_fields
assert not effectinfo.write_descrs_arrays
def test_filter_out_ooarray_of_void():
effects = frozenset([("array", ootype.Array(ootype.Void))])
effectinfo = effectinfo_from_writeanalyze(effects, None)
+ assert not effectinfo.readonly_descrs_fields
assert not effectinfo.write_descrs_fields
assert not effectinfo.write_descrs_arrays
def test_filter_out_instance_with_void():
effects = frozenset([("struct", ootype.Instance("x", ootype.ROOT, {"a": ootype.Void}), "a")])
effectinfo = effectinfo_from_writeanalyze(effects, None)
+ assert not effectinfo.readonly_descrs_fields
assert not effectinfo.write_descrs_fields
assert not effectinfo.write_descrs_arrays
Modified: pypy/branch/stringbuilder2/pypy/jit/metainterp/test/test_executor.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/jit/metainterp/test/test_executor.py (original)
+++ pypy/branch/stringbuilder2/pypy/jit/metainterp/test/test_executor.py Mon Jan 25 15:25:48 2010
@@ -273,4 +273,4 @@
elif rettype == 'int':
assert box.getint() == retvalue
else:
- assert retvalue is None
+ assert 0, "rettype is %r" % (rettype,)
Modified: pypy/branch/stringbuilder2/pypy/jit/metainterp/test/test_history.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/jit/metainterp/test/test_history.py (original)
+++ pypy/branch/stringbuilder2/pypy/jit/metainterp/test/test_history.py Mon Jan 25 15:25:48 2010
@@ -9,3 +9,10 @@
s = lltype.cast_pointer(lltype.Ptr(S), t)
const = ConstPtr(lltype.cast_opaque_ptr(llmemory.GCREF, s))
assert const._getrepr_() == "*T"
+
+def test_slicing():
+ h = History()
+ h.operations = [1, 2, 3, 4, 5]
+ rest = h.slice_history_at(2)
+ assert rest == [4, 5]
+ assert h.operations == [1, 2]
Modified: pypy/branch/stringbuilder2/pypy/jit/metainterp/test/test_jitprof.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/jit/metainterp/test/test_jitprof.py (original)
+++ pypy/branch/stringbuilder2/pypy/jit/metainterp/test/test_jitprof.py Mon Jan 25 15:25:48 2010
@@ -64,7 +64,7 @@
assert profiler.events == expected
assert profiler.times == [2, 1, 1, 1]
assert profiler.counters == [1, 1, 1, 1, 4, 3, 1, 1, 7, 1, 0, 0, 0,
- 0, 0, 0]
+ 0, 0, 0, 0]
def test_simple_loop_with_call(self):
@dont_look_inside
Modified: pypy/branch/stringbuilder2/pypy/jit/metainterp/test/test_optimizefindnode.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/jit/metainterp/test/test_optimizefindnode.py (original)
+++ pypy/branch/stringbuilder2/pypy/jit/metainterp/test/test_optimizefindnode.py Mon Jan 25 15:25:48 2010
@@ -1,6 +1,6 @@
import py, random
-from pypy.rpython.lltypesystem import lltype, llmemory
+from pypy.rpython.lltypesystem import lltype, llmemory, rclass
from pypy.rpython.ootypesystem import ootype
from pypy.rpython.lltypesystem.rclass import OBJECT, OBJECT_VTABLE
@@ -38,12 +38,13 @@
type_system = 'lltype'
def get_class_of_box(self, box):
- from pypy.rpython.lltypesystem import rclass
return box.getref(rclass.OBJECTPTR).typeptr
node_vtable = lltype.malloc(OBJECT_VTABLE, immortal=True)
+ node_vtable.name = rclass.alloc_array_name('node')
node_vtable_adr = llmemory.cast_ptr_to_adr(node_vtable)
node_vtable2 = lltype.malloc(OBJECT_VTABLE, immortal=True)
+ node_vtable2.name = rclass.alloc_array_name('node2')
node_vtable_adr2 = llmemory.cast_ptr_to_adr(node_vtable2)
cpu = runner.LLtypeCPU(None)
@@ -67,6 +68,12 @@
nextdescr = cpu.fielddescrof(NODE, 'next')
otherdescr = cpu.fielddescrof(NODE2, 'other')
+ NODEOBJ = lltype.GcStruct('NODEOBJ', ('parent', OBJECT),
+ ('ref', lltype.Ptr(OBJECT)))
+ nodeobj = lltype.malloc(NODEOBJ)
+ nodeobjvalue = lltype.cast_opaque_ptr(llmemory.GCREF, nodeobj)
+ refdescr = cpu.fielddescrof(NODEOBJ, 'ref')
+
arraydescr = cpu.arraydescrof(lltype.GcArray(lltype.Signed))
floatarraydescr = cpu.arraydescrof(lltype.GcArray(lltype.Float))
@@ -95,13 +102,40 @@
onedescr = cpu.fielddescrof(U, 'one')
FUNC = lltype.FuncType([lltype.Signed], lltype.Signed)
- nonwritedescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, EffectInfo([], []))
- writeadescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, EffectInfo([adescr], []))
- writearraydescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT, EffectInfo([adescr], [arraydescr]))
-
- cpu.class_sizes = {cpu.cast_adr_to_int(node_vtable_adr): cpu.sizeof(NODE),
- cpu.cast_adr_to_int(node_vtable_adr2): cpu.sizeof(NODE2),
- cpu.cast_adr_to_int(u_vtable_adr): cpu.sizeof(U)}
+ plaincalldescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT)
+ nonwritedescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,
+ EffectInfo([], [], []))
+ writeadescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,
+ EffectInfo([], [adescr], []))
+ writearraydescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,
+ EffectInfo([], [adescr], [arraydescr]))
+ readadescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,
+ EffectInfo([adescr], [], []))
+ mayforcevirtdescr = cpu.calldescrof(FUNC, FUNC.ARGS, FUNC.RESULT,
+ EffectInfo([nextdescr], [], [],
+ forces_virtual_or_virtualizable=True))
+ class LoopToken(AbstractDescr):
+ pass
+ asmdescr = LoopToken() # it can be whatever, it's not a descr though
+
+ from pypy.jit.metainterp.virtualref import VirtualRefInfo
+ class FakeWarmRunnerDesc:
+ pass
+ FakeWarmRunnerDesc.cpu = cpu
+ vrefinfo = VirtualRefInfo(FakeWarmRunnerDesc)
+ virtualtokendescr = vrefinfo.descr_virtual_token
+ virtualrefindexdescr = vrefinfo.descr_virtualref_index
+ virtualforceddescr = vrefinfo.descr_forced
+ jit_virtual_ref_vtable = vrefinfo.jit_virtual_ref_vtable
+ jvr_vtable_adr = llmemory.cast_ptr_to_adr(jit_virtual_ref_vtable)
+
+ cpu.class_sizes = {
+ cpu.cast_adr_to_int(node_vtable_adr): cpu.sizeof(NODE),
+ cpu.cast_adr_to_int(node_vtable_adr2): cpu.sizeof(NODE2),
+ cpu.cast_adr_to_int(u_vtable_adr): cpu.sizeof(U),
+ cpu.cast_adr_to_int(jvr_vtable_adr): cpu.sizeof(
+ vrefinfo.JIT_VIRTUAL_REF),
+ }
namespace = locals()
class OOtypeMixin(object):
Modified: pypy/branch/stringbuilder2/pypy/jit/metainterp/test/test_optimizeopt.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/jit/metainterp/test/test_optimizeopt.py (original)
+++ pypy/branch/stringbuilder2/pypy/jit/metainterp/test/test_optimizeopt.py Mon Jan 25 15:25:48 2010
@@ -87,7 +87,10 @@
def test_reuse_vinfo():
class FakeVInfo(object):
- pass
+ def set_content(self, fieldnums):
+ self.fieldnums = fieldnums
+ def equals(self, fieldnums):
+ return self.fieldnums == fieldnums
class FakeVirtualValue(optimizeopt.AbstractVirtualValue):
def _make_virtual(self, *args):
return FakeVInfo()
@@ -204,8 +207,9 @@
class Storage(compile.ResumeGuardDescr):
"for tests."
- def __init__(self):
- pass
+ def __init__(self, metainterp_sd=None, original_greenkey=None):
+ self.metainterp_sd = metainterp_sd
+ self.original_greenkey = original_greenkey
def store_final_boxes(self, op, boxes):
op.fail_args = boxes
def __eq__(self, other):
@@ -246,7 +250,10 @@
loop.token.specnodes = self.unpack_specnodes(spectext)
#
self.loop = loop
- optimize_loop_1(FakeMetaInterpStaticData(self.cpu), loop)
+ metainterp_sd = FakeMetaInterpStaticData(self.cpu)
+ if hasattr(self, 'vrefinfo'):
+ metainterp_sd.virtualref_info = self.vrefinfo
+ optimize_loop_1(metainterp_sd, loop)
#
expected = self.parse(optops)
self.assert_equal(loop, expected)
@@ -606,10 +613,10 @@
p3sub = getfield_gc(p3, descr=nextdescr)
i3 = getfield_gc(p3sub, descr=valuedescr)
escape(i3)
+ p1 = new_with_vtable(ConstClass(node_vtable))
p2sub = new_with_vtable(ConstClass(node_vtable2))
setfield_gc(p2sub, i1, descr=valuedescr)
setfield_gc(p2, p2sub, descr=nextdescr)
- p1 = new_with_vtable(ConstClass(node_vtable))
jump(i1, p1, p2)
"""
# The same as test_p123_simple, but in the end the "old" p2 contains
@@ -642,6 +649,32 @@
# ----------
+ def test_call_loopinvariant(self):
+ ops = """
+ [i1]
+ i2 = call_loopinvariant(1, i1, descr=nonwritedescr)
+ guard_no_exception() []
+ guard_value(i2, 1) []
+ i3 = call_loopinvariant(1, i1, descr=nonwritedescr)
+ guard_no_exception() []
+ guard_value(i2, 1) []
+ i4 = call_loopinvariant(1, i1, descr=nonwritedescr)
+ guard_no_exception() []
+ guard_value(i2, 1) []
+ jump(i1)
+ """
+ expected = """
+ [i1]
+ i2 = call(1, i1, descr=nonwritedescr)
+ guard_no_exception() []
+ guard_value(i2, 1) []
+ jump(i1)
+ """
+ self.optimize_loop(ops, 'Not', expected)
+
+
+ # ----------
+
def test_virtual_1(self):
ops = """
[i, p0]
@@ -919,6 +952,26 @@
"""
self.optimize_loop(ops, 'Not', expected)
+ def test_nonvirtual_dont_write_null_fields_on_force(self):
+ ops = """
+ [i]
+ p1 = new_with_vtable(ConstClass(node_vtable))
+ setfield_gc(p1, i, descr=valuedescr)
+ i1 = getfield_gc(p1, descr=valuedescr)
+ setfield_gc(p1, 0, descr=valuedescr)
+ escape(p1)
+ i2 = getfield_gc(p1, descr=valuedescr)
+ jump(i2)
+ """
+ expected = """
+ [i]
+ p1 = new_with_vtable(ConstClass(node_vtable))
+ escape(p1)
+ i2 = getfield_gc(p1, descr=valuedescr)
+ jump(i2)
+ """
+ self.optimize_loop(ops, 'Not', expected)
+
def test_getfield_gc_pure_1(self):
ops = """
[i]
@@ -1019,6 +1072,24 @@
"""
self.optimize_loop(ops, 'Not, Not', expected)
+ def test_nonvirtual_array_dont_write_null_fields_on_force(self):
+ ops = """
+ [i1]
+ p1 = new_array(5, descr=arraydescr)
+ setarrayitem_gc(p1, 0, i1, descr=arraydescr)
+ setarrayitem_gc(p1, 1, 0, descr=arraydescr)
+ escape(p1)
+ jump(i1)
+ """
+ expected = """
+ [i1]
+ p1 = new_array(5, descr=arraydescr)
+ setarrayitem_gc(p1, 0, i1, descr=arraydescr)
+ escape(p1)
+ jump(i1)
+ """
+ self.optimize_loop(ops, 'Not', expected)
+
def test_varray_2(self):
ops = """
[i0, p1]
@@ -1293,6 +1364,204 @@
"""
self.optimize_loop(ops, 'Not, Not', ops)
+ def test_duplicate_setfield_1(self):
+ ops = """
+ [p1, i1, i2]
+ setfield_gc(p1, i1, descr=valuedescr)
+ setfield_gc(p1, i2, descr=valuedescr)
+ jump(p1, i1, i2)
+ """
+ expected = """
+ [p1, i1, i2]
+ setfield_gc(p1, i2, descr=valuedescr)
+ jump(p1, i1, i2)
+ """
+ self.optimize_loop(ops, 'Not, Not, Not', expected)
+
+ def test_duplicate_setfield_2(self):
+ ops = """
+ [p1, i1, i3]
+ setfield_gc(p1, i1, descr=valuedescr)
+ i2 = getfield_gc(p1, descr=valuedescr)
+ setfield_gc(p1, i3, descr=valuedescr)
+ escape(i2)
+ jump(p1, i1, i3)
+ """
+ expected = """
+ [p1, i1, i3]
+ setfield_gc(p1, i3, descr=valuedescr)
+ escape(i1)
+ jump(p1, i1, i3)
+ """
+ self.optimize_loop(ops, 'Not, Not, Not', expected)
+
+ def test_duplicate_setfield_3(self):
+ ops = """
+ [p1, p2, i1, i3]
+ setfield_gc(p1, i1, descr=valuedescr)
+ i2 = getfield_gc(p2, descr=valuedescr)
+ setfield_gc(p1, i3, descr=valuedescr)
+ escape(i2)
+ jump(p1, p2, i1, i3)
+ """
+ # potential aliasing of p1 and p2 means that we cannot kill the
+ # the setfield_gc
+ self.optimize_loop(ops, 'Not, Not, Not, Not', ops)
+
+ def test_duplicate_setfield_4(self):
+ ops = """
+ [p1, i1, i2, p3]
+ setfield_gc(p1, i1, descr=valuedescr)
+ #
+ # some operations on which the above setfield_gc cannot have effect
+ i3 = getarrayitem_gc_pure(p3, 1, descr=arraydescr)
+ i4 = getarrayitem_gc(p3, i3, descr=arraydescr)
+ i5 = int_add(i3, i4)
+ setarrayitem_gc(p3, 0, i5, descr=arraydescr)
+ setfield_gc(p1, i4, descr=nextdescr)
+ #
+ setfield_gc(p1, i2, descr=valuedescr)
+ jump(p1, i1, i2, p3)
+ """
+ expected = """
+ [p1, i1, i2, p3]
+ #
+ i3 = getarrayitem_gc_pure(p3, 1, descr=arraydescr)
+ i4 = getarrayitem_gc(p3, i3, descr=arraydescr)
+ i5 = int_add(i3, i4)
+ setarrayitem_gc(p3, 0, i5, descr=arraydescr)
+ #
+ setfield_gc(p1, i2, descr=valuedescr)
+ setfield_gc(p1, i4, descr=nextdescr)
+ jump(p1, i1, i2, p3)
+ """
+ self.optimize_loop(ops, 'Not, Not, Not, Not', expected)
+
+ def test_duplicate_setfield_5(self):
+ ops = """
+ [p0, i1]
+ p1 = new_with_vtable(ConstClass(node_vtable))
+ setfield_gc(p1, i1, descr=valuedescr)
+ setfield_gc(p0, p1, descr=nextdescr)
+ setfield_raw(i1, i1, descr=valuedescr) # random op with side-effects
+ p2 = getfield_gc(p0, descr=nextdescr)
+ i2 = getfield_gc(p2, descr=valuedescr)
+ setfield_gc(p0, NULL, descr=nextdescr)
+ escape(i2)
+ jump(p0, i1)
+ """
+ expected = """
+ [p0, i1]
+ setfield_raw(i1, i1, descr=valuedescr)
+ setfield_gc(p0, NULL, descr=nextdescr)
+ escape(i1)
+ jump(p0, i1)
+ """
+ self.optimize_loop(ops, 'Not, Not', expected)
+
+ def test_duplicate_setfield_sideeffects_1(self):
+ ops = """
+ [p1, i1, i2]
+ setfield_gc(p1, i1, descr=valuedescr)
+ escape()
+ setfield_gc(p1, i2, descr=valuedescr)
+ jump(p1, i1, i2)
+ """
+ self.optimize_loop(ops, 'Not, Not, Not', ops)
+
+ def test_duplicate_setfield_residual_guard_1(self):
+ ops = """
+ [p1, i1, i2, i3]
+ setfield_gc(p1, i1, descr=valuedescr)
+ guard_true(i3) []
+ i4 = int_neg(i2)
+ setfield_gc(p1, i2, descr=valuedescr)
+ jump(p1, i1, i2, i4)
+ """
+ self.optimize_loop(ops, 'Not, Not, Not, Not', ops)
+
+ def test_duplicate_setfield_residual_guard_2(self):
+ # the difference with the previous test is that the field value is
+ # a virtual, which we try hard to keep virtual
+ ops = """
+ [p1, i2, i3]
+ p2 = new_with_vtable(ConstClass(node_vtable))
+ setfield_gc(p1, p2, descr=nextdescr)
+ guard_true(i3) []
+ i4 = int_neg(i2)
+ setfield_gc(p1, NULL, descr=nextdescr)
+ jump(p1, i2, i4)
+ """
+ expected = """
+ [p1, i2, i3]
+ guard_true(i3) [p1]
+ i4 = int_neg(i2)
+ setfield_gc(p1, NULL, descr=nextdescr)
+ jump(p1, i2, i4)
+ """
+ self.optimize_loop(ops, 'Not, Not, Not', expected)
+
+ def test_duplicate_setfield_residual_guard_3(self):
+ ops = """
+ [p1, i2, i3]
+ p2 = new_with_vtable(ConstClass(node_vtable))
+ setfield_gc(p2, i2, descr=valuedescr)
+ setfield_gc(p1, p2, descr=nextdescr)
+ guard_true(i3) []
+ i4 = int_neg(i2)
+ setfield_gc(p1, NULL, descr=nextdescr)
+ jump(p1, i2, i4)
+ """
+ expected = """
+ [p1, i2, i3]
+ guard_true(i3) [p1, i2]
+ i4 = int_neg(i2)
+ setfield_gc(p1, NULL, descr=nextdescr)
+ jump(p1, i2, i4)
+ """
+ self.optimize_loop(ops, 'Not, Not, Not', expected)
+
+ def test_duplicate_setfield_residual_guard_4(self):
+ # test that the setfield_gc does not end up between int_eq and
+ # the following guard_true
+ ops = """
+ [p1, i1, i2, i3]
+ setfield_gc(p1, i1, descr=valuedescr)
+ i5 = int_eq(i3, 5)
+ guard_true(i5) []
+ i4 = int_neg(i2)
+ setfield_gc(p1, i2, descr=valuedescr)
+ jump(p1, i1, i2, i4)
+ """
+ self.optimize_loop(ops, 'Not, Not, Not, Not', ops)
+
+ def test_duplicate_setfield_aliasing(self):
+ # a case where aliasing issues (and not enough cleverness) mean
+ # that we fail to remove any setfield_gc
+ ops = """
+ [p1, p2, i1, i2, i3]
+ setfield_gc(p1, i1, descr=valuedescr)
+ setfield_gc(p2, i2, descr=valuedescr)
+ setfield_gc(p1, i3, descr=valuedescr)
+ jump(p1, p2, i1, i2, i3)
+ """
+ self.optimize_loop(ops, 'Not, Not, Not, Not, Not', ops)
+
+ def test_duplicate_setfield_guard_value_const(self):
+ ops = """
+ [p1, i1, i2]
+ guard_value(p1, ConstPtr(myptr)) []
+ setfield_gc(p1, i1, descr=valuedescr)
+ setfield_gc(ConstPtr(myptr), i2, descr=valuedescr)
+ jump(p1, i1, i2)
+ """
+ expected = """
+ [i1, i2]
+ setfield_gc(ConstPtr(myptr), i2, descr=valuedescr)
+ jump(i1, i2)
+ """
+ self.optimize_loop(ops, 'Constant(myptr), Not, Not', expected)
+
def test_duplicate_getarrayitem_1(self):
ops = """
[p1]
@@ -1592,6 +1861,36 @@
"""
self.optimize_loop(ops, "Not", expected)
+ def test_remove_duplicate_pure_op(self):
+ ops = """
+ [p1, p2]
+ i1 = oois(p1, p2)
+ i2 = oois(p1, p2)
+ i3 = int_add(i1, 1)
+ i3b = int_is_true(i3)
+ guard_true(i3b) []
+ i4 = int_add(i2, 1)
+ i4b = int_is_true(i4)
+ guard_true(i4b) []
+ escape(i3)
+ escape(i4)
+ guard_true(i1) []
+ guard_true(i2) []
+ jump(p1, p2)
+ """
+ expected = """
+ [p1, p2]
+ i1 = oois(p1, p2)
+ i3 = int_add(i1, 1)
+ i3b = int_is_true(i3)
+ guard_true(i3b) []
+ escape(i3)
+ escape(i3)
+ guard_true(i1) []
+ jump(p1, p2)
+ """
+ self.optimize_loop(ops, "Not, Not", expected)
+
# ----------
def make_fail_descr(self):
@@ -1634,6 +1933,14 @@
tag = ('virtual', self.namespace[match.group(2)])
virtuals[pvar] = (tag, None, fieldstext)
#
+ r2 = re.compile(r"([\w\d()]+)[.](\w+)\s*=\s*([\w\d()]+)")
+ pendingfields = []
+ for match in r2.finditer(text):
+ pvar = match.group(1)
+ pfieldname = match.group(2)
+ pfieldvar = match.group(3)
+ pendingfields.append((pvar, pfieldname, pfieldvar))
+ #
def _variables_equal(box, varname, strict):
if varname not in virtuals:
if strict:
@@ -1655,11 +1962,21 @@
else:
virtuals[varname] = tag, box, fieldstext
#
- basetext = text[:ends[0]]
+ basetext = text.splitlines()[0]
varnames = [s.strip() for s in basetext.split(',')]
+ if varnames == ['']:
+ varnames = []
assert len(boxes) == len(varnames)
for box, varname in zip(boxes, varnames):
_variables_equal(box, varname, strict=True)
+ for pvar, pfieldname, pfieldvar in pendingfields:
+ box = oparse.getvar(pvar)
+ fielddescr = self.namespace[pfieldname.strip()]
+ fieldbox = executor.execute(self.cpu,
+ rop.GETFIELD_GC,
+ fielddescr,
+ box)
+ _variables_equal(fieldbox, pfieldvar, strict=True)
#
for match in parts:
pvar = match.group(1)
@@ -1918,6 +2235,57 @@
where p7v is a node_vtable, valuedescr=iv
''')
+ def test_expand_fail_lazy_setfield_1(self):
+ self.make_fail_descr()
+ ops = """
+ [p1, i2, i3]
+ p2 = new_with_vtable(ConstClass(node_vtable))
+ setfield_gc(p2, i2, descr=valuedescr)
+ setfield_gc(p1, p2, descr=nextdescr)
+ guard_true(i3, descr=fdescr) []
+ i4 = int_neg(i2)
+ setfield_gc(p1, NULL, descr=nextdescr)
+ jump(p1, i2, i4)
+ """
+ expected = """
+ [p1, i2, i3]
+ guard_true(i3, descr=fdescr) [p1, i2]
+ i4 = int_neg(i2)
+ setfield_gc(p1, NULL, descr=nextdescr)
+ jump(p1, i2, i4)
+ """
+ self.optimize_loop(ops, 'Not, Not, Not', expected)
+ self.loop.inputargs[0].value = self.nodebox.value
+ self.check_expanded_fail_descr('''
+ p1.nextdescr = p2
+ where p2 is a node_vtable, valuedescr=i2
+ ''')
+
+ def test_expand_fail_lazy_setfield_2(self):
+ self.make_fail_descr()
+ ops = """
+ [i2, i3]
+ p2 = new_with_vtable(ConstClass(node_vtable))
+ setfield_gc(p2, i2, descr=valuedescr)
+ setfield_gc(ConstPtr(myptr), p2, descr=nextdescr)
+ guard_true(i3, descr=fdescr) []
+ i4 = int_neg(i2)
+ setfield_gc(ConstPtr(myptr), NULL, descr=nextdescr)
+ jump(i2, i4)
+ """
+ expected = """
+ [i2, i3]
+ guard_true(i3, descr=fdescr) [i2]
+ i4 = int_neg(i2)
+ setfield_gc(ConstPtr(myptr), NULL, descr=nextdescr)
+ jump(i2, i4)
+ """
+ self.optimize_loop(ops, 'Not, Not', expected)
+ self.check_expanded_fail_descr('''
+ ConstPtr(myptr).nextdescr = p2
+ where p2 is a node_vtable, valuedescr=i2
+ ''')
+
class TestLLtype(BaseTestOptimizeOpt, LLtypeMixin):
@@ -2031,6 +2399,233 @@
"""
self.optimize_loop(ops, 'Not, Not, Not', expected)
+ def test_residual_call_invalidates_some_read_caches_1(self):
+ ops = """
+ [p1, i1, p2, i2]
+ setfield_gc(p1, i1, descr=valuedescr)
+ setfield_gc(p2, i2, descr=adescr)
+ i3 = call(i1, descr=readadescr)
+ setfield_gc(p1, i3, descr=valuedescr)
+ setfield_gc(p2, i3, descr=adescr)
+ jump(p1, i1, p2, i2)
+ """
+ expected = """
+ [p1, i1, p2, i2]
+ setfield_gc(p2, i2, descr=adescr)
+ i3 = call(i1, descr=readadescr)
+ setfield_gc(p1, i3, descr=valuedescr)
+ setfield_gc(p2, i3, descr=adescr)
+ jump(p1, i1, p2, i2)
+ """
+ self.optimize_loop(ops, 'Not, Not, Not, Not', expected)
+
+ def test_residual_call_invalidates_some_read_caches_2(self):
+ ops = """
+ [p1, i1, p2, i2]
+ setfield_gc(p1, i1, descr=valuedescr)
+ setfield_gc(p2, i2, descr=adescr)
+ i3 = call(i1, descr=writeadescr)
+ setfield_gc(p1, i3, descr=valuedescr)
+ setfield_gc(p2, i3, descr=adescr)
+ jump(p1, i1, p2, i2)
+ """
+ expected = """
+ [p1, i1, p2, i2]
+ setfield_gc(p2, i2, descr=adescr)
+ i3 = call(i1, descr=writeadescr)
+ setfield_gc(p1, i3, descr=valuedescr)
+ setfield_gc(p2, i3, descr=adescr)
+ jump(p1, i1, p2, i2)
+ """
+ self.optimize_loop(ops, 'Not, Not, Not, Not', expected)
+
+ def test_residual_call_invalidates_some_read_caches_3(self):
+ ops = """
+ [p1, i1, p2, i2]
+ setfield_gc(p1, i1, descr=valuedescr)
+ setfield_gc(p2, i2, descr=adescr)
+ i3 = call(i1, descr=plaincalldescr)
+ setfield_gc(p1, i3, descr=valuedescr)
+ setfield_gc(p2, i3, descr=adescr)
+ jump(p1, i1, p2, i2)
+ """
+ self.optimize_loop(ops, 'Not, Not, Not, Not', ops)
+
+ def test_call_assembler_invalidates_caches(self):
+ ops = '''
+ [p1, i1]
+ setfield_gc(p1, i1, descr=valuedescr)
+ i3 = call_assembler(i1, descr=asmdescr)
+ setfield_gc(p1, i3, descr=valuedescr)
+ jump(p1, i3)
+ '''
+ self.optimize_loop(ops, 'Not, Not', ops)
+
+ def test_vref_nonvirtual_nonescape(self):
+ ops = """
+ [p1]
+ p2 = virtual_ref(p1, 5)
+ virtual_ref_finish(p2, p1)
+ jump(p1)
+ """
+ expected = """
+ [p1]
+ i0 = force_token()
+ jump(p1)
+ """
+ self.optimize_loop(ops, 'Not', expected)
+
+ def test_vref_nonvirtual_escape(self):
+ ops = """
+ [p1]
+ p2 = virtual_ref(p1, 5)
+ escape(p2)
+ virtual_ref_finish(p2, p1)
+ jump(p1)
+ """
+ expected = """
+ [p1]
+ i0 = force_token()
+ p2 = new_with_vtable(ConstClass(jit_virtual_ref_vtable))
+ setfield_gc(p2, i0, descr=virtualtokendescr)
+ setfield_gc(p2, 5, descr=virtualrefindexdescr)
+ escape(p2)
+ setfield_gc(p2, p1, descr=virtualforceddescr)
+ setfield_gc(p2, 0, descr=virtualtokendescr)
+ jump(p1)
+ """
+ # XXX we should optimize a bit more the case of a nonvirtual.
+ # in theory it is enough to just do 'p2 = p1'.
+ self.optimize_loop(ops, 'Not', expected)
+
+ def test_vref_virtual_1(self):
+ ops = """
+ [p0, i1]
+ #
+ p1 = new_with_vtable(ConstClass(node_vtable))
+ p1b = new_with_vtable(ConstClass(node_vtable))
+ setfield_gc(p1b, 252, descr=valuedescr)
+ setfield_gc(p1, p1b, descr=nextdescr)
+ #
+ p2 = virtual_ref(p1, 3)
+ setfield_gc(p0, p2, descr=nextdescr)
+ call_may_force(i1, descr=mayforcevirtdescr)
+ guard_not_forced() [i1]
+ virtual_ref_finish(p2, p1)
+ setfield_gc(p0, NULL, descr=nextdescr)
+ jump(p0, i1)
+ """
+ expected = """
+ [p0, i1]
+ i3 = force_token()
+ #
+ p2 = new_with_vtable(ConstClass(jit_virtual_ref_vtable))
+ setfield_gc(p2, i3, descr=virtualtokendescr)
+ setfield_gc(p2, 3, descr=virtualrefindexdescr)
+ setfield_gc(p0, p2, descr=nextdescr)
+ #
+ call_may_force(i1, descr=mayforcevirtdescr)
+ guard_not_forced() [i1]
+ setfield_gc(p0, NULL, descr=nextdescr)
+ #
+ p1 = new_with_vtable(ConstClass(node_vtable))
+ p1b = new_with_vtable(ConstClass(node_vtable))
+ setfield_gc(p1b, 252, descr=valuedescr)
+ setfield_gc(p1, p1b, descr=nextdescr)
+ setfield_gc(p2, p1, descr=virtualforceddescr)
+ setfield_gc(p2, 0, descr=virtualtokendescr)
+ #
+ jump(p0, i1)
+ """
+ self.optimize_loop(ops, 'Not, Not', expected)
+
+ def test_vref_virtual_2(self):
+ self.make_fail_descr()
+ ops = """
+ [p0, i1]
+ #
+ p1 = new_with_vtable(ConstClass(node_vtable))
+ p1b = new_with_vtable(ConstClass(node_vtable))
+ setfield_gc(p1b, i1, descr=valuedescr)
+ setfield_gc(p1, p1b, descr=nextdescr)
+ #
+ p2 = virtual_ref(p1, 2)
+ setfield_gc(p0, p2, descr=nextdescr)
+ call_may_force(i1, descr=mayforcevirtdescr)
+ guard_not_forced(descr=fdescr) [p2, p1]
+ virtual_ref_finish(p2, p1)
+ setfield_gc(p0, NULL, descr=nextdescr)
+ jump(p0, i1)
+ """
+ expected = """
+ [p0, i1]
+ i3 = force_token()
+ #
+ p2 = new_with_vtable(ConstClass(jit_virtual_ref_vtable))
+ setfield_gc(p2, i3, descr=virtualtokendescr)
+ setfield_gc(p2, 2, descr=virtualrefindexdescr)
+ setfield_gc(p0, p2, descr=nextdescr)
+ #
+ call_may_force(i1, descr=mayforcevirtdescr)
+ guard_not_forced(descr=fdescr) [p2, i1]
+ setfield_gc(p0, NULL, descr=nextdescr)
+ #
+ p1 = new_with_vtable(ConstClass(node_vtable))
+ p1b = new_with_vtable(ConstClass(node_vtable))
+ setfield_gc(p1b, i1, descr=valuedescr)
+ setfield_gc(p1, p1b, descr=nextdescr)
+ setfield_gc(p2, p1, descr=virtualforceddescr)
+ setfield_gc(p2, 0, descr=virtualtokendescr)
+ #
+ jump(p0, i1)
+ """
+ # the point of this test is that 'i1' should show up in the fail_args
+ # of 'guard_not_forced', because it was stored in the virtual 'p1b'.
+ self.optimize_loop(ops, 'Not, Not', expected)
+ self.check_expanded_fail_descr('''p2, p1
+ where p1 is a node_vtable, nextdescr=p1b
+ where p1b is a node_vtable, valuedescr=i1
+ ''')
+
+ def test_vref_virtual_and_lazy_setfield(self):
+ self.make_fail_descr()
+ ops = """
+ [p0, i1]
+ #
+ p1 = new_with_vtable(ConstClass(node_vtable))
+ p1b = new_with_vtable(ConstClass(node_vtable))
+ setfield_gc(p1b, i1, descr=valuedescr)
+ setfield_gc(p1, p1b, descr=nextdescr)
+ #
+ p2 = virtual_ref(p1, 2)
+ setfield_gc(p0, p2, descr=refdescr)
+ call(i1, descr=nonwritedescr)
+ guard_no_exception(descr=fdescr) [p2, p1]
+ virtual_ref_finish(p2, p1)
+ setfield_gc(p0, NULL, descr=refdescr)
+ jump(p0, i1)
+ """
+ expected = """
+ [p0, i1]
+ i3 = force_token()
+ call(i1, descr=nonwritedescr)
+ guard_no_exception(descr=fdescr) [i3, i1, p0]
+ setfield_gc(p0, NULL, descr=refdescr)
+ jump(p0, i1)
+ """
+ self.optimize_loop(ops, 'Not, Not', expected)
+ # the fail_args contain [i3, i1, p0]:
+ # - i3 is from the virtual expansion of p2
+ # - i1 is from the virtual expansion of p1
+ # - p0 is from the extra pendingfields
+ self.loop.inputargs[0].value = self.nodeobjvalue
+ self.check_expanded_fail_descr('''p2, p1
+ p0.refdescr = p2
+ where p2 is a jit_virtual_ref_vtable, virtualtokendescr=i3, virtualrefindexdescr=2
+ where p1 is a node_vtable, nextdescr=p1b
+ where p1b is a node_vtable, valuedescr=i1
+ ''')
+
class TestOOtype(BaseTestOptimizeOpt, OOtypeMixin):
Modified: pypy/branch/stringbuilder2/pypy/jit/metainterp/test/test_pyjitpl.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/jit/metainterp/test/test_pyjitpl.py (original)
+++ pypy/branch/stringbuilder2/pypy/jit/metainterp/test/test_pyjitpl.py Mon Jan 25 15:25:48 2010
@@ -33,7 +33,8 @@
def test_simple_opimpl_exist():
rop = resoperation.rop
for opnum, opname in resoperation.opname.items():
- if opnum in (rop.SAME_AS, rop.CALL_PURE, rop.OOSEND_PURE):
+ if opnum in (rop.SAME_AS, rop.CALL_PURE, rop.OOSEND_PURE,
+ rop.FORCE_TOKEN):
continue
if rop._NOSIDEEFFECT_FIRST <= opnum <= rop._NOSIDEEFFECT_LAST:
assert hasattr(pyjitpl.MIFrame, 'opimpl_' + opname.lower()), opname
@@ -88,7 +89,7 @@
assert box.value == referencebox.value
return True
metainterp = pyjitpl.MetaInterp(FakeStaticData())
- metainterp.history = History(None)
+ metainterp.history = History()
b1 = BoxInt(1)
b2 = BoxInt(2)
c3 = ConstInt(3)
Modified: pypy/branch/stringbuilder2/pypy/jit/metainterp/test/test_recursive.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/jit/metainterp/test/test_recursive.py (original)
+++ pypy/branch/stringbuilder2/pypy/jit/metainterp/test/test_recursive.py Mon Jan 25 15:25:48 2010
@@ -1,5 +1,5 @@
import py
-from pypy.rlib.jit import JitDriver, we_are_jitted, OPTIMIZER_SIMPLE
+from pypy.rlib.jit import JitDriver, we_are_jitted, OPTIMIZER_SIMPLE, hint
from pypy.jit.metainterp.test.test_basic import LLJitMixin, OOJitMixin
from pypy.jit.metainterp.policy import StopAtXPolicy
from pypy.rpython.annlowlevel import hlstr
@@ -646,9 +646,303 @@
result += f('-c-----------l-', i+100)
self.meta_interp(g, [10], backendopt=True)
self.check_aborted_count(1)
- self.check_history(call_may_force=1, call=0)
+ self.check_history(call_assembler=1, call=0)
self.check_tree_loop_count(3)
+
+ def test_directly_call_assembler(self):
+ driver = JitDriver(greens = ['codeno'], reds = ['i'],
+ get_printable_location = lambda codeno : str(codeno),
+ can_inline = lambda codeno : False)
+
+ def portal(codeno):
+ i = 0
+ while i < 10:
+ driver.can_enter_jit(codeno = codeno, i = i)
+ driver.jit_merge_point(codeno = codeno, i = i)
+ if codeno == 2:
+ portal(1)
+ i += 1
+
+ self.meta_interp(portal, [2], inline=True)
+ self.check_history(call_assembler=1)
+
+ def test_directly_call_assembler_return(self):
+ driver = JitDriver(greens = ['codeno'], reds = ['i', 'k'],
+ get_printable_location = lambda codeno : str(codeno),
+ can_inline = lambda codeno : False)
+
+ def portal(codeno):
+ i = 0
+ k = codeno
+ while i < 10:
+ driver.can_enter_jit(codeno = codeno, i = i, k = k)
+ driver.jit_merge_point(codeno = codeno, i = i, k = k)
+ if codeno == 2:
+ k = portal(1)
+ i += 1
+ return k
+
+ self.meta_interp(portal, [2], inline=True)
+ self.check_history(call_assembler=1)
+
+ def test_directly_call_assembler_raise(self):
+
+ class MyException(Exception):
+ def __init__(self, x):
+ self.x = x
+
+ driver = JitDriver(greens = ['codeno'], reds = ['i'],
+ get_printable_location = lambda codeno : str(codeno),
+ can_inline = lambda codeno : False)
+
+ def portal(codeno):
+ i = 0
+ while i < 10:
+ driver.can_enter_jit(codeno = codeno, i = i)
+ driver.jit_merge_point(codeno = codeno, i = i)
+ if codeno == 2:
+ try:
+ portal(1)
+ except MyException, me:
+ i += me.x
+ i += 1
+ if codeno == 1:
+ raise MyException(1)
+
+ self.meta_interp(portal, [2], inline=True)
+ self.check_history(call_assembler=1)
+
+ def test_directly_call_assembler_fail_guard(self):
+ driver = JitDriver(greens = ['codeno'], reds = ['i', 'k'],
+ get_printable_location = lambda codeno : str(codeno),
+ can_inline = lambda codeno : False)
+
+ def portal(codeno, k):
+ i = 0
+ while i < 10:
+ driver.can_enter_jit(codeno=codeno, i=i, k=k)
+ driver.jit_merge_point(codeno=codeno, i=i, k=k)
+ if codeno == 2:
+ k += portal(1, k)
+ elif k > 40:
+ if i % 2:
+ k += 1
+ else:
+ k += 2
+ k += 1
+ i += 1
+ return k
+
+ res = self.meta_interp(portal, [2, 0], inline=True)
+ assert res == 13542
+
+ def test_directly_call_assembler_virtualizable(self):
+ class Thing(object):
+ def __init__(self, val):
+ self.val = val
+
+ class Frame(object):
+ _virtualizable2_ = ['thing']
+
+ driver = JitDriver(greens = ['codeno'], reds = ['frame', 'i'],
+ virtualizables = ['frame'],
+ get_printable_location = lambda codeno : str(codeno),
+ can_inline = lambda codeno : False)
+
+ def main(codeno):
+ frame = Frame()
+ frame.thing = Thing(0)
+ portal(codeno, frame)
+ return frame.thing.val
+
+ def portal(codeno, frame):
+ i = 0
+ while i < 10:
+ driver.can_enter_jit(frame=frame, codeno=codeno, i=i)
+ driver.jit_merge_point(frame=frame, codeno=codeno, i=i)
+ nextval = frame.thing.val
+ if codeno == 0:
+ subframe = Frame()
+ subframe.thing = Thing(nextval)
+ nextval = portal(1, subframe)
+ frame.thing = Thing(nextval + 1)
+ i += 1
+ return frame.thing.val
+
+ res = self.meta_interp(main, [0], inline=True)
+ assert res == main(0)
+
+ def test_directly_call_assembler_virtualizable_force(self):
+ class Thing(object):
+ def __init__(self, val):
+ self.val = val
+ class Frame(object):
+ _virtualizable2_ = ['thing']
+
+ driver = JitDriver(greens = ['codeno'], reds = ['frame', 'i'],
+ virtualizables = ['frame'],
+ get_printable_location = lambda codeno : str(codeno),
+ can_inline = lambda codeno : False)
+ class SomewhereElse(object):
+ pass
+
+ somewhere_else = SomewhereElse()
+
+ def change(newthing):
+ somewhere_else.frame.thing = newthing
+
+ def main(codeno):
+ frame = Frame()
+ somewhere_else.frame = frame
+ frame.thing = Thing(0)
+ portal(codeno, frame)
+ return frame.thing.val
+
+ def portal(codeno, frame):
+ i = 0
+ while i < 10:
+ driver.can_enter_jit(frame=frame, codeno=codeno, i=i)
+ driver.jit_merge_point(frame=frame, codeno=codeno, i=i)
+ nextval = frame.thing.val
+ if codeno == 0:
+ subframe = Frame()
+ subframe.thing = Thing(nextval)
+ nextval = portal(1, subframe)
+ elif frame.thing.val > 40:
+ change(Thing(13))
+ nextval = 13
+ frame.thing = Thing(nextval + 1)
+ i += 1
+ return frame.thing.val
+
+ res = self.meta_interp(main, [0], inline=True,
+ policy=StopAtXPolicy(change))
+ assert res == main(0)
+
+ def test_directly_call_assembler_virtualizable_with_array(self):
+ myjitdriver = JitDriver(greens = ['codeno'], reds = ['n', 'frame', 'x'],
+ virtualizables = ['frame'],
+ can_inline = lambda codeno : False)
+
+ class Frame(object):
+ _virtualizable2_ = ['l[*]', 's']
+
+ def __init__(self, l, s):
+ self = hint(self, access_directly=True,
+ fresh_virtualizable=True)
+ self.l = l
+ self.s = s
+
+ def main(codeno, n, a):
+ frame = Frame([a, a+1, a+2, a+3], 0)
+ return f(codeno, n, a, frame)
+
+ def f(codeno, n, a, frame):
+ x = 0
+ while n > 0:
+ myjitdriver.can_enter_jit(codeno=codeno, frame=frame, n=n, x=x)
+ myjitdriver.jit_merge_point(codeno=codeno, frame=frame, n=n,
+ x=x)
+ frame.s = hint(frame.s, promote=True)
+ n -= 1
+ x += frame.l[frame.s]
+ frame.s += 1
+ if codeno == 0:
+ subframe = Frame([n, n+1, n+2, n+3], 0)
+ x += f(1, 10, 1, subframe)
+ x += frame.l[frame.s]
+ x += len(frame.l)
+ frame.s -= 1
+ return x
+
+ res = self.meta_interp(main, [0, 10, 1], listops=True, inline=True)
+ assert res == main(0, 10, 1)
+
+ def test_directly_call_assembler_virtualizable_force_blackhole(self):
+ class Thing(object):
+ def __init__(self, val):
+ self.val = val
+
+ class Frame(object):
+ _virtualizable2_ = ['thing']
+
+ driver = JitDriver(greens = ['codeno'], reds = ['frame', 'i'],
+ virtualizables = ['frame'],
+ get_printable_location = lambda codeno : str(codeno),
+ can_inline = lambda codeno : False)
+ class SomewhereElse(object):
+ pass
+
+ somewhere_else = SomewhereElse()
+
+ def change(newthing, arg):
+ print arg
+ if arg > 30:
+ somewhere_else.frame.thing = newthing
+ arg = 13
+ return arg
+
+ def main(codeno):
+ frame = Frame()
+ somewhere_else.frame = frame
+ frame.thing = Thing(0)
+ portal(codeno, frame)
+ return frame.thing.val
+
+ def portal(codeno, frame):
+ i = 0
+ while i < 10:
+ driver.can_enter_jit(frame=frame, codeno=codeno, i=i)
+ driver.jit_merge_point(frame=frame, codeno=codeno, i=i)
+ nextval = frame.thing.val
+ if codeno == 0:
+ subframe = Frame()
+ subframe.thing = Thing(nextval)
+ nextval = portal(1, subframe)
+ else:
+ nextval = change(Thing(13), frame.thing.val)
+ frame.thing = Thing(nextval + 1)
+ i += 1
+ return frame.thing.val
+
+ res = self.meta_interp(main, [0], inline=True,
+ policy=StopAtXPolicy(change))
+ assert res == main(0)
+
+ def test_assembler_call_red_args(self):
+ driver = JitDriver(greens = ['codeno'], reds = ['i', 'k'],
+ get_printable_location = lambda codeno : str(codeno),
+ can_inline = lambda codeno : False)
+
+ def residual(k):
+ if k > 40:
+ return 0
+ return 1
+
+ def portal(codeno, k):
+ i = 0
+ while i < 10:
+ driver.can_enter_jit(codeno=codeno, i=i, k=k)
+ driver.jit_merge_point(codeno=codeno, i=i, k=k)
+ if codeno == 2:
+ k += portal(residual(k), k)
+ if codeno == 0:
+ k += 2
+ elif codeno == 1:
+ k += 1
+ i += 1
+ return k
+
+ res = self.meta_interp(portal, [2, 0], inline=True,
+ policy=StopAtXPolicy(residual))
+ assert res == portal(2, 0)
+ self.check_loops(call_assembler=2)
+
+ # There is a test which I fail to write.
+ # * what happens if we call recursive_call while blackholing
+ # this seems to be completely corner case and not really happening
+ # in the wild
class TestLLtype(RecursiveTests, LLJitMixin):
pass
Modified: pypy/branch/stringbuilder2/pypy/jit/metainterp/test/test_resume.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/jit/metainterp/test/test_resume.py (original)
+++ pypy/branch/stringbuilder2/pypy/jit/metainterp/test/test_resume.py Mon Jan 25 15:25:48 2010
@@ -12,6 +12,8 @@
rd_frame_info_list = None
rd_numb = None
rd_consts = []
+ rd_virtuals = None
+ rd_pendingfields = None
def test_tag():
assert tag(3, 1) == rffi.r_short(3<<2|1)
@@ -40,6 +42,12 @@
assert not tagged_list_eq([tag(1, TAGBOX)], [tag(-2, TAGBOX)])
assert not tagged_list_eq([tag(1, TAGBOX), tag(-2, TAGBOX)], [tag(1, TAGBOX)])
+def test_vinfo():
+ v1 = AbstractVirtualInfo()
+ v1.set_content([1, 2, 4])
+ assert v1.equals([1, 2, 4])
+ assert not v1.equals([1, 2, 6])
+
class MyMetaInterp:
_already_allocated_resume_virtuals = None
@@ -80,7 +88,6 @@
tag(0, TAGBOX),
tag(1, TAGBOX)])
storage.rd_numb = numb
- storage.rd_virtuals = None
b1s, b2s, b3s = [BoxInt(), BoxPtr(), BoxInt()]
assert b1s != b3s
@@ -103,7 +110,6 @@
tag(0, TAGBOX),
tag(1, TAGBOX)])
storage.rd_numb = numb
- storage.rd_virtuals = None
b1s, b2s, b3s = [BoxInt(), BoxPtr(), BoxInt()]
assert b1s != b3s
reader = ResumeDataReader(storage, [b1s, b2s, b3s], MyMetaInterp())
@@ -125,6 +131,7 @@
rd_virtuals = [FakeVinfo(), None]
rd_numb = []
rd_consts = []
+ rd_pendingfields = None
class FakeMetainterp(object):
_already_allocated_resume_virtuals = None
cpu = None
@@ -175,7 +182,6 @@
assert fi.jitcode is jitcode
assert fi.pc == 1
assert fi.exception_target == 2
- assert fi.level == 1
jitcode1 = "JITCODE1"
frame1 = FakeFrame(jitcode, 3, 4)
@@ -184,7 +190,6 @@
assert fi1.jitcode is jitcode
assert fi1.pc == 3
assert fi1.exception_target == 4
- assert fi1.level == 2
def test_Numbering_create():
l = [1, 2]
@@ -203,29 +208,32 @@
fs = [FakeFrame("code0", 0, -1, b1, c1, b2)]
storage = Storage()
- capture_resumedata(fs, None, storage)
+ capture_resumedata(fs, None, [], storage)
assert fs[0].parent_resumedata_snapshot is None
assert fs[0].parent_resumedata_frame_info_list is None
assert storage.rd_frame_info_list.prev is None
assert storage.rd_frame_info_list.jitcode == 'code0'
- assert storage.rd_snapshot.prev is None
- assert storage.rd_snapshot.boxes == fs[0].env
- assert storage.rd_snapshot.boxes is not fs[0].env
+ assert storage.rd_snapshot.boxes == [] # for virtualrefs
+ snapshot = storage.rd_snapshot.prev
+ assert snapshot.prev is None
+ assert snapshot.boxes == fs[0].env
+ assert snapshot.boxes is not fs[0].env
storage = Storage()
fs = [FakeFrame("code0", 0, -1, b1, c1, b2),
FakeFrame("code1", 3, 7, b3, c2, b1),
FakeFrame("code2", 9, -1, c3, b2)]
- capture_resumedata(fs, None, storage)
+ capture_resumedata(fs, None, [], storage)
frame_info_list = storage.rd_frame_info_list
assert frame_info_list.prev is fs[2].parent_resumedata_frame_info_list
assert frame_info_list.jitcode == 'code2'
assert frame_info_list.pc == 9
- snapshot = storage.rd_snapshot
+ assert storage.rd_snapshot.boxes == [] # for virtualrefs
+ snapshot = storage.rd_snapshot.prev
assert snapshot.prev is fs[2].parent_resumedata_snapshot
assert snapshot.boxes == fs[2].env
assert snapshot.boxes is not fs[2].env
@@ -249,8 +257,9 @@
fs[2].env = [b2, b3]
fs[2].pc = 15
vbs = [b1, b2]
- capture_resumedata(fs, vbs, storage)
-
+ vrs = [b3]
+ capture_resumedata(fs, vbs, vrs, storage)
+
frame_info_list = storage.rd_frame_info_list
assert frame_info_list.prev is fs[2].parent_resumedata_frame_info_list
assert frame_info_list.jitcode == 'code2'
@@ -261,6 +270,10 @@
assert snapshot.boxes is not vbs
snapshot = snapshot.prev
+ assert snapshot.boxes == vrs
+ assert snapshot.boxes is not vrs
+
+ snapshot = snapshot.prev
assert snapshot.prev is fs[2].parent_resumedata_snapshot
assert snapshot.boxes == fs[2].env
@@ -278,7 +291,7 @@
fs = [FakeFrame("code0", 0, -1, b1, c1, b2),
FakeFrame("code1", 3, 7, b3, c2, b1),
FakeFrame("code2", 9, -1, c3, b2)]
- capture_resumedata(fs, None, storage)
+ capture_resumedata(fs, None, [], storage)
memo = ResumeDataLoopMemo(FakeMetaInterpStaticData())
modifier = ResumeDataVirtualAdder(storage, memo)
liveboxes = modifier.finish({})
@@ -289,7 +302,7 @@
result = rebuild_from_resumedata(metainterp, newboxes, storage,
False)
- assert result is None
+ assert result == (None, [])
fs2 = [FakeFrame("code0", 0, -1, b1t, c1, b2t),
FakeFrame("code1", 3, 7, b3t, c2, b1t),
FakeFrame("code2", 9, -1, c3, b2t)]
@@ -302,7 +315,7 @@
fs = [FakeFrame("code0", 0, -1, b1, c1, b2),
FakeFrame("code1", 3, 7, b3, c2, b1),
FakeFrame("code2", 9, -1, c3, b2)]
- capture_resumedata(fs, [b4], storage)
+ capture_resumedata(fs, [b4], [], storage)
memo = ResumeDataLoopMemo(FakeMetaInterpStaticData())
modifier = ResumeDataVirtualAdder(storage, memo)
liveboxes = modifier.finish({})
@@ -313,7 +326,7 @@
result = rebuild_from_resumedata(metainterp, newboxes, storage,
True)
- assert result == [b4t]
+ assert result == ([b4t], [])
fs2 = [FakeFrame("code0", 0, -1, b1t, c1, b2t),
FakeFrame("code1", 3, 7, b3t, c2, b1t),
FakeFrame("code2", 9, -1, c3, b2t)]
@@ -326,10 +339,10 @@
fs = [FakeFrame("code0", 0, -1, b1, c1, b2),
FakeFrame("code1", 3, 7, b3, c2, b1),
FakeFrame("code2", 9, -1, c3, b2)]
- capture_resumedata(fs, None, storage)
+ capture_resumedata(fs, None, [], storage)
storage2 = Storage()
fs = fs[:-1] + [FakeFrame("code2", 10, -1, c3, b2, b4)]
- capture_resumedata(fs, None, storage2)
+ capture_resumedata(fs, None, [], storage2)
memo = ResumeDataLoopMemo(FakeMetaInterpStaticData())
modifier = ResumeDataVirtualAdder(storage, memo)
@@ -345,7 +358,7 @@
result = rebuild_from_resumedata(metainterp, newboxes, storage,
False)
- assert result is None
+ assert result == (None, [])
fs2 = [FakeFrame("code0", 0, -1, b1t, c1, b2t),
FakeFrame("code1", 3, 7, b3t, c2, b1t),
FakeFrame("code2", 9, -1, c3, b2t)]
@@ -356,7 +369,7 @@
metainterp.framestack = []
result = rebuild_from_resumedata(metainterp, newboxes, storage2,
False)
- assert result is None
+ assert result == (None, [])
fs2 = fs2[:-1] + [FakeFrame("code2", 10, -1, c3, b2t, b4t)]
assert metainterp.framestack == fs2
@@ -384,10 +397,10 @@
fs = [FakeFrame("code0", 0, -1, b1, c1, b2),
FakeFrame("code1", 3, 7, b3, c2, b1),
FakeFrame("code2", 9, -1, c3, b2)]
- capture_resumedata(fs, None, storage)
+ capture_resumedata(fs, None, [], storage)
storage2 = Storage()
fs = fs[:-1] + [FakeFrame("code2", 10, -1, c3, b2, b4)]
- capture_resumedata(fs, None, storage2)
+ capture_resumedata(fs, None, [], storage2)
memo = ResumeDataLoopMemo(FakeMetaInterpStaticData())
values = {b2: virtual_value(b2, b5, c4)}
@@ -443,7 +456,7 @@
LLtypeMixin.nodebox.constbox()]
storage = Storage()
fs = [FakeFrame("code0", 0, -1, c1, b2, b3)]
- capture_resumedata(fs, None, storage)
+ capture_resumedata(fs, None, [], storage)
memo = ResumeDataLoopMemo(FakeMetaInterpStaticData())
values = {b2: virtual_value(b2, b5, c4)}
@@ -455,7 +468,7 @@
storage2 = Storage()
fs = [FakeFrame("code0", 0, -1, b1, b4, b2)]
- capture_resumedata(fs, None, storage2)
+ capture_resumedata(fs, None, [], storage2)
values[b4] = virtual_value(b4, b6, c4)
modifier = ResumeDataVirtualAdder(storage2, memo)
liveboxes = modifier.finish(values)
@@ -468,7 +481,7 @@
b1, b2, b3 = [BoxPtr(), BoxPtr(), BoxInt()]
storage = Storage()
fs = [FakeFrame("code0", 0, -1, b1, b2)]
- capture_resumedata(fs, None, storage)
+ capture_resumedata(fs, None, [], storage)
memo = ResumeDataLoopMemo(FakeMetaInterpStaticData())
v1 = virtual_value(b1, b3, None)
@@ -962,6 +975,46 @@
assert ptr.a == 111
assert ptr.b == lltype.nullptr(LLtypeMixin.NODE)
+
+def test_virtual_adder_pending_fields():
+ b2s, b4s = [BoxPtr(), BoxPtr()]
+ storage = Storage()
+ memo = ResumeDataLoopMemo(FakeMetaInterpStaticData())
+ modifier = ResumeDataVirtualAdder(storage, memo)
+ modifier.liveboxes_from_env = {}
+ modifier.liveboxes = {}
+ modifier.vfieldboxes = {}
+
+ v2 = OptValue(b2s)
+ v4 = OptValue(b4s)
+ modifier.register_box(b2s)
+ modifier.register_box(b4s)
+
+ values = {b4s: v4, b2s: v2}
+ liveboxes = []
+ modifier._number_virtuals(liveboxes, values, 0)
+ assert liveboxes == [b2s, b4s]
+ modifier._add_pending_fields([(LLtypeMixin.nextdescr, b2s, b4s)])
+ storage.rd_consts = memo.consts[:]
+ storage.rd_numb = None
+ # resume
+ demo55.next = lltype.nullptr(LLtypeMixin.NODE)
+ b2t = BoxPtr(demo55o)
+ b4t = BoxPtr(demo66o)
+ newboxes = _resume_remap(liveboxes, [b2s, b4s], b2t, b4t)
+
+ metainterp = MyMetaInterp()
+ reader = ResumeDataReader(storage, newboxes, metainterp)
+ assert reader.virtuals is None
+ trace = metainterp.trace
+ b2set = (rop.SETFIELD_GC, [b2t, b4t], None, LLtypeMixin.nextdescr)
+ expected = [b2set]
+
+ for x, y in zip(expected, trace):
+ assert x == y
+ assert demo55.next == demo66
+
+
def test_invalidation_needed():
class options:
failargs_limit = 10
Modified: pypy/branch/stringbuilder2/pypy/jit/metainterp/test/test_virtualizable.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/jit/metainterp/test/test_virtualizable.py (original)
+++ pypy/branch/stringbuilder2/pypy/jit/metainterp/test/test_virtualizable.py Mon Jan 25 15:25:48 2010
@@ -28,7 +28,7 @@
hop.inputconst(lltype.Void, hop.args_v[1].value),
hop.inputconst(lltype.Void, {})]
hop.exception_cannot_occur()
- return hop.genop('promote_virtualizable',
+ return hop.genop('jit_force_virtualizable',
args_v, resulttype=lltype.Void)
debug_print = lloperation.llop.debug_print
@@ -907,6 +907,39 @@
res = self.meta_interp(f, [123], policy=StopAtXPolicy(g))
assert res == f(123)
+ def test_bridge_forces(self):
+ jitdriver = JitDriver(greens = [], reds = ['frame'],
+ virtualizables = ['frame'])
+
+ class Frame(object):
+ _virtualizable2_ = ['x', 'y']
+ class SomewhereElse:
+ pass
+ somewhere_else = SomewhereElse()
+
+ def g():
+ n = somewhere_else.top_frame.y + 700
+ debug_print(lltype.Void, '-+-+-+-+- external write:', n)
+ somewhere_else.top_frame.y = n
+
+ def f(n):
+ frame = Frame()
+ frame.x = n
+ frame.y = 10
+ somewhere_else.counter = 0
+ somewhere_else.top_frame = frame
+ while frame.x > 0:
+ jitdriver.can_enter_jit(frame=frame)
+ jitdriver.jit_merge_point(frame=frame)
+ if frame.y > 17:
+ g()
+ frame.x -= 5
+ frame.y += 1
+ return frame.y
+
+ res = self.meta_interp(f, [123], policy=StopAtXPolicy(g))
+ assert res == f(123)
+
def test_promote_index_in_virtualizable_list(self):
jitdriver = JitDriver(greens = [], reds = ['frame', 'n'],
virtualizables = ['frame'])
@@ -980,9 +1013,11 @@
for block, op in graph.iterblockops()
if op.opname == 'direct_call']
- assert direct_calls(f_graph) == ['__init__', 'force_if_necessary', 'll_portal_runner']
- assert direct_calls(portal_graph) == ['force_if_necessary', 'maybe_enter_jit']
-
+ assert direct_calls(f_graph) == ['__init__',
+ 'force_virtualizable_if_necessary',
+ 'll_portal_runner']
+ assert direct_calls(portal_graph)==['force_virtualizable_if_necessary',
+ 'maybe_enter_jit']
assert direct_calls(init_graph) == []
def test_virtual_child_frame(self):
@@ -1158,8 +1193,9 @@
self.check_loops(getfield_gc=0, setfield_gc=0)
def test_blackhole_should_not_reenter(self):
- from pypy.jit.backend.test.support import BaseCompiledMixin
- if isinstance(self, BaseCompiledMixin):
+ # Armin thinks this can occur and does not make interpreters slower
+ # so we don't check for assertionerror, to be discussed
+ if not self.basic:
py.test.skip("purely frontend test")
myjitdriver = JitDriver(greens = [], reds = ['frame', 'fail'],
@@ -1200,8 +1236,9 @@
f(10, True)
return f(10, False)
- einfo = py.test.raises(AssertionError, self.meta_interp, main, [])
- assert einfo.value.args[0] == "reentering same frame via blackhole"
+ self.meta_interp(main, [])
+ #einfo = py.test.raises(AssertionError, self.meta_interp, main, [])
+ #assert einfo.value.args[0] == "reentering same frame via blackhole"
def test_inlining(self):
class Frame(object):
Modified: pypy/branch/stringbuilder2/pypy/jit/metainterp/test/test_warmspot.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/jit/metainterp/test/test_warmspot.py (original)
+++ pypy/branch/stringbuilder2/pypy/jit/metainterp/test/test_warmspot.py Mon Jan 25 15:25:48 2010
@@ -4,6 +4,7 @@
from pypy.rlib.jit import JitDriver, OPTIMIZER_FULL, OPTIMIZER_SIMPLE
from pypy.rlib.jit import unroll_safe
from pypy.jit.backend.llgraph import runner
+from pypy.jit.metainterp.history import BoxInt
from pypy.jit.metainterp.test.test_basic import LLJitMixin, OOJitMixin
@@ -283,3 +284,80 @@
class TestOOWarmspot(WarmspotTests, OOJitMixin):
CPUClass = runner.OOtypeCPU
type_system = 'ootype'
+
+class TestWarmspotDirect(object):
+ def setup_class(cls):
+ from pypy.jit.metainterp.typesystem import llhelper
+ from pypy.jit.metainterp.support import annotate
+ from pypy.jit.metainterp.warmspot import WarmRunnerDesc
+ from pypy.rpython.lltypesystem.rclass import OBJECT, OBJECT_VTABLE
+ from pypy.rpython.lltypesystem import lltype, llmemory
+ exc_vtable = lltype.malloc(OBJECT_VTABLE, immortal=True)
+ cls.exc_vtable = exc_vtable
+
+ class FakeFailDescr(object):
+ def __init__(self, no):
+ self.no = no
+
+ def handle_fail(self, metainterp_sd):
+ if self.no == 0:
+ raise metainterp_sd.warmrunnerdesc.DoneWithThisFrameInt(3)
+ if self.no == 1:
+ raise metainterp_sd.warmrunnerdesc.ContinueRunningNormally(
+ [BoxInt(0), BoxInt(1)])
+ if self.no == 3:
+ exc = lltype.malloc(OBJECT)
+ exc.typeptr = exc_vtable
+ raise metainterp_sd.warmrunnerdesc.ExitFrameWithExceptionRef(
+ metainterp_sd.cpu,
+ lltype.cast_opaque_ptr(llmemory.GCREF, exc))
+ return self.no
+
+ class FakeCPU(object):
+ supports_floats = False
+ ts = llhelper
+ translate_support_code = False
+
+ def __init__(self, *args, **kwds):
+ pass
+
+ def nodescr(self, *args, **kwds):
+ pass
+ fielddescrof = nodescr
+ calldescrof = nodescr
+ sizeof = nodescr
+
+ def get_fail_descr_from_number(self, no):
+ return FakeFailDescr(no)
+
+ def execute_token(self, token):
+ assert token == 2
+ return FakeFailDescr(1)
+
+ driver = JitDriver(reds = ['red'], greens = ['green'])
+
+ def f(green):
+ red = 0
+ while red < 10:
+ driver.can_enter_jit(red=red, green=green)
+ driver.jit_merge_point(red=red, green=green)
+ red += 1
+ return red
+
+ rtyper = annotate(f, [0])
+ translator = rtyper.annotator.translator
+ translator.config.translation.gc = 'hybrid'
+ cls.desc = WarmRunnerDesc(translator, CPUClass=FakeCPU)
+
+ def test_call_helper(self):
+ from pypy.rpython.llinterp import LLException
+
+ assert self.desc.assembler_call_helper(0, 0) == 3
+ assert self.desc.assembler_call_helper(1, 0) == 10
+ assert self.desc.assembler_call_helper(2, 0) == 10
+ try:
+ self.desc.assembler_call_helper(3, 0)
+ except LLException, lle:
+ assert lle[0] == self.exc_vtable
+ else:
+ py.test.fail("DID NOT RAISE")
Modified: pypy/branch/stringbuilder2/pypy/jit/metainterp/test/test_warmstate.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/jit/metainterp/test/test_warmstate.py (original)
+++ pypy/branch/stringbuilder2/pypy/jit/metainterp/test/test_warmstate.py Mon Jan 25 15:25:48 2010
@@ -165,6 +165,7 @@
class FakeWarmRunnerDesc:
can_inline_ptr = None
get_printable_location_ptr = None
+ confirm_enter_jit_ptr = None
green_args_spec = [lltype.Signed, lltype.Float]
class FakeCell:
dont_trace_here = False
@@ -192,6 +193,7 @@
green_args_spec = [lltype.Signed, lltype.Float]
can_inline_ptr = llhelper(CAN_INLINE, can_inline)
get_printable_location_ptr = None
+ confirm_enter_jit_ptr = None
state = WarmEnterState(FakeWarmRunnerDesc())
def jit_getter(*args):
return FakeCell()
@@ -212,7 +214,30 @@
green_args_spec = [lltype.Signed, lltype.Float]
can_inline_ptr = None
get_printable_location_ptr = llhelper(GET_LOCATION, get_location)
+ confirm_enter_jit_ptr = None
+ get_jitcell_at_ptr = None
state = WarmEnterState(FakeWarmRunnerDesc())
state.make_jitdriver_callbacks()
res = state.get_location_str([BoxInt(5), BoxFloat(42.5)])
assert res == "hi there"
+
+def test_make_jitdriver_callbacks_4():
+ def confirm_enter_jit(x, y, z):
+ assert x == 5
+ assert y == 42.5
+ assert z == 3
+ return True
+ ENTER_JIT = lltype.Ptr(lltype.FuncType([lltype.Signed, lltype.Float,
+ lltype.Signed], lltype.Bool))
+ class FakeWarmRunnerDesc:
+ rtyper = None
+ green_args_spec = [lltype.Signed, lltype.Float]
+ can_inline_ptr = None
+ get_printable_location_ptr = None
+ confirm_enter_jit_ptr = llhelper(ENTER_JIT, confirm_enter_jit)
+ get_jitcell_at_ptr = None
+
+ state = WarmEnterState(FakeWarmRunnerDesc())
+ state.make_jitdriver_callbacks()
+ res = state.confirm_enter_jit(5, 42.5, 3)
+ assert res is True
Modified: pypy/branch/stringbuilder2/pypy/jit/metainterp/test/test_ztranslation.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/jit/metainterp/test/test_ztranslation.py (original)
+++ pypy/branch/stringbuilder2/pypy/jit/metainterp/test/test_ztranslation.py Mon Jan 25 15:25:48 2010
@@ -7,6 +7,8 @@
from pypy.rpython.lltypesystem import lltype, llmemory
from pypy.rpython.ootypesystem import ootype
+py.test.skip("Broken")
+
class TranslationTest:
CPUClass = None
Modified: pypy/branch/stringbuilder2/pypy/jit/metainterp/virtualizable.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/jit/metainterp/virtualizable.py (original)
+++ pypy/branch/stringbuilder2/pypy/jit/metainterp/virtualizable.py Mon Jan 25 15:25:48 2010
@@ -11,8 +11,8 @@
class VirtualizableInfo:
- token_none = 0
- token_tracing = -1
+ TOKEN_NONE = 0
+ TOKEN_TRACING_RESCALL = -1
def __init__(self, warmrunnerdesc):
self.warmrunnerdesc = warmrunnerdesc
@@ -153,16 +153,17 @@
def finish(self):
#
- def force_if_necessary(virtualizable):
+ def force_virtualizable_if_necessary(virtualizable):
if virtualizable.vable_token:
self.force_now(virtualizable)
- force_if_necessary._always_inline_ = True
+ force_virtualizable_if_necessary._always_inline_ = True
#
all_graphs = self.warmrunnerdesc.translator.graphs
ts = self.warmrunnerdesc.cpu.ts
(_, FUNCPTR) = ts.get_FuncType([self.VTYPEPTR], lltype.Void)
- funcptr = self.warmrunnerdesc.helper_func(FUNCPTR, force_if_necessary)
- rvirtualizable2.replace_promote_virtualizable_with_call(
+ funcptr = self.warmrunnerdesc.helper_func(
+ FUNCPTR, force_virtualizable_if_necessary)
+ rvirtualizable2.replace_force_virtualizable_with_call(
all_graphs, self.VTYPEPTR, funcptr)
def unwrap_virtualizable_box(self, virtualizable_box):
@@ -176,7 +177,7 @@
return rvirtualizable2.match_virtualizable_type(TYPE, self.VTYPEPTR)
def reset_vable_token(self, virtualizable):
- virtualizable.vable_token = self.token_none
+ virtualizable.vable_token = self.TOKEN_NONE
def clear_vable_token(self, virtualizable):
if virtualizable.vable_token:
@@ -185,14 +186,14 @@
def tracing_before_residual_call(self, virtualizable):
assert not virtualizable.vable_token
- virtualizable.vable_token = self.token_tracing
+ virtualizable.vable_token = self.TOKEN_TRACING_RESCALL
def tracing_after_residual_call(self, virtualizable):
if virtualizable.vable_token:
# not modified by the residual call; assert that it is still
- # set to 'tracing_vable_rti' and clear it.
- assert virtualizable.vable_token == self.token_tracing
- virtualizable.vable_token = self.token_none
+ # set to TOKEN_TRACING_RESCALL and clear it.
+ assert virtualizable.vable_token == self.TOKEN_TRACING_RESCALL
+ virtualizable.vable_token = self.TOKEN_NONE
return False
else:
# marker "modified during residual call" set.
@@ -200,32 +201,36 @@
def force_now(self, virtualizable):
token = virtualizable.vable_token
- virtualizable.vable_token = self.token_none
- if token == self.token_tracing:
+ if token == self.TOKEN_TRACING_RESCALL:
# The values in the virtualizable are always correct during
- # tracing. We only need to reset vable_token to token_none
+ # tracing. We only need to reset vable_token to TOKEN_NONE
# as a marker for the tracing, to tell it that this
# virtualizable escapes.
- pass
+ virtualizable.vable_token = self.TOKEN_NONE
else:
from pypy.jit.metainterp.compile import ResumeGuardForcedDescr
- faildescr = self.cpu.force(token)
- assert isinstance(faildescr, ResumeGuardForcedDescr)
- faildescr.force_virtualizable(self, virtualizable, token)
+ ResumeGuardForcedDescr.force_now(self.cpu, token)
+ assert virtualizable.vable_token == self.TOKEN_NONE
force_now._dont_inline_ = True
+ def forced_vable(self, virtualizable_boxes):
+ virtualizable_box = virtualizable_boxes[-1]
+ virtualizable = self.unwrap_virtualizable_box(virtualizable_box)
+ self.write_boxes(virtualizable, virtualizable_boxes)
+ virtualizable.vable_token = self.TOKEN_NONE
+
# ____________________________________________________________
#
# The 'vable_token' field of a virtualizable is either 0, -1, or points
# into the CPU stack to a particular field in the current frame. It is:
#
-# 1. 0 (token_none) if not in the JIT at all, except as described below.
+# 1. 0 (TOKEN_NONE) if not in the JIT at all, except as described below.
#
# 2. equal to 0 when tracing is in progress; except:
#
-# 3. equal to -1 (token_tracing) during tracing when we do a residual call,
-# calling random unknown other parts of the interpreter; it is
-# reset to 0 as soon as something occurs to the virtualizable.
+# 3. equal to -1 (TOKEN_TRACING_RESCALL) during tracing when we do a
+# residual call, calling random unknown other parts of the interpreter;
+# it is reset to 0 as soon as something occurs to the virtualizable.
#
# 4. when running the machine code with a virtualizable, it is set
# to the address in the CPU stack by the FORCE_TOKEN operation.
Modified: pypy/branch/stringbuilder2/pypy/jit/metainterp/warmspot.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/jit/metainterp/warmspot.py (original)
+++ pypy/branch/stringbuilder2/pypy/jit/metainterp/warmspot.py Mon Jan 25 15:25:48 2010
@@ -1,4 +1,4 @@
-import sys
+import sys, py
from pypy.rpython.lltypesystem import lltype, llmemory, rclass, rstr
from pypy.rpython.ootypesystem import ootype
from pypy.rpython.annlowlevel import llhelper, MixLevelHelperAnnotator,\
@@ -11,7 +11,7 @@
from pypy.rlib.objectmodel import we_are_translated
from pypy.rlib.unroll import unrolling_iterable
from pypy.rlib.rarithmetic import r_uint, intmask
-from pypy.rlib.debug import debug_print
+from pypy.rlib.debug import debug_print, fatalerror
from pypy.rpython.lltypesystem.lloperation import llop
from pypy.translator.simplify import get_funcobj, get_functype
from pypy.translator.unsimplify import call_final_function
@@ -140,7 +140,7 @@
# ____________________________________________________________
-class WarmRunnerDesc:
+class WarmRunnerDesc(object):
def __init__(self, translator, policy=None, backendopt=True, CPUClass=None,
optimizer=None, **kwds):
@@ -162,9 +162,13 @@
self.build_meta_interp(CPUClass, **kwds)
self.make_args_specification()
+ #
+ from pypy.jit.metainterp.virtualref import VirtualRefInfo
+ self.metainterp_sd.virtualref_info = VirtualRefInfo(self)
if self.jitdriver.virtualizables:
from pypy.jit.metainterp.virtualizable import VirtualizableInfo
self.metainterp_sd.virtualizable_info = VirtualizableInfo(self)
+ #
self.make_exception_classes()
self.make_driverhook_graphs()
self.make_enter_function()
@@ -177,6 +181,7 @@
)
self.rewrite_can_enter_jit()
self.rewrite_set_param()
+ self.rewrite_force_virtual()
self.add_profiler_finish()
self.metainterp_sd.finish_setup(optimizer=optimizer)
@@ -339,9 +344,7 @@
if sys.stdout == sys.__stdout__:
import pdb; pdb.post_mortem(sys.exc_info()[2])
raise
- debug_print('~~~ Crash in JIT!')
- debug_print('~~~ %s' % (e,))
- raise history.CrashInJIT("crash in JIT")
+ fatalerror('~~~ Crash in JIT! %s' % (e,), traceback=True)
crash_in_jit._dont_inline_ = True
if self.translator.rtyper.type_system.name == 'lltypesystem':
@@ -397,9 +400,13 @@
annhelper, self.jitdriver.can_inline, annmodel.s_Bool)
self.get_printable_location_ptr = self._make_hook_graph(
annhelper, self.jitdriver.get_printable_location, s_Str)
+ self.confirm_enter_jit_ptr = self._make_hook_graph(
+ annhelper, self.jitdriver.confirm_enter_jit, annmodel.s_Bool,
+ onlygreens=False)
annhelper.finish()
- def _make_hook_graph(self, annhelper, func, s_result, s_first_arg=None):
+ def _make_hook_graph(self, annhelper, func, s_result, s_first_arg=None,
+ onlygreens=True):
if func is None:
return None
#
@@ -407,7 +414,9 @@
if s_first_arg is not None:
extra_args_s.append(s_first_arg)
#
- args_s = self.portal_args_s[:len(self.green_args_spec)]
+ args_s = self.portal_args_s
+ if onlygreens:
+ args_s = args_s[:len(self.green_args_spec)]
graph = annhelper.getgraph(func, extra_args_s + args_s, s_result)
funcptr = annhelper.graph2delayed(graph)
return funcptr
@@ -432,7 +441,8 @@
self.PTR_JIT_ENTER_FUNCTYPE) = self.cpu.ts.get_FuncType(ALLARGS, lltype.Void)
(self.PORTAL_FUNCTYPE,
self.PTR_PORTAL_FUNCTYPE) = self.cpu.ts.get_FuncType(ALLARGS, RESTYPE)
-
+ (_, self.PTR_ASSEMBLER_HELPER_FUNCTYPE) = self.cpu.ts.get_FuncType(
+ [lltype.Signed, llmemory.GCREF], RESTYPE)
def rewrite_can_enter_jit(self):
FUNC = self.JIT_ENTER_FUNCTYPE
@@ -545,9 +555,63 @@
else:
value = cast_base_ptr_to_instance(Exception, value)
raise Exception, value
-
+
+ self.ll_portal_runner = ll_portal_runner # for debugging
self.portal_runner_ptr = self.helper_func(self.PTR_PORTAL_FUNCTYPE,
ll_portal_runner)
+ self.cpu.portal_calldescr = self.cpu.calldescrof(
+ self.PTR_PORTAL_FUNCTYPE.TO,
+ self.PTR_PORTAL_FUNCTYPE.TO.ARGS,
+ self.PTR_PORTAL_FUNCTYPE.TO.RESULT)
+
+ vinfo = self.metainterp_sd.virtualizable_info
+
+ def assembler_call_helper(failindex, virtualizableref):
+ fail_descr = self.cpu.get_fail_descr_from_number(failindex)
+ while True:
+ try:
+ if vinfo is not None:
+ virtualizable = lltype.cast_opaque_ptr(
+ vinfo.VTYPEPTR, virtualizableref)
+ vinfo.reset_vable_token(virtualizable)
+ loop_token = fail_descr.handle_fail(self.metainterp_sd)
+ fail_descr = self.cpu.execute_token(loop_token)
+ except self.ContinueRunningNormally, e:
+ args = ()
+ for _, name, _ in portalfunc_ARGS:
+ v = getattr(e, name)
+ args = args + (v,)
+ return ll_portal_runner(*args)
+ except self.DoneWithThisFrameVoid:
+ assert result_kind == 'void'
+ return
+ except self.DoneWithThisFrameInt, e:
+ assert result_kind == 'int'
+ return lltype.cast_primitive(RESULT, e.result)
+ except self.DoneWithThisFrameRef, e:
+ assert result_kind == 'ref'
+ return ts.cast_from_ref(RESULT, e.result)
+ except self.DoneWithThisFrameFloat, e:
+ assert result_kind == 'float'
+ return e.result
+ except self.ExitFrameWithExceptionRef, e:
+ value = ts.cast_to_baseclass(e.value)
+ if not we_are_translated():
+ raise LLException(ts.get_typeptr(value), value)
+ else:
+ value = cast_base_ptr_to_instance(Exception, value)
+ raise Exception, value
+
+ self.assembler_call_helper = assembler_call_helper # for debugging
+ self.cpu.assembler_helper_ptr = self.helper_func(
+ self.PTR_ASSEMBLER_HELPER_FUNCTYPE,
+ assembler_call_helper)
+ # XXX a bit ugly sticking
+ if vinfo is not None:
+ self.cpu.index_of_virtualizable = (vinfo.index_of_virtualizable -
+ self.num_green_args)
+ else:
+ self.cpu.index_of_virtualizable = -1
# ____________________________________________________________
# Now mutate origportalgraph to end with a call to portal_runner_ptr
@@ -599,6 +663,13 @@
op.opname = 'direct_call'
op.args[:3] = [closures[funcname]]
+ def rewrite_force_virtual(self):
+ if self.cpu.ts.name != 'lltype':
+ py.test.skip("rewrite_force_virtual: port it to ootype")
+ all_graphs = self.translator.graphs
+ vrefinfo = self.metainterp_sd.virtualref_info
+ vrefinfo.replace_force_virtual_with_call(all_graphs)
+
def decode_hp_hint_args(op):
# Returns (list-of-green-vars, list-of-red-vars) without Voids.
Modified: pypy/branch/stringbuilder2/pypy/jit/metainterp/warmstate.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/jit/metainterp/warmstate.py (original)
+++ pypy/branch/stringbuilder2/pypy/jit/metainterp/warmstate.py Mon Jan 25 15:25:48 2010
@@ -196,6 +196,7 @@
get_jitcell = self.make_jitcell_getter()
set_future_values = self.make_set_future_values()
self.make_jitdriver_callbacks()
+ confirm_enter_jit = self.confirm_enter_jit
def maybe_compile_and_run(*args):
"""Entry point to the JIT. Called at the point with the
@@ -211,8 +212,8 @@
if vinfo is not None:
virtualizable = args[vinfo.index_of_virtualizable]
virtualizable = vinfo.cast_to_vtype(virtualizable)
- assert virtualizable != globaldata.blackhole_virtualizable, (
- "reentering same frame via blackhole")
+ if globaldata.blackhole_virtualizable == virtualizable:
+ return
else:
virtualizable = None
@@ -227,6 +228,9 @@
cell.counter = n
return
# bound reached; start tracing
+ if not confirm_enter_jit(*args):
+ cell.counter = 0
+ return
from pypy.jit.metainterp.pyjitpl import MetaInterp
metainterp = MetaInterp(metainterp_sd)
try:
@@ -237,6 +241,8 @@
self.disable_noninlinable_function(metainterp)
raise
else:
+ if not confirm_enter_jit(*args):
+ return
# machine code was already compiled for these greenargs
# get the assembler and fill in the boxes
set_future_values(*args[num_green_args:])
@@ -252,7 +258,7 @@
if vinfo is not None:
vinfo.reset_vable_token(virtualizable)
loop_token = fail_descr.handle_fail(metainterp_sd)
-
+
maybe_compile_and_run._dont_inline_ = True
self.maybe_compile_and_run = maybe_compile_and_run
return maybe_compile_and_run
@@ -448,6 +454,7 @@
unwrap_greenkey = self.make_unwrap_greenkey()
if can_inline_ptr is None:
def can_inline_callable(*greenargs):
+ # XXX shouldn't it be False by default?
return True
else:
rtyper = self.warmrunnerdesc.rtyper
@@ -465,7 +472,16 @@
greenargs = unwrap_greenkey(greenkey)
return can_inline(*greenargs)
self.can_inline_callable = can_inline_greenkey
-
+
+ get_jitcell = self.make_jitcell_getter()
+ def get_assembler_token(greenkey):
+ greenargs = unwrap_greenkey(greenkey)
+ cell = get_jitcell(*greenargs)
+ if cell.counter >= 0:
+ return None
+ return cell.entry_loop_token
+ self.get_assembler_token = get_assembler_token
+
#
get_location_ptr = self.warmrunnerdesc.get_printable_location_ptr
if get_location_ptr is None:
@@ -483,3 +499,16 @@
res = hlstr(res)
return res
self.get_location_str = get_location_str
+ #
+ confirm_enter_jit_ptr = self.warmrunnerdesc.confirm_enter_jit_ptr
+ if confirm_enter_jit_ptr is None:
+ def confirm_enter_jit(*args):
+ return True
+ else:
+ rtyper = self.warmrunnerdesc.rtyper
+ #
+ def confirm_enter_jit(*args):
+ fn = support.maybe_on_top_of_llinterp(rtyper,
+ confirm_enter_jit_ptr)
+ return fn(*args)
+ self.confirm_enter_jit = confirm_enter_jit
Modified: pypy/branch/stringbuilder2/pypy/jit/tool/jitoutput.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/jit/tool/jitoutput.py (original)
+++ pypy/branch/stringbuilder2/pypy/jit/tool/jitoutput.py Mon Jan 25 15:25:48 2010
@@ -26,8 +26,12 @@
(('opt_ops',), '^opt ops:\s+(\d+)$'),
(('opt_guards',), '^opt guards:\s+(\d+)$'),
(('forcings',), '^forcings:\s+(\d+)$'),
- (('trace_too_long',), '^trace too long:\s+(\d+)$'),
- (('bridge_abort',), '^bridge abort:\s+(\d+)$'),
+ (('abort.trace_too_long',), '^abort: trace too long:\s+(\d+)$'),
+ (('abort.compiling',), '^abort: compiling:\s+(\d+)$'),
+ (('abort.vable_escape',), '^abort: vable escape:\s+(\d+)$'),
+ (('nvirtuals',), '^nvirtuals:\s+(\d+)$'),
+ (('nvholes',), '^nvholes:\s+(\d+)$'),
+ (('nvreused',), '^nvreused:\s+(\d+)$'),
]
class Ops(object):
@@ -35,6 +39,11 @@
calls = 0
pure_calls = 0
+class Aborts(object):
+ trace_too_long = 0
+ compiling = 0
+ vable_escape = 0
+
class OutputInfo(object):
tracing_no = 0
tracing_time = 0.0
@@ -45,13 +54,16 @@
guards = 0
opt_ops = 0
opt_guards = 0
- trace_too_long = 0
- bridge_abort = 0
+ forcings = 0
+ nvirtuals = 0
+ nvholes = 0
+ nvreused = 0
def __init__(self):
self.ops = Ops()
self.recorded_ops = Ops()
self.blackholed_ops = Ops()
+ self.abort = Aborts()
def parse_prof(output):
lines = output.splitlines()
Modified: pypy/branch/stringbuilder2/pypy/jit/tool/showstats.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/jit/tool/showstats.py (original)
+++ pypy/branch/stringbuilder2/pypy/jit/tool/showstats.py Mon Jan 25 15:25:48 2010
@@ -1,4 +1,6 @@
#!/usr/bin/env python
+from __future__ import division
+
import autopath
import sys, py
from pypy.tool import logparser
@@ -9,7 +11,7 @@
def main(argv):
log = logparser.parse_log_file(argv[0])
parts = logparser.extract_category(log, "jit-log-opt-")
- for oplist in parts:
+ for i, oplist in enumerate(parts):
loop = parse(oplist, no_namespace=True)
num_ops = 0
num_dmp = 0
@@ -21,7 +23,7 @@
num_ops += 1
if op.is_guard():
num_guards += 1
- print "Loop, length: %d, opcodes: %d, guards: %d" % (num_ops, num_dmp, num_guards)
+ print "Loop #%d, length: %d, opcodes: %d, guards: %d, %f" % (i, num_ops, num_dmp, num_guards, num_ops/num_dmp)
if __name__ == '__main__':
main(sys.argv[1:])
Modified: pypy/branch/stringbuilder2/pypy/jit/tool/test/test_jitoutput.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/jit/tool/test/test_jitoutput.py (original)
+++ pypy/branch/stringbuilder2/pypy/jit/tool/test/test_jitoutput.py Mon Jan 25 15:25:48 2010
@@ -46,8 +46,6 @@
assert info.opt_ops == 6
assert info.opt_guards == 1
assert info.forcings == 0
- assert info.trace_too_long == 0
- assert info.bridge_abort == 0
DATA = '''Tracing: 1 0.006992
Backend: 1 0.000525
@@ -66,8 +64,12 @@
opt ops: 6
opt guards: 1
forcings: 1
-trace too long: 2
-bridge abort: 3
+abort: trace too long: 10
+abort: compiling: 11
+abort: vable escape: 12
+nvirtuals: 13
+nvholes: 14
+nvreused: 15
'''
def test_parse():
@@ -90,5 +92,9 @@
assert info.opt_ops == 6
assert info.opt_guards == 1
assert info.forcings == 1
- assert info.trace_too_long == 2
- assert info.bridge_abort == 3
+ assert info.abort.trace_too_long == 10
+ assert info.abort.compiling == 11
+ assert info.abort.vable_escape == 12
+ assert info.nvirtuals == 13
+ assert info.nvholes == 14
+ assert info.nvreused == 15
Modified: pypy/branch/stringbuilder2/pypy/lib/_ctypes/array.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/lib/_ctypes/array.py (original)
+++ pypy/branch/stringbuilder2/pypy/lib/_ctypes/array.py Mon Jan 25 15:25:48 2010
@@ -90,7 +90,7 @@
def _CData_retval(self, resbuffer):
raise NotImplementedError
- def _CData_value(self, value):
+ def from_param(self, value):
# array accepts very strange parameters as part of structure
# or function argument...
from ctypes import c_char, c_wchar
@@ -104,7 +104,7 @@
if len(value) > self._length_:
raise RuntimeError("Invalid length")
value = self(*value)
- return _CDataMeta._CData_value(self, value)
+ return _CDataMeta.from_param(self, value)
def array_get_slice_params(self, index):
if index.step is not None:
Modified: pypy/branch/stringbuilder2/pypy/lib/_ctypes/primitive.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/lib/_ctypes/primitive.py (original)
+++ pypy/branch/stringbuilder2/pypy/lib/_ctypes/primitive.py Mon Jan 25 15:25:48 2010
@@ -290,6 +290,8 @@
self.value = value
def _ensure_objects(self):
+ if self._type_ in 'zZ':
+ return self._objects
return None
def _getvalue(self):
Modified: pypy/branch/stringbuilder2/pypy/lib/_ctypes/structure.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/lib/_ctypes/structure.py (original)
+++ pypy/branch/stringbuilder2/pypy/lib/_ctypes/structure.py Mon Jan 25 15:25:48 2010
@@ -130,10 +130,10 @@
def _alignmentofinstances(self):
return self._ffistruct.alignment
- def _CData_value(self, value):
+ def from_param(self, value):
if isinstance(value, tuple):
value = self(*value)
- return _CDataMeta._CData_value(self, value)
+ return _CDataMeta.from_param(self, value)
def _CData_output(self, resarray, base=None, index=-1):
res = self.__new__(self)
@@ -183,10 +183,11 @@
fieldtype = self._fieldtypes[name].ctype
except KeyError:
return _CData.__setattr__(self, name, value)
- if ensure_objects(value) is not None:
+ cobj = fieldtype.from_param(value)
+ if ensure_objects(cobj) is not None:
key = keepalive_key(getattr(self.__class__, name).num)
- store_reference(self, key, value._objects)
- arg = fieldtype._CData_value(value)
+ store_reference(self, key, cobj._objects)
+ arg = cobj._get_buffer_value()
if fieldtype._fficompositesize is not None:
from ctypes import memmove
dest = self._buffer.fieldaddress(name)
Modified: pypy/branch/stringbuilder2/pypy/lib/_ctypes/union.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/lib/_ctypes/union.py (original)
+++ pypy/branch/stringbuilder2/pypy/lib/_ctypes/union.py Mon Jan 25 15:25:48 2010
@@ -99,10 +99,11 @@
fieldtype = self._fieldtypes[name].ctype
except KeyError:
raise AttributeError(name)
- if ensure_objects(value) is not None:
+ cobj = fieldtype.from_param(value)
+ if ensure_objects(cobj) is not None:
key = keepalive_key(getattr(self.__class__, name).num)
- store_reference(self, key, value._objects)
- arg = fieldtype._CData_value(value)
+ store_reference(self, key, cobj._objects)
+ arg = cobj._get_buffer_value()
if fieldtype._fficompositesize is not None:
from ctypes import memmove
dest = self._buffer.buffer
Modified: pypy/branch/stringbuilder2/pypy/lib/app_test/ctypes_tests/test_keepalive.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/lib/app_test/ctypes_tests/test_keepalive.py (original)
+++ pypy/branch/stringbuilder2/pypy/lib/app_test/ctypes_tests/test_keepalive.py Mon Jan 25 15:25:48 2010
@@ -205,3 +205,50 @@
s.r = r
# obscure
assert s._objects == {'1': {}, '0:1': {'1': stuff}}
+
+ def test_c_char_p(self):
+ n = 2
+ xs = "hello" * n
+ x = c_char_p(xs)
+ del xs
+ import gc; gc.collect()
+ print 'x =', repr(x)
+ assert x.value == 'hellohello'
+ assert x._objects.keys() == ['0']
+ #
+ class datum(Structure):
+ _fields_ = [
+ ('dptr', c_char_p),
+ ('dsize', c_int),
+ ]
+ class union(Union):
+ _fields_ = [
+ ('dptr', c_char_p),
+ ('dsize', c_int),
+ ]
+ for wrap in [False, True]:
+ n = 2
+ xs = "hello" * n
+ if wrap:
+ xs = c_char_p(xs)
+ dat = datum()
+ dat.dptr = xs
+ dat.dsize = 15
+ del xs
+ import gc; gc.collect()
+ print 'dat.dptr =', repr(dat.dptr)
+ print 'dat._objects =', repr(dat._objects)
+ assert dat.dptr == "hellohello"
+ assert dat._objects.keys() == ['0']
+
+ xs = "hello" * n
+ if wrap:
+ xs = c_char_p(xs)
+ dat = union()
+ dat.dptr = xs
+ del xs
+ import gc; gc.collect()
+ print 'dat.dptr =', repr(dat.dptr)
+ print 'dat._objects =', repr(dat._objects)
+ assert dat.dptr == "hellohello"
+ assert dat._objects.keys() == ['0']
Modified: pypy/branch/stringbuilder2/pypy/lib/app_test/test_runpy.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/lib/app_test/test_runpy.py (original)
+++ pypy/branch/stringbuilder2/pypy/lib/app_test/test_runpy.py Mon Jan 25 15:25:48 2010
@@ -102,7 +102,7 @@
if verbose: print " Next level in:", sub_dir
pkg_fname = os.path.join(sub_dir, init_fname)
pkg_file = open(pkg_fname, "w")
- pkg_file.write("__path__ = ['%s']\n" % sub_dir)
+ pkg_file.write("__path__ = [%r]\n" % sub_dir)
pkg_file.close()
if verbose: print " Created:", pkg_fname
mod_fname = os.path.join(sub_dir, test_fname)
@@ -137,6 +137,12 @@
d1 = run_module(mod_name) # Read from source
__import__(mod_name)
os.remove(mod_fname)
+
+ #--- the block below is to check that "imp.find_module"
+ #--- manages to import the .pyc file alone. We don't
+ #--- support it in PyPy in the default configuration.
+ return
+
if verbose: print "Running from compiled:", mod_name
d2 = run_module(mod_name) # Read from bytecode
finally:
Modified: pypy/branch/stringbuilder2/pypy/module/__builtin__/__init__.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/module/__builtin__/__init__.py (original)
+++ pypy/branch/stringbuilder2/pypy/module/__builtin__/__init__.py Mon Jan 25 15:25:48 2010
@@ -1,6 +1,7 @@
from pypy.interpreter.error import OperationError
from pypy.interpreter import module
from pypy.interpreter.mixedmodule import MixedModule
+import pypy.module.imp.importing
# put builtins here that should be optimized somehow
@@ -35,9 +36,6 @@
'vars' : 'app_inspect.vars',
'dir' : 'app_inspect.dir',
- '_find_module' : 'app_misc.find_module',
- 'reload' : 'app_misc.reload',
-
'__filestub' : 'app_file_stub.file',
}
@@ -88,7 +86,8 @@
'compile' : 'compiling.compile',
'eval' : 'compiling.eval',
- '__import__' : 'importing.importhook',
+ '__import__' : 'pypy.module.imp.importing.importhook',
+ 'reload' : 'pypy.module.imp.importing.reload',
'range' : 'functional.range_int',
'xrange' : 'functional.W_XRange',
@@ -152,16 +151,3 @@
space.exception_is_valid_obj_as_class_w = ab.exception_is_valid_obj_as_class_w.__get__(space)
space.exception_getclass = ab.exception_getclass.__get__(space)
space.exception_issubclass_w = ab.exception_issubclass_w.__get__(space)
-
- def startup(self, space):
- # install zipimport hook if --withmod-zipimport is used
- if space.config.objspace.usemodules.zipimport:
- w_import = space.builtin.get('__import__')
- w_zipimport = space.call(w_import, space.newlist(
- [space.wrap('zipimport')]))
- w_sys = space.getbuiltinmodule('sys')
- w_path_hooks = space.getattr(w_sys, space.wrap('path_hooks'))
- w_append = space.getattr(w_path_hooks, space.wrap('append'))
- w_zipimporter = space.getattr(w_zipimport,
- space.wrap('zipimporter'))
- space.call(w_append, space.newlist([w_zipimporter]))
Modified: pypy/branch/stringbuilder2/pypy/module/__builtin__/descriptor.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/module/__builtin__/descriptor.py (original)
+++ pypy/branch/stringbuilder2/pypy/module/__builtin__/descriptor.py Mon Jan 25 15:25:48 2010
@@ -4,7 +4,7 @@
Arguments
from pypy.interpreter.gateway import interp2app
from pypy.interpreter.error import OperationError
-from pypy.objspace.descroperation import object_getattribute
+from pypy.objspace.descroperation import object_getattribute, object_setattr
from pypy.interpreter.function import StaticMethod, ClassMethod
from pypy.interpreter.typedef import GetSetProperty, descr_get_dict, \
descr_set_dict, interp_attrproperty_w
@@ -153,8 +153,11 @@
# XXX kill me? This is mostly to make tests happy, raising
# a TypeError instead of an AttributeError and using "readonly"
# instead of "read-only" in the error message :-/
- raise OperationError(space.w_TypeError, space.wrap(
- "Trying to set readonly attribute %s on property" % (attr,)))
+ if attr in ["__doc__", "fget", "fset", "fdel"]:
+ raise OperationError(space.w_TypeError, space.wrap(
+ "Trying to set readonly attribute %s on property" % (attr,)))
+ return space.call_function(object_setattr(space),
+ space.wrap(self), space.wrap(attr), w_value)
setattr.unwrap_spec = ['self', ObjSpace, str, W_Root]
W_Property.typedef = TypeDef(
Modified: pypy/branch/stringbuilder2/pypy/module/__builtin__/test/test_descriptor.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/module/__builtin__/test/test_descriptor.py (original)
+++ pypy/branch/stringbuilder2/pypy/module/__builtin__/test/test_descriptor.py Mon Jan 25 15:25:48 2010
@@ -301,3 +301,13 @@
pass
else:
raise Exception, "expected ZeroDivisionError from bad property"
+
+ def test_property_subclass(self):
+ class P(property):
+ pass
+
+ p = P()
+ p.name = 0
+ assert p.name == 0
+
+
Modified: pypy/branch/stringbuilder2/pypy/module/__pypy__/__init__.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/module/__pypy__/__init__.py (original)
+++ pypy/branch/stringbuilder2/pypy/module/__pypy__/__init__.py Mon Jan 25 15:25:48 2010
@@ -1,7 +1,7 @@
# Package initialisation
from pypy.interpreter.mixedmodule import MixedModule
-from pypy.module.__builtin__.importing import get_pyc_magic
+from pypy.module.imp.importing import get_pyc_magic
class Module(MixedModule):
appleveldefs = {
Modified: pypy/branch/stringbuilder2/pypy/module/_demo/__init__.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/module/_demo/__init__.py (original)
+++ pypy/branch/stringbuilder2/pypy/module/_demo/__init__.py Mon Jan 25 15:25:48 2010
@@ -12,3 +12,13 @@
appleveldefs = {
'DemoError' : 'app_demo.DemoError',
}
+
+ # Used in tests
+ demo_events = []
+ def setup_after_space_initialization(self):
+ Module.demo_events.append('setup')
+ def startup(self, space):
+ Module.demo_events.append('startup')
+ def shutdown(self, space):
+ Module.demo_events.append('shutdown')
+
Modified: pypy/branch/stringbuilder2/pypy/module/_stackless/interp_coroutine.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/module/_stackless/interp_coroutine.py (original)
+++ pypy/branch/stringbuilder2/pypy/module/_stackless/interp_coroutine.py Mon Jan 25 15:25:48 2010
@@ -275,11 +275,10 @@
return space.newtuple([])
items = [None] * index
f = self.subctx.topframe
- f.force_f_back()
while index > 0:
index -= 1
items[index] = space.wrap(f)
- f = f.f_back()
+ f = f.f_backref()
assert f is None
return space.newtuple(items)
Modified: pypy/branch/stringbuilder2/pypy/module/oracle/__init__.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/module/oracle/__init__.py (original)
+++ pypy/branch/stringbuilder2/pypy/module/oracle/__init__.py Mon Jan 25 15:25:48 2010
@@ -39,6 +39,7 @@
def startup(self, space):
from pypy.module.oracle.interp_error import get
state = get(space)
+ state.startup(space)
(state.w_DecimalType,
state.w_DateTimeType, state.w_DateType, state.w_TimedeltaType,
) = space.fixedview(space.appexec([], """():
Modified: pypy/branch/stringbuilder2/pypy/module/oracle/interp_error.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/module/oracle/interp_error.py (original)
+++ pypy/branch/stringbuilder2/pypy/module/oracle/interp_error.py Mon Jan 25 15:25:48 2010
@@ -4,32 +4,47 @@
from pypy.interpreter.typedef import interp_attrproperty, interp_attrproperty_w
from pypy.interpreter.gateway import interp2app
from pypy.interpreter.error import OperationError
+
from pypy.module.oracle import roci, config
+from pypy.rlib.unroll import unrolling_iterable
+
+exported_names = unrolling_iterable("""
+ DatabaseError OperationalError InterfaceError ProgrammingError
+ NotSupportedError IntegrityError InternalError DataError
+ Variable Connection""".split())
class State:
# XXX move to another file
+
def __init__(self, space):
- w_module = space.getbuiltinmodule('cx_Oracle')
- def get(name):
- return space.getattr(w_module, space.wrap(name))
+ "NOT_RPYTHON"
+ self.variableTypeByPythonType = {}
+ self.w_DecimalType = None
+ self.w_DateTimeType = None
+ self.w_DateType = None
+ self.w_TimedeltaType = None
- self.w_DatabaseError = get('DatabaseError')
- self.w_OperationalError = get('OperationalError')
- self.w_InterfaceError = get('InterfaceError')
- self.w_ProgrammingError = get('ProgrammingError')
- self.w_NotSupportedError = get('NotSupportedError')
- self.w_IntegrityError = get('IntegrityError')
- self.w_InternalError = get('InternalError')
- self.w_DataError = get('DataError')
- self.w_Variable = get('Variable')
- self.w_Connection = get('Connection')
+ for name in exported_names:
+ setattr(self, 'w_' + name, None)
+
+ def startup(self, space):
+ w_module = space.getbuiltinmodule('cx_Oracle')
+ for name in exported_names:
+ setattr(self, 'w_' + name, space.getattr(w_module, space.wrap(name)))
from pypy.module.oracle.interp_variable import all_variable_types
- self.variableTypeByPythonType = {}
for varType in all_variable_types:
w_type = space.gettypeobject(varType.typedef)
self.variableTypeByPythonType[w_type] = varType
+ (self.w_DecimalType,
+ self.w_DateTimeType, self.w_DateType, self.w_TimedeltaType,
+ ) = space.fixedview(space.appexec([], """():
+ import decimal, datetime
+ return (decimal.Decimal,
+ datetime.datetime, datetime.date, datetime.timedelta)
+ """))
+
def get(space):
return space.fromcache(State)
Modified: pypy/branch/stringbuilder2/pypy/module/posix/__init__.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/module/posix/__init__.py (original)
+++ pypy/branch/stringbuilder2/pypy/module/posix/__init__.py Mon Jan 25 15:25:48 2010
@@ -93,6 +93,8 @@
interpleveldefs['readlink'] = 'interp_posix.readlink'
if hasattr(os, 'fork'):
interpleveldefs['fork'] = 'interp_posix.fork'
+ if hasattr(os, 'openpty'):
+ interpleveldefs['openpty'] = 'interp_posix.openpty'
if hasattr(os, 'waitpid'):
interpleveldefs['waitpid'] = 'interp_posix.waitpid'
if hasattr(os, 'execv'):
Modified: pypy/branch/stringbuilder2/pypy/module/posix/interp_posix.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/module/posix/interp_posix.py (original)
+++ pypy/branch/stringbuilder2/pypy/module/posix/interp_posix.py Mon Jan 25 15:25:48 2010
@@ -507,6 +507,14 @@
raise wrap_oserror(space, e)
return space.wrap(pid)
+def openpty(space):
+ "Open a pseudo-terminal, returning open fd's for both master and slave end."
+ try:
+ master_fd, slave_fd = os.openpty()
+ except OSError, e:
+ raise wrap_oserror(space, e)
+ return space.newtuple([space.wrap(master_fd), space.wrap(slave_fd)])
+
def waitpid(space, pid, options):
""" waitpid(pid, options) -> (pid, status)
Modified: pypy/branch/stringbuilder2/pypy/module/posix/test/test_posix2.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/module/posix/test/test_posix2.py (original)
+++ pypy/branch/stringbuilder2/pypy/module/posix/test/test_posix2.py Mon Jan 25 15:25:48 2010
@@ -245,6 +245,21 @@
assert os.WEXITSTATUS(status1) == 4
pass # <- please, inspect.getsource(), don't crash
+
+ if hasattr(__import__(os.name), "openpty"):
+ def test_openpty(self):
+ os = self.posix
+ master_fd, slave_fd = self.posix.openpty()
+ try:
+ assert isinstance(master_fd, int)
+ assert isinstance(slave_fd, int)
+ os.write(slave_fd, 'x')
+ assert os.read(master_fd, 1) == 'x'
+ finally:
+ os.close(master_fd)
+ os.close(slave_fd)
+
+
if hasattr(__import__(os.name), "execv"):
def test_execv(self):
os = self.posix
@@ -312,7 +327,7 @@
fh.close()
from time import time, sleep
t0 = time()
- sleep(1)
+ sleep(1.1)
os.utime(path, None)
assert os.stat(path).st_atime > t0
os.utime(path, (int(t0), int(t0)))
Modified: pypy/branch/stringbuilder2/pypy/module/pypyjit/interp_jit.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/module/pypyjit/interp_jit.py (original)
+++ pypy/branch/stringbuilder2/pypy/module/pypyjit/interp_jit.py Mon Jan 25 15:25:48 2010
@@ -21,7 +21,7 @@
PyFrame._virtualizable2_ = ['last_instr', 'pycode',
'valuestackdepth', 'valuestack_w[*]',
- 'fastlocals_w[*]', 'f_forward',
+ 'fastlocals_w[*]',
'last_exception',
]
@@ -35,18 +35,17 @@
name = opcode_method_names[ord(bytecode.co_code[next_instr])]
return '%s #%d %s' % (bytecode.get_repr(), next_instr, name)
-def leave(next_instr, pycode, frame, ec):
- from pypy.interpreter.executioncontext import ExecutionContext
- # can't use a method here, since this function is seen later than the main
- # annotation XXX no longer true, could be fixed
- ExecutionContext._jit_rechain_frame(ec, frame)
-
def get_jitcell_at(next_instr, bytecode):
return bytecode.jit_cells.get(next_instr, None)
def set_jitcell_at(newcell, next_instr, bytecode):
bytecode.jit_cells[next_instr] = newcell
+def confirm_enter_jit(next_instr, bytecode, frame, ec):
+ return (frame.w_f_trace is None and
+ ec.profilefunc is None and
+ ec.w_tracefunc is None)
+
class PyPyJitDriver(JitDriver):
reds = ['frame', 'ec']
@@ -63,9 +62,9 @@
pypyjitdriver = PyPyJitDriver(can_inline = can_inline,
get_printable_location = get_printable_location,
- leave = leave,
get_jitcell_at = get_jitcell_at,
- set_jitcell_at = set_jitcell_at)
+ set_jitcell_at = set_jitcell_at,
+ confirm_enter_jit = confirm_enter_jit)
class __extend__(PyFrame):
Modified: pypy/branch/stringbuilder2/pypy/module/pypyjit/test/test_pypy_c.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/module/pypyjit/test/test_pypy_c.py (original)
+++ pypy/branch/stringbuilder2/pypy/module/pypyjit/test/test_pypy_c.py Mon Jan 25 15:25:48 2010
@@ -89,8 +89,12 @@
print >> f, source
# some support code...
print >> f, py.code.Source("""
- import sys, pypyjit
- pypyjit.set_param(threshold=3)
+ import sys
+ try: # make the file runnable by CPython
+ import pypyjit
+ pypyjit.set_param(threshold=3)
+ except ImportError:
+ pass
def check(args, expected):
print >> sys.stderr, 'trying:', args
@@ -113,8 +117,8 @@
assert result
assert result.splitlines()[-1].strip() == 'OK :-)'
self.parse_loops(logfilepath)
+ self.print_loops()
if self.total_ops > expected_max_ops:
- self.print_loops()
assert 0, "too many operations: got %d, expected maximum %d" % (
self.total_ops, expected_max_ops)
@@ -172,7 +176,7 @@
x = x + (i&j)
i = i + 1
return x
- ''', 194,
+ ''', 220,
([2117], 1083876708))
def test_factorial(self):
@@ -183,7 +187,7 @@
r *= n
n -= 1
return r
- ''', 26,
+ ''', 28,
([5], 120),
([20], 2432902008176640000L))
@@ -205,30 +209,43 @@
def main():
return richards.main(iterations = 1)
- ''' % (sys.path,), 7000,
+ ''' % (sys.path,), 7200,
([], 42))
def test_simple_call(self):
self.run_source('''
+ OFFSET = 0
def f(i):
- return i + 1
+ return i + 1 + OFFSET
def main(n):
i = 0
- while i < n:
+ while i < n+OFFSET:
i = f(f(i))
return i
- ''', 76,
+ ''', 96,
([20], 20),
([31], 32))
ops = self.get_by_bytecode("LOAD_GLOBAL")
- assert len(ops) == 2
- assert ops[0].get_opnames() == ["getfield_gc", "getarrayitem_gc",
+ assert len(ops) == 5
+ assert ops[0].get_opnames() == ["getfield_gc", "guard_value",
+ "getfield_gc", "guard_isnull",
"getfield_gc", "guard_nonnull_class"]
- assert not ops[1] # second LOAD_GLOBAL folded away
+ # the second getfield on the same globals is quicker
+ assert ops[1].get_opnames() == ["getfield_gc", "guard_nonnull_class"]
+ assert not ops[2] # second LOAD_GLOBAL of the same name folded away
+ # LOAD_GLOBAL of the same name but in different function partially
+ # folded away
+ # XXX could be improved
+ assert ops[3].get_opnames() == ["guard_value",
+ "getfield_gc", "guard_isnull"]
+ assert not ops[4]
ops = self.get_by_bytecode("CALL_FUNCTION")
assert len(ops) == 2
- for bytecode in ops:
- assert not bytecode.get_opnames("call")
+ for i, bytecode in enumerate(ops):
+ if i == 0:
+ assert "call(getexecutioncontext)" in str(bytecode)
+ else:
+ assert not bytecode.get_opnames("call")
assert not bytecode.get_opnames("new")
assert len(bytecode.get_opnames("guard")) <= 10
@@ -258,8 +275,11 @@
ops = self.get_by_bytecode("CALL_METHOD")
assert len(ops) == 2
- for bytecode in ops:
- assert not bytecode.get_opnames("call")
+ for i, bytecode in enumerate(ops):
+ if i == 0:
+ assert "call(getexecutioncontext)" in str(bytecode)
+ else:
+ assert not bytecode.get_opnames("call")
assert not bytecode.get_opnames("new")
assert len(bytecode.get_opnames("guard")) <= 9
assert len(ops[1]) < len(ops[0])
@@ -270,6 +290,35 @@
"guard_nonnull_class"]
assert not ops[1] # second LOAD_ATTR folded away
+ def test_static_classmethod_call(self):
+ self.run_source('''
+ class A(object):
+ @classmethod
+ def f(cls, i):
+ return i + (cls is A) + 1
+
+ @staticmethod
+ def g(i):
+ return i - 1
+
+ def main(n):
+ i = 0
+ a = A()
+ while i < n:
+ x = a.f(i)
+ i = a.g(x)
+ return i
+ ''', 105,
+ ([20], 20),
+ ([31], 31))
+ ops = self.get_by_bytecode("LOOKUP_METHOD")
+ assert len(ops) == 2
+ assert not ops[0].get_opnames("call")
+ assert not ops[0].get_opnames("new")
+ assert len(ops[0].get_opnames("guard")) <= 7
+ assert len(ops[0].get_opnames("getfield")) < 6
+ assert not ops[1] # second LOOKUP_METHOD folded away
+
def test_default_and_kw(self):
self.run_source('''
def f(i, j=1):
@@ -279,17 +328,45 @@
while i < n:
i = f(f(i), j=1)
return i
- ''', 98,
+ ''', 100,
([20], 20),
([31], 32))
ops = self.get_by_bytecode("CALL_FUNCTION")
assert len(ops) == 2
- for bytecode in ops:
- assert not bytecode.get_opnames("call")
+ for i, bytecode in enumerate(ops):
+ if i == 0:
+ assert "call(getexecutioncontext)" in str(bytecode)
+ else:
+ assert not bytecode.get_opnames("call")
assert not bytecode.get_opnames("new")
assert len(ops[0].get_opnames("guard")) <= 14
assert len(ops[1].get_opnames("guard")) <= 3
+ def test_kwargs(self):
+ self.run_source('''
+ d = {}
+
+ def g(**args):
+ return len(args)
+
+ def main(x):
+ s = 0
+ d = {}
+ for i in range(x):
+ s += g(**d)
+ d[str(i)] = i
+ if i % 100 == 99:
+ d = {}
+ return s
+ ''', 100000, ([100], 4950),
+ ([1000], 49500),
+ ([10000], 495000),
+ ([100000], 4950000))
+ assert len(self.loops) == 2
+ 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
+
def test_virtual_instance(self):
self.run_source('''
class A(object):
@@ -303,7 +380,7 @@
a.x = 2
i = i + a.x
return i
- ''', 63,
+ ''', 67,
([20], 20),
([31], 32))
@@ -334,7 +411,7 @@
while i < n:
i = i + a.x
return i
- ''', 39,
+ ''', 41,
([20], 20),
([31], 32))
@@ -375,15 +452,40 @@
i += 1
l.append(i)
return i, len(l)
- ''', 37,
+ ''', 39,
([20], (20, 18)),
([31], (31, 29)))
bytecode, = self.get_by_bytecode("CALL_METHOD")
assert len(bytecode.get_opnames("new_with_vtable")) == 1 # the forcing of the int
assert len(bytecode.get_opnames("call")) == 1 # the call to append
- assert len(bytecode.get_opnames("guard")) == 1 # guard_no_exception after the call
+ assert len(bytecode.get_opnames("guard")) == 2 # guard for profiling disabledness + guard_no_exception after the call
+ def test_range_iter(self):
+ self.run_source('''
+ def g(n):
+ return range(n)
+
+ def main(n):
+ s = 0
+ for i in range(n):
+ s += g(n)[i]
+ return s
+ ''', 143, ([1000], 1000 * 999 / 2))
+ bytecode, = self.get_by_bytecode("BINARY_SUBSCR")
+ assert bytecode.get_opnames("guard") == [
+ "guard_isnull", # check that the range list is not forced
+ "guard_false", # check that the index is >= 0
+ "guard_false", # check that the index is lower than the current length
+ ]
+ bytecode, _ = self.get_by_bytecode("FOR_ITER") # second bytecode is the end of the loop
+ assert bytecode.get_opnames("guard") == [
+ "guard_class", # check the class of the iterator
+ "guard_nonnull", # check that the iterator is not finished
+ "guard_isnull", # check that the range list is not forced
+ "guard_false", # check that the index is lower than the current length
+ ]
+
def test_exception_inside_loop_1(self):
py.test.skip("exceptions: in-progress")
self.run_source('''
@@ -445,7 +547,27 @@
def setup_class(cls):
if option.pypy_c is None:
py.test.skip("pass --pypy!")
+ if not has_info(option.pypy_c, 'translation.jit'):
+ py.test.skip("must give a pypy-c with the jit enabled")
cls.tmpdir = udir.join('pypy-jit')
cls.tmpdir.ensure(dir=1)
cls.counter = 0
cls.pypy_c = option.pypy_c
+
+def has_info(pypy_c, option):
+ g = os.popen('"%s" --info' % pypy_c, 'r')
+ lines = g.readlines()
+ g.close()
+ if not lines:
+ raise ValueError("cannot execute %r" % pypy_c)
+ for line in lines:
+ line = line.strip()
+ if line.startswith(option + ':'):
+ line = line[len(option)+1:].strip()
+ if line == 'True':
+ return True
+ elif line == 'False':
+ return False
+ else:
+ return line
+ raise ValueError(option + ' not found in ' + pypy_c)
Modified: pypy/branch/stringbuilder2/pypy/module/sys/vm.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/module/sys/vm.py (original)
+++ pypy/branch/stringbuilder2/pypy/module/sys/vm.py Mon Jan 25 15:25:48 2010
@@ -31,7 +31,6 @@
space.wrap("frame index must not be negative"))
ec = space.getexecutioncontext()
f = ec.gettopframe_nohidden()
- f.force_f_back()
while True:
if f is None:
raise OperationError(space.w_ValueError,
Modified: pypy/branch/stringbuilder2/pypy/module/thread/__init__.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/module/thread/__init__.py (original)
+++ pypy/branch/stringbuilder2/pypy/module/thread/__init__.py Mon Jan 25 15:25:48 2010
@@ -18,11 +18,6 @@
'allocate': 'os_lock.allocate_lock', # obsolete synonym
'LockType': 'os_lock.getlocktype(space)',
'_local': 'os_local.getlocaltype(space)',
-
- # custom interface for the 'imp' module
- '_importlock_held': 'importlock.held',
- '_importlock_acquire': 'importlock.acquire',
- '_importlock_release': 'importlock.release',
}
def __init__(self, space, *args):
Modified: pypy/branch/stringbuilder2/pypy/module/zipimport/__init__.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/module/zipimport/__init__.py (original)
+++ pypy/branch/stringbuilder2/pypy/module/zipimport/__init__.py Mon Jan 25 15:25:48 2010
@@ -14,4 +14,12 @@
appleveldefs = {
'ZipImportError' : 'app_zipimport.ZipImportError',
}
-
+
+ def setup_after_space_initialization(self):
+ """NOT_RPYTHON"""
+ space = self.space
+ # install zipimport hook
+ w_path_hooks = space.sys.get('path_hooks')
+ from pypy.module.zipimport.interp_zipimport import W_ZipImporter
+ w_zipimporter = space.gettypefor(W_ZipImporter)
+ space.call_method(w_path_hooks, 'append', w_zipimporter)
Modified: pypy/branch/stringbuilder2/pypy/module/zipimport/interp_zipimport.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/module/zipimport/interp_zipimport.py (original)
+++ pypy/branch/stringbuilder2/pypy/module/zipimport/interp_zipimport.py Mon Jan 25 15:25:48 2010
@@ -5,7 +5,7 @@
from pypy.interpreter.gateway import interp2app
from pypy.interpreter.typedef import TypeDef, GetSetProperty
from pypy.interpreter.module import Module
-from pypy.module.__builtin__ import importing
+from pypy.module.imp import importing
from pypy.rlib.unroll import unrolling_iterable
from pypy.rlib.rzipfile import RZipFile, BadZipfile
import os
@@ -149,9 +149,9 @@
real_name = self.name + os.path.sep + self.corr_zname(filename)
space.setattr(w_mod, w('__loader__'), space.wrap(self))
importing._prepare_module(space, w_mod, real_name, pkgpath)
- result = importing.load_source_module(space, w(modname), w_mod,
- filename, buf, write_pyc=False)
- return result
+ code_w = importing.parse_source_module(space, filename, buf)
+ importing.exec_code_module(space, w_mod, code_w)
+ return w_mod
def _parse_mtime(self, space, filename):
w = space.wrap
Modified: pypy/branch/stringbuilder2/pypy/module/zipimport/test/test_zipimport.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/module/zipimport/test/test_zipimport.py (original)
+++ pypy/branch/stringbuilder2/pypy/module/zipimport/test/test_zipimport.py Mon Jan 25 15:25:48 2010
@@ -4,7 +4,7 @@
import py
import time
import struct
-from pypy.module.__builtin__.importing import get_pyc_magic, _w_long
+from pypy.module.imp.importing import get_pyc_magic, _w_long
from StringIO import StringIO
from pypy.tool.udir import udir
@@ -255,6 +255,11 @@
l = [i for i in zipimport._zip_directory_cache]
assert len(l)
+ def test_path_hooks(self):
+ import sys
+ import zipimport
+ assert sys.path_hooks.count(zipimport.zipimporter) == 1
+
class AppTestZipimportDeflated(AppTestZipimport):
compression = ZIP_DEFLATED
Modified: pypy/branch/stringbuilder2/pypy/objspace/descroperation.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/objspace/descroperation.py (original)
+++ pypy/branch/stringbuilder2/pypy/objspace/descroperation.py Mon Jan 25 15:25:48 2010
@@ -35,7 +35,13 @@
w_descr = space.lookup(w_obj, name)
if w_descr is not None:
if space.is_data_descr(w_descr):
- return space.get(w_descr, w_obj)
+ # Only override if __get__ is defined, too, for compatibility
+ # with CPython.
+ w_get = space.lookup(w_descr, "__get__")
+ if w_get is not None:
+ w_type = space.type(w_obj)
+ return space.get_and_call_function(w_get, w_descr, w_obj,
+ w_type)
w_value = w_obj.getdictvalue_attr_is_in_class(space, name)
else:
w_value = w_obj.getdictvalue(space, name)
@@ -505,30 +511,42 @@
slice_max = Temp()[:]
del Temp
+def old_slice_range_getlength(space, w_obj):
+ # NB. the language ref is inconsistent with the new-style class
+ # behavior when w_obj doesn't implement __len__(), so we just
+ # follow cpython. Also note that CPython slots make it easier
+ # to check for object implementing it or not. We just catch errors
+ # so this behavior is slightly different
+ try:
+ return space.len(w_obj)
+ except OperationError, e:
+ if not ((e.match(space, space.w_AttributeError) or
+ e.match(space, space.w_TypeError))):
+ raise
+ return None
+
def old_slice_range(space, w_obj, w_start, w_stop):
"""Only for backward compatibility for __getslice__()&co methods."""
+ w_length = None
if space.is_w(w_start, space.w_None):
w_start = space.wrap(0)
else:
- w_start = space.wrap(space.getindex_w(w_start, None))
- if space.is_true(space.lt(w_start, space.wrap(0))):
- try:
- w_start = space.add(w_start, space.len(w_obj))
- except OperationError, e:
- if not ((e.match(space, space.w_AttributeError) or
- e.match(space, space.w_TypeError))):
- raise
- # NB. the language ref is inconsistent with the new-style class
- # behavior when w_obj doesn't implement __len__(), so we just
- # follow cpython. Also note that CPython slots make it easier
- # to check for object implementing it or not. We just catch errors
- # so this behavior is slightly different
+ start = space.getindex_w(w_start, None)
+ w_start = space.wrap(start)
+ if start < 0:
+ w_length = old_slice_range_getlength(space, w_obj)
+ if w_length is not None:
+ w_start = space.add(w_start, w_length)
if space.is_w(w_stop, space.w_None):
w_stop = space.wrap(slice_max)
else:
- w_stop = space.wrap(space.getindex_w(w_stop, None))
- if space.is_true(space.lt(w_stop, space.wrap(0))):
- w_stop = space.add(w_stop, space.len(w_obj))
+ stop = space.getindex_w(w_stop, None)
+ w_stop = space.wrap(stop)
+ if stop < 0:
+ if w_length is None:
+ w_length = old_slice_range_getlength(space, w_obj)
+ if w_length is not None:
+ w_stop = space.add(w_stop, w_length)
return w_start, w_stop
# regular methods def helpers
Modified: pypy/branch/stringbuilder2/pypy/objspace/flow/flowcontext.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/objspace/flow/flowcontext.py (original)
+++ pypy/branch/stringbuilder2/pypy/objspace/flow/flowcontext.py Mon Jan 25 15:25:48 2010
@@ -5,6 +5,7 @@
from pypy.interpreter.argument import ArgumentsForTranslation
from pypy.objspace.flow.model import *
from pypy.objspace.flow.framestate import FrameState
+from pypy.rlib import jit
class OperationThatShouldNotBePropagatedError(OperationError):
@@ -260,8 +261,8 @@
except StopFlowing:
continue # restarting a dead SpamBlock
try:
- old_frame = self.some_frame
- self.some_frame = frame
+ old_frameref = self.topframeref
+ self.topframeref = jit.non_virtual_ref(frame)
self.crnt_frame = frame
try:
w_result = frame.dispatch(frame.pycode,
@@ -269,7 +270,7 @@
self)
finally:
self.crnt_frame = None
- self.some_frame = old_frame
+ self.topframeref = old_frameref
except OperationThatShouldNotBePropagatedError, e:
raise Exception(
@@ -384,6 +385,9 @@
operr = OperationError(operr.w_type, operr.w_value)
return operr
+ def exception_trace(self, frame, operationerr):
+ pass # overridden for performance only
+
# hack for unrolling iterables, don't use this
def replace_in_stack(self, oldvalue, newvalue):
w_new = Constant(newvalue)
Modified: pypy/branch/stringbuilder2/pypy/objspace/std/celldict.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/objspace/std/celldict.py (original)
+++ pypy/branch/stringbuilder2/pypy/objspace/std/celldict.py Mon Jan 25 15:25:48 2010
@@ -1,4 +1,8 @@
-from pypy.interpreter.pycode import CO_CONTAINSGLOBALS
+""" A very simple cell dict implementation. The dictionary maps keys to cell.
+This ensures that the function (dict, key) -> cell is pure. By itself, this
+optimization is not helping at all, but in conjunction with the JIT it can
+speed up global lookups a lot."""
+
from pypy.objspace.std.dictmultiobject import IteratorImplementation
from pypy.objspace.std.dictmultiobject import W_DictMultiObject, _is_sane_hash
from pypy.rlib import jit
@@ -19,31 +23,22 @@
def __init__(self, space):
self.space = space
self.content = {}
- self.unshadowed_builtins = {}
- def getcell(self, key, make_new=True):
+ def getcell(self, key, makenew):
+ if makenew or jit.we_are_jitted():
+ # when we are jitting, we always go through the pure function
+ # below, to ensure that we have no residual dict lookup
+ return self._getcell_makenew(key)
+ return self.content.get(key, None)
+
+ @jit.purefunction_promote
+ def _getcell_makenew(self, key):
res = self.content.get(key, None)
if res is not None:
return res
- if not make_new:
- return None
result = self.content[key] = ModuleCell()
return result
- def add_unshadowed_builtin(self, name, builtin_impl):
- assert isinstance(builtin_impl, ModuleDictImplementation)
- self.unshadowed_builtins[name] = builtin_impl
-
- def invalidate_unshadowed_builtin(self, name):
- impl = self.unshadowed_builtins[name]
- try:
- cell = impl.content[name]
- except KeyError:
- pass
- else:
- w_value = cell.invalidate()
- cell = impl.content[name] = ModuleCell(w_value)
-
def impl_setitem(self, w_key, w_value):
space = self.space
if space.is_w(space.type(w_key), space.w_str):
@@ -52,11 +47,7 @@
self._as_rdict().setitem(w_key, w_value)
def impl_setitem_str(self, name, w_value, shadows_type=True):
- self.getcell(name).w_value = w_value
-
- if name in self.unshadowed_builtins:
- self.invalidate_unshadowed_builtin(name)
- del self.unshadowed_builtins[name]
+ self.getcell(name, True).w_value = w_value
def impl_delitem(self, w_key):
space = self.space
@@ -64,17 +55,25 @@
if space.is_w(w_key_type, space.w_str):
key = space.str_w(w_key)
cell = self.getcell(key, False)
- if cell is None:
+ if cell is None or cell.w_value is None:
raise KeyError
+ # note that we don't remove the cell from self.content, to make
+ # sure that a key that was found at any point in the dict, still
+ # maps to the same cell later (even if this cell no longer
+ # represents a key)
cell.invalidate()
- del self.content[key]
elif _is_sane_hash(space, w_key_type):
raise KeyError
else:
self._as_rdict().delitem(w_key)
def impl_length(self):
- return len(self.content)
+ # inefficient, but do we care?
+ res = 0
+ for cell in self.content.itervalues():
+ if cell.w_value is not None:
+ res += 1
+ return res
def impl_getitem(self, w_lookup):
space = self.space
@@ -91,6 +90,7 @@
res = self.getcell(lookup, False)
if res is None:
return None
+ # note that even if the res.w_value is None, the next line is fine
return res.w_value
def impl_iter(self):
@@ -98,39 +98,34 @@
def impl_keys(self):
space = self.space
- return [space.wrap(key) for key in self.content.iterkeys()]
+ return [space.wrap(key) for key, cell in self.content.iteritems()
+ if cell.w_value is not None]
def impl_values(self):
- return [cell.w_value for cell in self.content.itervalues()]
+ return [cell.w_value for cell in self.content.itervalues()
+ if cell.w_value is not None]
def impl_items(self):
space = self.space
return [space.newtuple([space.wrap(key), cell.w_value])
- for (key, cell) in self.content.iteritems()]
+ for (key, cell) in self.content.iteritems()
+ if cell.w_value is not None]
def impl_clear(self):
- # inefficient, but who cares
for k, cell in self.content.iteritems():
cell.invalidate()
- for k in self.unshadowed_builtins:
- self.invalidate_unshadowed_builtin(k)
- self.content.clear()
- self.unshadowed_builtins.clear()
-
def _as_rdict(self):
r_dict_content = self.initialize_as_rdict()
for k, cell in self.content.iteritems():
- r_dict_content[self.space.wrap(k)] = cell.w_value
+ if cell.w_value is not None:
+ r_dict_content[self.space.wrap(k)] = cell.w_value
cell.invalidate()
- for k in self.unshadowed_builtins:
- self.invalidate_unshadowed_builtin(k)
self._clear_fields()
return self
def _clear_fields(self):
self.content = None
- self.unshadowed_builtins = None
class ModuleDictIteratorImplementation(IteratorImplementation):
def __init__(self, space, dictimplementation):
@@ -138,99 +133,8 @@
self.iterator = dictimplementation.content.iteritems()
def next_entry(self):
- # note that this 'for' loop only runs once, at most
for key, cell in self.iterator:
- return (self.space.wrap(key), cell.w_value)
+ if cell.w_value is not None:
+ return (self.space.wrap(key), cell.w_value)
else:
return None, None
-
-
-class State(object):
- def __init__(self, space):
- self.space = space
- self.invalidcell = ModuleCell()
- self.always_invalid_cache = []
- self.neverused_dictcontent = {}
-
-class GlobalCacheHolder(object):
- def __init__(self, space):
- self.cache = None
- state = space.fromcache(State)
- self.dictcontent = state.neverused_dictcontent
-
- def getcache(self, space, code, w_globals):
- if type(w_globals) is ModuleDictImplementation:
- content = w_globals.content
- else:
- content = None
- if self.dictcontent is content:
- return self.cache
- return self.getcache_slow(space, code, w_globals, content)
- getcache._always_inline_ = True
-
- def getcache_slow(self, space, code, w_globals, content):
- state = space.fromcache(State)
- if content is None:
- cache = state.always_invalid_cache
- if len(code.co_names_w) > len(cache):
- cache = [state.invalidcell] * len(code.co_names_w)
- state.always_invalid_cache = cache
- else:
- cache = [state.invalidcell] * len(code.co_names_w)
- self.cache = cache
- self.dictcontent = content
- return cache
- getcache_slow._dont_inline_ = True
-
-def init_code(code):
- if code.co_flags & CO_CONTAINSGLOBALS:
- code.globalcacheholder = GlobalCacheHolder(code.space)
- else:
- code.globalcacheholder = None
-
-
-def get_global_cache(space, code, w_globals):
- from pypy.interpreter.pycode import PyCode
- assert isinstance(code, PyCode)
- holder = code.globalcacheholder
- if holder is not None:
- return holder.getcache(space, code, w_globals)
- return None
-
-def getimplementation(w_dict):
- if type(w_dict) is ModuleDictImplementation and w_dict.r_dict_content is None:
- return w_dict
- else:
- return None
-
-def LOAD_GLOBAL(f, nameindex, *ignored):
- cell = f.cache_for_globals[nameindex]
- w_value = cell.w_value
- if w_value is None:
- # slow path
- w_value = load_global_fill_cache(f, nameindex)
- f.pushvalue(w_value)
-LOAD_GLOBAL._always_inline_ = True
-
-def find_cell_from_dict(implementation, name):
- if implementation is not None:
- return implementation.getcell(name, False)
- return None
-
- at jit.dont_look_inside
-def load_global_fill_cache(f, nameindex):
- name = f.space.str_w(f.getname_w(nameindex))
- implementation = getimplementation(f.w_globals)
- if implementation is not None:
- cell = implementation.getcell(name, False)
- if cell is None:
- builtin_impl = getimplementation(f.get_builtin().getdict())
- cell = find_cell_from_dict(builtin_impl, name)
- if cell is not None:
- implementation.add_unshadowed_builtin(name, builtin_impl)
-
- if cell is not None:
- f.cache_for_globals[nameindex] = cell
- return cell.w_value
- return f._load_global(f.getname_u(nameindex))
-load_global_fill_cache._dont_inline_ = True
Modified: pypy/branch/stringbuilder2/pypy/objspace/std/objspace.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/objspace/std/objspace.py (original)
+++ pypy/branch/stringbuilder2/pypy/objspace/std/objspace.py Mon Jan 25 15:25:48 2010
@@ -71,16 +71,8 @@
# Import all the object types and implementations
self.model = StdTypeModel(self.config)
- from pypy.objspace.std.celldict import get_global_cache
class StdObjSpaceFrame(pyframe.PyFrame):
- if self.config.objspace.std.withcelldict:
- def __init__(self, space, code, w_globals, closure):
- pyframe.PyFrame.__init__(self, space, code, w_globals, closure)
- self.cache_for_globals = get_global_cache(space, code, w_globals)
-
- from pypy.objspace.std.celldict import LOAD_GLOBAL
-
if self.config.objspace.std.optimized_int_add:
if self.config.objspace.std.withsmallint:
def BINARY_ADD(f, oparg, *ignored):
@@ -662,15 +654,23 @@
w_value = w_obj.getdictvalue_attr_is_in_class(self, name)
if w_value is not None:
return w_value
- try:
- return self.get(w_descr, w_obj)
- except OperationError, e:
- if not e.match(self, self.w_AttributeError):
- raise
- else:
+ w_get = self.lookup(w_descr, "__get__")
+ if w_get is not None:
+ # __get__ is allowed to raise an AttributeError to trigger use
+ # of __getattr__.
+ try:
+ return self.get_and_call_function(w_get, w_descr, w_obj,
+ w_type)
+ except OperationError, e:
+ if not e.match(self, self.w_AttributeError):
+ raise
+ if e is None:
w_value = w_obj.getdictvalue(self, name)
if w_value is not None:
return w_value
+ # No value in __dict__. Fallback to the descriptor if we have it.
+ if w_descr is not None:
+ return w_descr
w_descr = self.lookup(w_obj, '__getattr__')
if w_descr is not None:
Modified: pypy/branch/stringbuilder2/pypy/objspace/std/rangeobject.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/objspace/std/rangeobject.py (original)
+++ pypy/branch/stringbuilder2/pypy/objspace/std/rangeobject.py Mon Jan 25 15:25:48 2010
@@ -56,7 +56,9 @@
def getitem(w_self, i):
if i < 0:
i += w_self.length
- if i >= w_self.length or i < 0:
+ if i < 0:
+ raise IndexError
+ elif i >= w_self.length:
raise IndexError
return w_self.start + i * w_self.step
@@ -194,24 +196,24 @@
if w_rangelist is None:
raise OperationError(space.w_StopIteration, space.w_None)
assert isinstance(w_rangelist, W_RangeListObject)
+ index = w_rangeiter.index
if w_rangelist.w_list is not None:
try:
w_item = space.getitem(w_rangelist.w_list,
- wrapint(space, w_rangeiter.index))
+ wrapint(space, index))
except OperationError, e:
w_rangeiter.w_seq = None
if not e.match(space, space.w_IndexError):
raise
raise OperationError(space.w_StopIteration, space.w_None)
else:
- try:
- w_item = wrapint(
- space,
- w_rangelist.getitem(w_rangeiter.index))
- except IndexError:
+ if index >= w_rangelist.length:
w_rangeiter.w_seq = None
raise OperationError(space.w_StopIteration, space.w_None)
- w_rangeiter.index += 1
+ w_item = wrapint(
+ space,
+ w_rangelist.getitem_unchecked(index))
+ w_rangeiter.index = index + 1
return w_item
# XXX __length_hint__()
Modified: pypy/branch/stringbuilder2/pypy/objspace/std/test/test_celldict.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/objspace/std/test/test_celldict.py (original)
+++ pypy/branch/stringbuilder2/pypy/objspace/std/test/test_celldict.py Mon Jan 25 15:25:48 2010
@@ -1,262 +1,31 @@
import py
from pypy.conftest import gettestobjspace, option
-from pypy.objspace.std.celldict import get_global_cache, ModuleCell, ModuleDictImplementation
+from pypy.objspace.std.celldict import ModuleCell, ModuleDictImplementation
+from pypy.objspace.std.test.test_dictmultiobject import FakeSpace
from pypy.interpreter import gateway
-# this file tests mostly the effects of caching global lookup. The dict
-# implementation itself is tested in test_dictmultiobject.py
-
-
-class AppTestCellDict(object):
- def setup_class(cls):
- if option.runappdirect:
- py.test.skip("not appdirect tests")
- cls.space = gettestobjspace(**{"objspace.std.withcelldict": True})
- cls.w_impl_used = cls.space.appexec([], """():
- import __pypy__
- def impl_used(obj):
- assert "ModuleDictImplementation" in __pypy__.internal_repr(obj)
- return impl_used
- """)
- def is_in_cache(space, w_code, w_globals, w_name):
- name = space.str_w(w_name)
- cache = get_global_cache(space, w_code, w_globals)
- index = [space.str_w(w_n) for w_n in w_code.co_names_w].index(name)
- return space.wrap(cache[index].w_value is not None)
- is_in_cache = gateway.interp2app(is_in_cache)
- cls.w_is_in_cache = cls.space.wrap(is_in_cache)
- stored_builtins = []
- def rescue_builtins(space):
- w_dict = space.builtin.getdict()
- content = {}
- for key, cell in w_dict.content.iteritems():
- newcell = ModuleCell()
- newcell.w_value = cell.w_value
- content[key] = newcell
- stored_builtins.append(content)
- rescue_builtins = gateway.interp2app(rescue_builtins)
- cls.w_rescue_builtins = cls.space.wrap(rescue_builtins)
- def restore_builtins(space):
- w_dict = space.builtin.getdict()
- assert isinstance(w_dict, ModuleDictImplementation)
- w_dict.content = stored_builtins.pop()
- w_dict.fallback = None
- restore_builtins = gateway.interp2app(restore_builtins)
- cls.w_restore_builtins = cls.space.wrap(restore_builtins)
-
- def test_same_code_in_different_modules(self):
- import sys
- mod1 = type(sys)("abc")
- self.impl_used(mod1.__dict__)
- glob1 = mod1.__dict__
- mod2 = type(sys)("abc")
- self.impl_used(mod2.__dict__)
- glob2 = mod2.__dict__
- def f():
- return x + 1
- code = f.func_code
- f1 = type(f)(code, glob1)
- mod1.x = 1
- assert not self.is_in_cache(code, glob1, "x")
- assert f1() == 2
- assert self.is_in_cache(code, glob1, "x")
- assert f1() == 2
- assert self.is_in_cache(code, glob1, "x")
- mod1.x = 2
- assert f1() == 3
- assert self.is_in_cache(code, glob1, "x")
- assert f1() == 3
- assert self.is_in_cache(code, glob1, "x")
- f2 = type(f)(code, glob2)
- mod2.x = 5
- assert not self.is_in_cache(code, glob2, "x")
- assert f2() == 6
- assert self.is_in_cache(code, glob2, "x")
- assert f2() == 6
- assert self.is_in_cache(code, glob2, "x")
- mod2.x = 7
- assert f2() == 8
- assert self.is_in_cache(code, glob2, "x")
- assert f2() == 8
- assert self.is_in_cache(code, glob2, "x")
-
- def test_override_builtins(self):
- import sys, __builtin__
- mod1 = type(sys)("abc")
- glob1 = mod1.__dict__
- self.impl_used(mod1.__dict__)
- def f():
- return len(x)
- code = f.func_code
- f1 = type(f)(f.func_code, glob1)
- mod1.x = []
- assert not self.is_in_cache(code, glob1, "len")
- assert not self.is_in_cache(code, glob1, "x")
- assert f1() == 0
- assert self.is_in_cache(code, glob1, "len")
- assert self.is_in_cache(code, glob1, "x")
- assert f1() == 0
- mod1.x.append(1)
- assert f1() == 1
- assert self.is_in_cache(code, glob1, "len")
- assert self.is_in_cache(code, glob1, "x")
- mod1.len = lambda x: 15
- assert not self.is_in_cache(code, glob1, "len")
- mod1.x.append(1)
- assert f1() == 15
- assert self.is_in_cache(code, glob1, "len")
- assert f1() == 15
- assert self.is_in_cache(code, glob1, "len")
- del mod1.len
- mod1.x.append(1)
- assert not self.is_in_cache(code, glob1, "len")
- assert f1() == 3
- assert self.is_in_cache(code, glob1, "len")
- assert f1() == 3
- assert self.is_in_cache(code, glob1, "len")
- orig_len = __builtins__.len
- try:
- __builtins__.len = lambda x: 12
- mod1.x.append(1)
- assert self.is_in_cache(code, glob1, "len")
- assert f1() == 12
- assert self.is_in_cache(code, glob1, "len")
- assert f1() == 12
- assert self.is_in_cache(code, glob1, "len")
- finally:
- __builtins__.len = orig_len
-
- def test_override_builtins2(self):
- import sys, __builtin__
- mod1 = type(sys)("abc")
- glob1 = mod1.__dict__
- self.impl_used(mod1.__dict__)
- def f():
- return l(x)
- code = f.func_code
- f1 = type(f)(f.func_code, glob1)
- mod1.x = []
- __builtin__.l = len
- try:
- assert not self.is_in_cache(code, glob1, "l")
- assert not self.is_in_cache(code, glob1, "x")
- assert f1() == 0
- assert self.is_in_cache(code, glob1, "l")
- assert self.is_in_cache(code, glob1, "x")
- assert f1() == 0
- mod1.x.append(1)
- assert f1() == 1
- assert self.is_in_cache(code, glob1, "l")
- assert self.is_in_cache(code, glob1, "x")
- del __builtin__.l
- mod1.l = len
- mod1.x.append(1)
- assert not self.is_in_cache(code, glob1, "l")
- assert f1() == 2
- assert self.is_in_cache(code, glob1, "l")
- assert self.is_in_cache(code, glob1, "x")
- finally:
- if hasattr(__builtins__, "l"):
- del __builtins__.l
-
- def test_generator(self):
- import sys, __builtin__
- mod1 = type(sys)("abc")
- glob1 = mod1.__dict__
- self.impl_used(mod1.__dict__)
- def f():
- yield 1
- yield x
- yield len(x)
- code = f.func_code
- f1 = type(f)(f.func_code, glob1)
- mod1.x = []
- gen = f1()
- assert not self.is_in_cache(code, glob1, "len")
- assert not self.is_in_cache(code, glob1, "x")
- v = gen.next()
- assert v == 1
- assert not self.is_in_cache(code, glob1, "len")
- assert not self.is_in_cache(code, glob1, "x")
- v = gen.next()
- assert v is mod1.x
- assert not self.is_in_cache(code, glob1, "len")
- assert self.is_in_cache(code, glob1, "x")
- v = gen.next()
- assert v == 0
- assert self.is_in_cache(code, glob1, "len")
- assert self.is_in_cache(code, glob1, "x")
-
- def test_degenerate_to_rdict(self):
- import sys
- mod1 = type(sys)("abc")
- self.impl_used(mod1.__dict__)
- glob1 = mod1.__dict__
- def f():
- return x + 1
- code = f.func_code
- f1 = type(f)(code, glob1)
- mod1.x = 1
- assert not self.is_in_cache(code, glob1, "x")
- assert f1() == 2
- assert self.is_in_cache(code, glob1, "x")
- glob1[1] = 2
- assert not self.is_in_cache(code, glob1, "x")
- assert f1() == 2
- assert not self.is_in_cache(code, glob1, "x")
-
- def test_degenerate_builtin_to_rdict(self):
- import sys, __builtin__
- mod1 = type(sys)("abc")
- self.impl_used(mod1.__dict__)
- glob1 = mod1.__dict__
- def f():
- return len(x)
- code = f.func_code
- f1 = type(f)(code, glob1)
- mod1.x = [1, 2]
- assert not self.is_in_cache(code, glob1, "x")
- assert not self.is_in_cache(code, glob1, "len")
- assert f1() == 2
- assert self.is_in_cache(code, glob1, "x")
- assert self.is_in_cache(code, glob1, "len")
- self.rescue_builtins()
- try:
- __builtin__.__dict__[1] = 2
- assert not self.is_in_cache(code, glob1, "len")
- assert f1() == 2
- assert not self.is_in_cache(code, glob1, "len")
- finally:
- self.restore_builtins()
-
- def test_mapping_as_locals(self):
- import sys
- if sys.version_info < (2,5) or not hasattr(sys, 'pypy_objspaceclass'):
- skip("need CPython 2.5 or PyPy for non-dictionaries in exec statements")
- class M(object):
- def __getitem__(self, key):
- return key
- def __setitem__(self, key, value):
- self.result[key] = value
- m = M()
- m.result = {}
- exec "x=m" in {}, m
- assert m.result == {'x': 'm'}
- exec "y=n" in m # NOTE: this doesn't work in CPython 2.4
- assert m.result == {'x': 'm', 'y': 'n'}
-
- def test_subclass_of_dict_as_locals(self):
- import sys
- if sys.version_info < (2,5) or not hasattr(sys, 'pypy_objspaceclass'):
- skip("need CPython 2.5 or PyPy for non-dictionaries in exec statements")
- class M(dict):
- def __getitem__(self, key):
- return key
- def __setitem__(self, key, value):
- dict.__setitem__(self, key, value)
- m = M()
- exec "x=m" in {}, m
- assert m == {'x': 'm'}
- exec "y=n" in m # NOTE: this doesn't work in CPython 2.4
- assert m == {'x': 'm', 'y': 'n'}
+space = FakeSpace()
+class TestCellDict(object):
+ def test_basic_property(self):
+ d = ModuleDictImplementation(space)
+ d.setitem("a", 1)
+ assert d.getcell("a", False) is d.getcell("a", False)
+ acell = d.getcell("a", False)
+ d.setitem("b", 2)
+ assert d.getcell("b", False) is d.getcell("b", False)
+ assert d.getcell("c", True) is d.getcell("c", True)
+
+ assert d.getitem("a") == 1
+ assert d.getitem("b") == 2
+
+ d.delitem("a")
+ py.test.raises(KeyError, d.delitem, "a")
+ assert d.getitem("a") is None
+ assert d.getcell("a", False) is acell
+ assert d.length() == 1
+
+ d.clear()
+ assert d.getitem("a") is None
+ assert d.getcell("a", False) is acell
+ assert d.length() == 0
Modified: pypy/branch/stringbuilder2/pypy/objspace/std/test/test_userobject.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/objspace/std/test/test_userobject.py (original)
+++ pypy/branch/stringbuilder2/pypy/objspace/std/test/test_userobject.py Mon Jan 25 15:25:48 2010
@@ -1,5 +1,6 @@
import py
from pypy.interpreter import gateway
+from pypy.objspace.test import test_descriptor
class AppTestUserObject:
@@ -297,3 +298,10 @@
class AppTestWithGetAttributeShortcut(AppTestUserObject):
OPTIONS = {"objspace.std.getattributeshortcut": True}
+
+class AppTestDescriptorWithGetAttributeShortcut(
+ test_descriptor.AppTest_Descriptor):
+ # for the individual tests see
+ # ====> ../../test/test_descriptor.py
+
+ OPTIONS = {"objspace.std.getattributeshortcut": True}
Modified: pypy/branch/stringbuilder2/pypy/objspace/test/test_descriptor.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/objspace/test/test_descriptor.py (original)
+++ pypy/branch/stringbuilder2/pypy/objspace/test/test_descriptor.py Mon Jan 25 15:25:48 2010
@@ -1,6 +1,13 @@
+import py
+from pypy.conftest import gettestobjspace
class AppTest_Descriptor:
+ OPTIONS = {}
+
+ def setup_class(cls):
+ cls.space = gettestobjspace(**cls.OPTIONS)
+
def test_non_data_descr(self):
class X(object):
def f(self):
@@ -12,6 +19,49 @@
del x.f
assert x.f() == 42
+ def test_set_without_get(self):
+ class Descr(object):
+
+ def __init__(self, name):
+ self.name = name
+
+ def __set__(self, obj, value):
+ obj.__dict__[self.name] = value
+ descr = Descr("a")
+
+ class X(object):
+ a = descr
+
+ x = X()
+ assert x.a is descr
+ x.a = 42
+ assert x.a == 42
+
+ def test_failing_get(self):
+ # when __get__() raises AttributeError,
+ # __getattr__ is called...
+ class X(object):
+ def get_v(self):
+ raise AttributeError
+ v = property(get_v)
+
+ def __getattr__(self, name):
+ if name == 'v':
+ return 42
+ x = X()
+ assert x.v == 42
+
+ # ... but the __dict__ is not searched
+ class Y(object):
+ def get_w(self):
+ raise AttributeError
+ def set_w(self, value):
+ raise AttributeError
+ w = property(get_w, set_w)
+ y = Y()
+ y.__dict__['w'] = 42
+ raises(AttributeError, getattr, y, 'w')
+
def test_member(self):
class X(object):
def __init__(self):
Modified: pypy/branch/stringbuilder2/pypy/objspace/test/test_descroperation.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/objspace/test/test_descroperation.py (original)
+++ pypy/branch/stringbuilder2/pypy/objspace/test/test_descroperation.py Mon Jan 25 15:25:48 2010
@@ -174,6 +174,29 @@
(0, slice_max),
]
+ def test_getslice_nolength(self):
+ class Sq(object):
+ def __getslice__(self, start, stop):
+ return (start, stop)
+ def __getitem__(self, key):
+ return "booh"
+
+ sq = Sq()
+
+ assert sq[1:3] == (1,3)
+ slice_min, slice_max = sq[:]
+ assert slice_min == 0
+ assert slice_max >= 2**31-1
+ assert sq[1:] == (1, slice_max)
+ assert sq[:3] == (0, 3)
+ assert sq[:] == (0, slice_max)
+ # negative indices, but no __len__
+ assert sq[-1:3] == (-1, 3)
+ assert sq[1:-3] == (1, -3)
+ assert sq[-1:-3] == (-1, -3)
+ # extended slice syntax always uses __getitem__()
+ assert sq[::] == "booh"
+
def test_ipow(self):
x = 2
x **= 5
Modified: pypy/branch/stringbuilder2/pypy/rlib/debug.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/rlib/debug.py (original)
+++ pypy/branch/stringbuilder2/pypy/rlib/debug.py Mon Jan 25 15:25:48 2010
@@ -19,6 +19,14 @@
hop.exception_cannot_occur()
hop.genop('debug_assert', vlist)
+def fatalerror(msg, traceback=False):
+ from pypy.rpython.lltypesystem import lltype
+ from pypy.rpython.lltypesystem.lloperation import llop
+ if traceback:
+ llop.debug_print_traceback(lltype.Void)
+ llop.debug_fatalerror(lltype.Void, msg)
+fatalerror._dont_inline_ = True
+
class DebugLog(list):
def debug_print(self, *args):
Modified: pypy/branch/stringbuilder2/pypy/rlib/jit.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/rlib/jit.py (original)
+++ pypy/branch/stringbuilder2/pypy/rlib/jit.py Mon Jan 25 15:25:48 2010
@@ -2,6 +2,7 @@
import sys
from pypy.rpython.extregistry import ExtRegistryEntry
from pypy.rlib.objectmodel import CDefinedIntSymbolic
+from pypy.rlib.objectmodel import keepalive_until_here
from pypy.rlib.unroll import unrolling_iterable
def purefunction(func):
@@ -19,6 +20,12 @@
func._jit_unroll_safe_ = True
return func
+def loop_invariant(func):
+ dont_look_inside(func)
+ func._jit_loop_invariant_ = True
+ return func
+
+
def purefunction_promote(func):
import inspect
purefunction(func)
@@ -80,8 +87,9 @@
def we_are_jitted():
+ """ Considered as true during tracing and blackholing,
+ so its consquences are reflected into jitted code """
return False
-# timeshifts to True
_we_are_jitted = CDefinedIntSymbolic('0 /* we are not jitted here */',
default=0)
@@ -98,6 +106,85 @@
hop.exception_cannot_occur()
return hop.inputconst(lltype.Signed, _we_are_jitted)
+
+##def force_virtualizable(virtualizable):
+## pass
+
+##class Entry(ExtRegistryEntry):
+## _about_ = force_virtualizable
+
+## def compute_result_annotation(self):
+## from pypy.annotation import model as annmodel
+## return annmodel.s_None
+
+## def specialize_call(self, hop):
+## [vinst] = hop.inputargs(hop.args_r[0])
+## cname = inputconst(lltype.Void, None)
+## cflags = inputconst(lltype.Void, {})
+## hop.exception_cannot_occur()
+## return hop.genop('jit_force_virtualizable', [vinst, cname, cflags],
+## resulttype=lltype.Void)
+
+# ____________________________________________________________
+# VRefs
+
+def virtual_ref(x):
+
+ """Creates a 'vref' object that contains a reference to 'x'. Calls
+ to virtual_ref/virtual_ref_finish must be properly nested. The idea
+ is that the object 'x' is supposed to be JITted as a virtual between
+ the calls to virtual_ref and virtual_ref_finish, but the 'vref'
+ object can escape at any point in time. If at runtime it is
+ dereferenced (by the call syntax 'vref()'), it returns 'x', which is
+ then forced."""
+ return DirectJitVRef(x)
+virtual_ref.oopspec = 'virtual_ref(x)'
+
+def virtual_ref_finish(x):
+ """See docstring in virtual_ref(x). Note that virtual_ref_finish
+ takes as argument the real object, not the vref."""
+ keepalive_until_here(x) # otherwise the whole function call is removed
+virtual_ref_finish.oopspec = 'virtual_ref_finish(x)'
+
+def non_virtual_ref(x):
+ """Creates a 'vref' that just returns x when called; nothing more special.
+ Used for None or for frames outside JIT scope."""
+ return DirectVRef(x)
+
+# ---------- implementation-specific ----------
+
+class DirectVRef(object):
+ def __init__(self, x):
+ self._x = x
+ def __call__(self):
+ return self._x
+
+class DirectJitVRef(DirectVRef):
+ def __init__(self, x):
+ assert x is not None, "virtual_ref(None) is not allowed"
+ DirectVRef.__init__(self, x)
+
+class Entry(ExtRegistryEntry):
+ _about_ = (non_virtual_ref, DirectJitVRef)
+
+ def compute_result_annotation(self, s_obj):
+ from pypy.rlib import _jit_vref
+ return _jit_vref.SomeVRef(s_obj)
+
+ def specialize_call(self, hop):
+ return hop.r_result.specialize_call(hop)
+
+class Entry(ExtRegistryEntry):
+ _type_ = DirectVRef
+
+ def compute_annotation(self):
+ from pypy.rlib import _jit_vref
+ assert isinstance(self.instance, DirectVRef)
+ s_obj = self.bookkeeper.immutablevalue(self.instance())
+ return _jit_vref.SomeVRef(s_obj)
+
+vref_None = non_virtual_ref(None)
+
# ____________________________________________________________
# User interface for the hotpath JIT policy
@@ -135,7 +222,8 @@
def __init__(self, greens=None, reds=None, virtualizables=None,
get_jitcell_at=None, set_jitcell_at=None,
can_inline=None, get_printable_location=None,
- leave=None):
+ confirm_enter_jit=None,
+ leave=None): # XXX 'leave' is deprecated
if greens is not None:
self.greens = greens
if reds is not None:
@@ -152,6 +240,7 @@
self.set_jitcell_at = set_jitcell_at
self.get_printable_location = get_printable_location
self.can_inline = can_inline
+ self.confirm_enter_jit = confirm_enter_jit
self.leave = leave
def _freeze_(self):
Modified: pypy/branch/stringbuilder2/pypy/rlib/rgc.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/rlib/rgc.py (original)
+++ pypy/branch/stringbuilder2/pypy/rlib/rgc.py Mon Jan 25 15:25:48 2010
@@ -1,5 +1,7 @@
import gc
from pypy.rpython.extregistry import ExtRegistryEntry
+from pypy.rlib.objectmodel import we_are_translated
+
# ____________________________________________________________
# General GC features
@@ -334,7 +336,12 @@
from pypy.rpython.lltypesystem import lltype, llmemory
from pypy.rlib.objectmodel import keepalive_until_here
- assert source != dest
+ # supports non-overlapping copies only
+ if not we_are_translated():
+ if source == dest:
+ assert (source_start + length <= dest_start or
+ dest_start + length <= source_start)
+
TP = lltype.typeOf(source).TO
assert TP == lltype.typeOf(dest).TO
if isinstance(TP.OF, lltype.Ptr) and TP.OF.TO._gckind == 'gc':
@@ -357,3 +364,9 @@
keepalive_until_here(source)
keepalive_until_here(dest)
ll_arraycopy._annspecialcase_ = 'specialize:ll'
+ll_arraycopy._jit_look_inside_ = False
+
+def no_collect(func):
+ func._dont_inline_ = True
+ func._gc_no_collect_ = True
+ return func
Modified: pypy/branch/stringbuilder2/pypy/rpython/llinterp.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/rpython/llinterp.py (original)
+++ pypy/branch/stringbuilder2/pypy/rpython/llinterp.py Mon Jan 25 15:25:48 2010
@@ -543,10 +543,22 @@
def op_debug_llinterpcall(self, pythonfunction, *args_ll):
return pythonfunction(*args_ll)
- def op_jit_marker(self, *args):
- pass
+ def op_debug_start_traceback(self, *args):
+ pass # xxx write debugging code here?
+
+ def op_debug_reraise_traceback(self, *args):
+ pass # xxx write debugging code here?
+
+ def op_debug_record_traceback(self, *args):
+ pass # xxx write debugging code here?
- def op_promote_virtualizable(self, *args):
+ def op_debug_print_traceback(self, *args):
+ pass # xxx write debugging code here?
+
+ def op_debug_catch_exception(self, *args):
+ pass # xxx write debugging code here?
+
+ def op_jit_marker(self, *args):
pass
def op_get_exception_addr(self, *args):
Modified: pypy/branch/stringbuilder2/pypy/rpython/lltypesystem/ll2ctypes.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/rpython/lltypesystem/ll2ctypes.py (original)
+++ pypy/branch/stringbuilder2/pypy/rpython/lltypesystem/ll2ctypes.py Mon Jan 25 15:25:48 2010
@@ -21,8 +21,7 @@
from pypy.rlib.rarithmetic import r_uint, r_singlefloat, intmask
from pypy.annotation import model as annmodel
from pypy.rpython.llinterp import LLInterpreter, LLException
-from pypy.rpython.lltypesystem.rclass import OBJECT
-from pypy.rpython.annlowlevel import base_ptr_lltype
+from pypy.rpython.lltypesystem.rclass import OBJECT, OBJECT_VTABLE
from pypy.rpython import raddress
from pypy.translator.platform import platform
@@ -31,7 +30,6 @@
_ctypes_cache = {}
_eci_cache = {}
-_parent_cache = {}
def _setup_ctypes_cache():
from pypy.rpython.lltypesystem import rffi
@@ -255,7 +253,6 @@
convert_struct(field_value, csubstruct)
subcontainer = getattr(container, field_name)
substorage = subcontainer._storage
- update_parent_cache(substorage, subcontainer)
elif field_name == STRUCT._arrayfld: # inlined var-sized part
csubarray = getattr(cstruct, field_name)
convert_array(field_value, csubarray)
@@ -314,7 +311,6 @@
struct_storage = getattr(ctypes_storage, field_name)
struct_use_ctypes_storage(struct_container, struct_storage)
struct_container._setparentstructure(container, field_name)
- update_parent_cache(ctypes_storage, struct_container)
elif isinstance(FIELDTYPE, lltype.Array):
assert FIELDTYPE._hints.get('nolength', False) == False
arraycontainer = _array_of_known_length(FIELDTYPE)
@@ -500,25 +496,6 @@
_callback2obj = {}
_callback_exc_info = None
-# this is just another hack that passes around references to applevel types
-# disguised as base_ptr_lltype
-class Dummy(object):
- pass
-
-_opaque_cache = {Dummy():0}
-_opaque_list = [Dummy()]
-
-def new_opaque_object(llobj):
- try:
- return _opaque_cache[llobj]
- except KeyError:
- assert len(_opaque_cache) == len(_opaque_list)
- ctypes_type = get_ctypes_type(base_ptr_lltype())
- val = ctypes.cast(len(_opaque_cache), ctypes_type)
- _opaque_list.append(llobj)
- _opaque_cache[llobj] = val
- return val
-
def get_rtyper():
llinterp = LLInterpreter.current_interpreter
if llinterp is not None:
@@ -542,8 +519,6 @@
return ctypes.c_void_p(0)
return get_ctypes_type(T)()
- if T is base_ptr_lltype():
- return new_opaque_object(llobj)
if T == llmemory.GCREF:
if isinstance(llobj._obj, _llgcopaque):
return ctypes.c_void_p(llobj._obj.intval)
@@ -655,8 +630,6 @@
raise NotImplementedError(T)
container._ctypes_storage_was_allocated()
storage = container._storage
- if lltype.parentlink(container)[0] is not None:
- update_parent_cache(storage, container)
p = ctypes.pointer(storage)
if index:
p = ctypes.cast(p, ctypes.c_void_p)
@@ -694,29 +667,37 @@
if isinstance(T, lltype.Ptr):
if not cobj: # NULL pointer
return lltype.nullptr(T.TO)
- if T is base_ptr_lltype():
- return _opaque_list[ctypes.cast(cobj, ctypes.c_void_p).value]
if isinstance(T.TO, lltype.Struct):
+ REAL_TYPE = T.TO
if T.TO._arrayfld is not None:
carray = getattr(cobj.contents, T.TO._arrayfld)
container = lltype._struct(T.TO, carray.length)
else:
# special treatment of 'OBJECT' subclasses
- if get_rtyper() and lltype._castdepth(T.TO, OBJECT) > 0:
- ctypes_object = get_ctypes_type(lltype.Ptr(OBJECT))
- as_obj = ctypes2lltype(lltype.Ptr(OBJECT),
- ctypes.cast(cobj, ctypes_object))
- TObj = get_rtyper().get_type_for_typeptr(as_obj.typeptr)
- if TObj != T.TO:
- ctypes_instance = get_ctypes_type(lltype.Ptr(TObj))
- return lltype.cast_pointer(T,
- ctypes2lltype(lltype.Ptr(TObj),
- ctypes.cast(cobj, ctypes_instance)))
- container = lltype._struct(T.TO)
+ if get_rtyper() and lltype._castdepth(REAL_TYPE, OBJECT) >= 0:
+ # figure out the real type of the object
+ containerheader = lltype._struct(OBJECT)
+ cobjheader = ctypes.cast(cobj,
+ get_ctypes_type(lltype.Ptr(OBJECT)))
+ struct_use_ctypes_storage(containerheader,
+ cobjheader.contents)
+ REAL_TYPE = get_rtyper().get_type_for_typeptr(
+ containerheader.typeptr)
+ REAL_T = lltype.Ptr(REAL_TYPE)
+ cobj = ctypes.cast(cobj, get_ctypes_type(REAL_T))
+ container = lltype._struct(REAL_TYPE)
struct_use_ctypes_storage(container, cobj.contents)
- addr = ctypes.addressof(cobj.contents)
- if addr in _parent_cache:
- setparentstructure(container, _parent_cache[addr])
+ if REAL_TYPE != T.TO:
+ p = container._as_ptr()
+ container = lltype.cast_pointer(T, p)._as_obj()
+ # special treatment of 'OBJECT_VTABLE' subclasses
+ if get_rtyper() and lltype._castdepth(REAL_TYPE,
+ OBJECT_VTABLE) >= 0:
+ # figure out the real object that this vtable points to,
+ # and just return that
+ p = get_rtyper().get_real_typeptr_for_typeptr(
+ container._as_ptr())
+ container = lltype.cast_pointer(T, p)._as_obj()
elif isinstance(T.TO, lltype.Array):
if T.TO._hints.get('nolength', False):
container = _array_of_unknown_length(T.TO)
@@ -1163,46 +1144,6 @@
return hop.genop('cast_adr_to_int', [adr],
resulttype = lltype.Signed)
-# ------------------------------------------------------------
-
-def parentchain(container):
- current = container
- links = []
- while True:
- link = lltype.parentlink(current)
- if link[0] is None:
- try:
- addr = ctypes.addressof(container._storage)
- actual = _parent_cache[addr]
- if len(links) < len(actual):
- return actual
- except KeyError:
- pass
- return links
- links.append(link)
- current = link[0]
-
-def update_parent_cache(storage, container):
- chain = parentchain(container)
- addr = ctypes.addressof(storage)
- try:
- current = _parent_cache[addr]
- if len(chain) > len(current):
- _parent_cache[addr] = chain
- except KeyError:
- _parent_cache[addr] = chain
-
-def setparentstructure(container, chain):
- TP = lltype.typeOf(container)
- current = container
- for i, elem in enumerate(chain):
- if lltype.typeOf(elem[0]) == TP:
- chain = chain[i + 1:]
- break
- for elem in chain:
- current._setparentstructure(*elem)
- current = elem[0]
-
# ____________________________________________________________
# errno
Modified: pypy/branch/stringbuilder2/pypy/rpython/lltypesystem/lloperation.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/rpython/lltypesystem/lloperation.py (original)
+++ pypy/branch/stringbuilder2/pypy/rpython/lltypesystem/lloperation.py Mon Jan 25 15:25:48 2010
@@ -427,7 +427,8 @@
# __________ used by the JIT ________
'jit_marker': LLOp(),
- 'promote_virtualizable':LLOp(canrun=True),
+ 'jit_force_virtualizable':LLOp(canrun=True),
+ 'jit_force_virtual': LLOp(canrun=True),
'get_exception_addr': LLOp(),
'get_exc_value_addr': LLOp(),
'do_malloc_fixedsize_clear': LLOp(canunwindgc=True),
@@ -535,6 +536,11 @@
'debug_fatalerror': LLOp(),
'debug_llinterpcall': LLOp(), # Python func call 'res=arg[0](*arg[1:])'
# in backends, abort() or whatever is fine
+ 'debug_start_traceback': LLOp(),
+ 'debug_record_traceback': LLOp(),
+ 'debug_catch_exception': LLOp(),
+ 'debug_reraise_traceback': LLOp(),
+ 'debug_print_traceback': LLOp(),
# __________ instrumentation _________
'instrument_count': LLOp(),
Modified: pypy/branch/stringbuilder2/pypy/rpython/lltypesystem/opimpl.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/rpython/lltypesystem/opimpl.py (original)
+++ pypy/branch/stringbuilder2/pypy/rpython/lltypesystem/opimpl.py Mon Jan 25 15:25:48 2010
@@ -444,8 +444,11 @@
def op_gc_stack_bottom():
pass # marker for trackgcroot.py
-def op_promote_virtualizable(object, fieldname, flags):
- pass # XXX should do something
+def op_jit_force_virtualizable(*args):
+ pass
+
+def op_jit_force_virtual(x):
+ return x
def op_get_group_member(TYPE, grpptr, memberoffset):
from pypy.rpython.lltypesystem import llgroup
Modified: pypy/branch/stringbuilder2/pypy/rpython/lltypesystem/rclass.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/rpython/lltypesystem/rclass.py (original)
+++ pypy/branch/stringbuilder2/pypy/rpython/lltypesystem/rclass.py Mon Jan 25 15:25:48 2010
@@ -86,6 +86,13 @@
vtable = vtable.super
return vtable
+def alloc_array_name(name):
+ p = malloc(Array(Char), len(name)+1, immortal=True)
+ for i in range(len(name)):
+ p[i] = name[i]
+ p[len(name)] = '\x00'
+ return p
+
class ClassRepr(AbstractClassRepr):
def __init__(self, rtyper, classdef):
@@ -192,10 +199,7 @@
name = 'object'
else:
name = rsubcls.classdef.shortname
- vtable.name = malloc(Array(Char), len(name)+1, immortal=True)
- for i in range(len(name)):
- vtable.name[i] = name[i]
- vtable.name[len(name)] = '\x00'
+ vtable.name = alloc_array_name(name)
if hasattr(rsubcls.classdef, 'my_instantiate_graph'):
graph = rsubcls.classdef.my_instantiate_graph
vtable.instantiate = self.rtyper.getcallable(graph)
@@ -379,7 +383,7 @@
ll_runtime_type_info,
OBJECT, destrptr)
vtable = self.rclass.getvtable()
- self.rtyper.type_for_typeptr[vtable._obj] = self.lowleveltype.TO
+ self.rtyper.set_type_for_typeptr(vtable, self.lowleveltype.TO)
self.rtyper.lltype2vtable[self.lowleveltype.TO] = vtable
def common_repr(self): # -> object or nongcobject reprs
@@ -689,3 +693,23 @@
break
raise AttributeError("%s has no field %s" % (lltype.typeOf(widest),
name))
+
+def declare_type_for_typeptr(vtable, TYPE):
+ """Hack for custom low-level-only 'subclasses' of OBJECT:
+ call this somewhere annotated, in order to declare that it is
+ of the given TYPE and has got the corresponding vtable."""
+
+class Entry(ExtRegistryEntry):
+ _about_ = declare_type_for_typeptr
+ def compute_result_annotation(self, s_vtable, s_TYPE):
+ assert s_vtable.is_constant()
+ assert s_TYPE.is_constant()
+ return annmodel.s_None
+ def specialize_call(self, hop):
+ vtable = hop.args_v[0].value
+ TYPE = hop.args_v[1].value
+ assert lltype.typeOf(vtable) == CLASSTYPE
+ assert isinstance(TYPE, GcStruct)
+ assert lltype._castdepth(TYPE, OBJECT) > 0
+ hop.rtyper.set_type_for_typeptr(vtable, TYPE)
+ return hop.inputconst(lltype.Void, None)
Modified: pypy/branch/stringbuilder2/pypy/rpython/lltypesystem/rlist.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/rpython/lltypesystem/rlist.py (original)
+++ pypy/branch/stringbuilder2/pypy/rpython/lltypesystem/rlist.py Mon Jan 25 15:25:48 2010
@@ -368,8 +368,7 @@
else:
LIST = typeOf(l).TO
newitems = malloc(LIST.items.TO, n)
- for i in range(n):
- newitems[i] = olditems[i]
+ rgc.ll_arraycopy(olditems, newitems, 0, 0, n)
return newitems
ll_list2fixed.oopspec = 'list.list2fixed(l)'
Modified: pypy/branch/stringbuilder2/pypy/rpython/lltypesystem/test/test_ll2ctypes.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/rpython/lltypesystem/test/test_ll2ctypes.py (original)
+++ pypy/branch/stringbuilder2/pypy/rpython/lltypesystem/test/test_ll2ctypes.py Mon Jan 25 15:25:48 2010
@@ -928,34 +928,6 @@
assert op.args[1].value == pypy.rpython.lltypesystem.rstr.LLHelpers
assert op.args[3].value == -2
- def test_pass_around_t_object(self):
- from pypy.rpython.annlowlevel import base_ptr_lltype
- T = base_ptr_lltype()
-
- class X(object):
- _TYPE = T
- x = 10
-
- def callback(x):
- return x.x
-
- c_source = py.code.Source("""
- long eating_callback(void *arg, long(*call)(void*))
- {
- return call(arg);
- }
- """)
-
- eci = ExternalCompilationInfo(separate_module_sources=[c_source],
- export_symbols=['eating_callback'])
-
- args = [T, rffi.CCallback([T], rffi.LONG)]
- eating_callback = rffi.llexternal('eating_callback', args, rffi.LONG,
- compilation_info=eci)
-
- res = eating_callback(X(), callback)
- assert res == 10
-
def test_recursive_struct_more(self):
NODE = lltype.ForwardReference()
NODE.become(lltype.Struct('NODE', ('value', lltype.Signed),
@@ -1134,7 +1106,104 @@
#import pdb; pdb.set_trace()
assert adr1_2 == adr1
assert adr1 == adr1_2
-
+
+ def test_object_subclass(self):
+ from pypy.rpython.lltypesystem import rclass
+ from pypy.rpython.annlowlevel import cast_instance_to_base_ptr
+ from pypy.rpython.annlowlevel import cast_base_ptr_to_instance
+ class S:
+ pass
+ def f(n):
+ s = S()
+ s.x = n
+ ls = cast_instance_to_base_ptr(s)
+ as_num = rffi.cast(lltype.Signed, ls)
+ # --- around this point, only 'as_num' is passed
+ t = rffi.cast(rclass.OBJECTPTR, as_num)
+ u = cast_base_ptr_to_instance(S, t)
+ return u.x
+ res = interpret(f, [123])
+ assert res == 123
+
+ def test_object_subclass_2(self):
+ from pypy.rpython.lltypesystem import rclass
+ SCLASS = lltype.GcStruct('SCLASS',
+ ('parent', rclass.OBJECT),
+ ('n', lltype.Signed))
+ sclass_vtable = lltype.malloc(rclass.OBJECT_VTABLE, zero=True,
+ immortal=True)
+ sclass_vtable.name = rclass.alloc_array_name('SClass')
+ def f(n):
+ rclass.declare_type_for_typeptr(sclass_vtable, SCLASS)
+ s = lltype.malloc(SCLASS)
+ s.parent.typeptr = sclass_vtable
+ s.n = n
+ as_num = rffi.cast(lltype.Signed, s)
+ # --- around this point, only 'as_num' is passed
+ t = rffi.cast(lltype.Ptr(SCLASS), as_num)
+ return t.n
+ res = interpret(f, [123])
+ assert res == 123
+
+ def test_object_subclass_3(self):
+ from pypy.rpython.lltypesystem import rclass
+ from pypy.rpython.annlowlevel import cast_instance_to_base_ptr
+ from pypy.rpython.annlowlevel import cast_base_ptr_to_instance
+ class S:
+ pass
+ def f(n):
+ s = S()
+ s.x = n
+ ls = cast_instance_to_base_ptr(s)
+ as_num = rffi.cast(lltype.Signed, ls)
+ # --- around this point, only 'as_num' is passed
+ r = rffi.cast(llmemory.GCREF, as_num)
+ t = lltype.cast_opaque_ptr(rclass.OBJECTPTR, r)
+ u = cast_base_ptr_to_instance(S, t)
+ return u.x
+ res = interpret(f, [123])
+ assert res == 123
+
+ def test_object_subclass_4(self):
+ from pypy.rpython.lltypesystem import rclass
+ SCLASS = lltype.GcStruct('SCLASS',
+ ('parent', rclass.OBJECT),
+ ('n', lltype.Signed))
+ sclass_vtable = lltype.malloc(rclass.OBJECT_VTABLE, zero=True,
+ immortal=True)
+ sclass_vtable.name = rclass.alloc_array_name('SClass')
+ def f(n):
+ rclass.declare_type_for_typeptr(sclass_vtable, SCLASS)
+ s = lltype.malloc(SCLASS)
+ s.parent.typeptr = sclass_vtable
+ s.n = n
+ as_num = rffi.cast(lltype.Signed, s)
+ # --- around this point, only 'as_num' is passed
+ r = rffi.cast(llmemory.GCREF, as_num)
+ t = lltype.cast_opaque_ptr(lltype.Ptr(SCLASS), r)
+ return t.n
+ res = interpret(f, [123])
+ assert res == 123
+
+ def test_object_subclass_5(self):
+ from pypy.rpython.lltypesystem import rclass
+ from pypy.rpython.annlowlevel import cast_instance_to_base_ptr
+ from pypy.rpython.annlowlevel import cast_base_ptr_to_instance
+ class S:
+ x = 5 # entry in the vtable
+ class T(S):
+ x = 6
+ def f():
+ s = T()
+ ls = cast_instance_to_base_ptr(s)
+ as_num = rffi.cast(lltype.Signed, ls)
+ # --- around this point, only 'as_num' is passed
+ t = rffi.cast(rclass.OBJECTPTR, as_num)
+ u = cast_base_ptr_to_instance(S, t)
+ return u.x
+ res = interpret(f, [])
+ assert res == 6
+
class TestPlatform(object):
def test_lib_on_libpaths(self):
from pypy.translator.platform import platform
Modified: pypy/branch/stringbuilder2/pypy/rpython/memory/gctransform/framework.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/rpython/memory/gctransform/framework.py (original)
+++ pypy/branch/stringbuilder2/pypy/rpython/memory/gctransform/framework.py Mon Jan 25 15:25:48 2010
@@ -567,6 +567,12 @@
f.close()
def transform_graph(self, graph):
+ func = getattr(graph, 'func', None)
+ if func and getattr(func, '_gc_no_collect_', False):
+ if self.collect_analyzer.analyze_direct_call(graph):
+ raise Exception("no_collect function can trigger collection: %s"
+ % func.__name__)
+
if self.write_barrier_ptr:
self.clean_sets = (
find_clean_setarrayitems(self.collect_analyzer, graph).union(
Modified: pypy/branch/stringbuilder2/pypy/rpython/memory/gctransform/test/test_framework.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/rpython/memory/gctransform/test/test_framework.py (original)
+++ pypy/branch/stringbuilder2/pypy/rpython/memory/gctransform/test/test_framework.py Mon Jan 25 15:25:48 2010
@@ -1,5 +1,6 @@
from pypy.objspace.flow.model import Constant, SpaceOperation
from pypy.annotation.model import SomeInteger
+from pypy.annotation.listdef import s_list_of_strings
from pypy.rpython.memory.gc.marksweep import MarkSweepGC
from pypy.rpython.memory.gctransform.test.test_transform import rtype, \
rtype_and_transform
@@ -34,7 +35,6 @@
from pypy.rpython.llinterp import LLInterpreter
from pypy.translator.c.genc import CStandaloneBuilder
from pypy.translator.c import gc
- from pypy.annotation.listdef import s_list_of_strings
t = rtype(entrypoint, [s_list_of_strings])
cbuild = CStandaloneBuilder(t, entrypoint, t.config,
@@ -113,6 +113,50 @@
gg = graphof(t, g)
assert CollectAnalyzer(t).analyze_direct_call(gg)
+def test_no_collect():
+ from pypy.rlib import rgc
+ from pypy.translator.c.genc import CStandaloneBuilder
+ from pypy.translator.c import gc
+
+ @rgc.no_collect
+ def g():
+ return 1
+
+ assert g._dont_inline_
+ assert g._gc_no_collect_
+
+ def entrypoint(argv):
+ return g() + 2
+
+ t = rtype(entrypoint, [s_list_of_strings])
+ cbuild = CStandaloneBuilder(t, entrypoint, t.config,
+ gcpolicy=FrameworkGcPolicy2)
+ db = cbuild.generate_graphs_for_llinterp()
+
+def test_no_collect_detection():
+ from pypy.rlib import rgc
+ from pypy.translator.c.genc import CStandaloneBuilder
+ from pypy.translator.c import gc
+
+ class A(object):
+ def __init__(self, x):
+ self.x = x
+
+ @rgc.no_collect
+ def g():
+ return A(1).x
+
+ assert g._dont_inline_
+ assert g._gc_no_collect_
+
+ def entrypoint(argv):
+ return g() + 2
+
+ t = rtype(entrypoint, [s_list_of_strings])
+ cbuild = CStandaloneBuilder(t, entrypoint, t.config,
+ gcpolicy=FrameworkGcPolicy2)
+ f = py.test.raises(Exception, cbuild.generate_graphs_for_llinterp)
+ assert str(f.value) == 'no_collect function can trigger collection: g'
class WriteBarrierTransformer(FrameworkGCTransformer):
clean_sets = {}
Modified: pypy/branch/stringbuilder2/pypy/rpython/module/ll_os.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/rpython/module/ll_os.py (original)
+++ pypy/branch/stringbuilder2/pypy/rpython/module/ll_os.py Mon Jan 25 15:25:48 2010
@@ -1400,6 +1400,30 @@
return extdef([], int, llimpl=fork_llimpl,
export_name="ll_os.ll_os_fork")
+ @registering_if(os, 'openpty')
+ def register_os_openpty(self):
+ os_openpty = self.llexternal(
+ 'openpty',
+ [rffi.INTP, rffi.INTP, rffi.VOIDP, rffi.VOIDP, rffi.VOIDP],
+ rffi.INT,
+ compilation_info=ExternalCompilationInfo(libraries=['util']))
+ def openpty_llimpl():
+ master_p = lltype.malloc(rffi.INTP.TO, 1, flavor='raw')
+ slave_p = lltype.malloc(rffi.INTP.TO, 1, flavor='raw')
+ result = os_openpty(master_p, slave_p, None, None, None)
+ master_fd = master_p[0]
+ slave_fd = slave_p[0]
+ lltype.free(master_p, flavor='raw')
+ lltype.free(slave_p, flavor='raw')
+ if result == -1:
+ raise OSError(rposix.get_errno(), "os_openpty failed")
+ return (rffi.cast(lltype.Signed, master_fd),
+ rffi.cast(lltype.Signed, slave_fd))
+
+ return extdef([], (int, int), "ll_os.ll_os_openpty",
+ llimpl=openpty_llimpl)
+
+
@registering(os._exit)
def register_os__exit(self):
os__exit = self.llexternal('_exit', [rffi.INT], lltype.Void)
Modified: pypy/branch/stringbuilder2/pypy/rpython/rlist.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/rpython/rlist.py (original)
+++ pypy/branch/stringbuilder2/pypy/rpython/rlist.py Mon Jan 25 15:25:48 2010
@@ -11,6 +11,7 @@
from pypy.rlib.debug import ll_assert
from pypy.rlib.rarithmetic import ovfcheck, widen
from pypy.rpython.annlowlevel import ADTInterface
+from pypy.rlib import rgc
ADTIFixedList = ADTInterface(None, {
'll_newlist': (['SELF', Signed ], 'self'),
@@ -525,13 +526,24 @@
return LIST.ITEM
+def ll_arraycopy(source, dest, source_start, dest_start, length):
+ SRCTYPE = typeOf(source)
+ if isinstance(SRCTYPE, Ptr):
+ # lltype
+ rgc.ll_arraycopy(source.ll_items(), dest.ll_items(),
+ source_start, dest_start, length)
+ else:
+ # ootype -- XXX improve the case of array->array copy?
+ i = 0
+ while i < length:
+ item = source.ll_getitem_fast(source_start + i)
+ dest.ll_setitem_fast(dest_start + i, item)
+ i += 1
+
def ll_copy(RESLIST, l):
length = l.ll_length()
new_lst = RESLIST.ll_newlist(length)
- i = 0
- while i < length:
- new_lst.ll_setitem_fast(i, l.ll_getitem_fast(i))
- i += 1
+ ll_arraycopy(l, new_lst, 0, 0, length)
return new_lst
def ll_len(l):
@@ -574,15 +586,8 @@
except OverflowError:
raise MemoryError
l = RESLIST.ll_newlist(newlength)
- j = 0
- while j < len1:
- l.ll_setitem_fast(j, l1.ll_getitem_fast(j))
- j += 1
- i = 0
- while i < len2:
- l.ll_setitem_fast(j, l2.ll_getitem_fast(i))
- i += 1
- j += 1
+ ll_arraycopy(l1, l, 0, 0, len1)
+ ll_arraycopy(l2, l, 0, len1, len2)
return l
def ll_insert_nonneg(l, index, newitem):
@@ -769,12 +774,7 @@
except OverflowError:
raise MemoryError
l1._ll_resize_ge(newlength)
- i = 0
- j = len1
- while i < len2:
- l1.ll_setitem_fast(j, l2.ll_getitem_fast(i))
- i += 1
- j += 1
+ ll_arraycopy(l2, l1, 0, len1, len2)
ll_extend.oopspec = 'list.extend(l1, l2)'
def ll_extend_with_str(lst, s, getstrlen, getstritem):
@@ -867,12 +867,7 @@
ll_assert(start <= len1, "list slice start larger than list length")
newlength = len1 - start
l = RESLIST.ll_newlist(newlength)
- j = 0
- i = start
- while i < len1:
- l.ll_setitem_fast(j, l1.ll_getitem_fast(i))
- i += 1
- j += 1
+ ll_arraycopy(l1, l, start, 0, newlength)
return l
ll_listslice_startonly._annenforceargs_ = (None, None, int)
@@ -885,22 +880,14 @@
stop = length
newlength = stop - start
l = RESLIST.ll_newlist(newlength)
- j = 0
- i = start
- while i < stop:
- l.ll_setitem_fast(j, l1.ll_getitem_fast(i))
- i += 1
- j += 1
+ ll_arraycopy(l1, l, start, 0, newlength)
return l
def ll_listslice_minusone(RESLIST, l1):
newlength = l1.ll_length() - 1
ll_assert(newlength >= 0, "empty list is sliced with [:-1]")
l = RESLIST.ll_newlist(newlength)
- j = 0
- while j < newlength:
- l.ll_setitem_fast(j, l1.ll_getitem_fast(j))
- j += 1
+ ll_arraycopy(l1, l, 0, 0, newlength)
return l
def ll_listdelslice_startonly(l, start):
@@ -945,13 +932,8 @@
ll_assert(start <= l1.ll_length(), "l[start:x] = l with start > len(l)")
ll_assert(count == stop - start,
"setslice cannot resize lists in RPython")
- # XXX but it should be easy enough to support, soon
- j = start
- i = 0
- while i < count:
- l1.ll_setitem_fast(j, l2.ll_getitem_fast(i))
- i += 1
- j += 1
+ # XXX ...but it would be easy enough to support if really needed
+ ll_arraycopy(l2, l1, 0, start, count)
ll_listsetslice.oopspec = 'list.setslice(l1, start, stop, l2)'
# ____________________________________________________________
Modified: pypy/branch/stringbuilder2/pypy/rpython/rptr.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/rpython/rptr.py (original)
+++ pypy/branch/stringbuilder2/pypy/rpython/rptr.py Mon Jan 25 15:25:48 2010
@@ -39,6 +39,14 @@
attr = hop.args_s[1].const
if isinstance(hop.s_result, annmodel.SomeLLADTMeth):
return hop.inputarg(hop.r_result, arg=0)
+ try:
+ self.lowleveltype._example()._lookup_adtmeth(attr)
+ except AttributeError:
+ pass
+ else:
+ assert hop.s_result.is_constant()
+ return hop.inputconst(hop.r_result, hop.s_result.const)
+ assert attr in self.lowleveltype.TO._flds # check that the field exists
FIELD_TYPE = getattr(self.lowleveltype.TO, attr)
if isinstance(FIELD_TYPE, lltype.ContainerType):
if (attr, FIELD_TYPE) == self.lowleveltype.TO._first_struct():
Modified: pypy/branch/stringbuilder2/pypy/rpython/rtyper.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/rpython/rtyper.py (original)
+++ pypy/branch/stringbuilder2/pypy/rpython/rtyper.py Mon Jan 25 15:25:48 2010
@@ -133,15 +133,33 @@
return result
def get_type_for_typeptr(self, typeptr):
+ search = typeptr._obj
try:
- return self.type_for_typeptr[typeptr._obj]
+ return self.type_for_typeptr[search]
except KeyError:
- # rehash the dictionary
+ # rehash the dictionary, and perform a linear scan
+ # for the case of ll2ctypes typeptr
+ found = None
type_for_typeptr = {}
for key, value in self.type_for_typeptr.items():
type_for_typeptr[key] = value
+ if key == search:
+ found = value
self.type_for_typeptr = type_for_typeptr
- return self.type_for_typeptr[typeptr._obj]
+ if found is None:
+ raise KeyError(search)
+ return found
+
+ def set_type_for_typeptr(self, typeptr, TYPE):
+ self.type_for_typeptr[typeptr._obj] = TYPE
+
+ def get_real_typeptr_for_typeptr(self, typeptr):
+ # perform a linear scan for the case of ll2ctypes typeptr
+ search = typeptr._obj
+ for key, value in self.type_for_typeptr.items():
+ if key == search:
+ return key._as_ptr()
+ raise KeyError(search)
def makekey(self, s_obj):
return pair(self.type_system, s_obj).rtyper_makekey(self)
Modified: pypy/branch/stringbuilder2/pypy/rpython/rvirtualizable2.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/rpython/rvirtualizable2.py (original)
+++ pypy/branch/stringbuilder2/pypy/rpython/rvirtualizable2.py Mon Jan 25 15:25:48 2010
@@ -52,10 +52,10 @@
#if not flags.get('access_directly'):
if cname.value in self.my_redirected_fields:
cflags = inputconst(lltype.Void, flags)
- llops.genop('promote_virtualizable', [vinst, cname, cflags])
+ llops.genop('jit_force_virtualizable', [vinst, cname, cflags])
-def replace_promote_virtualizable_with_call(graphs, VTYPEPTR, funcptr):
+def replace_force_virtualizable_with_call(graphs, VTYPEPTR, funcptr):
# funcptr should be an ll or oo function pointer with a VTYPEPTR argument
c_funcptr = inputconst(lltype.typeOf(funcptr), funcptr)
count = 0
@@ -65,7 +65,7 @@
continue
newoplist = []
for i, op in enumerate(block.operations):
- if (op.opname == 'promote_virtualizable' and
+ if (op.opname == 'jit_force_virtualizable' and
match_virtualizable_type(op.args[0].concretetype,
VTYPEPTR)):
if op.args[-1].value.get('access_directly', False):
@@ -75,7 +75,7 @@
count += 1
newoplist.append(op)
block.operations = newoplist
- log("replaced %d 'promote_virtualizable' with %r" % (count, funcptr))
+ log("replaced %d 'jit_force_virtualizable' with %r" % (count, funcptr))
def match_virtualizable_type(TYPE, VTYPEPTR):
if isinstance(TYPE, ootype.Instance):
Modified: pypy/branch/stringbuilder2/pypy/rpython/test/test_rlist.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/rpython/test/test_rlist.py (original)
+++ pypy/branch/stringbuilder2/pypy/rpython/test/test_rlist.py Mon Jan 25 15:25:48 2010
@@ -410,13 +410,18 @@
assert res.item2 == 9
def test_bltn_list(self):
- def dummyfn():
- l1 = [42]
- l2 = list(l1)
- l2[0] = 0
- return l1[0]
- res = self.interpret(dummyfn, ())
- assert res == 42
+ # test for ll_copy()
+ for resize1 in [False, True]:
+ for resize2 in [False, True]:
+ def dummyfn():
+ l1 = [42]
+ if resize1: l1.append(43)
+ l2 = list(l1)
+ if resize2: l2.append(44)
+ l2[0] = 0
+ return l1[0]
+ res = self.interpret(dummyfn, ())
+ assert res == 42
def test_is_true(self):
def is_true(lst):
Modified: pypy/branch/stringbuilder2/pypy/rpython/test/test_rptr.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/rpython/test/test_rptr.py (original)
+++ pypy/branch/stringbuilder2/pypy/rpython/test/test_rptr.py Mon Jan 25 15:25:48 2010
@@ -337,3 +337,13 @@
return f([1])
s, t = ll_rtype(lltest, [])
assert s.is_constant() == False
+
+def test_staticadtmeths():
+ ll_func = staticAdtMethod(lambda x: x + 42)
+ S = GcStruct('S', adtmeths={'ll_func': ll_func})
+ def f():
+ return malloc(S).ll_func(5)
+ s, t = ll_rtype(f, [])
+ graphf = t.graphs[0]
+ for op in graphf.startblock.operations:
+ assert op.opname != 'getfield'
Modified: pypy/branch/stringbuilder2/pypy/rpython/test/test_rvirtualizable2.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/rpython/test/test_rvirtualizable2.py (original)
+++ pypy/branch/stringbuilder2/pypy/rpython/test/test_rvirtualizable2.py Mon Jan 25 15:25:48 2010
@@ -1,7 +1,7 @@
import py
from pypy.rpython.lltypesystem import lltype
from pypy.rpython.test.tool import BaseRtypingTest, LLRtypeMixin, OORtypeMixin
-from pypy.rpython.rvirtualizable2 import replace_promote_virtualizable_with_call
+from pypy.rpython.rvirtualizable2 import replace_force_virtualizable_with_call
from pypy.rlib.jit import hint
from pypy.objspace.flow.model import summary
from pypy.rpython.llinterp import LLInterpreter
@@ -33,15 +33,15 @@
def __init__(self, v0):
self.v0 = v0
-def get_promote_virtualizable_flags(graph):
+def get_force_virtualizable_flags(graph):
res = []
for block, op in graph.iterblockops():
- if op.opname == 'promote_virtualizable':
+ if op.opname == 'jit_force_virtualizable':
res.append(op.args[-1].value)
return res
class BaseTest(BaseRtypingTest):
- def test_generate_promote_virtualizable(self):
+ def test_generate_force_virtualizable(self):
def fn(n):
vinst = V(n)
return vinst.v
@@ -51,11 +51,11 @@
op_getfield = block.operations[-1]
assert op_getfield.opname in ('getfield', 'oogetfield')
v_inst = op_getfield.args[0]
- assert op_promote.opname == 'promote_virtualizable'
+ assert op_promote.opname == 'jit_force_virtualizable'
assert op_promote.args[0] is v_inst
assert op_promote.args[-1].value == {}
- def test_generate_promote_virtualizable_subclass(self):
+ def test_generate_force_virtualizable_subclass(self):
def fn(n):
V(n) # to attach v to V
vinst = SubclassV(n)
@@ -66,11 +66,11 @@
op_getfield = block.operations[-1]
assert op_getfield.opname in ('getfield', 'oogetfield')
v_inst = op_getfield.args[0]
- assert op_promote.opname == 'promote_virtualizable'
+ assert op_promote.opname == 'jit_force_virtualizable'
assert op_promote.args[0] is v_inst
assert op_promote.args[-1].value == {}
- def test_no_promote_virtualizable_for_other_fields(self):
+ def test_no_force_virtualizable_for_other_fields(self):
def fn(n):
vinst = V(n)
return vinst.w
@@ -81,7 +81,7 @@
assert op_getfield.opname in ('getfield', 'oogetfield')
assert op_call.opname == 'direct_call' # to V.__init__
- def test_generate_promote_virtualizable_array(self):
+ def test_generate_force_virtualizable_array(self):
def fn(n):
vinst = VArray([n, n+1])
return vinst.lst[1]
@@ -93,7 +93,7 @@
assert op_getarrayitem.opname == 'direct_call' # to ll_getitem_xxx
assert op_getfield.opname in ('getfield', 'oogetfield')
v_inst = op_getfield.args[0]
- assert op_promote.opname == 'promote_virtualizable'
+ assert op_promote.opname == 'jit_force_virtualizable'
assert op_promote.args[0] is v_inst
assert op_promote.args[-1].value == {}
@@ -130,13 +130,13 @@
TYPE = self.gettype(w_inst)
assert 'virtualizable2_accessor' not in TYPE._hints
- def replace_promote_virtualizable(self, rtyper, graphs):
+ def replace_force_virtualizable(self, rtyper, graphs):
from pypy.annotation import model as annmodel
from pypy.rpython.annlowlevel import MixLevelHelperAnnotator
graph = graphs[0]
for block, op in graph.iterblockops():
- if op.opname == 'promote_virtualizable':
+ if op.opname == 'jit_force_virtualizable':
v_inst_ll_type = op.args[0].concretetype
break
@@ -150,11 +150,10 @@
s_vinst = annmodel.SomeOOInstance(v_inst_ll_type)
funcptr = annhelper.delayedfunction(mycall, [s_vinst], annmodel.s_None)
annhelper.finish()
- replace_promote_virtualizable_with_call(graphs, v_inst_ll_type,
- funcptr)
+ replace_force_virtualizable_with_call(graphs, v_inst_ll_type, funcptr)
return funcptr
- def test_replace_promote_virtualizable_with_call(self):
+ def test_replace_force_virtualizable_with_call(self):
def fn(n):
vinst = V(n)
return vinst.v
@@ -162,7 +161,7 @@
block = graph.startblock
op_getfield = block.operations[-1]
assert op_getfield.opname in ('getfield', 'oogetfield')
- funcptr = self.replace_promote_virtualizable(rtyper, [graph])
+ funcptr = self.replace_force_virtualizable(rtyper, [graph])
if getattr(conftest.option, 'view', False):
graph.show()
op_promote = block.operations[-2]
@@ -190,9 +189,9 @@
g_graph = t._graphof(g)
expected = [{'access_directly': True}] * 3
- assert get_promote_virtualizable_flags(g_graph) == expected
+ assert get_force_virtualizable_flags(g_graph) == expected
- self.replace_promote_virtualizable(typer, [g_graph])
+ self.replace_force_virtualizable(typer, [g_graph])
assert summary(g_graph) == {self.GETFIELD: 2, self.SETFIELD: 1, 'int_add': 1}
res = self.interpret(f, [23])
@@ -213,7 +212,7 @@
f_graph = t._graphof(f)
g_graph = t._graphof(g)
- self.replace_promote_virtualizable(typer, [f_graph, g_graph])
+ self.replace_force_virtualizable(typer, [f_graph, g_graph])
t.checkgraphs()
res = self.interpret(f, [23])
@@ -236,12 +235,12 @@
g_graphs.sort()
assert g_graphs[0][0] is None
- assert get_promote_virtualizable_flags(g_graphs[0][1]) == [{}]
+ assert get_force_virtualizable_flags(g_graphs[0][1]) == [{}]
expected = [{'access_directly': True}]
- assert get_promote_virtualizable_flags(g_graphs[1][1]) == expected
+ assert get_force_virtualizable_flags(g_graphs[1][1]) == expected
- self.replace_promote_virtualizable(typer, [g_graphs[0][1],
- g_graphs[1][1]])
+ self.replace_force_virtualizable(typer, [g_graphs[0][1],
+ g_graphs[1][1]])
assert summary(g_graphs[0][1]) == {'direct_call': 1, self.GETFIELD: 1}
assert summary(g_graphs[1][1]) == {self.GETFIELD: 1}
@@ -276,8 +275,9 @@
assert summary(g_graphs[1][1]) == {self.SETFIELD: 1}
h_graph = t._graphof(h)
- assert summary(h_graph) == {'promote_virtualizable': 1, self.GETFIELD: 1}
- assert get_promote_virtualizable_flags(h_graph) == [{}]
+ assert summary(h_graph) == {'jit_force_virtualizable': 1,
+ self.GETFIELD: 1}
+ assert get_force_virtualizable_flags(h_graph) == [{}]
res = self.interpret(f, [23])
assert res == 23
@@ -303,7 +303,7 @@
t, typer, graph = self.gengraph(f, [int])
g_graph = t._graphof(A.g.im_func)
- self.replace_promote_virtualizable(typer, [g_graph])
+ self.replace_force_virtualizable(typer, [g_graph])
assert summary(g_graph) == {self.GETFIELD: 1, 'int_mul': 1}
Modified: pypy/branch/stringbuilder2/pypy/rpython/tool/rffi_platform.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/rpython/tool/rffi_platform.py (original)
+++ pypy/branch/stringbuilder2/pypy/rpython/tool/rffi_platform.py Mon Jan 25 15:25:48 2010
@@ -644,7 +644,7 @@
else:
raise CompilationError("Library %s is not installed" % (name,))
-def check_boehm(platform=None):
+def configure_boehm(platform=None):
if platform is None:
from pypy.translator.platform import platform
if sys.platform == 'win32':
@@ -658,13 +658,10 @@
includes=includes,
libraries=['gc'],
)
- try:
- return configure_external_library(
- 'gc', eci,
- [dict(prefix='gc-', include_dir='include', library_dir=library_dir)],
- symbol='GC_init')
- except CompilationError:
- return None
+ return configure_external_library(
+ 'gc', eci,
+ [dict(prefix='gc-', include_dir='include', library_dir=library_dir)],
+ symbol='GC_init')
if __name__ == '__main__':
doc = """Example:
Modified: pypy/branch/stringbuilder2/pypy/tool/gcc_cache.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/tool/gcc_cache.py (original)
+++ pypy/branch/stringbuilder2/pypy/tool/gcc_cache.py Mon Jan 25 15:25:48 2010
@@ -10,7 +10,7 @@
def cache_file_path(c_files, eci, cachename):
cache_dir = cache_dir_root.join(cachename).ensure(dir=1)
filecontents = [c_file.read() for c_file in c_files]
- key = repr((filecontents, eci))
+ key = repr((filecontents, eci, platform.key()))
hash = md5(key).hexdigest()
return cache_dir.join(hash)
Modified: pypy/branch/stringbuilder2/pypy/tool/udir.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/tool/udir.py (original)
+++ pypy/branch/stringbuilder2/pypy/tool/udir.py Mon Jan 25 15:25:48 2010
@@ -18,7 +18,7 @@
#
import autopath
-import os
+import os, sys
import py
from py.path import local
@@ -30,6 +30,8 @@
else:
return basename.split('/')[-2]
+PYPY_KEEP = int(os.environ.get('PYPY_USESSION_KEEP', '3'))
+
def make_udir(dir=None, basename=None):
if dir is not None:
dir = local(dir)
@@ -37,6 +39,8 @@
try:
p = py.path.local(__file__).dirpath()
basename = svn_info(py.path.svnwc(p).info().url)
+ if isinstance(basename, unicode):
+ basename = basename.encode(sys.getdefaultencoding())
except:
basename = ''
if not basename.startswith('-'):
@@ -45,7 +49,7 @@
basename = basename + '-'
return local.make_numbered_dir(rootdir = dir,
prefix = 'usession' + basename,
- keep = 3)
+ keep = PYPY_KEEP)
udir = make_udir(dir = os.environ.get('PYPY_USESSION_DIR'),
basename = os.environ.get('PYPY_USESSION_BASENAME'))
Modified: pypy/branch/stringbuilder2/pypy/translator/backendopt/test/test_writeanalyze.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/translator/backendopt/test/test_writeanalyze.py (original)
+++ pypy/branch/stringbuilder2/pypy/translator/backendopt/test/test_writeanalyze.py Mon Jan 25 15:25:48 2010
@@ -4,14 +4,15 @@
from pypy.translator.translator import TranslationContext, graphof
from pypy.translator.simplify import get_funcobj
from pypy.translator.backendopt.writeanalyze import WriteAnalyzer, top_set
+from pypy.translator.backendopt.writeanalyze import ReadWriteAnalyzer
from pypy.translator.backendopt.all import backend_optimizations
from pypy.conftest import option
-class BaseTestCanRaise(object):
+class BaseTest(object):
type_system = None
-
+ Analyzer = WriteAnalyzer
def translate(self, func, sig):
t = TranslationContext()
@@ -19,7 +20,10 @@
t.buildrtyper(type_system=self.type_system).specialize()
if option.view:
t.view()
- return t, WriteAnalyzer(t)
+ return t, self.Analyzer(t)
+
+
+class BaseTestWriteAnalyze(BaseTest):
def test_writes_simple(self):
def g(x):
@@ -146,7 +150,7 @@
assert not result
-class TestLLtype(BaseTestCanRaise):
+class TestLLtype(BaseTestWriteAnalyze):
type_system = 'lltype'
def test_list(self):
@@ -205,7 +209,7 @@
assert name.endswith("foobar")
-class TestOOtype(BaseTestCanRaise):
+class TestOOtype(BaseTestWriteAnalyze):
type_system = 'ootype'
def test_array(self):
@@ -240,3 +244,88 @@
result = wa.analyze(ggraph.startblock.operations[0])
assert result is top_set
+
+
+class TestLLtypeReadWriteAnalyze(BaseTest):
+ Analyzer = ReadWriteAnalyzer
+ type_system = 'lltype'
+
+ def test_read_simple(self):
+ def g(x):
+ return True
+
+ def f(x):
+ return g(x - 1)
+ t, wa = self.translate(f, [int])
+ fgraph = graphof(t, f)
+ result = wa.analyze(fgraph.startblock.operations[0])
+ assert not result
+
+ def test_read_really(self):
+ class A(object):
+ def __init__(self, y):
+ self.y = y
+ def f(self):
+ self.x = 1
+ return self.y
+ def h(flag):
+ obj = A(flag)
+ return obj.f()
+
+ t, wa = self.translate(h, [int])
+ hgraph = graphof(t, h)
+ op_call_f = hgraph.startblock.operations[-1]
+
+ # check that we fished the expected ops
+ assert op_call_f.opname == "direct_call"
+ assert get_funcobj(op_call_f.args[0].value)._name == 'A.f'
+
+ result = wa.analyze(op_call_f)
+ assert len(result) == 2
+ result = list(result)
+ result.sort()
+ [(struct1, T1, name1), (struct2, T2, name2)] = result
+ assert struct1 == "readstruct"
+ assert name1.endswith("y")
+ assert struct2 == "struct"
+ assert name2.endswith("x")
+ assert T1 == T2
+
+ def test_contains(self):
+ def g(x, y, z):
+ l = [x]
+ return f(l, y, z)
+ def f(x, y, z):
+ return y in x
+
+ t, wa = self.translate(g, [int, int, int])
+ ggraph = graphof(t, g)
+ assert ggraph.startblock.operations[-1].opname == 'direct_call'
+
+ result = wa.analyze(ggraph.startblock.operations[-1])
+ ARRAYPTR = list(result)[0][1]
+ assert list(result) == [("readarray", ARRAYPTR)]
+ assert isinstance(ARRAYPTR.TO, lltype.GcArray)
+
+ def test_adt_method(self):
+ def ll_callme(n):
+ return n
+ ll_callme = lltype.staticAdtMethod(ll_callme)
+ S = lltype.GcStruct('S', ('x', lltype.Signed),
+ adtmeths = {'yep': True,
+ 'callme': ll_callme})
+ def g(x, y, z):
+ p = lltype.malloc(S)
+ p.x = x
+ if p.yep:
+ z *= p.callme(y)
+ return z
+ def f(x, y, z):
+ return g(x, y, z)
+
+ t, wa = self.translate(f, [int, int, int])
+ fgraph = graphof(t, f)
+ assert fgraph.startblock.operations[-1].opname == 'direct_call'
+
+ result = wa.analyze(fgraph.startblock.operations[-1])
+ assert list(result) == [("struct", lltype.Ptr(S), "x")]
Modified: pypy/branch/stringbuilder2/pypy/translator/backendopt/writeanalyze.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/translator/backendopt/writeanalyze.py (original)
+++ pypy/branch/stringbuilder2/pypy/translator/backendopt/writeanalyze.py Mon Jan 25 15:25:48 2010
@@ -45,3 +45,15 @@
elif methname in ('ll_getitem_fast', 'll_length'):
return self.bottom_result()
return graphanalyze.GraphAnalyzer.analyze_external_method(self, op, TYPE, meth)
+
+
+class ReadWriteAnalyzer(WriteAnalyzer):
+
+ def analyze_simple_operation(self, op):
+ if op.opname == "getfield":
+ return frozenset([
+ ("readstruct", op.args[0].concretetype, op.args[1].value)])
+ elif op.opname == "getarrayitem":
+ return frozenset([
+ ("readarray", op.args[0].concretetype)])
+ return WriteAnalyzer.analyze_simple_operation(self, op)
Modified: pypy/branch/stringbuilder2/pypy/translator/benchmark/bench-custom.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/translator/benchmark/bench-custom.py (original)
+++ pypy/branch/stringbuilder2/pypy/translator/benchmark/bench-custom.py Mon Jan 25 15:25:48 2010
@@ -34,7 +34,7 @@
benchmarks.append(b)
exes = get_executables(args)
- pythons = 'python2.5 python2.4 python2.3'.split()
+ pythons = 'python2.6 python2.5 python2.4'.split()
full_pythons = []
for python in pythons:
full_python = py.path.local.sysfind(python)
@@ -44,6 +44,7 @@
sys.stdout.flush()
refs = {}
+ final_error_count = 0
if not options.nocpython:
exes = full_pythons + exes
@@ -52,7 +53,10 @@
if i is not None:
for exe in exes:
for b in benchmarks:
- benchmark_result.result(exe, allowcreate=True).run_benchmark(b, verbose=options.verbose)
+ br = benchmark_result.result(exe, allowcreate=True)
+ result = br.run_benchmark(b, verbose=options.verbose)
+ if not result:
+ final_error_count += 1
if options.relto:
relto = options.relto
@@ -83,6 +87,10 @@
print row
print
+ if final_error_count:
+ raise SystemExit("%d benchmark run(s) failed (see -FAILED- above)"
+ % final_error_count)
+
if __name__ == '__main__':
from optparse import OptionParser
parser = OptionParser()
Modified: pypy/branch/stringbuilder2/pypy/translator/benchmark/benchmarks.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/translator/benchmark/benchmarks.py (original)
+++ pypy/branch/stringbuilder2/pypy/translator/benchmark/benchmarks.py Mon Jan 25 15:25:48 2010
@@ -1,15 +1,16 @@
import os, sys, time, pickle, re, py
+import yaml
class BenchmarkFailed(Exception):
pass
PYSTONE_CMD = 'from test import pystone;pystone.main(%s)'
PYSTONE_PATTERN = 'This machine benchmarks at'
-PYSTONE_ASCENDING_GOOD = True
RICHARDS_CMD = 'from richards import *;main(iterations=%d)'
RICHARDS_PATTERN = 'Average time per iteration:'
-RICHARDS_ASCENDING_GOOD = False
+
+TIME_FMT = 'max mem used: %Mk\nelapsed time: %e\nsystem time: %S\nuser time: %U\nCPU use: %P'
def get_result(txt, pattern):
for line in txt.split('\n'):
@@ -36,60 +37,40 @@
return Benchmark(self._basename, self._run, self.asc_good, self.units,
self.check, self.sizefactor * n)
def run(self, exe):
- global latest_output
- latest_output = ''
try:
- result = self._run(exe, self.sizefactor)
+ result, latest_output = self._run(exe, self.sizefactor)
+ self.latest_output = latest_output
except BenchmarkFailed, e:
result = '-FAILED-'
- self.latest_output = latest_output
return result
-def external_dependency(dirname, svnurl, revision):
- """Check out (if necessary) a given fixed revision of a svn url."""
- dirpath = py.path.local(__file__).dirpath().join(dirname)
- revtag = dirpath.join('-svn-rev-')
- if dirpath.check():
- if not revtag.check() or int(revtag.read()) != revision:
- print >> sys.stderr, ("Out-of-date benchmark checkout!"
- " I won't update it automatically.")
- print >> sys.stderr, ("To continue, move away or remove the "
- "%r directory." % (dirname,))
- sys.exit(1)
- return True
- CMD = "svn co -r%d %s@%d %s" % (revision, svnurl, revision, dirpath)
- print >> sys.stderr, CMD
- err = os.system(CMD)
- if err != 0:
- print >> sys.stderr, "* checkout failed, skipping this benchmark"
- return False
- revtag.write(str(revision))
+def external_dependency(dirname, svnurl, revision=None):
+ directory = py.path.local(__file__).dirpath().join(dirname)
+ wc = py.path.svnwc(directory)
+ wc.checkout(svnurl, rev=revision)
return True
def run_cmd(cmd):
- global latest_output
- #print "running", cmd
pipe = os.popen(cmd + ' 2>&1')
r = pipe.read()
status = pipe.close()
- latest_output = r
if status:
raise BenchmarkFailed(status)
return r
-def run_pystone(executable='/usr/local/bin/python', sizefactor=1):
+def run_pystone(executable, sizefactor=1):
from pypy.tool import autopath
distdir = py.path.local(autopath.pypydir).dirpath()
pystone = py.path.local(autopath.libpythondir).join('test', 'pystone.py')
txt = run_cmd('"%s" "%s" %d' % (executable, pystone, 50000 * sizefactor))
- return get_result(txt, PYSTONE_PATTERN)
+ return get_result(txt, PYSTONE_PATTERN), txt
-def run_richards(executable='/usr/local/bin/python', sizefactor=1):
+def run_richards(executable, sizefactor=1):
richards = py.path.local(__file__).dirpath().dirpath().join('goal').join('richards.py')
txt = run_cmd('"%s" %s %d' % (executable, richards, 5 * sizefactor))
- return get_result(txt, RICHARDS_PATTERN)
+ return get_result(txt, RICHARDS_PATTERN), txt
-def run_translate(executable='/usr/local/bin/python'):
+def run_translate(executable):
translate = py.path.local(__file__).dirpath().dirpath().join('goal').join('translate.py')
target = py.path.local(__file__).dirpath().dirpath().join('goal').join('targetrpystonedalone.py')
argstr = '%s %s --batch --backendopt --no-compile %s > /dev/null 2> /dev/null'
@@ -100,39 +81,7 @@
raise BenchmarkFailed(status)
return r
-def run_docutils(executable='/usr/local/bin/python'):
- docutilssvnpath = 'docutils' # subdir of the local dir
- translatetxt = py.path.local(__file__).dirpath().dirpath().dirpath().join('doc').join('translation.txt')
- command = """import sys
-sys.modules['unicodedata'] = sys # docutils need 'import unicodedata' to work, but no more...
-sys.path[0:0] = ['%s', '%s/extras']
-from docutils.core import publish_cmdline
-publish_cmdline(writer_name='html')
-"""%(docutilssvnpath, docutilssvnpath)
- T = time.time()
- pid = os.fork()
- if not pid:
- davenull = os.open('/dev/null', os.O_RDWR)
- os.dup2(davenull, 0)
- os.dup2(davenull, 1)
- os.dup2(davenull, 2)
- status = os.spawnv(os.P_WAIT, executable, [executable, '-c', command, str(translatetxt)])
- os._exit(status)
- else:
- status = os.waitpid(pid, 0)[1]
- r = time.time() - T
- if status:
- raise BenchmarkFailed(status)
- return r
-
-def check_docutils():
- return False # useless benchmark - I've seen 15% of difference
- # between two successive runs on the same machine!
- #return external_dependency('docutils',
- # 'svn://svn.berlios.de/docutils/trunk/docutils',
- # 4821)
-
-def run_templess(executable='/usr/local/bin/python', sizefactor=1):
+def run_templess(executable, sizefactor=1):
""" run some script in the templess package
templess is some simple templating language, to check out use
@@ -149,7 +98,7 @@
for line in txt.split('\n'):
if '.' in line:
try:
- return float(line) / sizefactor
+ return float(line) / sizefactor, txt
except ValueError:
pass
else:
@@ -160,7 +109,7 @@
'http://johnnydebris.net/templess/trunk',
100)
-def run_gadfly(executable='/usr/local/bin/python', sizefactor=1):
+def run_gadfly(executable, sizefactor=1):
""" run some tests in the gadfly pure Python database """
here = py.path.local(__file__).dirpath()
gadfly = here.join('gadfly')
@@ -168,14 +117,14 @@
command = 'PYTHONPATH="%s" "%s" "%s" %d' % (gadfly, executable, testscript,
sizefactor)
txt = run_cmd(command)
- return get_result(txt, 'Total running time:') / sizefactor
+ return get_result(txt, 'Total running time:') / sizefactor, txt
def check_gadfly():
return external_dependency('gadfly',
'http://codespeak.net/svn/user/arigo/hack/pypy-hack/gadflyZip',
70117)
-def run_mako(executable='/usr/local/bin/python', sizefactor=1):
+def run_mako(executable, sizefactor=1):
""" run some tests in the mako templating system """
here = py.path.local(__file__).dirpath()
mako = here.join('mako')
@@ -184,29 +133,64 @@
executable, testscript,
2000 * sizefactor)
txt = run_cmd(command)
- return get_result(txt, 'Mako:')
+ return get_result(txt, 'Mako:'), txt
def check_mako():
return external_dependency('mako',
'http://codespeak.net/svn/user/arigo/hack/pypy-hack/mako',
- 70118)
+ 70118)
def check_translate():
return False # XXX what should we do about the dependency on ctypes?
-BENCHMARKS = [Benchmark('richards', run_richards, RICHARDS_ASCENDING_GOOD, 'ms'),
- Benchmark('pystone', run_pystone, PYSTONE_ASCENDING_GOOD, ''),
- Benchmark('translate', run_translate, RICHARDS_ASCENDING_GOOD, 'ms', check_translate),
- Benchmark('docutils', run_docutils, RICHARDS_ASCENDING_GOOD,
- 's', check_docutils),
- Benchmark('templess', run_templess, RICHARDS_ASCENDING_GOOD,
+class LanguageShootoutBenchmark(Benchmark):
+ def __init__(self, name, sizefactor=1, test=False):
+ self.test = test
+ self.basename = name
+ Benchmark.__init__(self, name, self.runner, False, 'ms',
+ self.check, sizefactor)
+
+ def __mul__(self, i):
+ return LanguageShootoutBenchmark(self.name, self.sizefactor * i,
+ self.test)
+
+ def runner(self, executable, sizefactor=1):
+ shootout = py.path.local(__file__).dirpath().join(
+ 'shootout_benchmarks')
+ argsfile = shootout.join('tests.yml')
+ if self.test:
+ kind = 'test'
+ else:
+ kind = 'run'
+ args = yaml.load(argsfile.read())[self.basename][kind]['args']
+ progname = str(shootout.join(self.basename)) + '.py'
+ cmd = 'time -f "%s" %s %s %s %d' % (TIME_FMT, executable, progname,
+ " ".join(args), sizefactor)
+ txt = run_cmd(cmd)
+ return get_result(txt, 'elapsed time:'), txt
+
+ def check(self):
+ return external_dependency('shootout_benchmarks',
+ 'http://codespeak.net/svn/pypy/benchmarks/shootout')
+
+BENCHMARKS = [Benchmark('richards', run_richards, False, 'ms'),
+ Benchmark('pystone', run_pystone, True, ''),
+ Benchmark('translate', run_translate, False, 'ms',
+ check_translate),
+ Benchmark('templess', run_templess, False,
's', check_templess),
- Benchmark('gadfly2', run_gadfly, RICHARDS_ASCENDING_GOOD,
+ Benchmark('gadfly2', run_gadfly, False,
's', check_gadfly),
- Benchmark('mako', run_mako, RICHARDS_ASCENDING_GOOD,
+ Benchmark('mako', run_mako, False,
's', check_mako),
]
+SHOOTOUT_NAMES = ['binary-trees', 'fannkuch', 'fasta', 'float',
+ 'meteor-contest', 'nbody', 'spectral-norm']
+
+#for name in SHOOTOUT_NAMES:
+# BENCHMARKS.append(LanguageShootoutBenchmark(name))
+
BENCHMARKS_BY_NAME = {}
for _b in BENCHMARKS:
BENCHMARKS_BY_NAME[_b.name] = _b
Modified: pypy/branch/stringbuilder2/pypy/translator/benchmark/jitbench.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/translator/benchmark/jitbench.py (original)
+++ pypy/branch/stringbuilder2/pypy/translator/benchmark/jitbench.py Mon Jan 25 15:25:48 2010
@@ -4,7 +4,7 @@
parser = OptionParser()
parser.add_option(
'--size-factor-list', dest='sizefactorlist',
- default='1,2,5,1,2,5,1,2,5',
+ default='1,2,5,20,1,2,5,20,1,2,5,20',
)
options, args = parser.parse_args(sys.argv[1:])
args = args or [sys.executable]
@@ -13,9 +13,18 @@
os.chdir(os.path.dirname(sys.argv[0]) or '.')
+errors = []
+
for sizefactor in sizefactors:
for executable in executables:
sys.argv[1:] = [executable, '--pickle=jitbench.benchmark_result',
'-v', '--no-cpython',
'--size-factor=%d' % sizefactor]
- execfile('bench-custom.py')
+ try:
+ execfile('bench-custom.py')
+ except SystemExit, e:
+ errors.append('%s:*%s: %s' % (executable, sizefactor, e))
+
+if errors:
+ print '\n'.join(errors)
+ sys.exit(1)
Modified: pypy/branch/stringbuilder2/pypy/translator/benchmark/result.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/translator/benchmark/result.py (original)
+++ pypy/branch/stringbuilder2/pypy/translator/benchmark/result.py Mon Jan 25 15:25:48 2010
@@ -88,7 +88,7 @@
def run_benchmark(self, benchmark, verbose=False):
self.asc_goods[benchmark.name] = benchmark.asc_good
if self.run_counts.get(benchmark.name, 0) > self.max_results:
- return
+ return -1
print 'running', benchmark.name, 'for', self.exe_name,
if verbose and self.pypy_rev > 0:
print '[rev %d]' % self.pypy_rev,
@@ -97,12 +97,15 @@
print new_result
if verbose:
print '{'
- for line in benchmark.latest_output.splitlines(False):
+ lines = benchmark.latest_output.splitlines(False)
+ for line in lines[:80]:
print '\t' + line
+ if len(lines) > 80:
+ print '\t....'
print '}'
self.run_counts[benchmark.name] = self.run_counts.get(benchmark.name, 0) + 1
if new_result == '-FAILED-':
- return
+ return 0
self.benchmarks.setdefault(benchmark.name, []).append(new_result)
if benchmark.name in self.best_benchmarks:
old_result = self.best_benchmarks[benchmark.name]
@@ -111,6 +114,7 @@
else:
new_result = min(new_result, old_result)
self.best_benchmarks[benchmark.name] = new_result
+ return 1
def getstat(self, *args):
# oh for supplied-p!
Modified: pypy/branch/stringbuilder2/pypy/translator/c/funcgen.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/translator/c/funcgen.py (original)
+++ pypy/branch/stringbuilder2/pypy/translator/c/funcgen.py Mon Jan 25 15:25:48 2010
@@ -793,8 +793,12 @@
def OP_JIT_MARKER(self, op):
return '/* JIT_MARKER %s */' % op
- def OP_PROMOTE_VIRTUALIZABLE(self, op):
- return '/* PROMOTE_VIRTUALIZABLE %s */' % op
+ def OP_JIT_FORCE_VIRTUALIZABLE(self, op):
+ return '/* JIT_FORCE_VIRTUALIZABLE %s */' % op
+
+ def OP_JIT_FORCE_VIRTUAL(self, op):
+ return '%s = %s; /* JIT_FORCE_VIRTUAL */' % (self.expr(op.result),
+ self.expr(op.args[0]))
def OP_GET_GROUP_MEMBER(self, op):
typename = self.db.gettype(op.result.concretetype)
@@ -813,5 +817,26 @@
self.expr(op.args[1]),
self.expr(op.args[2]))
+ def getdebugfunctionname(self):
+ name = self.functionname
+ if not name:
+ return "?"
+ if name.startswith('pypy_g_'):
+ name = name[7:]
+ return name
+
+ def OP_DEBUG_RECORD_TRACEBACK(self, op):
+ #if self.functionname is None, we print "?" as the argument */
+ return 'PYPY_DEBUG_RECORD_TRACEBACK("%s");' % (
+ self.getdebugfunctionname(),)
+
+ def OP_DEBUG_CATCH_EXCEPTION(self, op):
+ gottype = self.expr(op.args[0])
+ exprs = []
+ for c_limited_type in op.args[1:]:
+ exprs.append('%s == %s' % (gottype, self.expr(c_limited_type)))
+ return 'PYPY_DEBUG_CATCH_EXCEPTION("%s", %s, %s);' % (
+ self.getdebugfunctionname(), gottype, ' || '.join(exprs))
+
assert not USESLOTS or '__dict__' not in dir(FunctionCodeGenerator)
Modified: pypy/branch/stringbuilder2/pypy/translator/c/gc.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/translator/c/gc.py (original)
+++ pypy/branch/stringbuilder2/pypy/translator/c/gc.py Mon Jan 25 15:25:48 2010
@@ -215,8 +215,8 @@
def compilation_info(self):
eci = BasicGcPolicy.compilation_info(self)
- from pypy.rpython.tool.rffi_platform import check_boehm
- eci = eci.merge(check_boehm())
+ from pypy.rpython.tool.rffi_platform import configure_boehm
+ eci = eci.merge(configure_boehm())
pre_include_bits = []
if sys.platform == "linux2":
@@ -253,6 +253,9 @@
nbytes = funcgen.expr(op.args[0])
return 'GC_set_max_heap_size(%s);' % (nbytes,)
+ def GC_KEEPALIVE(self, funcgen, v):
+ return 'pypy_asm_keepalive(%s);' % funcgen.expr(v)
+
class BoehmGcRuntimeTypeInfo_OpaqueNode(ContainerNode):
nodekind = 'boehm rtti'
globalcontainer = True
Modified: pypy/branch/stringbuilder2/pypy/translator/c/genc.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/translator/c/genc.py (original)
+++ pypy/branch/stringbuilder2/pypy/translator/c/genc.py Mon Jan 25 15:25:48 2010
@@ -430,12 +430,16 @@
bk = self.translator.annotator.bookkeeper
return getfunctionptr(bk.getdesc(self.entrypoint).getuniquegraph())
- def cmdexec(self, args='', env=None, err=False):
+ def cmdexec(self, args='', env=None, err=False, expect_crash=False):
assert self._compiled
res = self.translator.platform.execute(self.executable_name, args,
env=env)
if res.returncode != 0:
+ if expect_crash:
+ return res.out, res.err
raise Exception("Returned %d" % (res.returncode,))
+ if expect_crash:
+ raise Exception("Program did not crash!")
if err:
return res.out, res.err
return res.out
@@ -711,6 +715,7 @@
print >> fc, '/*** Implementations ***/'
print >> fc
print >> fc, '#define PYPY_NOT_MAIN_FILE'
+ print >> fc, '#define PYPY_FILE_NAME "%s"' % name
print >> fc, '#include "common_header.h"'
print >> fc, '#include "structdef.h"'
print >> fc, '#include "forwarddecl.h"'
@@ -783,6 +788,7 @@
print >> f, '/***********************************************************/'
print >> f, '/*** Implementations ***/'
print >> f
+ print >> f, '#define PYPY_FILE_NAME "%s"' % os.path.basename(f.name)
for line in preimplementationlines:
print >> f, line
print >> f, '#include "src/g_include.h"'
Modified: pypy/branch/stringbuilder2/pypy/translator/c/src/g_include.h
==============================================================================
--- pypy/branch/stringbuilder2/pypy/translator/c/src/g_include.h (original)
+++ pypy/branch/stringbuilder2/pypy/translator/c/src/g_include.h Mon Jan 25 15:25:48 2010
@@ -17,11 +17,7 @@
#include "src/mem.h"
#include "src/exception.h"
#include "src/support.h"
-#ifndef AVR
-#include "src/trace.h"
-#else
- #define PY_LONG_LONG long long
-#endif
+#define PY_LONG_LONG long long
#ifndef PYPY_STANDALONE
# include "src/pyobj.h"
@@ -51,7 +47,8 @@
/*** modules ***/
#ifdef HAVE_RTYPER /* only if we have an RTyper */
# include "src/rtyper.h"
-# include "src/debug.h"
+# include "src/debug_print.h"
+# include "src/debug_traceback.h"
#ifndef AVR
# include "src/ll_os.h"
# include "src/ll_strtod.h"
Modified: pypy/branch/stringbuilder2/pypy/translator/c/src/main.h
==============================================================================
--- pypy/branch/stringbuilder2/pypy/translator/c/src/main.h (original)
+++ pypy/branch/stringbuilder2/pypy/translator/c/src/main.h Mon Jan 25 15:25:48 2010
@@ -36,12 +36,8 @@
exitcode = STANDALONE_ENTRY_POINT(list);
if (RPyExceptionOccurred()) {
- /* fish for the exception type, at least */
-#ifndef AVR
- fprintf(stderr, "Fatal RPython error: %s\n",
- RPyFetchExceptionType()->ov_name->items);
-#endif
- abort();
+ /* print the RPython traceback */
+ pypy_debug_catch_fatal_exception();
}
return exitcode;
Modified: pypy/branch/stringbuilder2/pypy/translator/c/test/test_boehm.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/translator/c/test/test_boehm.py (original)
+++ pypy/branch/stringbuilder2/pypy/translator/c/test/test_boehm.py Mon Jan 25 15:25:48 2010
@@ -3,12 +3,16 @@
from pypy.rpython.lltypesystem import lltype, llmemory
from pypy.rpython.lltypesystem.lloperation import llop
from pypy.rpython.memory.test import snippet
-from pypy.rpython.tool.rffi_platform import check_boehm
from pypy.translator.c.genc import CExtModuleBuilder
+from pypy.rlib.objectmodel import keepalive_until_here
from pypy import conftest
def setup_module(mod):
- if not check_boehm():
+ from pypy.rpython.tool.rffi_platform import configure_boehm
+ from pypy.translator.platform import CompilationError
+ try:
+ configure_boehm()
+ except CompilationError:
py.test.skip("Boehm GC not present")
class AbstractGCTestClass(object):
@@ -287,6 +291,7 @@
assert a.index == i & ~1
else:
count_free += 1
+ keepalive_until_here(keepalive)
return count_free
c_fn = self.getcompiled(fn, [int])
res = c_fn(7000)
Modified: pypy/branch/stringbuilder2/pypy/translator/c/test/test_genc.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/translator/c/test/test_genc.py (original)
+++ pypy/branch/stringbuilder2/pypy/translator/c/test/test_genc.py Mon Jan 25 15:25:48 2010
@@ -334,6 +334,7 @@
f = compile(prob_with_pyobj, [object])
from sys import getrefcount as g
obj = None
+ import gc; gc.collect()
before = g(obj)
f(obj)
after = g(obj)
Modified: pypy/branch/stringbuilder2/pypy/translator/c/test/test_stackless.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/translator/c/test/test_stackless.py (original)
+++ pypy/branch/stringbuilder2/pypy/translator/c/test/test_stackless.py Mon Jan 25 15:25:48 2010
@@ -20,8 +20,11 @@
import py
py.test.skip("stackless + refcounting doesn't work any more for now")
elif cls.gcpolicy == "boehm":
- from pypy.rpython.tool.rffi_platform import check_boehm
- if not check_boehm():
+ from pypy.rpython.tool.rffi_platform import configure_boehm
+ from pypy.translator.platform import CompilationError
+ try:
+ configure_boehm()
+ except CompilationError:
py.test.skip("Boehm GC not present")
def wrap_stackless_function(self, fn):
Modified: pypy/branch/stringbuilder2/pypy/translator/c/test/test_standalone.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/translator/c/test/test_standalone.py (original)
+++ pypy/branch/stringbuilder2/pypy/translator/c/test/test_standalone.py Mon Jan 25 15:25:48 2010
@@ -10,6 +10,7 @@
from pypy.annotation.listdef import s_list_of_strings
from pypy.tool.udir import udir
from pypy.tool.autopath import pypydir
+from pypy.conftest import option
class StandaloneTests(object):
@@ -21,8 +22,10 @@
t.buildrtyper().specialize()
cbuilder = CStandaloneBuilder(t, entry_point, t.config)
- cbuilder.generate_source()
+ cbuilder.generate_source(defines=cbuilder.DEBUG_DEFINES)
cbuilder.compile()
+ if option.view:
+ t.view()
return t, cbuilder
@@ -377,6 +380,186 @@
assert not err
assert path.check(file=0)
+ def test_fatal_error(self):
+ def g(x):
+ if x == 1:
+ raise ValueError
+ else:
+ raise KeyError
+ def entry_point(argv):
+ if len(argv) < 3:
+ g(len(argv))
+ return 0
+ t, cbuilder = self.compile(entry_point)
+ #
+ out, err = cbuilder.cmdexec("", expect_crash=True)
+ assert out.strip() == ''
+ lines = err.strip().splitlines()
+ assert lines[-1] == 'Fatal RPython error: ValueError'
+ assert len(lines) >= 4
+ l0, l1, l2 = lines[-4:-1]
+ assert l0 == 'RPython traceback:'
+ assert re.match(r' File "\w+.c", line \d+, in entry_point', l1)
+ assert re.match(r' File "\w+.c", line \d+, in g', l2)
+ #
+ out2, err2 = cbuilder.cmdexec("x", expect_crash=True)
+ assert out2.strip() == ''
+ lines2 = err2.strip().splitlines()
+ assert lines2[-1] == 'Fatal RPython error: KeyError'
+ l0, l1, l2 = lines2[-4:-1]
+ assert l0 == 'RPython traceback:'
+ assert re.match(r' File "\w+.c", line \d+, in entry_point', l1)
+ assert re.match(r' File "\w+.c", line \d+, in g', l2)
+ assert lines2[-2] != lines[-2] # different line number
+ assert lines2[-3] == lines[-3] # same line number
+
+ def test_fatal_error_finally_1(self):
+ # a simple case of try:finally:
+ def g(x):
+ if x == 1:
+ raise KeyError
+ def h(x):
+ try:
+ g(x)
+ finally:
+ os.write(1, 'done.\n')
+ def entry_point(argv):
+ if len(argv) < 3:
+ h(len(argv))
+ return 0
+ t, cbuilder = self.compile(entry_point)
+ #
+ out, err = cbuilder.cmdexec("", expect_crash=True)
+ assert out.strip() == 'done.'
+ lines = err.strip().splitlines()
+ assert lines[-1] == 'Fatal RPython error: KeyError'
+ assert len(lines) >= 5
+ l0, l1, l2, l3 = lines[-5:-1]
+ assert l0 == 'RPython traceback:'
+ assert re.match(r' File "\w+.c", line \d+, in entry_point', l1)
+ assert re.match(r' File "\w+.c", line \d+, in h', l2)
+ assert re.match(r' File "\w+.c", line \d+, in g', l3)
+
+ def test_fatal_error_finally_2(self):
+ # a try:finally: in which we raise and catch another exception
+ def raiseme(x):
+ if x == 1:
+ raise ValueError
+ def raise_and_catch(x):
+ try:
+ raiseme(x)
+ except ValueError:
+ pass
+ def g(x):
+ if x == 1:
+ raise KeyError
+ def h(x):
+ try:
+ g(x)
+ finally:
+ raise_and_catch(x)
+ os.write(1, 'done.\n')
+ def entry_point(argv):
+ if len(argv) < 3:
+ h(len(argv))
+ return 0
+ t, cbuilder = self.compile(entry_point)
+ #
+ out, err = cbuilder.cmdexec("", expect_crash=True)
+ assert out.strip() == 'done.'
+ lines = err.strip().splitlines()
+ assert lines[-1] == 'Fatal RPython error: KeyError'
+ assert len(lines) >= 5
+ l0, l1, l2, l3 = lines[-5:-1]
+ assert l0 == 'RPython traceback:'
+ assert re.match(r' File "\w+.c", line \d+, in entry_point', l1)
+ assert re.match(r' File "\w+.c", line \d+, in h', l2)
+ assert re.match(r' File "\w+.c", line \d+, in g', l3)
+
+ def test_fatal_error_finally_3(self):
+ py.test.skip("not implemented: "
+ "a try:finally: in which we raise the *same* exception")
+
+ def test_fatal_error_finally_4(self):
+ # a try:finally: in which we raise (and don't catch) an exception
+ def raiseme(x):
+ if x == 1:
+ raise ValueError
+ def g(x):
+ if x == 1:
+ raise KeyError
+ def h(x):
+ try:
+ g(x)
+ finally:
+ raiseme(x)
+ os.write(1, 'done.\n')
+ def entry_point(argv):
+ if len(argv) < 3:
+ h(len(argv))
+ return 0
+ t, cbuilder = self.compile(entry_point)
+ #
+ out, err = cbuilder.cmdexec("", expect_crash=True)
+ assert out.strip() == ''
+ lines = err.strip().splitlines()
+ assert lines[-1] == 'Fatal RPython error: ValueError'
+ assert len(lines) >= 5
+ l0, l1, l2, l3 = lines[-5:-1]
+ assert l0 == 'RPython traceback:'
+ assert re.match(r' File "\w+.c", line \d+, in entry_point', l1)
+ assert re.match(r' File "\w+.c", line \d+, in h', l2)
+ assert re.match(r' File "\w+.c", line \d+, in raiseme', l3)
+
+ def test_assertion_error(self):
+ def g(x):
+ assert x != 1
+ def f(argv):
+ try:
+ g(len(argv))
+ finally:
+ print 'done'
+ def entry_point(argv):
+ f(argv)
+ return 0
+ t, cbuilder = self.compile(entry_point)
+ out, err = cbuilder.cmdexec("", expect_crash=True)
+ assert out.strip() == ''
+ lines = err.strip().splitlines()
+ assert lines[-1] == 'Fatal RPython error: AssertionError'
+ assert len(lines) >= 4
+ l0, l1, l2 = lines[-4:-1]
+ assert l0 == 'RPython traceback:'
+ assert re.match(r' File "\w+.c", line \d+, in f', l1)
+ assert re.match(r' File "\w+.c", line \d+, in g', l2)
+ # The traceback stops at f() because it's the first function that
+ # captures the AssertionError, which makes the program abort.
+
+ def test_ll_assert_error(self):
+ py.test.skip("implement later, maybe: tracebacks even with ll_assert")
+ def g(x):
+ ll_assert(x != 1, "foobar")
+ def f(argv):
+ try:
+ g(len(argv))
+ finally:
+ print 'done'
+ def entry_point(argv):
+ f(argv)
+ return 0
+ t, cbuilder = self.compile(entry_point)
+ out, err = cbuilder.cmdexec("", expect_crash=True)
+ assert out.strip() == ''
+ lines = err.strip().splitlines()
+ assert lines[-1] == 'PyPy assertion failed: foobar'
+ assert len(lines) >= 4
+ l0, l1, l2 = lines[-4:-1]
+ assert l0 == 'RPython traceback:'
+ assert re.match(r' File "\w+.c", line \d+, in f', l1)
+ assert re.match(r' File "\w+.c", line \d+, in g', l2)
+ # The traceback stops at f() because it's the first function that
+ # captures the AssertionError, which makes the program abort.
+
class TestMaemo(TestStandalone):
def setup_class(cls):
@@ -407,7 +590,7 @@
t.buildrtyper().specialize()
#
cbuilder = CStandaloneBuilder(t, entry_point, t.config)
- cbuilder.generate_source()
+ cbuilder.generate_source(defines=cbuilder.DEBUG_DEFINES)
cbuilder.compile()
#
return t, cbuilder
Modified: pypy/branch/stringbuilder2/pypy/translator/cli/opcodes.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/translator/cli/opcodes.py (original)
+++ pypy/branch/stringbuilder2/pypy/translator/cli/opcodes.py Mon Jan 25 15:25:48 2010
@@ -77,6 +77,11 @@
'gc_set_max_heap_size': Ignore,
'resume_point': Ignore,
'debug_assert': Ignore,
+ 'debug_start_traceback': Ignore,
+ 'debug_record_traceback': Ignore,
+ 'debug_catch_exception': Ignore,
+ 'debug_reraise_traceback': Ignore,
+ 'debug_print_traceback': Ignore,
'debug_print': [DebugPrint],
'debug_start': [PushAllArgs, 'call void [pypylib]pypy.runtime.DebugPrint::DEBUG_START(string)'],
'debug_stop': [PushAllArgs, 'call void [pypylib]pypy.runtime.DebugPrint::DEBUG_STOP(string)'],
@@ -84,7 +89,8 @@
'debug_fatalerror': [PushAllArgs, 'call void [pypylib]pypy.runtime.Debug::DEBUG_FATALERROR(string)'],
'keepalive': Ignore,
'jit_marker': Ignore,
- 'promote_virtualizable': Ignore,
+ 'jit_force_virtualizable': Ignore,
+ 'jit_force_virtual': DoNothing,
}
# __________ numeric operations __________
Modified: pypy/branch/stringbuilder2/pypy/translator/driver.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/translator/driver.py (original)
+++ pypy/branch/stringbuilder2/pypy/translator/driver.py Mon Jan 25 15:25:48 2010
@@ -428,10 +428,13 @@
def possibly_check_for_boehm(self):
if self.config.translation.gc == "boehm":
- from pypy.rpython.tool.rffi_platform import check_boehm
- if not check_boehm(self.translator.platform):
+ from pypy.rpython.tool.rffi_platform import configure_boehm
+ from pypy.translator.platform import CompilationError
+ try:
+ configure_boehm(self.translator.platform)
+ except CompilationError, e:
i = 'Boehm GC not installed. Try e.g. "translate.py --gc=hybrid"'
- raise Exception(i)
+ raise Exception(str(e) + '\n' + i)
def task_database_c(self):
translator = self.translator
Modified: pypy/branch/stringbuilder2/pypy/translator/exceptiontransform.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/translator/exceptiontransform.py (original)
+++ pypy/branch/stringbuilder2/pypy/translator/exceptiontransform.py Mon Jan 25 15:25:48 2010
@@ -3,11 +3,10 @@
from pypy.translator.unsimplify import insert_empty_block, split_block
from pypy.translator.backendopt import canraise, inline, support, removenoops
from pypy.objspace.flow.model import Block, Constant, Variable, Link, \
- c_last_exception, SpaceOperation, checkgraph, FunctionGraph
+ c_last_exception, SpaceOperation, checkgraph, FunctionGraph, mkentrymap
from pypy.rpython.lltypesystem import lltype, llmemory, rffi
from pypy.rpython.ootypesystem import ootype
from pypy.rpython.lltypesystem import lloperation
-from pypy.rpython.lltypesystem.llmemory import NULL
from pypy.rpython import rtyper
from pypy.rpython import rclass
from pypy.rpython.rmodel import inputconst
@@ -16,6 +15,7 @@
from pypy.rlib.debug import ll_assert
from pypy.annotation import model as annmodel
from pypy.rpython.annlowlevel import MixLevelHelperAnnotator
+from pypy.tool.sourcetools import func_with_new_name
PrimitiveErrorValue = {lltype.Signed: -1,
lltype.Unsigned: r_uint(-1),
@@ -26,7 +26,7 @@
lltype.Char: chr(255),
lltype.UniChar: unichr(0xFFFF), # XXX is this always right?
lltype.Bool: True,
- llmemory.Address: NULL,
+ llmemory.Address: llmemory.NULL,
lltype.Void: None}
for TYPE in rffi.NUMBER_TYPES:
@@ -45,6 +45,9 @@
def error_constant(T):
return Constant(error_value(T), T)
+def constant_value(llvalue):
+ return Constant(llvalue, lltype.typeOf(llvalue))
+
class BaseExceptionTransformer(object):
def __init__(self, translator):
@@ -64,6 +67,10 @@
(n_i_error_ll_exc_type,
n_i_error_ll_exc) = self.get_builtin_exception(NotImplementedError)
+ self.c_assertion_error_ll_exc_type = constant_value(
+ assertion_error_ll_exc_type)
+ self.c_n_i_error_ll_exc_type = constant_value(n_i_error_ll_exc_type)
+
def rpyexc_occured():
exc_type = exc_data.exc_type
return bool(exc_type)
@@ -80,10 +87,14 @@
def rpyexc_raise(etype, evalue):
# assert(!RPyExceptionOccurred());
- ll_assert(etype != assertion_error_ll_exc_type, "AssertionError!")
- ll_assert(etype != n_i_error_ll_exc_type, "NotImplementedError!")
exc_data.exc_type = etype
exc_data.exc_value = evalue
+ lloperation.llop.debug_start_traceback(lltype.Void, etype)
+
+ def rpyexc_reraise(etype, evalue):
+ exc_data.exc_type = etype
+ exc_data.exc_value = evalue
+ lloperation.llop.debug_reraise_traceback(lltype.Void, etype)
def rpyexc_fetch_exception():
evalue = rpyexc_fetch_value()
@@ -92,7 +103,8 @@
def rpyexc_restore_exception(evalue):
if evalue:
- rpyexc_raise(rclass.ll_inst_type(evalue), evalue)
+ exc_data.exc_type = rclass.ll_inst_type(evalue)
+ exc_data.exc_value = evalue
def rpyexc_raise_runtime_error():
rpyexc_raise(runtime_error_ll_exc_type, runtime_error_ll_exc)
@@ -119,14 +131,21 @@
self.rpyexc_raise_ptr = self.build_func(
"RPyRaiseException",
- rpyexc_raise,
+ self.noinline(rpyexc_raise),
+ [self.lltype_of_exception_type, self.lltype_of_exception_value],
+ lltype.Void,
+ jitcallkind='rpyexc_raise') # for the JIT
+
+ self.rpyexc_reraise_ptr = self.build_func(
+ "RPyReRaiseException",
+ rpyexc_reraise,
[self.lltype_of_exception_type, self.lltype_of_exception_value],
lltype.Void,
jitcallkind='rpyexc_raise') # for the JIT
self.rpyexc_raise_runtime_error_ptr = self.build_func(
"RPyRaiseRuntimeError",
- rpyexc_raise_runtime_error,
+ self.noinline(rpyexc_raise_runtime_error),
[], lltype.Void)
self.rpyexc_fetch_exception_ptr = self.build_func(
@@ -136,7 +155,7 @@
self.rpyexc_restore_exception_ptr = self.build_func(
"RPyRestoreException",
- rpyexc_restore_exception,
+ self.noinline(rpyexc_restore_exception),
[self.lltype_of_exception_value], lltype.Void)
self.build_extra_funcs()
@@ -144,6 +163,11 @@
self.mixlevelannotator.finish()
self.lltype_to_classdef = translator.rtyper.lltype_to_classdef_mapping()
+ def noinline(self, fn):
+ fn = func_with_new_name(fn, fn.__name__)
+ fn._dont_inline_ = True
+ return fn
+
def build_func(self, name, fn, inputtypes, rettype, **kwds):
l2a = annmodel.lltype_to_annotation
graph = self.mixlevelannotator.getgraph(fn, map(l2a, inputtypes), l2a(rettype))
@@ -184,13 +208,18 @@
# collect the blocks before changing them
n_need_exc_matching_blocks = 0
n_gen_exc_checks = 0
+ #
+ entrymap = mkentrymap(graph)
+ if graph.exceptblock in entrymap:
+ for link in entrymap[graph.exceptblock]:
+ self.transform_jump_to_except_block(graph, entrymap, link)
+ #
for block in list(graph.iterblocks()):
self.replace_stack_unwind(block)
self.replace_fetch_restore_operations(block)
need_exc_matching, gen_exc_checks = self.transform_block(graph, block)
n_need_exc_matching_blocks += need_exc_matching
n_gen_exc_checks += gen_exc_checks
- self.transform_except_block(graph, graph.exceptblock)
cleanup_graph(graph)
removenoops.remove_superfluous_keep_alive(graph)
return n_need_exc_matching_blocks, n_gen_exc_checks
@@ -268,18 +297,54 @@
self.insert_matching(lastblock, graph)
return need_exc_matching, n_gen_exc_checks
- def transform_except_block(self, graph, block):
- # attach an except block -- let's hope that nobody uses it
- graph.exceptblock = Block([Variable('etype'), # exception class
- Variable('evalue')]) # exception value
- graph.exceptblock.operations = ()
- graph.exceptblock.closeblock()
-
+ def comes_from_last_exception(self, entrymap, link):
+ seen = {}
+ pending = [(link, link.args[1])]
+ while pending:
+ link, v = pending.pop()
+ if (link, v) in seen:
+ continue
+ seen[link, v] = True
+ if link.last_exc_value is not None and v is link.last_exc_value:
+ return True
+ block = link.prevblock
+ if block is None:
+ continue
+ for op in block.operations[::-1]:
+ if v is op.result:
+ if op.opname == 'cast_pointer':
+ v = op.args[0]
+ else:
+ break
+ for link in entrymap.get(block, ()):
+ for v1, v2 in zip(link.args, block.inputargs):
+ if v2 is v:
+ pending.append((link, v1))
+ return False
+
+ def transform_jump_to_except_block(self, graph, entrymap, link):
+ reraise = self.comes_from_last_exception(entrymap, link)
result = Variable()
result.concretetype = lltype.Void
- block.operations = [SpaceOperation(
- "direct_call", [self.rpyexc_raise_ptr] + block.inputargs, result)]
- l = Link([error_constant(graph.returnblock.inputargs[0].concretetype)], graph.returnblock)
+ block = Block([copyvar(None, v)
+ for v in graph.exceptblock.inputargs])
+ if reraise:
+ block.operations = [
+ SpaceOperation("direct_call",
+ [self.rpyexc_reraise_ptr] + block.inputargs,
+ result),
+ ]
+ else:
+ block.operations = [
+ SpaceOperation("direct_call",
+ [self.rpyexc_raise_ptr] + block.inputargs,
+ result),
+ SpaceOperation('debug_record_traceback', [],
+ varoftype(lltype.Void)),
+ ]
+ link.target = block
+ RETTYPE = graph.returnblock.inputargs[0].concretetype
+ l = Link([error_constant(RETTYPE)], graph.returnblock)
block.recloseblock(l)
def insert_matching(self, block, graph):
@@ -328,6 +393,11 @@
llops = rtyper.LowLevelOpList(None)
var_value = self.gen_getfield('exc_value', llops)
var_type = self.gen_getfield('exc_type' , llops)
+ #
+ c_check1 = self.c_assertion_error_ll_exc_type
+ c_check2 = self.c_n_i_error_ll_exc_type
+ llops.genop('debug_catch_exception', [var_type, c_check1, c_check2])
+ #
self.gen_setfield('exc_value', self.c_null_evalue, llops)
self.gen_setfield('exc_type', self.c_null_etype, llops)
excblock.operations[:] = llops
@@ -361,7 +431,12 @@
block.exitswitch = var_no_exc
#exception occurred case
+ b = Block([])
+ b.operations = [SpaceOperation('debug_record_traceback', [],
+ varoftype(lltype.Void))]
l = Link([error_constant(returnblock.inputargs[0].concretetype)], returnblock)
+ b.closeblock(l)
+ l = Link([], b)
l.exitcase = l.llexitcase = False
#non-exception case
Modified: pypy/branch/stringbuilder2/pypy/translator/goal/app_main.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/translator/goal/app_main.py (original)
+++ pypy/branch/stringbuilder2/pypy/translator/goal/app_main.py Mon Jan 25 15:25:48 2010
@@ -228,7 +228,7 @@
newpath.insert(0, '')
# remove duplicates
_seen = {}
- sys.path = []
+ del sys.path[:]
for dir in newpath:
if dir not in _seen:
sys.path.append(dir)
Modified: pypy/branch/stringbuilder2/pypy/translator/jvm/opcodes.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/translator/jvm/opcodes.py (original)
+++ pypy/branch/stringbuilder2/pypy/translator/jvm/opcodes.py Mon Jan 25 15:25:48 2010
@@ -97,9 +97,15 @@
'gc_set_max_heap_size': Ignore,
'resume_point': Ignore,
'jit_marker': Ignore,
- 'promote_virtualizable': Ignore,
+ 'jit_force_virtualizable': Ignore,
+ 'jit_force_virtual': DoNothing,
'debug_assert': [], # TODO: implement?
+ 'debug_start_traceback': Ignore,
+ 'debug_record_traceback': Ignore,
+ 'debug_catch_exception': Ignore,
+ 'debug_reraise_traceback': Ignore,
+ 'debug_print_traceback': Ignore,
# __________ numeric operations __________
Modified: pypy/branch/stringbuilder2/pypy/translator/platform/__init__.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/translator/platform/__init__.py (original)
+++ pypy/branch/stringbuilder2/pypy/translator/platform/__init__.py Mon Jan 25 15:25:48 2010
@@ -52,6 +52,8 @@
name = "abstract platform"
c_environ = None
+ relevant_environ = []
+
so_prefixes = ['']
def __init__(self, cc):
@@ -98,6 +100,12 @@
return (self.__class__ is other.__class__ and
self.__dict__ == other.__dict__)
+ def key(self):
+ bits = [self.__class__.__name__, 'cc=%s' % self.cc]
+ for varname in self.relevant_environ:
+ bits.append('%s=%s' % (varname, os.environ.get(varname)))
+ return ' '.join(bits)
+
# some helpers which seem to be cross-platform enough
def _execute_c_compiler(self, cc, args, outname):
@@ -171,8 +179,15 @@
else:
host_factory = Linux64
elif sys.platform == 'darwin':
- from pypy.translator.platform.darwin import Darwin
- host_factory = Darwin
+ from pypy.translator.platform.darwin import Darwin_i386, Darwin_x86_64
+ import platform
+ if platform.machine() == 'i386':
+ if sys.maxint <= 2147483647:
+ host_factory = Darwin_i386
+ else:
+ host_factory = Darwin_x86_64
+ else:
+ host_factory = Darwin
elif sys.platform == 'freebsd7':
from pypy.translator.platform.freebsd7 import Freebsd7, Freebsd7_64
import platform
Modified: pypy/branch/stringbuilder2/pypy/translator/platform/darwin.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/translator/platform/darwin.py (original)
+++ pypy/branch/stringbuilder2/pypy/translator/platform/darwin.py Mon Jan 25 15:25:48 2010
@@ -4,7 +4,7 @@
class Darwin(posix.BasePosix):
name = "darwin"
-
+
link_flags = ['-mmacosx-version-min=10.4']
cflags = ['-O3', '-fomit-frame-pointer', '-mmacosx-version-min=10.4']
standalone_only = ['-mdynamic-no-pic']
@@ -44,3 +44,13 @@
include_dirs = self._includedirs(eci.include_dirs)
return (args + frameworks + include_dirs)
+class Darwin_i386(Darwin):
+ name = "darwin_i386"
+ link_flags = ['-arch', 'i386', '-mmacosx-version-min=10.4']
+ cflags = ['-arch', 'i386', '-O3', '-fomit-frame-pointer', '-mmacosx-version-min=10.4']
+
+class Darwin_x86_64(Darwin):
+ name = "darwin_x86_64"
+ link_flags = ['-arch', 'x86_64', '-mmacosx-version-min=10.4']
+ cflags = ['-arch', 'x86_64', '-O3', '-fomit-frame-pointer', '-mmacosx-version-min=10.4']
+
Modified: pypy/branch/stringbuilder2/pypy/translator/platform/linux.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/translator/platform/linux.py (original)
+++ pypy/branch/stringbuilder2/pypy/translator/platform/linux.py Mon Jan 25 15:25:48 2010
@@ -11,7 +11,7 @@
link_flags = ['-pthread', '-lrt']
cflags = ['-O3', '-pthread', '-fomit-frame-pointer']
standalone_only = []
- shared_only = []
+ shared_only = ['-fPIC']
so_ext = 'so'
so_prefixes = ['lib', '']
Modified: pypy/branch/stringbuilder2/pypy/translator/platform/posix.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/translator/platform/posix.py (original)
+++ pypy/branch/stringbuilder2/pypy/translator/platform/posix.py Mon Jan 25 15:25:48 2010
@@ -10,6 +10,8 @@
exe_ext = ''
make_cmd = 'make'
+ relevant_environ=['CPATH', 'LIBRARY_PATH', 'C_INCLUDE_PATH']
+
def __init__(self, cc=None):
if cc is None:
cc = 'gcc'
Modified: pypy/branch/stringbuilder2/pypy/translator/platform/test/test_darwin.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/translator/platform/test/test_darwin.py (original)
+++ pypy/branch/stringbuilder2/pypy/translator/platform/test/test_darwin.py Mon Jan 25 15:25:48 2010
@@ -2,17 +2,25 @@
""" File containing darwin platform tests
"""
-import py, sys
+import py, sys, platform
if sys.platform != 'darwin':
py.test.skip("Darwin only")
from pypy.tool.udir import udir
-from pypy.translator.platform.darwin import Darwin
+from pypy.translator.platform.darwin import Darwin_i386, Darwin_x86_64
from pypy.translator.platform.test.test_platform import TestPlatform as BasicTest
from pypy.translator.tool.cbuild import ExternalCompilationInfo
+if platform.machine() == 'i386':
+ if sys.maxint <= 2147483647:
+ host_factory = Darwin_i386
+ else:
+ host_factory = Darwin_x86_64
+else:
+ host_factory = Darwin
+
class TestDarwin(BasicTest):
- platform = Darwin()
+ platform = host_factory()
def test_frameworks(self):
objcfile = udir.join('test_simple.m')
@@ -39,3 +47,81 @@
res = self.platform.execute(executable)
self.check_res(res)
+ def test_64_32_results(self):
+ if platform.machine() != 'i386':
+ py.test.skip("i386 only")
+ plat32 = Darwin_i386()
+ plat64 = Darwin_x86_64()
+ cfile = udir.join('test_int_size.c')
+ cfile.write(r'''
+ #include <stdio.h>
+ #include <limits.h>
+
+ int main() {
+ printf("%d\n", INT_MAX < LONG_MAX);
+ return 0;
+ }
+ ''')
+ eci = ExternalCompilationInfo()
+ executable = plat32.compile([cfile], eci)
+ res = plat32.execute(executable)
+ self.check_res(res, '0\n')
+ if host_factory == Darwin_x86_64:
+ executable = plat64.compile([cfile], eci)
+ res = plat64.execute(executable)
+ self.check_res(res, '1\n')
+
+ def test_longsize(self):
+ if platform.machine() != 'i386':
+ py.test.skip("i386 only")
+ cfile = udir.join('test_int_size.c')
+ cfile.write(r'''
+ #include <stdio.h>
+ #include <limits.h>
+
+ int main() {
+ printf("%ld\n", LONG_MAX);
+ return 0;
+ }
+ ''')
+ eci = ExternalCompilationInfo()
+ executable = self.platform.compile([cfile], eci)
+ res = self.platform.execute(executable)
+ self.check_res(res, str(sys.maxint) + '\n')
+
+ def test_32bit_makefile(self):
+ if platform.machine() != 'i386':
+ py.test.skip("i386 only")
+ plat32 = Darwin_i386()
+ plat64 = Darwin_x86_64()
+ eci = ExternalCompilationInfo()
+ cfile_content =r'''
+ #include <stdio.h>
+ #include <limits.h>
+
+ int main() {
+ printf("%d\n", INT_MAX < LONG_MAX);
+ return 0;
+ }
+ '''
+
+ tmpdir = udir.join('32_makefile' + self.__class__.__name__).ensure(dir=1)
+ cfile = tmpdir.join('test_int_size.c')
+ cfile.write(cfile_content)
+ mk = plat32.gen_makefile([cfile], ExternalCompilationInfo(),
+ path=tmpdir)
+ mk.write()
+ plat32.execute_makefile(mk)
+ res = plat32.execute(tmpdir.join('test_int_size'))
+ self.check_res(res, '0\n')
+ if host_factory == Darwin_x86_64:
+ tmpdir = udir.join('64_makefile' + self.__class__.__name__).ensure(dir=1)
+ cfile = tmpdir.join('test_int_size.c')
+ cfile.write(cfile_content)
+ mk = plat64.gen_makefile([cfile], ExternalCompilationInfo(),
+ path=tmpdir)
+ mk.write()
+ plat64.execute_makefile(mk)
+ res = plat64.execute(tmpdir.join('test_int_size'))
+ self.check_res(res, '1\n')
+
Modified: pypy/branch/stringbuilder2/pypy/translator/platform/test/test_platform.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/translator/platform/test/test_platform.py (original)
+++ pypy/branch/stringbuilder2/pypy/translator/platform/test/test_platform.py Mon Jan 25 15:25:48 2010
@@ -115,6 +115,16 @@
finally:
del os.environ['_SOME_VARIABLE_2']
+ def test_key(self):
+ class XPlatform(Platform):
+ relevant_environ = ['CPATH']
+
+ def __init__(self):
+ self.cc = 'xcc'
+ x = XPlatform()
+ res = x.key()
+ assert res.startswith('XPlatform cc=xcc CPATH=')
+
def test_equality():
class X(Platform):
def __init__(self):
Modified: pypy/branch/stringbuilder2/pypy/translator/test/test_exceptiontransform.py
==============================================================================
--- pypy/branch/stringbuilder2/pypy/translator/test/test_exceptiontransform.py (original)
+++ pypy/branch/stringbuilder2/pypy/translator/test/test_exceptiontransform.py Mon Jan 25 15:25:48 2010
@@ -95,7 +95,7 @@
return 3 + x
return 4 + x
t, g = self.transform_func(foo, [int])
- assert len(list(g.iterblocks())) == 9
+ assert len(list(g.iterblocks())) == 10
f = self.compile(foo, [int])
result = interpret(foo, [6])
assert result == 2
@@ -126,7 +126,7 @@
return 1 + x
return 4 + x
t, g = self.transform_func(foo, [int])
- assert len(list(g.iterblocks())) == 5
+ assert len(list(g.iterblocks())) == 6
f = self.compile(foo, [int])
result = interpret(foo, [6])
assert result == 2
@@ -175,6 +175,34 @@
etrafo.create_exception_handling(g)
assert etrafo.raise_analyzer.analyze_direct_call(g)
+ def test_reraise_is_not_raise(self):
+ def one(x):
+ if x == 1:
+ raise ValueError()
+ elif x == 2:
+ raise TypeError()
+ return x - 5
+ def foo(x):
+ try:
+ return one(x)
+ except ValueError:
+ return -42
+ t, g = self.transform_func(foo, [int])
+ for block in g.iterblocks():
+ for op in block.operations:
+ # the operation 'debug_record_traceback' should only show up
+ # in a normal raise, not in a reraise
+ assert op.opname != 'debug_record_traceback'
+ f = self.compile(foo, [int])
+ result = interpret(foo, [7])
+ assert result == 2
+ result = f(7)
+ assert result == 2
+ result = interpret(foo, [1])
+ assert result == -42
+ result = f(1)
+ assert result == -42
+
class TestLLType(BaseTestExceptionTransform):
type_system = 'lltype'
More information about the Pypy-commit
mailing list