Author: Philip Jenvey <pjen...@underboss.org>
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
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to