Author: Philip Jenvey <[email protected]>
Branch:
Changeset: r69137:2d71669b2c3c
Date: 2014-02-13 11:59 -0800
http://bitbucket.org/pypy/pypy/changeset/2d71669b2c3c/
Log: merge upstream
diff --git a/include/PyPy.h b/include/PyPy.h
new file mode 100644
--- /dev/null
+++ b/include/PyPy.h
@@ -0,0 +1,54 @@
+#ifndef _PYPY_H_
+#define _PYPY_H_
+
+/* This header is meant to be included in programs that use PyPy as an
+ embedded library. */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/* You should call this first once. */
+void rpython_startup_code(void);
+
+
+/* Initialize the home directory of PyPy. It is necessary to call this.
+
+ Call it with "home" being the file name of the libpypy.so, for
+ example; it will be used as a starting point when searching for the
+ lib-python and lib_pypy directories. They are searched from
+ "home/..", "home/../..", etc. Returns 0 if everything was fine. If
+ an error occurs, returns 1 and (if verbose != 0) prints some
+ information to stderr.
+ */
+int pypy_setup_home(char *home, int verbose);
+
+
+/* If your program has multiple threads, then you need to call
+ pypy_init_threads() once at init time, and then pypy_thread_attach()
+ once in each other thread that just started and in which you want to
+ run Python code (including via callbacks, see below).
+ */
+void pypy_init_threads(void);
+void pypy_thread_attach(void);
+
+
+/* The main entry point: executes "source" as plain Python code.
+ Returns 0 if everything was fine. If a Python exception is
+ uncaught, it is printed to stderr and 1 is returned.
+
+ Usually, the Python code from "source" should use cffi to fill in
+ global variables of "function pointer" type in your program. Use
+ cffi callbacks to do so. Once it is done, there is no need to call
+ pypy_execute_source() any more: from C, you call directly the
+ functions (which are "callbacks" from the point of view of Python).
+ */
+int pypy_execute_source(char *source);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/pypy/doc/project-ideas.rst b/pypy/doc/project-ideas.rst
--- a/pypy/doc/project-ideas.rst
+++ b/pypy/doc/project-ideas.rst
@@ -142,32 +142,17 @@
* `hg`
-Experiment (again) with LLVM backend for RPython compilation
-------------------------------------------------------------
-
-We already tried working with LLVM and at the time, LLVM was not mature enough
-for our needs. It's possible that this has changed, reviving the LLVM backend
-(or writing new from scratch) for static compilation would be a good project.
-
-(On the other hand, just generating C code and using clang might be enough.
-The issue with that is the so-called "asmgcc GC root finder", which has tons
-of issues of this own. In my opinion (arigo), it would be definitely a
-better project to try to optimize the alternative, the "shadowstack" GC root
-finder, which is nicely portable. So far it gives a pypy that is around
-7% slower.)
-
Embedding PyPy
----------------------------------------
Note: there is a basic proof-of-concept for that as a `uwsgi pypy plugin`_
Being able to embed PyPy, say with its own limited C API, would be
-useful. But here is the most interesting variant, straight from
-EuroPython live discussion :-) We can have a generic "libpypy.so" that
-can be used as a placeholder dynamic library, and when it gets loaded,
-it runs a .py module that installs (via ctypes) the interface it wants
-exported. This would give us a one-size-fits-all generic .so file to be
-imported by any application that wants to load .so files :-)
+useful. But there is a possibly better variant: use CFFI. With some
+minimal tools atop CFFI, it would be possible to write a pure Python
+library, and then compile automatically from it an .so/.dll file that is
+a dynamic-link library with whatever C API we want. This gives us a
+one-size-fits-all generic way to make .so/.dll files from Python.
.. _`uwsgi pypy plugin`: http://uwsgi-docs.readthedocs.org/en/latest/PyPy.html
diff --git a/pypy/goal/targetpypystandalone.py
b/pypy/goal/targetpypystandalone.py
--- a/pypy/goal/targetpypystandalone.py
+++ b/pypy/goal/targetpypystandalone.py
@@ -90,9 +90,10 @@
return f
""")
- @entrypoint('main', [rffi.CCHARP, lltype.Signed], c_name='pypy_setup_home')
+ @entrypoint('main', [rffi.CCHARP, rffi.INT], c_name='pypy_setup_home')
def pypy_setup_home(ll_home, verbose):
from pypy.module.sys.initpath import pypy_find_stdlib
+ verbose = rffi.cast(lltype.Signed, verbose)
if ll_home:
home = rffi.charp2str(ll_home)
else:
@@ -120,7 +121,8 @@
@entrypoint('main', [rffi.CCHARP], c_name='pypy_execute_source')
def pypy_execute_source(ll_source):
source = rffi.charp2str(ll_source)
- return _pypy_execute_source(source)
+ res = _pypy_execute_source(source)
+ return rffi.cast(rffi.INT, res)
@entrypoint('main', [], c_name='pypy_init_threads')
def pypy_init_threads():
diff --git a/pypy/interpreter/test/test_targetpypy.py
b/pypy/interpreter/test/test_targetpypy.py
--- a/pypy/interpreter/test/test_targetpypy.py
+++ b/pypy/interpreter/test/test_targetpypy.py
@@ -12,8 +12,10 @@
_, d = create_entry_point(space, None)
execute_source = d['pypy_execute_source']
lls = rffi.str2charp("import sys; sys.modules['xyz'] = 3")
- execute_source(lls)
+ res = execute_source(lls)
lltype.free(lls, flavor='raw')
+ assert lltype.typeOf(res) == rffi.INT
+ assert rffi.cast(lltype.Signed, res) == 0
x = space.int_w(space.getitem(space.getattr(space.builtin_modules['sys'],
space.wrap('modules')),
space.wrap('xyz')))
@@ -24,5 +26,5 @@
# did not crash - the same globals
pypy_setup_home = d['pypy_setup_home']
lls = rffi.str2charp(__file__)
- pypy_setup_home(lls, 1)
+ pypy_setup_home(lls, rffi.cast(rffi.INT, 1))
lltype.free(lls, flavor='raw')
diff --git a/pypy/module/bz2/interp_bz2.py b/pypy/module/bz2/interp_bz2.py
--- a/pypy/module/bz2/interp_bz2.py
+++ b/pypy/module/bz2/interp_bz2.py
@@ -31,7 +31,7 @@
_compilation_info_ = eci
calling_conv = 'c'
- CHECK_LIBRARY = platform.Has('dump("x", (int)&BZ2_bzCompress)')
+ CHECK_LIBRARY = platform.Has('dump("x", (long)&BZ2_bzCompress)')
off_t = platform.SimpleType("off_t", rffi.LONGLONG)
size_t = platform.SimpleType("size_t", rffi.ULONG)
diff --git a/rpython/memory/gc/incminimark.py b/rpython/memory/gc/incminimark.py
--- a/rpython/memory/gc/incminimark.py
+++ b/rpython/memory/gc/incminimark.py
@@ -1837,6 +1837,11 @@
#
if self.objects_with_finalizers.non_empty():
self.deal_with_objects_with_finalizers()
+ elif self.old_objects_with_weakrefs.non_empty():
+ # Weakref support: clear the weak pointers to dying objects
+ # (if we call deal_with_objects_with_finalizers(), it will
+ # invoke invalidate_old_weakrefs() itself directly)
+ self.invalidate_old_weakrefs()
ll_assert(not self.objects_to_trace.non_empty(),
"objects_to_trace should be empty")
@@ -1846,9 +1851,7 @@
self.more_objects_to_trace.delete()
#
- # Weakref support: clear the weak pointers to dying objects
- if self.old_objects_with_weakrefs.non_empty():
- self.invalidate_old_weakrefs()
+ # Light finalizers
if self.old_objects_with_light_finalizers.non_empty():
self.deal_with_old_objects_with_finalizers()
#objects_to_trace processed fully, can move on to sweeping
@@ -2206,6 +2209,12 @@
self._recursively_bump_finalization_state_from_2_to_3(y)
self._recursively_bump_finalization_state_from_1_to_2(x)
+ # Clear the weak pointers to dying objects. Also clears them if
+ # they point to objects which have the GCFLAG_FINALIZATION_ORDERING
+ # bit set here. These are objects which will be added to
+ # run_finalizers().
+ self.invalidate_old_weakrefs()
+
while marked.non_empty():
x = marked.popleft()
state = self._finalization_state(x)
@@ -2333,7 +2342,9 @@
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:
+ tid = self.header(pointing_to).tid
+ if ((tid & (GCFLAG_VISITED | GCFLAG_FINALIZATION_ORDERING)) ==
+ GCFLAG_VISITED):
new_with_weakref.append(obj)
else:
(obj + offset).address[0] = llmemory.NULL
diff --git a/rpython/memory/test/gc_test_base.py
b/rpython/memory/test/gc_test_base.py
--- a/rpython/memory/test/gc_test_base.py
+++ b/rpython/memory/test/gc_test_base.py
@@ -29,6 +29,7 @@
GC_CAN_SHRINK_ARRAY = False
GC_CAN_SHRINK_BIG_ARRAY = False
BUT_HOW_BIG_IS_A_BIG_STRING = 3*WORD
+ WREF_IS_INVALID_BEFORE_DEL_IS_CALLED = False
def setup_class(cls):
cls._saved_logstate = py.log._getstate()
@@ -370,15 +371,23 @@
class A(object):
count = 0
a = A()
+ expected_invalid = self.WREF_IS_INVALID_BEFORE_DEL_IS_CALLED
class B(object):
def __del__(self):
# when __del__ is called, the weakref to myself is still valid
- # in RPython (at least with most GCs; this test might be
- # skipped for specific GCs)
- if self.ref() is self:
- a.count += 10 # ok
+ # in RPython with most GCs. However, this can lead to strange
+ # bugs with incminimark. https://bugs.pypy.org/issue1687
+ # So with incminimark, we expect the opposite.
+ if expected_invalid:
+ if self.ref() is None:
+ a.count += 10 # ok
+ else:
+ a.count = 666 # not ok
else:
- a.count = 666 # not ok
+ if self.ref() is self:
+ a.count += 10 # ok
+ else:
+ a.count = 666 # not ok
def g():
b = B()
ref = weakref.ref(b)
diff --git a/rpython/memory/test/test_incminimark_gc.py
b/rpython/memory/test/test_incminimark_gc.py
--- a/rpython/memory/test/test_incminimark_gc.py
+++ b/rpython/memory/test/test_incminimark_gc.py
@@ -1,6 +1,38 @@
-from rpython.rlib.rarithmetic import LONG_BIT
+from rpython.rtyper.lltypesystem import lltype
+from rpython.rtyper.lltypesystem.lloperation import llop
from rpython.memory.test import test_minimark_gc
class TestIncrementalMiniMarkGC(test_minimark_gc.TestMiniMarkGC):
from rpython.memory.gc.incminimark import IncrementalMiniMarkGC as GCClass
+ WREF_IS_INVALID_BEFORE_DEL_IS_CALLED = True
+
+ def test_weakref_not_in_stack(self):
+ import weakref
+ class A(object):
+ pass
+ class B(object):
+ def __init__(self, next):
+ self.next = next
+ def g():
+ a = A()
+ a.x = 5
+ wr = weakref.ref(a)
+ llop.gc__collect(lltype.Void) # make everything old
+ assert wr() is not None
+ assert a.x == 5
+ return wr
+ def f():
+ ref = g()
+ llop.gc__collect(lltype.Void, 1) # start a major cycle
+ # at this point the stack is scanned, and the weakref points
+ # to an object not found, but still reachable:
+ b = ref()
+ llop.debug_print(lltype.Void, b)
+ assert b is not None
+ llop.gc__collect(lltype.Void) # finish the major cycle
+ # assert does not crash, because 'b' is still kept alive
+ b.x = 42
+ return ref() is b
+ res = self.interpret(f, [])
+ assert res == True
diff --git a/rpython/rlib/objectmodel.py b/rpython/rlib/objectmodel.py
--- a/rpython/rlib/objectmodel.py
+++ b/rpython/rlib/objectmodel.py
@@ -366,6 +366,9 @@
def compute_result_annotation(self, s_l, s_sizehint):
from rpython.annotator import model as annmodel
+ if annmodel.s_None.contains(s_l):
+ return # first argument is only None so far, but we
+ # expect a generalization later
if not isinstance(s_l, annmodel.SomeList):
raise annmodel.AnnotatorError("First argument must be a list")
if not isinstance(s_sizehint, annmodel.SomeInteger):
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit