[pypy-commit] pypy reflex-support: merge default into branch
wlav
noreply at buildbot.pypy.org
Wed Jan 9 04:28:23 CET 2013
Author: Wim Lavrijsen <WLavrijsen at lbl.gov>
Branch: reflex-support
Changeset: r59885:4297455b87c7
Date: 2013-01-08 19:28 -0800
http://bitbucket.org/pypy/pypy/changeset/4297455b87c7/
Log: merge default into branch
diff --git a/pypy/doc/Makefile b/pypy/doc/Makefile
--- a/pypy/doc/Makefile
+++ b/pypy/doc/Makefile
@@ -32,38 +32,38 @@
-rm -rf $(BUILDDIR)/*
html:
- python config/generate.py
+ # python config/generate.py #readthedocs will not run this Makefile
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
dirhtml:
- python config/generate.py
+ # python config/generate.py #readthedocs will not run this Makefile
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
pickle:
- python config/generate.py
+ # python config/generate.py #readthedocs will not run this Makefile
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
@echo
@echo "Build finished; now you can process the pickle files."
json:
- python config/generate.py
+ # python config/generate.py #readthedocs will not run this Makefile
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
@echo
@echo "Build finished; now you can process the JSON files."
htmlhelp:
- python config/generate.py
+ # python config/generate.py #readthedocs will not run this Makefile
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
@echo
@echo "Build finished; now you can run HTML Help Workshop with the" \
".hhp project file in $(BUILDDIR)/htmlhelp."
qthelp:
- python config/generate.py
+ # python config/generate.py #readthedocs will not run this Makefile
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
@echo
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
@@ -73,7 +73,7 @@
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/PyPy.qhc"
latex:
- python config/generate.py
+ # python config/generate.py #readthedocs will not run this Makefile
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
@@ -81,26 +81,26 @@
"run these through (pdf)latex."
man:
- python config/generate.py
+ # python config/generate.py #readthedocs will not run this Makefile
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
@echo
@echo "Build finished. The manual pages are in $(BUILDDIR)/man"
changes:
- python config/generate.py
+ # python config/generate.py #readthedocs will not run this Makefile
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
@echo
@echo "The overview file is in $(BUILDDIR)/changes."
linkcheck:
- python config/generate.py
+ # python config/generate.py #readthedocs will not run this Makefile
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
@echo
@echo "Link check complete; look for any errors in the above output " \
"or in $(BUILDDIR)/linkcheck/output.txt."
doctest:
- python config/generate.py
+ # python config/generate.py #readthedocs will not run this Makefile
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
@echo "Testing of doctests in the sources finished, look at the " \
"results in $(BUILDDIR)/doctest/output.txt."
diff --git a/pypy/doc/conf.py b/pypy/doc/conf.py
--- a/pypy/doc/conf.py
+++ b/pypy/doc/conf.py
@@ -38,7 +38,7 @@
# General information about the project.
project = u'PyPy'
-copyright = u'2011, The PyPy Project'
+copyright = u'2013, The PyPy Project'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
diff --git a/pypy/doc/config/translation.no__thread.txt b/pypy/doc/config/translation.no__thread.txt
--- a/pypy/doc/config/translation.no__thread.txt
+++ b/pypy/doc/config/translation.no__thread.txt
@@ -1,3 +1,3 @@
Don't use gcc __thread attribute for fast thread local storage
-implementation . Increases the chance that moving the resulting
+implementation. Increases the chance that moving the resulting
executable to another same processor Linux machine will work.
diff --git a/pypy/doc/pypyconfig.py b/pypy/doc/pypyconfig.py
--- a/pypy/doc/pypyconfig.py
+++ b/pypy/doc/pypyconfig.py
@@ -3,6 +3,10 @@
def setup(app):
import sys, os
sys.path.insert(0, os.path.abspath("../../"))
+
+ #Autmatically calls make_cmdlline_overview
+ from pypy.doc.config import generate
+
from pypy.config import makerestdoc
import py
role = makerestdoc.register_config_role(py.path.local())
diff --git a/pypy/doc/whatsnew-head.rst b/pypy/doc/whatsnew-head.rst
--- a/pypy/doc/whatsnew-head.rst
+++ b/pypy/doc/whatsnew-head.rst
@@ -5,6 +5,11 @@
.. this is a revision shortly after release-2.0-beta1
.. startrev: 0e6161a009c6
+.. branch: callback-jit
+Callbacks from C are now better JITted
+
+.. branch: remove-globals-in-jit
+
.. branch: length-hint
Implement __lenght_hint__ according to PEP 424
diff --git a/pypy/doc/windows.rst b/pypy/doc/windows.rst
--- a/pypy/doc/windows.rst
+++ b/pypy/doc/windows.rst
@@ -56,11 +56,24 @@
----------------------------
On Windows, there is no standard place where to download, build and
-install third-party libraries. We chose to install them in the parent
+install third-party libraries. We recommend installing them in the parent
directory of the pypy checkout. For example, if you installed pypy in
``d:\pypy\trunk\`` (This directory contains a README file), the base
-directory is ``d:\pypy``. You may choose different values by setting the
-INCLUDE, LIB and PATH (for DLLs)
+directory is ``d:\pypy``. You must then set the
+INCLUDE, LIB and PATH (for DLLs) environment variables appropriately.
+
+Abridged method (for -Ojit builds using Visual Studio 2008)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Download the versions of all the external packages
+from
+https://bitbucket.org/pypy/pypy/downloads/local.zip
+Then expand it into the base directory (base_dir) and modify your environment to reflect this::
+
+ set PATH=<base_dir>\bin;%PATH%
+ set INCLUDE=<base_dir>\include;%INCLUDE%
+ set LIB=<base_dir>\lib;%LIB%
+
+Now you should be good to go. Read on for more information.
The Boehm garbage collector
~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/pypy/interpreter/typedef.py b/pypy/interpreter/typedef.py
--- a/pypy/interpreter/typedef.py
+++ b/pypy/interpreter/typedef.py
@@ -105,6 +105,13 @@
# typical usage (case 1 is the most common kind of app-level subclasses;
# case 2 is the memory-saving kind defined with __slots__).
#
+# +----------------------------------------------------------------+
+# | NOTE: if withmapdict is enabled, the following doesn't apply! |
+# | Map dicts can flexibly allow any slots/__dict__/__weakref__ to |
+# | show up only when needed. In particular there is no way with |
+# | mapdict to prevent some objects from being weakrefable. |
+# +----------------------------------------------------------------+
+#
# dict slots del weakrefable
#
# 1. Y N N Y UserDictWeakref
diff --git a/pypy/jit/backend/arm/test/test_gc_integration.py b/pypy/jit/backend/arm/test/test_gc_integration.py
--- a/pypy/jit/backend/arm/test/test_gc_integration.py
+++ b/pypy/jit/backend/arm/test/test_gc_integration.py
@@ -2,25 +2,13 @@
""" Tests for register allocation for common constructs
"""
-import py
-from pypy.jit.metainterp.history import BoxInt, \
- BoxPtr, TreeLoop, TargetToken
-from pypy.jit.metainterp.resoperation import rop, ResOperation
-from pypy.jit.codewriter import heaptracker
-from pypy.jit.backend.llsupport.descr import GcCache
-from pypy.jit.backend.llsupport.gc import GcLLDescription
+from pypy.jit.metainterp.history import TargetToken
+from pypy.jit.backend.llsupport.gc import GcLLDescription, GcLLDescr_boehm
from pypy.jit.backend.detect_cpu import getcpuclass
from pypy.jit.backend.arm.arch import WORD
from pypy.rpython.lltypesystem import lltype, llmemory, rffi
-from pypy.rpython.annlowlevel import llhelper
-from pypy.rpython.lltypesystem import rclass
-from pypy.jit.backend.llsupport.gc import GcLLDescr_framework
-from pypy.jit.backend.arm.test.test_regalloc import MockAssembler
from pypy.jit.backend.arm.test.test_regalloc import BaseTestRegalloc
-from pypy.jit.backend.arm.regalloc import ARMFrameManager, VFPRegisterManager
-from pypy.jit.codewriter.effectinfo import EffectInfo
-from pypy.jit.backend.arm.regalloc import Regalloc
CPU = getcpuclass()
@@ -44,23 +32,14 @@
return ['compressed'] + shape[1:]
-class MockGcDescr(GcCache):
- get_malloc_slowpath_addr = None
- write_barrier_descr = None
- moving_gc = True
+class MockGcDescr(GcLLDescr_boehm):
gcrootmap = MockGcRootMap()
- def initialize(self):
- pass
-
- _record_constptrs = GcLLDescr_framework._record_constptrs.im_func
- rewrite_assembler = GcLLDescr_framework.rewrite_assembler.im_func
-
class TestRegallocGcIntegration(BaseTestRegalloc):
cpu = CPU(None, None)
- cpu.gc_ll_descr = MockGcDescr(False)
+ cpu.gc_ll_descr = MockGcDescr(None, None, None)
cpu.setup_once()
S = lltype.GcForwardReference()
diff --git a/pypy/jit/backend/llgraph/runner.py b/pypy/jit/backend/llgraph/runner.py
--- a/pypy/jit/backend/llgraph/runner.py
+++ b/pypy/jit/backend/llgraph/runner.py
@@ -877,13 +877,16 @@
#
assembler_helper_ptr = jd.assembler_helper_adr.ptr # fish
try:
- return assembler_helper_ptr(pframe, vable)
+ result = assembler_helper_ptr(pframe, vable)
except LLException, lle:
assert self.last_exception is None, "exception left behind"
self.last_exception = lle
# fish op
op = self.current_op
return op.result and op.result.value
+ if isinstance(result, float):
+ result = support.cast_to_floatstorage(result)
+ return result
def execute_same_as(self, _, x):
return x
diff --git a/pypy/jit/metainterp/pyjitpl.py b/pypy/jit/metainterp/pyjitpl.py
--- a/pypy/jit/metainterp/pyjitpl.py
+++ b/pypy/jit/metainterp/pyjitpl.py
@@ -1379,16 +1379,15 @@
"""The 'residual_call' operation is emitted in two cases:
when we have to generate a residual CALL operation, but also
to handle an indirect_call that may need to be inlined."""
- assert isinstance(funcbox, Const)
- sd = self.metainterp.staticdata
- key = sd.cpu.ts.getaddr_for_box(funcbox)
- jitcode = sd.bytecode_for_address(key)
- if jitcode is not None:
- # we should follow calls to this graph
- return self.metainterp.perform_call(jitcode, argboxes)
- else:
- # but we should not follow calls to that graph
- return self.do_residual_call(funcbox, argboxes, calldescr)
+ if isinstance(funcbox, Const):
+ sd = self.metainterp.staticdata
+ key = sd.cpu.ts.getaddr_for_box(funcbox)
+ jitcode = sd.bytecode_for_address(key)
+ if jitcode is not None:
+ # we should follow calls to this graph
+ return self.metainterp.perform_call(jitcode, argboxes)
+ # but we should not follow calls to that graph
+ return self.do_residual_call(funcbox, argboxes, calldescr)
# ____________________________________________________________
diff --git a/pypy/jit/metainterp/resume.py b/pypy/jit/metainterp/resume.py
--- a/pypy/jit/metainterp/resume.py
+++ b/pypy/jit/metainterp/resume.py
@@ -1085,6 +1085,9 @@
def consume_virtualref_info(self, vrefinfo, numb, end):
# we have to decode a list of references containing pairs
# [..., virtual, vref, ...] stopping at 'end'
+ if vrefinfo is None:
+ assert end == 0
+ return
assert (end & 1) == 0
for i in range(0, end, 2):
virtual = self.decode_ref(numb.nums[i])
diff --git a/pypy/jit/metainterp/test/test_ajit.py b/pypy/jit/metainterp/test/test_ajit.py
--- a/pypy/jit/metainterp/test/test_ajit.py
+++ b/pypy/jit/metainterp/test/test_ajit.py
@@ -3979,6 +3979,8 @@
rgc.add_memory_pressure(1234)
return 3
+ self.interp_operations(f, [])
+
def test_external_call(self):
from pypy.rlib.objectmodel import invoke_around_extcall
diff --git a/pypy/jit/metainterp/test/test_call.py b/pypy/jit/metainterp/test/test_call.py
new file mode 100644
--- /dev/null
+++ b/pypy/jit/metainterp/test/test_call.py
@@ -0,0 +1,27 @@
+
+from pypy.jit.metainterp.test.support import LLJitMixin
+from pypy.rlib import jit
+
+class TestCall(LLJitMixin):
+ def test_indirect_call(self):
+ @jit.dont_look_inside
+ def f1(x):
+ return x + 1
+
+ @jit.dont_look_inside
+ def f2(x):
+ return x + 2
+
+ @jit.dont_look_inside
+ def choice(i):
+ if i:
+ return f1
+ return f2
+
+ def f(i):
+ func = choice(i)
+ return func(i)
+
+ res = self.interp_operations(f, [3])
+ assert res == f(3)
+
diff --git a/pypy/jit/metainterp/test/test_warmspot.py b/pypy/jit/metainterp/test/test_warmspot.py
--- a/pypy/jit/metainterp/test/test_warmspot.py
+++ b/pypy/jit/metainterp/test/test_warmspot.py
@@ -519,6 +519,44 @@
self.check_trace_count(1)
+ def test_callback_jit_merge_point(self):
+ from pypy.rlib.objectmodel import register_around_callback_hook
+ from pypy.rpython.lltypesystem import lltype, rffi
+ from pypy.translator.tool.cbuild import ExternalCompilationInfo
+
+ callback_jit_driver = JitDriver(greens = ['name'], reds = 'auto')
+
+ def callback_merge_point(name):
+ callback_jit_driver.jit_merge_point(name=name)
+
+ @callback_jit_driver.inline(callback_merge_point)
+ def callback_hook(name):
+ pass
+
+ def callback(a, b):
+ if a > b:
+ return 1
+ return -1
+
+ CB_TP = rffi.CCallback([lltype.Signed, lltype.Signed], lltype.Signed)
+ eci = ExternalCompilationInfo(includes=['stdlib.h'])
+ qsort = rffi.llexternal('qsort',
+ [rffi.VOIDP, lltype.Signed, lltype.Signed,
+ CB_TP], lltype.Void, compilation_info=eci)
+ ARR = rffi.CArray(lltype.Signed)
+
+ def main():
+ register_around_callback_hook(callback_hook)
+ raw = lltype.malloc(ARR, 10, flavor='raw')
+ for i in range(10):
+ raw[i] = 10 - i
+ qsort(raw, 10, rffi.sizeof(lltype.Signed), callback)
+ lltype.free(raw, flavor='raw')
+
+ self.meta_interp(main, [])
+ self.check_trace_count(1)
+
+
class TestLLWarmspot(WarmspotTests, LLJitMixin):
CPUClass = runner.LLGraphCPU
type_system = 'lltype'
diff --git a/pypy/jit/metainterp/warmspot.py b/pypy/jit/metainterp/warmspot.py
--- a/pypy/jit/metainterp/warmspot.py
+++ b/pypy/jit/metainterp/warmspot.py
@@ -290,11 +290,13 @@
callgraph = inlinable_static_callers(self.translator.graphs, store_calls=True)
new_callgraph = []
new_portals = set()
+ inlined_jit_merge_points = set()
for caller, block, op_call, callee in callgraph:
func = getattr(callee, 'func', None)
_inline_jit_merge_point_ = getattr(func, '_inline_jit_merge_point_', None)
if _inline_jit_merge_point_:
_inline_jit_merge_point_._always_inline_ = True
+ inlined_jit_merge_points.add(_inline_jit_merge_point_)
op_jmp_call, jmp_graph = get_jmp_call(callee, _inline_jit_merge_point_)
#
# now we move the op_jmp_call from callee to caller, just
@@ -315,6 +317,9 @@
# inline them!
inline_threshold = 0.1 # we rely on the _always_inline_ set above
auto_inlining(self.translator, inline_threshold, new_callgraph)
+ # clean up _always_inline_ = True, it can explode later
+ for item in inlined_jit_merge_points:
+ del item._always_inline_
# make a fresh copy of the JitDriver in all newly created
# jit_merge_points
@@ -1011,6 +1016,9 @@
origblock.operations.append(newop)
origblock.exitswitch = None
origblock.recloseblock(Link([v_result], origportalgraph.returnblock))
+ # the origportal now can raise (even if it did not raise before),
+ # which means that we cannot inline it anywhere any more, but that's
+ # fine since any forced inlining has been done before
#
checkgraph(origportalgraph)
diff --git a/pypy/module/_cffi_backend/ccallback.py b/pypy/module/_cffi_backend/ccallback.py
--- a/pypy/module/_cffi_backend/ccallback.py
+++ b/pypy/module/_cffi_backend/ccallback.py
@@ -3,10 +3,10 @@
"""
import os
from pypy.interpreter.error import OperationError, operationerrfmt
-from pypy.rpython.lltypesystem import lltype, llmemory, rffi
+from pypy.rpython.lltypesystem import lltype, rffi
from pypy.rlib.objectmodel import compute_unique_id, keepalive_until_here
-from pypy.rlib import clibffi, rweakref, rgc
-from pypy.rlib.rarithmetic import r_ulonglong
+from pypy.rlib import clibffi, rweakref
+from pypy.rlib import jit
from pypy.module._cffi_backend.cdataobj import W_CData
from pypy.module._cffi_backend.ctypefunc import SIZE_OF_FFI_ARG, BIG_ENDIAN
@@ -77,6 +77,7 @@
space.wrap("expected a function ctype"))
return ctype
+ @jit.unroll_safe
def invoke(self, ll_args):
space = self.space
ctype = self.getfunctype()
diff --git a/pypy/module/_weakref/test/test_weakref.py b/pypy/module/_weakref/test/test_weakref.py
--- a/pypy/module/_weakref/test/test_weakref.py
+++ b/pypy/module/_weakref/test/test_weakref.py
@@ -114,19 +114,28 @@
class A(object):
def __eq__(self, other):
return True
+ def __ne__(self, other):
+ return False
a1 = A()
a2 = A()
ref1 = _weakref.ref(a1)
ref2 = _weakref.ref(a2)
assert ref1 == ref2
+ assert not (ref1 != ref2)
+ assert not (ref1 == [])
+ assert ref1 != []
del a1
gc.collect()
assert not ref1 == ref2
assert ref1 != ref2
+ assert not (ref1 == [])
+ assert ref1 != []
del a2
gc.collect()
assert not ref1 == ref2
assert ref1 != ref2
+ assert not (ref1 == [])
+ assert ref1 != []
def test_getweakrefs(self):
import _weakref, gc
@@ -298,6 +307,13 @@
if seen_callback:
assert seen_callback == [True, True, True]
+ def test_type_weakrefable(self):
+ import _weakref, gc
+ w = _weakref.ref(list)
+ assert w() is list
+ gc.collect()
+ assert w() is list
+
class AppTestProxy(object):
spaceconfig = dict(usemodules=('_weakref',))
@@ -435,6 +451,8 @@
class A(object):
def __eq__(self, other):
return True
+ def __ne__(self, other):
+ return False
a = A()
assert _weakref.ref(a) == a
diff --git a/pypy/module/pyexpat/interp_pyexpat.py b/pypy/module/pyexpat/interp_pyexpat.py
--- a/pypy/module/pyexpat/interp_pyexpat.py
+++ b/pypy/module/pyexpat/interp_pyexpat.py
@@ -182,6 +182,8 @@
def clear(self):
self.next_id = 0
+ self._last_object_id = -1
+ self._last_object = None
self.storage = {}
@staticmethod
@@ -194,10 +196,18 @@
@staticmethod
def get_object(id):
- return global_storage.storage[id]
+ if id == global_storage._last_object_id:
+ return global_storage._last_object
+ result = global_storage.storage[id]
+ global_storage._last_object_id = id
+ global_storage._last_object = result
+ return result
@staticmethod
def free_nonmoving_id(id):
+ if id == global_storage._last_object_id:
+ global_storage._last_object = None
+ global_storage._last_object_id = -1
del global_storage.storage[id]
global_storage = Storage()
diff --git a/pypy/module/pypyjit/interp_jit.py b/pypy/module/pypyjit/interp_jit.py
--- a/pypy/module/pypyjit/interp_jit.py
+++ b/pypy/module/pypyjit/interp_jit.py
@@ -6,7 +6,7 @@
from pypy.tool.pairtype import extendabletype
from pypy.rlib.rarithmetic import r_uint, intmask
from pypy.rlib.jit import JitDriver, hint, we_are_jitted, dont_look_inside
-from pypy.rlib import jit
+from pypy.rlib import jit, objectmodel
from pypy.rlib.jit import current_trace_length, unroll_parameters
import pypy.interpreter.pyopcode # for side-effects
from pypy.interpreter.error import OperationError, operationerrfmt
@@ -97,6 +97,15 @@
is_being_profiled=self.is_being_profiled)
return jumpto
+callback_jit_driver = JitDriver(greens = ['name'], reds = 'auto')
+
+def callback_merge_point(name):
+ callback_jit_driver.jit_merge_point(name=name)
+
+ at callback_jit_driver.inline(callback_merge_point)
+def callback_hook(name):
+ pass
+
def _get_adapted_tick_counter():
# Normally, the tick counter is decremented by 100 for every
# Python opcode. Here, to better support JIT compilation of
diff --git a/pypy/module/pypyjit/policy.py b/pypy/module/pypyjit/policy.py
--- a/pypy/module/pypyjit/policy.py
+++ b/pypy/module/pypyjit/policy.py
@@ -106,7 +106,7 @@
'posix', '_socket', '_sre', '_lsprof', '_weakref',
'__pypy__', 'cStringIO', '_collections', 'struct',
'mmap', 'marshal', '_codecs', 'rctime', 'cppyy',
- '_cffi_backend']:
+ '_cffi_backend', 'pyexpat']:
if modname == 'pypyjit' and 'interp_resop' in rest:
return False
return True
diff --git a/pypy/rlib/objectmodel.py b/pypy/rlib/objectmodel.py
--- a/pypy/rlib/objectmodel.py
+++ b/pypy/rlib/objectmodel.py
@@ -595,6 +595,16 @@
llhelper(rffi.AroundFnPtr, before)
llhelper(rffi.AroundFnPtr, after)
+def register_around_callback_hook(hook):
+ """ Register a hook that's called before a callback from C calls RPython.
+ Primary usage is for JIT to have 'started from' hook.
+ """
+ from pypy.rpython.lltypesystem import rffi
+ from pypy.rpython.annlowlevel import llhelper
+
+ rffi.aroundstate.callback_hook = hook
+ llhelper(rffi.CallbackHookPtr, hook)
+
def is_in_callback():
from pypy.rpython.lltypesystem import rffi
return rffi.stackcounter.stacks_counter > 1
diff --git a/pypy/rlib/rgc.py b/pypy/rlib/rgc.py
--- a/pypy/rlib/rgc.py
+++ b/pypy/rlib/rgc.py
@@ -139,6 +139,52 @@
hop.exception_cannot_occur()
return hop.genop(opname, vlist, resulttype = hop.r_result.lowleveltype)
+def copy_struct_item(source, dest, si, di):
+ TP = lltype.typeOf(source).TO.OF
+ i = 0
+ while i < len(TP._names):
+ setattr(dest[di], TP._names[i], getattr(source[si], TP._names[i]))
+ i += 1
+
+class CopyStructEntry(ExtRegistryEntry):
+ _about_ = copy_struct_item
+
+ def compute_result_annotation(self, s_source, s_dest, si, di):
+ pass
+
+ def specialize_call(self, hop):
+ v_source, v_dest, v_si, v_di = hop.inputargs(hop.args_r[0],
+ hop.args_r[1],
+ lltype.Signed,
+ lltype.Signed)
+ hop.exception_cannot_occur()
+ TP = v_source.concretetype.TO.OF
+ for name, TP in TP._flds.iteritems():
+ c_name = hop.inputconst(lltype.Void, name)
+ v_fld = hop.genop('getinteriorfield', [v_source, v_si, c_name],
+ resulttype=TP)
+ hop.genop('setinteriorfield', [v_dest, v_di, c_name, v_fld])
+
+
+ at specialize.ll()
+def copy_item(source, dest, si, di):
+ TP = lltype.typeOf(source)
+ if isinstance(TP.TO.OF, lltype.Struct):
+ copy_struct_item(source, dest, si, di)
+ else:
+ dest[di] = source[si]
+
+ at specialize.memo()
+def _contains_gcptr(TP):
+ if not isinstance(TP, lltype.Struct):
+ if isinstance(TP, lltype.Ptr) and TP.TO._gckind == 'gc':
+ return True
+ return False
+ for TP in TP._flds.itervalues():
+ if _contains_gcptr(TP):
+ return True
+ return False
+
@jit.oopspec('list.ll_arraycopy(source, dest, source_start, dest_start, length)')
@enforceargs(None, None, int, int, int)
@specialize.ll()
@@ -150,7 +196,7 @@
# and also, maybe, speed up very small cases
if length <= 1:
if length == 1:
- dest[dest_start] = source[source_start]
+ copy_item(source, dest, source_start, dest_start)
return
# supports non-overlapping copies only
@@ -161,7 +207,7 @@
TP = lltype.typeOf(source).TO
assert TP == lltype.typeOf(dest).TO
- if isinstance(TP.OF, lltype.Ptr) and TP.OF.TO._gckind == 'gc':
+ if _contains_gcptr(TP.OF):
# perform a write barrier that copies necessary flags from
# source to dest
if not llop.gc_writebarrier_before_copy(lltype.Bool, source, dest,
@@ -170,7 +216,7 @@
# if the write barrier is not supported, copy by hand
i = 0
while i < length:
- dest[i + dest_start] = source[i + source_start]
+ copy_item(source, dest, i + source_start, i + dest_start)
i += 1
return
source_addr = llmemory.cast_ptr_to_adr(source)
diff --git a/pypy/rlib/test/test_rgc.py b/pypy/rlib/test/test_rgc.py
--- a/pypy/rlib/test/test_rgc.py
+++ b/pypy/rlib/test/test_rgc.py
@@ -134,6 +134,46 @@
assert check.called
+def test_ll_arraycopy_array_of_structs():
+ TP = lltype.GcArray(lltype.Struct('x', ('x', lltype.Signed),
+ ('y', lltype.Signed)))
+ def f():
+ a1 = lltype.malloc(TP, 3)
+ a2 = lltype.malloc(TP, 3)
+ for i in range(3):
+ a1[i].x = 2 * i
+ a1[i].y = 2 * i + 1
+ rgc.ll_arraycopy(a1, a2, 0, 0, 3)
+ for i in range(3):
+ assert a2[i].x == 2 * i
+ assert a2[i].y == 2 * i + 1
+
+
+ interpret(f, [])
+ a1 = lltype.malloc(TP, 3)
+ a2 = lltype.malloc(TP, 3)
+ a1[1].x = 3
+ a1[1].y = 15
+ rgc.copy_struct_item(a1, a2, 1, 2)
+ assert a2[2].x == 3
+ assert a2[2].y == 15
+
+def test__contains_gcptr():
+ assert not rgc._contains_gcptr(lltype.Signed)
+ assert not rgc._contains_gcptr(
+ lltype.Struct('x', ('x', lltype.Signed)))
+ assert rgc._contains_gcptr(
+ lltype.Struct('x', ('x', lltype.Signed),
+ ('y', lltype.Ptr(lltype.GcArray(lltype.Signed)))))
+ assert rgc._contains_gcptr(
+ lltype.Struct('x', ('x', lltype.Signed),
+ ('y', llmemory.GCREF)))
+ assert rgc._contains_gcptr(lltype.Ptr(lltype.GcStruct('x')))
+ assert not rgc._contains_gcptr(lltype.Ptr(lltype.Struct('x')))
+ GCPTR = lltype.Ptr(lltype.GcStruct('x'))
+ assert rgc._contains_gcptr(
+ lltype.Struct('FOO', ('s', lltype.Struct('BAR', ('y', GCPTR)))))
+
def test_ll_arraycopy_small():
TYPE = lltype.GcArray(lltype.Signed)
for length in range(5):
diff --git a/pypy/rpython/lltypesystem/rffi.py b/pypy/rpython/lltypesystem/rffi.py
--- a/pypy/rpython/lltypesystem/rffi.py
+++ b/pypy/rpython/lltypesystem/rffi.py
@@ -1,6 +1,6 @@
import py
from pypy.annotation import model as annmodel
-from pypy.rpython.lltypesystem import lltype
+from pypy.rpython.lltypesystem import lltype, rstr
from pypy.rpython.lltypesystem import ll2ctypes
from pypy.rpython.lltypesystem.llmemory import cast_adr_to_ptr, cast_ptr_to_adr
from pypy.rpython.lltypesystem.llmemory import itemoffsetof, raw_memcopy
@@ -13,7 +13,7 @@
from pypy.rlib.unroll import unrolling_iterable
from pypy.rpython.tool.rfficache import platform, sizeof_c_type
from pypy.translator.tool.cbuild import ExternalCompilationInfo
-from pypy.rpython.annlowlevel import llhelper
+from pypy.rpython.annlowlevel import llhelper, llstr
from pypy.rlib.objectmodel import we_are_translated
from pypy.rlib.rstring import StringBuilder, UnicodeBuilder, assert_str0
from pypy.rlib import jit
@@ -279,9 +279,18 @@
callable_name = getattr(callable, '__name__', '?')
if callbackholder is not None:
callbackholder.callbacks[callable] = True
+ callable_name_descr = str(callable).replace('"', '\\"')
args = ', '.join(['a%d' % i for i in range(len(TP.TO.ARGS))])
source = py.code.Source(r"""
- def wrapper(%s): # no *args - no GIL for mallocing the tuple
+ def inner_wrapper(%(args)s):
+ if aroundstate is not None:
+ callback_hook = aroundstate.callback_hook
+ if callback_hook:
+ callback_hook(llstr("%(callable_name_descr)s"))
+ return callable(%(args)s)
+ inner_wrapper._never_inline_ = True
+
+ def wrapper(%(args)s): # no *args - no GIL for mallocing the tuple
llop.gc_stack_bottom(lltype.Void) # marker for trackgcroot.py
if aroundstate is not None:
after = aroundstate.after
@@ -290,7 +299,7 @@
# from now on we hold the GIL
stackcounter.stacks_counter += 1
try:
- result = callable(%s)
+ result = inner_wrapper(%(args)s)
except Exception, e:
os.write(2,
"Warning: uncaught exception in callback: %%s %%s\n" %%
@@ -308,10 +317,11 @@
# by llexternal, it is essential that no exception checking occurs
# after the call to before().
return result
- """ % (args, args))
+ """ % locals())
miniglobals = locals().copy()
miniglobals['Exception'] = Exception
miniglobals['os'] = os
+ miniglobals['llstr'] = llstr
miniglobals['we_are_translated'] = we_are_translated
miniglobals['stackcounter'] = stackcounter
exec source.compile() in miniglobals
@@ -319,10 +329,14 @@
_make_wrapper_for._annspecialcase_ = 'specialize:memo'
AroundFnPtr = lltype.Ptr(lltype.FuncType([], lltype.Void))
+CallbackHookPtr = lltype.Ptr(lltype.FuncType([lltype.Ptr(rstr.STR)], lltype.Void))
+
class AroundState:
+ callback_hook = None
+
def _cleanup_(self):
- self.before = None # or a regular RPython function
- self.after = None # or a regular RPython function
+ self.before = None # or a regular RPython function
+ self.after = None # or a regular RPython function
aroundstate = AroundState()
aroundstate._cleanup_()
diff --git a/pypy/rpython/lltypesystem/test/test_lltype.py b/pypy/rpython/lltypesystem/test/test_lltype.py
--- a/pypy/rpython/lltypesystem/test/test_lltype.py
+++ b/pypy/rpython/lltypesystem/test/test_lltype.py
@@ -808,7 +808,6 @@
assert F.RESULT == Signed
assert F.ARGS == (Signed,)
-
class TestTrackAllocation:
def test_automatic_tracking(self):
# calls to start_tracking_allocations/stop_tracking_allocations
diff --git a/pypy/rpython/memory/gc/minimark.py b/pypy/rpython/memory/gc/minimark.py
--- a/pypy/rpython/memory/gc/minimark.py
+++ b/pypy/rpython/memory/gc/minimark.py
@@ -2000,6 +2000,17 @@
(obj + offset).address[0] = llmemory.NULL
continue # no need to remember this weakref any longer
#
+ elif self.header(pointing_to).tid & GCFLAG_NO_HEAP_PTRS:
+ # see test_weakref_to_prebuilt: it's not useful to put
+ # weakrefs into 'old_objects_with_weakrefs' if they point
+ # to a prebuilt object (they are immortal). If moreover
+ # the 'pointing_to' prebuilt object still has the
+ # GCFLAG_NO_HEAP_PTRS flag, then it's even wrong, because
+ # 'pointing_to' will not get the GCFLAG_VISITED during
+ # the next major collection. Solve this by not registering
+ # the weakref into 'old_objects_with_weakrefs'.
+ continue
+ #
self.old_objects_with_weakrefs.append(obj)
def invalidate_old_weakrefs(self):
@@ -2013,6 +2024,9 @@
continue # weakref itself dies
offset = self.weakpointer_offset(self.get_type_id(obj))
pointing_to = (obj + offset).address[0]
+ ll_assert((self.header(pointing_to).tid & GCFLAG_NO_HEAP_PTRS)
+ == 0, "registered old weakref should not "
+ "point to a NO_HEAP_PTRS obj")
if self.header(pointing_to).tid & GCFLAG_VISITED:
new_with_weakref.append(obj)
else:
diff --git a/pypy/rpython/memory/test/test_gc.py b/pypy/rpython/memory/test/test_gc.py
--- a/pypy/rpython/memory/test/test_gc.py
+++ b/pypy/rpython/memory/test/test_gc.py
@@ -557,6 +557,19 @@
res = self.interpret(f, [20]) # for GenerationGC, enough for a minor collection
assert res == True
+ def test_weakref_to_prebuilt(self):
+ import weakref
+ class A:
+ pass
+ a = A()
+ def f(x):
+ ref = weakref.ref(a)
+ assert ref() is a
+ llop.gc__collect(lltype.Void)
+ return ref() is a
+ res = self.interpret(f, [20]) # for GenerationGC, enough for a minor collection
+ assert res == True
+
def test_many_weakrefs(self):
# test for the case where allocating the weakref itself triggers
# a collection
diff --git a/pypy/translator/goal/app_main.py b/pypy/translator/goal/app_main.py
--- a/pypy/translator/goal/app_main.py
+++ b/pypy/translator/goal/app_main.py
@@ -584,7 +584,12 @@
python_startup,
'exec')
exec co_python_startup in mainmodule.__dict__
+ mainmodule.__file__ = python_startup
run_toplevel(run_it)
+ try:
+ del mainmodule.__file__
+ except (AttributeError, TypeError):
+ pass
# Then we need a prompt.
inspect = True
else:
diff --git a/pypy/translator/goal/targetpypystandalone.py b/pypy/translator/goal/targetpypystandalone.py
--- a/pypy/translator/goal/targetpypystandalone.py
+++ b/pypy/translator/goal/targetpypystandalone.py
@@ -28,6 +28,11 @@
w_call_startup_gateway = space.wrap(gateway.interp2app(call_startup))
withjit = space.config.objspace.usemodules.pypyjit
+ if withjit:
+ from pypy.module.pypyjit.interp_jit import callback_hook
+ from pypy.rlib import objectmodel
+ objectmodel.register_around_callback_hook(callback_hook)
+
def entry_point(argv):
if withjit:
from pypy.jit.backend.hlinfo import highleveljitinfo
diff --git a/pypy/translator/goal/test2/test_app_main.py b/pypy/translator/goal/test2/test_app_main.py
--- a/pypy/translator/goal/test2/test_app_main.py
+++ b/pypy/translator/goal/test2/test_app_main.py
@@ -376,6 +376,30 @@
child.expect('Traceback')
child.expect('NameError')
+ def test_pythonstartup_file1(self, monkeypatch):
+ monkeypatch.setenv('PYTHONPATH', None)
+ monkeypatch.setenv('PYTHONSTARTUP', demo_script)
+ child = self.spawn([])
+ child.expect('File: [^\n]+\.py')
+ child.expect('goodbye')
+ child.expect('>>> ')
+ child.sendline('[myvalue]')
+ child.expect(re.escape('[42]'))
+ child.expect('>>> ')
+ child.sendline('__file__')
+ child.expect('Traceback')
+ child.expect('NameError')
+
+ def test_pythonstartup_file2(self, monkeypatch):
+ monkeypatch.setenv('PYTHONPATH', None)
+ monkeypatch.setenv('PYTHONSTARTUP', crashing_demo_script)
+ child = self.spawn([])
+ child.expect('Traceback')
+ child.expect('>>> ')
+ child.sendline('__file__')
+ child.expect('Traceback')
+ child.expect('NameError')
+
def test_ignore_python_startup(self):
old = os.environ.get('PYTHONSTARTUP', '')
try:
diff --git a/pypy/translator/platform/linux.py b/pypy/translator/platform/linux.py
--- a/pypy/translator/platform/linux.py
+++ b/pypy/translator/platform/linux.py
@@ -36,7 +36,13 @@
# places where we need to look for libffi.a
# XXX obscuuure! only look for libffi.a if run with translate.py
if 'translate' in sys.modules:
- return self.library_dirs_for_libffi() + ['/usr/lib']
+ if sys.maxint > 2**32:
+ host = 'x86_64'
+ else:
+ host = 'x86'
+ return self.library_dirs_for_libffi() + [
+ '/usr/lib',
+ '/usr/lib/%s-linux-gnu/' % host]
else:
return []
diff --git a/pypy/translator/platform/test/test_distutils.py b/pypy/translator/platform/test/test_distutils.py
--- a/pypy/translator/platform/test/test_distutils.py
+++ b/pypy/translator/platform/test/test_distutils.py
@@ -8,3 +8,6 @@
def test_nice_errors(self):
py.test.skip("Unsupported")
+
+ def test_900_files(self):
+ py.test.skip('Makefiles not suppoerted')
diff --git a/pypy/translator/platform/test/test_platform.py b/pypy/translator/platform/test/test_platform.py
--- a/pypy/translator/platform/test/test_platform.py
+++ b/pypy/translator/platform/test/test_platform.py
@@ -59,6 +59,34 @@
res = self.platform.execute(executable)
self.check_res(res)
+ def test_900_files(self):
+ txt = '#include <stdio.h>\n'
+ for i in range(900):
+ txt += 'int func%03d();\n' % i
+ txt += 'int main() {\n int j=0;'
+ for i in range(900):
+ txt += ' j += func%03d();\n' % i
+ txt += ' printf("%d\\n", j);\n'
+ txt += ' return 0;};\n'
+ cfile = udir.join('test_900_files.c')
+ cfile.write(txt)
+ cfiles = [cfile]
+ for i in range(900):
+ cfile2 = udir.join('implement%03d.c' %i)
+ cfile2.write('''
+ int func%03d()
+ {
+ return %d;
+ }
+ ''' % (i, i))
+ cfiles.append(cfile2)
+ mk = self.platform.gen_makefile(cfiles, ExternalCompilationInfo(), path=udir)
+ mk.write()
+ self.platform.execute_makefile(mk)
+ res = self.platform.execute(udir.join('test_900_files'))
+ self.check_res(res, '%d\n' %sum(range(900)))
+
+
def test_nice_errors(self):
cfile = udir.join('test_nice_errors.c')
cfile.write('')
diff --git a/pypy/translator/platform/windows.py b/pypy/translator/platform/windows.py
--- a/pypy/translator/platform/windows.py
+++ b/pypy/translator/platform/windows.py
@@ -326,17 +326,33 @@
for rule in rules:
m.rule(*rule)
-
+
+ objects = ' $(OBJECTS)'
+ create_obj_response_file = []
+ if len(' '.join(rel_ofiles)) > 4000:
+ # cmd.exe has a limit of ~4000 characters before a command line is too long.
+ # Use a response file instead, at the cost of making the Makefile very ugly.
+ for i in range(len(rel_ofiles) - 1):
+ create_obj_response_file.append('echo %s >> obj_names.rsp' % \
+ rel_ofiles[i])
+ # use cmd /c for the last one so that the file is flushed
+ create_obj_response_file.append('cmd /c echo %s >> obj_names.rsp' % \
+ rel_ofiles[-1])
+ objects = ' @obj_names.rsp'
if self.version < 80:
m.rule('$(TARGET)', '$(OBJECTS)',
- '$(CC_LINK) /nologo $(LDFLAGS) $(LDFLAGSEXTRA) $(OBJECTS) /out:$@ $(LIBDIRS) $(LIBS)')
+ create_obj_response_file + [\
+ '$(CC_LINK) /nologo $(LDFLAGS) $(LDFLAGSEXTRA)' + objects + ' /out:$@ $(LIBDIRS) $(LIBS)',
+ ])
else:
m.rule('$(TARGET)', '$(OBJECTS)',
- ['$(CC_LINK) /nologo $(LDFLAGS) $(LDFLAGSEXTRA) $(OBJECTS) $(LINKFILES) /out:$@ $(LIBDIRS) $(LIBS) /MANIFEST /MANIFESTFILE:$*.manifest',
+ create_obj_response_file + [\
+ '$(CC_LINK) /nologo $(LDFLAGS) $(LDFLAGSEXTRA)' + objects + ' $(LINKFILES) /out:$@ $(LIBDIRS) $(LIBS) /MANIFEST /MANIFESTFILE:$*.manifest',
'mt.exe -nologo -manifest $*.manifest -outputresource:$@;1',
])
m.rule('debugmode_$(TARGET)', '$(OBJECTS)',
- ['$(CC_LINK) /nologo /DEBUG $(LDFLAGS) $(LDFLAGSEXTRA) $(OBJECTS) $(LINKFILES) /out:$@ $(LIBDIRS) $(LIBS)',
+ create_obj_response_file + [\
+ '$(CC_LINK) /nologo /DEBUG $(LDFLAGS) $(LDFLAGSEXTRA)' + objects + ' $(LINKFILES) /out:$@ $(LIBDIRS) $(LIBS)',
])
if shared:
More information about the pypy-commit
mailing list