[pypy-commit] pypy cpyext-gc-cycle: Added additional flags for objects

2019-01-11 Thread stevie_92
Author: Stefan Beyer 
Branch: cpyext-gc-cycle
Changeset: r95598:c03fe327893a
Date: 2018-03-19 10:52 +0100
http://bitbucket.org/pypy/pypy/changeset/c03fe327893a/

Log:Added additional flags for objects Implemented refcount overhead
(for non-cyclic refcount) Implemented buffer for potential roots of
cycles Fixed assert to allow for recursive cpyext calls Added some
cycle detection tests from experimental branch (disabled now)

diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py
--- a/pypy/module/cpyext/api.py
+++ b/pypy/module/cpyext/api.py
@@ -208,10 +208,11 @@
 # running and should not themselves release the GIL).
 #
 # **make_generic_cpy_call():** RPython to C, with the GIL held.  Before
-# the call, must assert that the global variable is 0 and set the
-# current thread identifier into the global variable.  After the call,
-# assert that the global variable still contains the current thread id,
-# and reset it to 0.
+# the call, must assert that the global variable is 0 or the current
+# thread identifier (recursive call) and set the current thread identifier
+# into the global variable.  After the call, assert that the global variable
+# still contains the current thread id, and reset it to the value it held
+# before the call.
 #
 # **make_wrapper():** C to RPython; by default assume that the GIL is
 # held, but accepts gil="acquire", "release", "around",
@@ -1763,7 +1764,8 @@
 
 # see "Handling of the GIL" above
 tid = rthread.get_ident()
-assert cpyext_glob_tid_ptr[0] == 0
+tid_before = cpyext_glob_tid_ptr[0]
+assert tid_before == 0 or tid_before == tid
 cpyext_glob_tid_ptr[0] = tid
 
 preexist_error = PyErr_Occurred(space)
@@ -1772,7 +1774,7 @@
 result = call_external_function(func, *boxed_args)
 finally:
 assert cpyext_glob_tid_ptr[0] == tid
-cpyext_glob_tid_ptr[0] = 0
+cpyext_glob_tid_ptr[0] = tid_before
 for i, ARG in unrolling_arg_types:
 # note that this loop is nicely unrolled statically by RPython
 _pyobj = to_decref[i]
diff --git a/pypy/module/cpyext/include/boolobject.h 
b/pypy/module/cpyext/include/boolobject.h
--- a/pypy/module/cpyext/include/boolobject.h
+++ b/pypy/module/cpyext/include/boolobject.h
@@ -13,8 +13,8 @@
 #define Py_True ((PyObject *) &_Py_TrueStruct)
 
 /* Macros for returning Py_True or Py_False, respectively */
-#define Py_RETURN_TRUE return Py_INCREF(Py_True), Py_True
-#define Py_RETURN_FALSE return Py_INCREF(Py_False), Py_False
+#define Py_RETURN_TRUE do { Py_INCREF(Py_True); return Py_True; } while(0)
+#define Py_RETURN_FALSE do { Py_INCREF(Py_False); return Py_False; } while(0)
 
 #ifdef __cplusplus
 }
diff --git a/pypy/module/cpyext/include/object.h 
b/pypy/module/cpyext/include/object.h
--- a/pypy/module/cpyext/include/object.h
+++ b/pypy/module/cpyext/include/object.h
@@ -2,6 +2,7 @@
 #define Py_OBJECT_H
 
 #include 
+#include 
 
 #ifdef __cplusplus
 extern "C" {
@@ -12,7 +13,13 @@
 #define PY_SSIZE_T_MAX ((Py_ssize_t)(((size_t)-1)>>1))
 #define PY_SSIZE_T_MIN (-PY_SSIZE_T_MAX-1)
 
-#define Py_RETURN_NONE return Py_INCREF(Py_None), Py_None
+#define PY_REFCNT_FROM_PYPY (4L << ((long)(log(PY_SSIZE_T_MAX) / log(2) - 2)))
+#define PY_REFCNT_GREEN (4L << ((long)(log(PY_SSIZE_T_MAX) / log(2) - 7)))
+#define PY_REFCNT_OVERFLOW (1L << ((long)(log(PY_SSIZE_T_MAX) / log(2) - 7) / 
2L - 1L))
+#define PY_REFCNT_MASK ((PY_REFCNT_OVERFLOW << 1L) - 1L)
+#define Py_RETURN_NONE return (PyObject *)(Py_None))->ob_refcnt & 
PY_REFCNT_OVERFLOW) == 0) ? \
+  ((PyObject *)(Py_None))->ob_refcnt++ : 
Py_IncRef((PyObject *)(Py_None))), Py_None
+
 
 /*
 CPython has this for backwards compatibility with really old extensions, and 
now
@@ -34,14 +41,21 @@
 #define Py_XDECREF(ob)  (Py_DecRef((PyObject *)(ob)))
 #else
 /* Fast version */
-#define Py_INCREF(ob)   (((PyObject *)(ob))->ob_refcnt++)
-#define Py_DECREF(op)   \
-do {\
-if (--((PyObject *)(op))->ob_refcnt != 0)   \
-;   \
-else\
-_Py_Dealloc((PyObject *)(op));  \
-} while (0)
+#define Py_INCREF(ob)   do {   
  \
+if (!(((PyObject *)(ob))->ob_refcnt & 
PY_REFCNT_OVERFLOW))   \
+((PyObject *)(ob))->ob_refcnt++;   
  \
+else   
  \
+Py_IncRef((PyObject *)(ob));   
 \
+} while (0)
+#define Py_DECREF(ob)   do {   
  \
+  

[pypy-commit] pypy cpyext-gc-cycle: Removed unnecessary code

2019-01-11 Thread stevie_92
Author: Stefan Beyer 
Branch: cpyext-gc-cycle
Changeset: r95602:65ead3f78618
Date: 2018-04-12 10:21 +0200
http://bitbucket.org/pypy/pypy/changeset/65ead3f78618/

Log:Removed unnecessary code

diff --git a/pypy/module/cpyext/include/object.h 
b/pypy/module/cpyext/include/object.h
--- a/pypy/module/cpyext/include/object.h
+++ b/pypy/module/cpyext/include/object.h
@@ -14,8 +14,7 @@
 #define PY_SSIZE_T_MIN (-PY_SSIZE_T_MAX-1)
 
 #define PY_REFCNT_FROM_PYPY (4L << ((long)(log(PY_SSIZE_T_MAX) / log(2) - 2)))
-#define PY_REFCNT_GREEN (4L << ((long)(log(PY_SSIZE_T_MAX) / log(2) - 7)))
-#define PY_REFCNT_OVERFLOW (1L << ((long)(log(PY_SSIZE_T_MAX) / log(2) - 7) / 
2L - 1L))
+#define PY_REFCNT_OVERFLOW (1L << ((long)(log(PY_SSIZE_T_MAX) / log(2) - 4) - 
1L))
 #define PY_REFCNT_MASK ((PY_REFCNT_OVERFLOW << 1L) - 1L)
 #define Py_RETURN_NONE return (PyObject *)(Py_None))->ob_refcnt & 
PY_REFCNT_OVERFLOW) == 0) ? \
   ((PyObject *)(Py_None))->ob_refcnt++ : 
Py_IncRef((PyObject *)(Py_None))), Py_None
@@ -48,12 +47,11 @@
 Py_IncRef((PyObject *)(ob));   
 \
 } while (0)
 #define Py_DECREF(ob)   do {   
  \
-if (!(((PyObject *)(ob))->ob_refcnt & 
PY_REFCNT_GREEN) ||\
-(((PyObject *)(ob))->ob_refcnt & 
PY_REFCNT_OVERFLOW))\
-Py_DecRef((PyObject *)(ob));   
 \
+if PyObject *)(ob))->ob_refcnt & 
PY_REFCNT_OVERFLOW))\
+Py_DecRef((PyObject *)(ob));   
  \
 else if (--((PyObject *)(ob))->ob_refcnt & 
PY_REFCNT_MASK)   \
 ;  
  \
-else if ((!((PyObject *)(ob))->ob_refcnt) & 
PY_REFCNT_FROM_PYPY) \
+else   
  \
 _Py_Dealloc((PyObject *)(ob)); 
  \
 } while (0)
 
diff --git a/pypy/module/cpyext/pyobject.py b/pypy/module/cpyext/pyobject.py
--- a/pypy/module/cpyext/pyobject.py
+++ b/pypy/module/cpyext/pyobject.py
@@ -18,9 +18,8 @@
 from rpython.rtyper.annlowlevel import llhelper, cast_instance_to_base_ptr
 from rpython.rlib import rawrefcount, jit
 from rpython.rlib.debug import ll_assert, fatalerror, debug_print
-from rpython.rlib.rawrefcount import (
-REFCNT_MASK, REFCNT_FROM_PYPY, REFCNT_OVERFLOW, REFCNT_CYCLE_BUFFERED,
-REFCNT_CLR_MASK, REFCNT_CLR_GREEN, REFCNT_CLR_PURPLE)
+from rpython.rlib.rawrefcount import (REFCNT_MASK, REFCNT_FROM_PYPY,
+  REFCNT_OVERFLOW)
 from pypy.module.cpyext.api import slot_function
 from pypy.module.cpyext.typeobjectdefs import visitproc
 
@@ -401,31 +400,13 @@
 rawrefcount.decref(pyobj)
 rc = pyobj.c_ob_refcnt
 if rc & REFCNT_MASK == 0:
-if rc & REFCNT_FROM_PYPY == 0 and rc & REFCNT_CLR_MASK != 
REFCNT_CLR_PURPLE:
-state = space.fromcache(State)
-generic_cpy_call(space, state.C._Py_Dealloc, pyobj)
-elif rc & REFCNT_CLR_MASK != REFCNT_CLR_GREEN:
-possible_root(space, pyobj)
+state = space.fromcache(State)
+generic_cpy_call(space, state.C._Py_Dealloc, pyobj)
 #else:
 #w_obj = rawrefcount.to_obj(W_Root, ref)
 #if w_obj is not None:
 #assert pyobj.c_ob_refcnt >= rawrefcount.REFCNT_FROM_PYPY
 
-@jit.dont_look_inside
-def possible_root(space, obj):
-#debug_print("possible root", obj)
-rc = obj.c_ob_refcnt
-if not obj.c_ob_type or not obj.c_ob_type.c_tp_traverse:
-#debug_print("mark green", obj)
-rc = rc & ~REFCNT_CLR_MASK | REFCNT_CLR_GREEN
-elif rc & REFCNT_CLR_MASK != REFCNT_CLR_PURPLE:
-rc = rc & ~REFCNT_CLR_MASK | REFCNT_CLR_PURPLE
-if rc & REFCNT_CYCLE_BUFFERED == 0:
-#debug_print("mark purple", obj)
-rawrefcount.buffer_pyobj(obj)
-rc = rc | REFCNT_CYCLE_BUFFERED
-obj.c_ob_refcnt = rc
-
 @cpython_api([PyObject], lltype.Void)
 def Py_IncRef(space, obj):
 incref(space, obj)
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
@@ -3067,9 +3067,6 @@
 objint = llmemory.cast_adr_to_int(obj, "symbolic")
 self._pyobj(pyobject).c_ob_pypy_link = objint
 
-def rawrefcount_buffer_pyobj(self, pyobject):
-self.rrc_buffered.append(pyobject)
-
 def rawrefcount_from_obj(self, gcobj):
 obj = llmemory.cast_ptr_to_adr(gcobj)
 if self.is_in_nursery(obj):
@@ -3254,12 

[pypy-commit] pypy cpyext-gc-cycle: Fixed cpyext test

2019-01-11 Thread stevie_92
Author: Stefan Beyer 
Branch: cpyext-gc-cycle
Changeset: r95611:fa88e83164e0
Date: 2018-08-03 13:11 +0200
http://bitbucket.org/pypy/pypy/changeset/fa88e83164e0/

Log:Fixed cpyext test

diff --git a/pypy/module/cpyext/test/test_cpyext.py 
b/pypy/module/cpyext/test/test_cpyext.py
--- a/pypy/module/cpyext/test/test_cpyext.py
+++ b/pypy/module/cpyext/test/test_cpyext.py
@@ -3,7 +3,7 @@
 import pytest
 
 from pypy.tool.cpyext.extbuild import SystemCompilationInfo, HERE
-from pypy.interpreter.gateway import unwrap_spec, interp2app
+from pypy.interpreter.gateway import unwrap_spec, interp2app, ObjSpace
 from pypy.interpreter.error import OperationError
 from rpython.rtyper.lltypesystem import lltype
 from pypy.module.cpyext import api
@@ -214,8 +214,8 @@
 def debug_collect(space):
 rawrefcount._collect()
 
-def print_pyobj_list(space):
-rawrefcount._print_pyobj_list()
+def in_pygclist(space, int_addr):
+return space.wrap(rawrefcount._in_pygclist(int_addr))
 
 class AppTestCpythonExtensionBase(LeakCheckingTest):
 
@@ -227,7 +227,8 @@
 if not cls.runappdirect:
 cls.sys_info = get_cpyext_info(space)
 cls.w_debug_collect = space.wrap(interp2app(debug_collect))
-cls.w_print_pyobj_list = space.wrap(interp2app(print_pyobj_list))
+cls.w_in_pygclist = space.wrap(
+interp2app(in_pygclist, unwrap_spec=[ObjSpace, int]))
 cls.preload_builtins(space)
 else:
 def w_import_module(self, name, init=None, body='', filename=None,
@@ -929,7 +930,7 @@
  ),
 ])
 
-def test_gc_pyobj_list(self):
+def test_gc_track(self):
 """
 Test if Py_GC_Track and Py_GC_Untrack are adding and removing container
 objects from the list of all garbage-collected PyObjects.
@@ -937,17 +938,16 @@
 if self.runappdirect:
 skip('cannot import module with undefined functions')
 
-# TODO: remove unnecessary stuff, add gc_(un)track asserts
 init = """
 if (Py_IsInitialized()) {
 PyObject* m;
-if (PyType_Ready() < 0)
+if (PyType_Ready() < 0)
 return;
-m = Py_InitModule("cycle", module_methods);
+m = Py_InitModule("foo", module_methods);
 if (m == NULL)
 return;
-Py_INCREF();
-PyModule_AddObject(m, "Cycle", (PyObject *));
+Py_INCREF();
+PyModule_AddObject(m, "Foo", (PyObject *));
 }
 """
 body = """
@@ -955,85 +955,22 @@
 #include "structmember.h"
 typedef struct {
 PyObject_HEAD
-PyObject *next;
-PyObject *val;
-} Cycle;
-static PyTypeObject CycleType;
-static int Cycle_traverse(Cycle *self, visitproc visit, void *arg)
-{
-int vret;
-if (self->next) {
-vret = visit(self->next, arg);
-if (vret != 0)
-return vret;
-}
-if (self->val) {
-vret = visit(self->val, arg);
-if (vret != 0)
-return vret;
-}
-return 0;
-}
-static int Cycle_clear(Cycle *self)
-{
-PyObject *tmp;
-tmp = self->next;
-self->next = NULL;
-Py_XDECREF(tmp);
-tmp = self->val;
-self->val = NULL;
-Py_XDECREF(tmp);
-return 0;
-}
-static void Cycle_dealloc(Cycle* self)
-{
-Cycle_clear(self);
-Py_TYPE(self)->tp_free((PyObject*)self);
-}
-static PyObject* Cycle_new(PyTypeObject *type, PyObject *args,
+} Foo;
+static PyTypeObject FooType;
+static PyObject* Foo_new(PyTypeObject *type, PyObject *args,
PyObject *kwds)
 {
-Cycle *self;
-self = PyObject_GC_New(Cycle, type);
-if (self != NULL) {
-self->next = PyString_FromString("");
-if (self->next == NULL) {
-Py_DECREF(self);
-return NULL;
-}
-}
+Foo *self;
+self = PyObject_GC_New(Foo, type);
 PyObject_GC_Track(self);
 return (PyObject *)self;
 }
-static int Cycle_init(Cycle *self, PyObject *args, PyObject *kwds)
-{
-PyObject *next=NULL, *tmp;
-static char *kwlist[] = {"next", NULL};
-if (! PyArg_ParseTupleAndKeywords(args, kwds, "|O", kwlist,
-  ))
-return -1;
-if (next) {
-tmp = self->next;
-Py_INCREF(next);
-self->next = next;
-Py_XDECREF(tmp);
-}
-return 0;
-}
-   

[pypy-commit] pypy cpyext-gc-cycle: Call tp_traverse from incminimark

2019-01-11 Thread stevie_92
Author: Stefan Beyer 
Branch: cpyext-gc-cycle
Changeset: r95599:fb1c6fe11349
Date: 2018-03-20 16:38 +0100
http://bitbucket.org/pypy/pypy/changeset/fb1c6fe11349/

Log:Call tp_traverse from incminimark Mark cpython objects reachable by
pypy objects

diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py
--- a/pypy/module/cpyext/api.py
+++ b/pypy/module/cpyext/api.py
@@ -1293,7 +1293,10 @@
 # if do tuple_attach of the prebuilt empty tuple, we need to call
 # _PyPy_Malloc)
 builder.attach_all(space)
-
+
+#import rpython.rlib.rawrefcount
+#rawrefcount.init_traverse(generic_cpy_call_gc)
+
 setup_init_functions(eci, prefix)
 return modulename.new(ext='')
 
@@ -1716,6 +1719,11 @@
 return make_generic_cpy_call(FT, False)(space, func, *args)
 
 @specialize.ll()
+def generic_cpy_call_gc(func, *args):
+FT = lltype.typeOf(func).TO
+return make_generic_cpy_call_gc(FT, False)(func, *args)
+
+@specialize.ll()
 def generic_cpy_call_expect_null(space, func, *args):
 FT = lltype.typeOf(func).TO
 return make_generic_cpy_call(FT, True)(space, func, *args)
@@ -1815,3 +1823,75 @@
 return result
 
 return generic_cpy_call
+
+@specialize.memo()
+def make_generic_cpy_call_gc(FT, expect_null):
+from pypy.module.cpyext.pyobject import is_pyobj, make_ref, decref
+from pypy.module.cpyext.pyobject import get_w_obj_and_decref
+from pypy.module.cpyext.pyerrors import PyErr_Occurred
+unrolling_arg_types = unrolling_iterable(enumerate(FT.ARGS))
+RESULT_TYPE = FT.RESULT
+
+# copied and modified from rffi.py
+# We need tons of care to ensure that no GC operation and no
+# exception checking occurs in call_external_function.
+argnames = ', '.join(['a%d' % i for i in range(len(FT.ARGS))])
+source = py.code.Source("""
+def cpy_call_external(funcptr, %(argnames)s):
+# NB. it is essential that no exception checking occurs here!
+res = funcptr(%(argnames)s)
+return res
+""" % locals())
+miniglobals = {'__name__':__name__, # for module name propagation
+   }
+exec source.compile() in miniglobals
+call_external_function = specialize.ll()(miniglobals['cpy_call_external'])
+call_external_function._dont_inline_ = True
+call_external_function._gctransformer_hint_close_stack_ = True
+# don't inline, as a hack to guarantee that no GC pointer is alive
+# anywhere in call_external_function
+
+@specialize.ll()
+def generic_cpy_call(func, *args):
+boxed_args = ()
+to_decref = ()
+assert len(args) == len(FT.ARGS)
+for i, ARG in unrolling_arg_types:
+arg = args[i]
+_pyobj = None
+if is_PyObject(ARG):
+assert is_pyobj(arg)
+
+boxed_args += (arg,)
+to_decref += (_pyobj,)
+
+# see "Handling of the GIL" above
+tid = rthread.get_ident()
+tid_before = cpyext_glob_tid_ptr[0]
+assert tid_before == 0 or tid_before == tid
+cpyext_glob_tid_ptr[0] = tid
+
+try:
+# Call the function
+result = call_external_function(func, *boxed_args)
+finally:
+assert cpyext_glob_tid_ptr[0] == tid
+cpyext_glob_tid_ptr[0] = tid_before
+for i, ARG in unrolling_arg_types:
+# note that this loop is nicely unrolled statically by RPython
+_pyobj = to_decref[i]
+if _pyobj is not None:
+pyobj = rffi.cast(PyObject, _pyobj)
+rawrefcount.decref(pyobj)
+
+if is_PyObject(RESULT_TYPE):
+ret = None
+
+# Check for exception consistency
+# XXX best attempt, will miss preexisting error that is
+# overwritten with a new error of the same type
+
+return ret
+return result
+
+return generic_cpy_call
\ No newline at end of file
diff --git a/pypy/module/cpyext/include/object.h 
b/pypy/module/cpyext/include/object.h
--- a/pypy/module/cpyext/include/object.h
+++ b/pypy/module/cpyext/include/object.h
@@ -321,6 +321,8 @@
 #define _PyGC_FINALIZED(o) 1
 #define PyType_IS_GC(tp) 1
 
+/* TODO: implement like in cpython
+   (see 
https://github.com/python/cpython/blob/517da1e58f4c489d4b31579852cde5f7113da08e/Include/objimpl.h#L295)
 */
 #define PyObject_GC_Track(o)  do { } while(0)
 #define PyObject_GC_UnTrack(o)do { } while(0)
 #define _PyObject_GC_TRACK(o) do { } while(0)
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
@@ -193,13 +193,27 @@
 VISIT_FUNCTYPE = rffi.CCallback([PyObject, rffi.VOIDP],
 rffi.INT_real)
 
-def traverse(obj, func_ptr):
-from pypy.module.cpyext.api import generic_cpy_call
-from pypy.module.cpyext.typeobjectdefs import 

[pypy-commit] pypy cpyext-gc-cycle: Implemented cpython-like GC list for cpyext

2019-01-11 Thread stevie_92
Author: Stefan Beyer 
Branch: cpyext-gc-cycle
Changeset: r95604:e5ba3fd47f96
Date: 2018-07-04 17:56 +0200
http://bitbucket.org/pypy/pypy/changeset/e5ba3fd47f96/

Log:Implemented cpython-like GC list for cpyext Added some code for
cpyext-only boehm GC support

diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py
--- a/pypy/module/cpyext/api.py
+++ b/pypy/module/cpyext/api.py
@@ -751,6 +751,8 @@
 PyVarObjectFields = PyObjectFields + (("ob_size", Py_ssize_t), )
 PyVarObjectStruct = cts.gettype('PyVarObject')
 PyVarObject = cts.gettype('PyVarObject *')
+PyGC_Head = cts.gettype('PyGC_Head')
+PyGC_HeadPtr = cts.gettype('PyGC_Head *')
 
 Py_buffer = cts.gettype('Py_buffer')
 Py_bufferP = cts.gettype('Py_buffer *')
@@ -1173,6 +1175,9 @@
 state.C._PyPy_object_dealloc = rffi.llexternal(
 '_PyPy_object_dealloc', [PyObject], lltype.Void,
 compilation_info=eci, _nowrapper=True)
+state.C._PyPy_InitPyObjList = rffi.llexternal(
+'_PyPy_InitPyObjList', [], PyGC_HeadPtr,
+compilation_info=eci, _nowrapper=True)
 
 
 def init_function(func):
@@ -1294,6 +1299,9 @@
 ll2ctypes.lltype2ctypes(func.get_llhelper(space)),
 ctypes.c_void_p)
 
+# initialize the pyobj_list for the gc
+space.fromcache(State).C._PyPy_InitPyObjList()
+
 # we need to call this *after* the init code above, because it might
 # indirectly call some functions which are attached to pypyAPI (e.g., we
 # if do tuple_attach of the prebuilt empty tuple, we need to call
@@ -1826,75 +1834,3 @@
 return result
 
 return generic_cpy_call
-
-@specialize.memo()
-def make_generic_cpy_call_gc(FT, expect_null):
-from pypy.module.cpyext.pyobject import is_pyobj, make_ref, decref
-from pypy.module.cpyext.pyobject import get_w_obj_and_decref
-from pypy.module.cpyext.pyerrors import PyErr_Occurred
-unrolling_arg_types = unrolling_iterable(enumerate(FT.ARGS))
-RESULT_TYPE = FT.RESULT
-
-# copied and modified from rffi.py
-# We need tons of care to ensure that no GC operation and no
-# exception checking occurs in call_external_function.
-argnames = ', '.join(['a%d' % i for i in range(len(FT.ARGS))])
-source = py.code.Source("""
-def cpy_call_external(funcptr, %(argnames)s):
-# NB. it is essential that no exception checking occurs here!
-res = funcptr(%(argnames)s)
-return res
-""" % locals())
-miniglobals = {'__name__':__name__, # for module name propagation
-   }
-exec source.compile() in miniglobals
-call_external_function = specialize.ll()(miniglobals['cpy_call_external'])
-call_external_function._dont_inline_ = True
-call_external_function._gctransformer_hint_close_stack_ = True
-# don't inline, as a hack to guarantee that no GC pointer is alive
-# anywhere in call_external_function
-
-@specialize.ll()
-def generic_cpy_call(func, *args):
-boxed_args = ()
-to_decref = ()
-assert len(args) == len(FT.ARGS)
-for i, ARG in unrolling_arg_types:
-arg = args[i]
-_pyobj = None
-if is_PyObject(ARG):
-assert is_pyobj(arg)
-
-boxed_args += (arg,)
-to_decref += (_pyobj,)
-
-# see "Handling of the GIL" above
-tid = rthread.get_ident()
-tid_before = cpyext_glob_tid_ptr[0]
-assert tid_before == 0 or tid_before == tid
-cpyext_glob_tid_ptr[0] = tid
-
-try:
-# Call the function
-result = call_external_function(func, *boxed_args)
-finally:
-assert cpyext_glob_tid_ptr[0] == tid
-cpyext_glob_tid_ptr[0] = tid_before
-for i, ARG in unrolling_arg_types:
-# note that this loop is nicely unrolled statically by RPython
-_pyobj = to_decref[i]
-if _pyobj is not None:
-pyobj = rffi.cast(PyObject, _pyobj)
-rawrefcount.decref(pyobj)
-
-if is_PyObject(RESULT_TYPE):
-ret = None
-
-# Check for exception consistency
-# XXX best attempt, will miss preexisting error that is
-# overwritten with a new error of the same type
-
-return ret
-return result
-
-return generic_cpy_call
\ No newline at end of file
diff --git a/pypy/module/cpyext/include/object.h 
b/pypy/module/cpyext/include/object.h
--- a/pypy/module/cpyext/include/object.h
+++ b/pypy/module/cpyext/include/object.h
@@ -279,7 +279,7 @@
  ) & ~(SIZEOF_VOID_P - 1)  \
)
 
-
+
 #define PyObject_INIT(op, typeobj) \
 ( Py_TYPE(op) = (typeobj), ((PyObject *)(op))->ob_refcnt = 1,\
   ((PyObject *)(op))->ob_pypy_link = 0, (op) )
@@ -309,22 +309,65 @@
 
 #define PyObject_GC_NewVar(type, typeobj, n) \
 ( (type *) _PyObject_GC_NewVar((typeobj), (n)) )
- 

[pypy-commit] pypy cpyext-gc-cycle: Fixed some formatting issues

2019-01-11 Thread stevie_92
Author: Stefan Beyer 
Branch: cpyext-gc-cycle
Changeset: r95613:80824650968a
Date: 2018-08-24 09:30 +0200
http://bitbucket.org/pypy/pypy/changeset/80824650968a/

Log:Fixed some formatting issues

diff --git a/pypy/module/cpyext/parse/cpyext_object.h 
b/pypy/module/cpyext/parse/cpyext_object.h
--- a/pypy/module/cpyext/parse/cpyext_object.h
+++ b/pypy/module/cpyext/parse/cpyext_object.h
@@ -332,4 +332,4 @@
 typedef struct _gchdr_pyobject {
 Py_ssize_t ob_refcnt;
 Py_ssize_t ob_pypy_link;
-} GCHdr_PyObject;
\ No newline at end of file
+} GCHdr_PyObject;
diff --git a/pypy/module/cpyext/pyobject.py b/pypy/module/cpyext/pyobject.py
--- a/pypy/module/cpyext/pyobject.py
+++ b/pypy/module/cpyext/pyobject.py
@@ -406,6 +406,7 @@
 #if w_obj is not None:
 #assert pyobj.c_ob_refcnt >= rawrefcount.REFCNT_FROM_PYPY
 
+
 @init_function
 def write_w_marker_deallocating(space):
 if we_are_translated():
diff --git a/pypy/module/cpyext/src/object.c b/pypy/module/cpyext/src/object.c
--- a/pypy/module/cpyext/src/object.c
+++ b/pypy/module/cpyext/src/object.c
@@ -221,4 +221,4 @@
 {
 obj->ob_size = size;
 return (PyVarObject*)PyObject_Init((PyObject*)obj, type);
-}
\ No newline at end of file
+}
___
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit


[pypy-commit] pypy cpyext-gc-cycle: Implemented pyobj as gc and vice-versa

2019-01-11 Thread stevie_92
Author: Stefan Beyer 
Branch: cpyext-gc-cycle
Changeset: r95607:a189719f68e4
Date: 2018-07-06 23:56 +0200
http://bitbucket.org/pypy/pypy/changeset/a189719f68e4/

Log:Implemented pyobj as gc and vice-versa Cleaned cpyext and
gc/rawrefcount tests Cleaned translation options

diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py
--- a/pypy/module/cpyext/api.py
+++ b/pypy/module/cpyext/api.py
@@ -43,7 +43,6 @@
 from rpython.rlib import rstackovf
 from pypy.objspace.std.typeobject import W_TypeObject, find_best_base
 from pypy.module.cpyext.cparser import CTypeSpace
-from rpython.rlib.debug import ll_assert, debug_print, debug_start, debug_stop
 
 DEBUG_WRAPPER = True
 
@@ -753,6 +752,7 @@
 PyVarObject = cts.gettype('PyVarObject *')
 PyGC_Head = cts.gettype('PyGC_Head')
 PyGC_HeadPtr = cts.gettype('PyGC_Head *')
+GCHdr_PyObject = cts.gettype('GCHdr_PyObject *')
 
 Py_buffer = cts.gettype('Py_buffer')
 Py_bufferP = cts.gettype('Py_buffer *')
@@ -1175,8 +1175,17 @@
 state.C._PyPy_object_dealloc = rffi.llexternal(
 '_PyPy_object_dealloc', [PyObject], lltype.Void,
 compilation_info=eci, _nowrapper=True)
-state.C._PyPy_InitPyObjList = rffi.llexternal(
-'_PyPy_InitPyObjList', [], PyGC_HeadPtr,
+state.C._PyPy_subtype_dealloc = rffi.llexternal(
+'_PyPy_subtype_dealloc', [PyObject], lltype.Void,
+compilation_info=eci, _nowrapper=True)
+state.C._PyPy_init_pyobj_list = rffi.llexternal(
+'_PyPy_init_pyobj_list', [], PyGC_HeadPtr,
+compilation_info=eci, _nowrapper=True)
+state.C._PyPy_gc_as_pyobj = rffi.llexternal(
+'_PyPy_gc_as_pyobj', [PyGC_HeadPtr], GCHdr_PyObject,
+compilation_info=eci, _nowrapper=True)
+state.C._PyPy_pyobj_as_gc = rffi.llexternal(
+'_PyPy_pyobj_as_gc', [GCHdr_PyObject], PyGC_HeadPtr,
 compilation_info=eci, _nowrapper=True)
 
 
@@ -1300,7 +1309,7 @@
 ctypes.c_void_p)
 
 # initialize the pyobj_list for the gc
-pyobj_list = space.fromcache(State).C._PyPy_InitPyObjList()
+pyobj_list = space.fromcache(State).C._PyPy_init_pyobj_list()
 rawrefcount._init_pyobj_list(pyobj_list)
 
 # we need to call this *after* the init code above, because it might
@@ -1309,9 +1318,6 @@
 # _PyPy_Malloc)
 builder.attach_all(space)
 
-#import rpython.rlib.rawrefcount
-#rawrefcount.init_traverse(generic_cpy_call_gc)
-
 setup_init_functions(eci, prefix)
 return modulename.new(ext='')
 
diff --git a/pypy/module/cpyext/include/object.h 
b/pypy/module/cpyext/include/object.h
--- a/pypy/module/cpyext/include/object.h
+++ b/pypy/module/cpyext/include/object.h
@@ -326,8 +326,8 @@
 
 #define _PyGC_REFS(o) _PyGCHead_REFS(_Py_AS_GC(o))
 
-#define _PyGC_REFS_UNTRACKED(-2)
-#define _PyGC_REFS_REACHABLE(-3)
+#define _PyGC_REFS_UNTRACKED   (-2)
+#define _PyGC_REFS_REACHABLE   (-3)
 #define _PyGC_REFS_TENTATIVELY_UNREACHABLE (-4)
 
 #define _PyGC_IS_TRACKED(o) (_PyGC_REFS(o) != _PyGC_REFS_UNTRACKED)
@@ -435,7 +435,9 @@
 #define _PyObject_GC_Del PyObject_GC_Del
 PyAPI_FUNC(void) _PyPy_subtype_dealloc(PyObject *);
 PyAPI_FUNC(void) _PyPy_object_dealloc(PyObject *);
-PyAPI_FUNC(PyGC_Head *) _PyPy_InitPyObjList();
+PyAPI_FUNC(PyGC_Head *) _PyPy_init_pyobj_list();
+PyAPI_FUNC(GCHdr_PyObject *) _PyPy_gc_as_pyobj(PyGC_Head *);
+PyAPI_FUNC(PyGC_Head *) _PyPy_pyobj_as_gc(GCHdr_PyObject *);
 
 #ifdef __cplusplus
 }
diff --git a/pypy/module/cpyext/parse/cpyext_object.h 
b/pypy/module/cpyext/parse/cpyext_object.h
--- a/pypy/module/cpyext/parse/cpyext_object.h
+++ b/pypy/module/cpyext/parse/cpyext_object.h
@@ -324,7 +324,12 @@
 
 
 typedef struct _gc_head {
-void *gc_next;
-void *gc_prev;
+struct _gc_head *gc_next;
+struct _gc_head *gc_prev;
 Py_ssize_t gc_refs;
-} PyGC_Head;
\ No newline at end of file
+} PyGC_Head;
+
+typedef struct _gchdr_pyobject {
+Py_ssize_t ob_refcnt;
+Py_ssize_t ob_pypy_link;
+} GCHdr_PyObject;
\ No newline at end of file
diff --git a/pypy/module/cpyext/src/object.c b/pypy/module/cpyext/src/object.c
--- a/pypy/module/cpyext/src/object.c
+++ b/pypy/module/cpyext/src/object.c
@@ -38,13 +38,25 @@
 PyGC_Head *_pypy_rawrefcount_pyobj_list = &_internal_pyobj_list;
 
 PyGC_Head *
-_PyPy_InitPyObjList()
+_PyPy_init_pyobj_list()
 {
 _pypy_rawrefcount_pyobj_list->gc_next = _pypy_rawrefcount_pyobj_list;
 _pypy_rawrefcount_pyobj_list->gc_prev = _pypy_rawrefcount_pyobj_list;
 return _pypy_rawrefcount_pyobj_list;
 }
 
+GCHdr_PyObject *
+_PyPy_gc_as_pyobj(PyGC_Head *g)
+{
+return (GCHdr_PyObject *)FROM_GC(g);
+}
+
+PyGC_Head *
+_PyPy_pyobj_as_gc(GCHdr_PyObject *obj)
+{
+return AS_GC(obj);
+}
+
 void
 _Py_Dealloc(PyObject *obj)
 {
@@ -118,7 +130,7 @@
 if (type->tp_itemsize)
 size += nitems * type->tp_itemsize;
 
-g = (PyObject*)_PyPy_Malloc(size);
+g = (PyGC_Head*)_PyPy_Malloc(size);
 if (g == NULL)
 return NULL;

[pypy-commit] pypy cpyext-gc-cycle: Added some dot tests

2019-01-11 Thread stevie_92
Author: Stefan Beyer 
Branch: cpyext-gc-cycle
Changeset: r95617:c46c894a7c06
Date: 2019-01-11 10:40 +0100
http://bitbucket.org/pypy/pypy/changeset/c46c894a7c06/

Log:Added some dot tests

diff --git a/rpython/memory/gc/test/dot/free_cpython_self.dot 
b/rpython/memory/gc/test/dot/free_cpython_self.dot
new file mode 100644
--- /dev/null
+++ b/rpython/memory/gc/test/dot/free_cpython_self.dot
@@ -0,0 +1,4 @@
+digraph G {
+"a" [type=C, alive=n];
+"a" -> "a";
+}
diff --git a/rpython/memory/gc/test/dot/free_cross_multi_1a.dot 
b/rpython/memory/gc/test/dot/free_cross_multi_1a.dot
new file mode 100644
--- /dev/null
+++ b/rpython/memory/gc/test/dot/free_cross_multi_1a.dot
@@ -0,0 +1,9 @@
+digraph G {
+"a" [type=B, alive=n];
+"b" [type=C, alive=n];
+"c" [type=C, alive=n];
+"a" -> "b";
+"b" -> "a";
+"a" -> "c";
+"c" -> "a";
+}
diff --git a/rpython/memory/gc/test/dot/free_cross_multi_1b.dot 
b/rpython/memory/gc/test/dot/free_cross_multi_1b.dot
new file mode 100644
--- /dev/null
+++ b/rpython/memory/gc/test/dot/free_cross_multi_1b.dot
@@ -0,0 +1,10 @@
+digraph G {
+"a" [type=B, alive=n];
+"b" [type=C, alive=n];
+"c" [type=C, alive=n];
+"a" -> "b";
+"b" -> "a";
+"a" -> "c";
+"c" -> "a";
+"b" -> "c";
+}
diff --git a/rpython/memory/gc/test/dot/free_cross_multi_2a.dot 
b/rpython/memory/gc/test/dot/free_cross_multi_2a.dot
new file mode 100644
--- /dev/null
+++ b/rpython/memory/gc/test/dot/free_cross_multi_2a.dot
@@ -0,0 +1,9 @@
+digraph G {
+"a" [type=B, alive=n];
+"b" [type=C, alive=n];
+"c" [type=C, alive=n];
+"a" -> "b";
+"b" -> "c";
+"c" -> "a";
+"b" -> "a";
+}
diff --git a/rpython/memory/gc/test/dot/free_cross_multi_2b.dot 
b/rpython/memory/gc/test/dot/free_cross_multi_2b.dot
new file mode 100644
--- /dev/null
+++ b/rpython/memory/gc/test/dot/free_cross_multi_2b.dot
@@ -0,0 +1,11 @@
+digraph G {
+"a" [type=B, alive=n];
+"b" [type=C, alive=n];
+"c" [type=C, alive=n];
+"d" [type=B, alive=n];
+"a" -> "b";
+"b" -> "c";
+"c" -> "d";
+"b" -> "a";
+"d" -> "a";
+}
diff --git a/rpython/memory/gc/test/dot/free_cross_multi_2c.dot 
b/rpython/memory/gc/test/dot/free_cross_multi_2c.dot
new file mode 100644
--- /dev/null
+++ b/rpython/memory/gc/test/dot/free_cross_multi_2c.dot
@@ -0,0 +1,13 @@
+digraph G {
+"a" [type=B, alive=n];
+"b" [type=C, alive=n];
+"c" [type=C, alive=n];
+"d" [type=B, alive=n];
+"e" [type=P, alive=n];
+"a" -> "b";
+"b" -> "c";
+"c" -> "d";
+"b" -> "a";
+"d" -> "e";
+"e" -> "a";
+}
diff --git a/rpython/memory/gc/test/dot/free_cross_multi_3a.dot 
b/rpython/memory/gc/test/dot/free_cross_multi_3a.dot
new file mode 100644
--- /dev/null
+++ b/rpython/memory/gc/test/dot/free_cross_multi_3a.dot
@@ -0,0 +1,9 @@
+digraph G {
+"a" [type=P, alive=n];
+"b" [type=B, alive=n];
+"c" [type=C, alive=n];
+"a" -> "b";
+"b" -> "a";
+"b" -> "c";
+"c" -> "b";
+}
diff --git a/rpython/memory/gc/test/dot/free_cross_multi_3b.dot 
b/rpython/memory/gc/test/dot/free_cross_multi_3b.dot
new file mode 100644
--- /dev/null
+++ b/rpython/memory/gc/test/dot/free_cross_multi_3b.dot
@@ -0,0 +1,11 @@
+digraph G {
+"a" [type=P, alive=n];
+"b" [type=B, alive=n];
+"c" [type=C, alive=n];
+"d" [type=C, alive=n];
+"a" -> "b";
+"b" -> "a";
+"b" -> "c";
+"c" -> "d";
+"d" -> "b";
+}
diff --git a/rpython/memory/gc/test/dot/free_cross_multi_3c.dot 
b/rpython/memory/gc/test/dot/free_cross_multi_3c.dot
new file mode 100644
--- /dev/null
+++ b/rpython/memory/gc/test/dot/free_cross_multi_3c.dot
@@ -0,0 +1,11 @@
+digraph G {
+"a" [type=P, alive=n];
+"b" [type=P, alive=n];
+"c" [type=B, alive=n];
+"d" [type=C, alive=n];
+"a" -> "b";
+"b" -> "c";
+"c" -> "d";
+"d" -> "c";
+"c" -> "a";
+}
diff --git a/rpython/memory/gc/test/dot/free_cross_simple_1.dot 
b/rpython/memory/gc/test/dot/free_cross_simple_1.dot
new file mode 100644
--- /dev/null
+++ b/rpython/memory/gc/test/dot/free_cross_simple_1.dot
@@ -0,0 +1,6 @@
+digraph G {
+"a" [type=B, alive=n];
+"b" [type=C, alive=n];
+"a" -> "b";
+"b" -> "a";
+}
diff --git a/rpython/memory/gc/test/dot/free_cross_simple_2.dot 
b/rpython/memory/gc/test/dot/free_cross_simple_2.dot
new file mode 100644
--- /dev/null
+++ b/rpython/memory/gc/test/dot/free_cross_simple_2.dot
@@ -0,0 +1,10 @@
+digraph G {
+"a" [type=P, alive=n];
+"b" [type=B, alive=n];
+"c" [type=C, alive=n];
+"d" [type=B, alive=n];
+"a" -> "b";
+"b" -> "c";
+"c" -> "d";
+"d" -> "a";
+}
diff --git a/rpython/memory/gc/test/dot/free_cross_simple_3.dot 
b/rpython/memory/gc/test/dot/free_cross_simple_3.dot
new file mode 100644
--- /dev/null
+++ b/rpython/memory/gc/test/dot/free_cross_simple_3.dot
@@ -0,0 +1,12 @@
+digraph G {
+"a" [type=P, alive=n];
+"b" [type=P, alive=n];
+"c" [type=B, alive=n];
+"d" [type=C, alive=n];
+"e" [type=B, 

[pypy-commit] pypy cpyext-gc-cycle: Cleaned up code in incminimark

2019-01-11 Thread stevie_92
Author: Stefan Beyer 
Branch: cpyext-gc-cycle
Changeset: r95612:5b3e2b3a25bf
Date: 2018-08-24 09:17 +0200
http://bitbucket.org/pypy/pypy/changeset/5b3e2b3a25bf/

Log:Cleaned up code in incminimark

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
@@ -3030,9 +3030,6 @@
 self.rrc_dealloc_trigger_callback = dealloc_trigger_callback
 self.rrc_dealloc_pending = self.AddressStack()
 self.rrc_tp_traverse = tp_traverse
-self.rrc_pyobjects_to_scan = self.AddressStack()
-self.rrc_more_pyobjects_to_scan = self.AddressStack()
-self.rrc_pyobjects_to_trace = self.AddressStack()
 self.rrc_pyobj_list = self._pygchdr(pyobj_list)
 self.rrc_gc_as_pyobj = gc_as_pyobj
 self.rrc_pyobj_as_gc = pyobj_as_gc
@@ -3205,16 +3202,8 @@
 self._pyobj(pyobject).c_ob_refcnt = rc
 _rrc_free._always_inline_ = True
 
-NO_CYCLE_DETECTION = False
-
 def rrc_major_collection_trace(self):
-debug_start("gc-rrc-trace")
-if self.NO_CYCLE_DETECTION:
-self.rrc_p_list_old.foreach(self._rrc_major_trace, None)
-else:
-self.rrc_major_collection_trace_cycle()
-self.rrc_p_list_old.foreach(self._rrc_major_trace, None) # for 
now, remove later
-debug_stop("gc-rrc-trace")
+self.rrc_p_list_old.foreach(self._rrc_major_trace, None)
 
 def _rrc_major_trace(self, pyobject, ignore):
 from rpython.rlib.rawrefcount import REFCNT_FROM_PYPY
@@ -3230,77 +3219,6 @@
 self.objects_to_trace.append(obj)
 self.visit_all_objects()
 
-def rrc_major_collection_trace_cycle(self):
-assert not self.objects_to_trace.non_empty()
-assert not self.rrc_pyobjects_to_scan.non_empty()
-assert not self.rrc_more_pyobjects_to_scan.non_empty()
-assert not self.rrc_pyobjects_to_trace.non_empty()
-
-self._rrc_gc_print_list()
-
-# initially, scan all real pyobjects (not proxies) which are linked to 
objects
-#self.rrc_p_list_old.foreach(self._rrc_major_scan_non_rc_roots, None)
-self.rrc_o_list_old.foreach(self._rrc_major_scan_non_rc_roots, None)
-
-# as long as we find new pyobjects which should be marked, recursively
-# mark them
-while self.rrc_pyobjects_to_trace.non_empty():
-while self.rrc_pyobjects_to_trace.non_empty():
-pyobject = self.rrc_pyobjects_to_trace.pop()
-self._rrc_traverse(pyobject)
-
-# see if we found new pypy objects to trace
-if self.objects_to_trace.non_empty():
-self.visit_all_objects()
-self.objects_to_trace.delete()
-self.objects_to_trace = self.AddressStack()
-
-# look if there are some pyobjects with linked objects which were
-# not marked previously, but are marked now
-swap = self.rrc_pyobjects_to_scan
-self.rrc_pyobjects_to_scan = self.rrc_more_pyobjects_to_scan
-self.rrc_more_pyobjects_to_scan = swap
-self.rrc_pyobjects_to_scan.foreach(
-self._rrc_major_scan_non_rc_roots, None)
-self.rrc_pyobjects_to_scan.delete()
-self.rrc_pyobjects_to_scan = self.AddressStack()
-
-self.rrc_more_pyobjects_to_scan.delete()
-self.rrc_more_pyobjects_to_scan = self.AddressStack()
-
-def _rrc_mark_cpyobj(self, pyobj):
-# if the pyobj is not marked, remember it and if there is a linked pypy
-# object also remember it
-visited = True # TODO: check if visited (via 'cast' to PyGC_Head)
-if not visited:
-# TODO: mark visited
-pyobject = llmemory.cast_ptr_to_adr(pyobj)
-self.rrc_more_pyobjects_to_scan.append(pyobject)
-intobj = pyobj.c_ob_pypy_link
-if intobj != 0:
-obj = llmemory.cast_int_to_adr(intobj)
-hdr = self.header(obj)
-if not (hdr.tid & GCFLAG_VISITED):
-self.objects_to_trace.append(obj)
-
-def _rrc_major_scan_non_rc_roots(self, pyobject, ignore):
-# check in the object header of the linked pypy object, if it is marked
-# or not
-pyobj = self._pyobj(pyobject)
-intobj = pyobj.c_ob_pypy_link
-obj = llmemory.cast_int_to_adr(intobj)
-hdr = self.header(obj)
-if hdr.tid & GCFLAG_VISITED:
-visited = True  # TODO: check if visited
-if not visited:
-# process the pyobject now
-# TODO: mark visited
-self.rrc_pyobjects_to_trace.append(pyobject)
-else:
-# save the pyobject for later, in case its linked object becomes
-# marked
-self.rrc_more_pyobjects_to_scan.append(pyobject)
-
 def 

[pypy-commit] pypy cpyext-gc-cycle: Fixed rawrefcount tests

2019-01-11 Thread stevie_92
Author: Stefan Beyer 
Branch: cpyext-gc-cycle
Changeset: r95610:c1219f8ea34b
Date: 2018-08-03 09:43 +0200
http://bitbucket.org/pypy/pypy/changeset/c1219f8ea34b/

Log:Fixed rawrefcount tests

diff --git a/rpython/memory/gc/test/test_rawrefcount.py 
b/rpython/memory/gc/test/test_rawrefcount.py
--- a/rpython/memory/gc/test/test_rawrefcount.py
+++ b/rpython/memory/gc/test/test_rawrefcount.py
@@ -334,146 +334,66 @@
 self._collect(major=True)
 check_alive(0)
 
-def test_cycle_self_reference_free(self):
+def test_linked_cycle_self_reference_dies_without_external_reference(self):
+p1, p1ref, r1, r1addr, check_alive = (
+self._rawrefcount_pair(42))
+r1.c_ob_refcnt += 1
+p1.next = p1
+check_alive(+1)
+self._collect(major=True, expected_trigger=1)
+py.test.raises(RuntimeError, "p1.x")  # dead
+assert r1.c_ob_refcnt == 1  # in the pending list
+assert r1.c_ob_pypy_link == 0
+assert self.gc.rawrefcount_next_dead() == r1addr
+assert self.gc.rawrefcount_next_dead() == llmemory.NULL
+assert self.gc.rawrefcount_next_dead() == llmemory.NULL
+self.gc.check_no_more_rawrefcount_state()
+lltype.free(r1, flavor='raw')
+
+def test_linked_cycle_self_reference_survives_with_pyobj_reference(self):
 p1, p1ref, r1, r1addr, check_alive = (
 self._rawrefcount_pair(42, create_immortal=True))
+r1.c_ob_refcnt += 2  # the pyobject is kept alive
 p1.next = p1
-check_alive(0)
+check_alive(+2)
 self._collect(major=True)
-py.test.raises(RuntimeError, "r1.c_ob_refcnt")  # dead
+check_alive(+2)
+r1.c_ob_refcnt -= 1 # the external reference from pyobj is removed
+check_alive(+1)
+self._collect(major=True, expected_trigger=1)
 py.test.raises(RuntimeError, "p1.x")  # dead
+assert r1.c_ob_refcnt == 1  # in the pending list
+assert r1.c_ob_pypy_link == 0
+assert self.gc.rawrefcount_next_dead() == r1addr
+assert self.gc.rawrefcount_next_dead() == llmemory.NULL
+assert self.gc.rawrefcount_next_dead() == llmemory.NULL
+self.gc.check_no_more_rawrefcount_state()
+lltype.free(r1, flavor='raw')
 
-def test_cycle_self_reference_not_free(self):
+def test_linked_cycle_self_reference_survives_with_pypy_reference(self):
 p1, p1ref, r1, r1addr, check_alive = (
 self._rawrefcount_pair(42, create_immortal=True))
-r1.c_ob_refcnt += 1  # the pyobject is kept alive
+r1.c_ob_refcnt += 1
 p1.next = p1
+self.stackroots.append(p1)
 check_alive(+1)
 self._collect(major=True)
+assert p1.x == 42
+assert self.trigger == []
 check_alive(+1)
+p1 = self.stackroots.pop()
+check_alive(+1)
+self._collect(major=True, expected_trigger=1)
+py.test.raises(RuntimeError, "p1.x")  # dead
+assert r1.c_ob_refcnt == 1
+assert r1.c_ob_pypy_link == 0
+assert self.gc.rawrefcount_next_dead() == r1addr
+self.gc.check_no_more_rawrefcount_state()
+lltype.free(r1, flavor='raw')
 
-# def test_simple_cycle_free(self):
-# self.gc.rawrefcount_init(lambda: self.trigger.append(1))
-# r1 = self._rawrefcount_cycle_obj()
-# r2 = self._rawrefcount_cycle_obj()
-# r1.next = r2
-# r2.next = r1
-# self._rawrefcount_buffer_obj(r1)
-# self.gc.rrc_collect_cycles()
-# assert r1.base.c_ob_refcnt & REFCNT_MASK == 0
-# assert r2.base.c_ob_refcnt & REFCNT_MASK == 0
-#
-# def test_simple_cycle_not_free(self):
-# self.gc.rawrefcount_init(lambda: self.trigger.append(1))
-# r1 = self._rawrefcount_cycle_obj()
-# r2 = self._rawrefcount_cycle_obj()
-# r1.next = r2
-# r2.next = r1
-# r2.base.c_ob_refcnt += 1
-# self._rawrefcount_buffer_obj(r1)
-# self.gc.rrc_collect_cycles()
-# assert r1.base.c_ob_refcnt & REFCNT_MASK == 1
-# assert r2.base.c_ob_refcnt & REFCNT_MASK == 2
-#
-# def test_complex_cycle_free(self):
-# self.gc.rawrefcount_init(lambda: self.trigger.append(1))
-# r1 = self._rawrefcount_cycle_obj()
-# r2 = self._rawrefcount_cycle_obj()
-# r3 = self._rawrefcount_cycle_obj()
-# r1.next = r2
-# r1.prev = r2
-# r2.base.c_ob_refcnt += 1
-# r2.next = r3
-# r3.prev = r1
-# self._rawrefcount_buffer_obj(r1)
-# self.gc.rrc_collect_cycles()
-# assert r1.base.c_ob_refcnt & REFCNT_MASK == 0
-# assert r2.base.c_ob_refcnt & REFCNT_MASK == 0
-# assert r3.base.c_ob_refcnt & REFCNT_MASK == 0
-#
-# def test_complex_cycle_not_free(self):
-# self.gc.rawrefcount_init(lambda: self.trigger.append(1))
-# r1 = self._rawrefcount_cycle_obj()
-# r2 = 

[pypy-commit] pypy cpyext-gc-cycle: Refactored call to tp_traverse from incminimark so there are no dependencies to pypy

2019-01-11 Thread stevie_92
Author: Stefan Beyer 
Branch: cpyext-gc-cycle
Changeset: r95600:94b062729ca4
Date: 2018-03-23 11:46 +0100
http://bitbucket.org/pypy/pypy/changeset/94b062729ca4/

Log:Refactored call to tp_traverse from incminimark so there are no
dependencies to pypy

diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py
--- a/pypy/module/cpyext/api.py
+++ b/pypy/module/cpyext/api.py
@@ -1719,11 +1719,6 @@
 return make_generic_cpy_call(FT, False)(space, func, *args)
 
 @specialize.ll()
-def generic_cpy_call_gc(func, *args):
-FT = lltype.typeOf(func).TO
-return make_generic_cpy_call_gc(FT, False)(func, *args)
-
-@specialize.ll()
 def generic_cpy_call_expect_null(space, func, *args):
 FT = lltype.typeOf(func).TO
 return make_generic_cpy_call(FT, True)(space, func, *args)
diff --git a/pypy/module/cpyext/pyobject.py b/pypy/module/cpyext/pyobject.py
--- a/pypy/module/cpyext/pyobject.py
+++ b/pypy/module/cpyext/pyobject.py
@@ -20,8 +20,7 @@
 from rpython.rlib.debug import ll_assert, fatalerror, debug_print
 from rpython.rlib.rawrefcount import (
 REFCNT_MASK, REFCNT_FROM_PYPY, REFCNT_OVERFLOW, REFCNT_CYCLE_BUFFERED,
-REFCNT_CLR_MASK, REFCNT_CLR_GREEN, REFCNT_CLR_PURPLE,
-W_MARKER_DEALLOCATING)
+REFCNT_CLR_MASK, REFCNT_CLR_GREEN, REFCNT_CLR_PURPLE)
 from pypy.module.cpyext.api import slot_function
 from pypy.module.cpyext.typeobjectdefs import visitproc
 
@@ -254,6 +253,8 @@
 w_obj._cpyext_attach_pyobj(space, py_obj)
 
 
+w_marker_deallocating = W_Root()
+
 @jit.dont_look_inside
 def from_ref(space, ref):
 """
@@ -265,7 +266,7 @@
 return None
 w_obj = rawrefcount.to_obj(W_Root, ref)
 if w_obj is not None:
-if w_obj is not W_MARKER_DEALLOCATING:
+if w_obj is not w_marker_deallocating:
 return w_obj
 fatalerror(
 "*** Invalid usage of a dying CPython object ***\n"
@@ -318,7 +319,7 @@
 
 def pyobj_has_w_obj(pyobj):
 w_obj = rawrefcount.to_obj(W_Root, pyobj)
-return w_obj is not None and w_obj is not W_MARKER_DEALLOCATING
+return w_obj is not None and w_obj is not w_marker_deallocating
 
 def w_obj_has_pyobj(w_obj):
 return bool(rawrefcount.from_obj(PyObject, w_obj))
@@ -454,7 +455,7 @@
 @init_function
 def write_w_marker_deallocating(space):
 if we_are_translated():
-llptr = cast_instance_to_base_ptr(W_MARKER_DEALLOCATING)
+llptr = cast_instance_to_base_ptr(w_marker_deallocating)
 state = space.fromcache(State)
 state.C.set_marker(rffi.cast(Py_ssize_t, llptr))
 
diff --git a/pypy/module/cpyext/state.py b/pypy/module/cpyext/state.py
--- a/pypy/module/cpyext/state.py
+++ b/pypy/module/cpyext/state.py
@@ -1,8 +1,8 @@
 from rpython.rlib.objectmodel import we_are_translated, specialize
-from rpython.rtyper.lltypesystem import rffi, lltype
+from rpython.rtyper.lltypesystem import rffi, lltype, llmemory
 from pypy.interpreter.error import OperationError, oefmt
 from pypy.interpreter import executioncontext
-from rpython.rtyper.annlowlevel import llhelper
+from rpython.rtyper.annlowlevel import llhelper, llhelper_args
 from rpython.rlib.rdynload import DLLHANDLE
 from rpython.rlib import rawrefcount
 import sys
@@ -70,7 +70,10 @@
 decref(space, ob)
 print 'dealloc_trigger DONE'
 return "RETRY"
-rawrefcount.init(dealloc_trigger)
+def tp_traverse(obj_addr, callback, args):
+# TODO: implement
+pass
+rawrefcount.init(dealloc_trigger, tp_traverse)
 else:
 if space.config.translation.gc == "boehm":
 action = BoehmPyObjDeallocAction(space)
@@ -80,6 +83,25 @@
 pyobj_dealloc_action = PyObjDeallocAction(space)
 self.dealloc_trigger = lambda: pyobj_dealloc_action.fire()
 
+def _rawrefcount_tp_traverse(space, pyobj_ptr, callback, args):
+from pypy.module.cpyext.api import (generic_cpy_call,
+PyObject)
+from pypy.module.cpyext.typeobjectdefs import visitproc
+# convert to pointers with correct types (PyObject)
+callback_addr = llmemory.cast_ptr_to_adr(callback)
+callback_ptr = llmemory.cast_adr_to_ptr(callback_addr,
+visitproc)
+pyobj_addr = llmemory.cast_ptr_to_adr(pyobj_ptr)
+pyobj = llmemory.cast_adr_to_ptr(pyobj_addr, PyObject)
+# now call tp_traverse (if possible)
+if pyobj.c_ob_type and pyobj.c_ob_type.c_tp_traverse:
+generic_cpy_call(space, pyobj.c_ob_type.c_tp_traverse,
+ pyobj,
+ callback_ptr, args)
+self.tp_traverse = (lambda o, v, a:
+  

[pypy-commit] pypy cpyext-gc-cycle: Finished implementation of dot file tests for rawrefcount

2019-01-11 Thread stevie_92
Author: Stefan Beyer 
Branch: cpyext-gc-cycle
Changeset: r95615:48c91f03eaa6
Date: 2018-12-27 16:22 +0100
http://bitbucket.org/pypy/pypy/changeset/48c91f03eaa6/

Log:Finished implementation of dot file tests for rawrefcount Removed
obsolete tests, that will be replaced by dot tests

diff --git a/rpython/memory/gc/test/test_rawrefcount.py 
b/rpython/memory/gc/test/test_rawrefcount.py
--- a/rpython/memory/gc/test/test_rawrefcount.py
+++ b/rpython/memory/gc/test/test_rawrefcount.py
@@ -387,66 +387,11 @@
 self._collect(major=True)
 check_alive(0)
 
-def test_linked_cycle_self_reference_dies_without_external_reference(self):
-p1, p1ref, r1, r1addr, check_alive = (
-self._rawrefcount_pair(42))
-r1.c_ob_refcnt += 1
-p1.next = p1
-check_alive(+1)
-self._collect(major=True, expected_trigger=1)
-py.test.raises(RuntimeError, "p1.x")  # dead
-assert r1.c_ob_refcnt == 1  # in the pending list
-assert r1.c_ob_pypy_link == 0
-assert self.gc.rawrefcount_next_dead() == r1addr
-assert self.gc.rawrefcount_next_dead() == llmemory.NULL
-assert self.gc.rawrefcount_next_dead() == llmemory.NULL
-self.gc.check_no_more_rawrefcount_state()
-lltype.free(r1, flavor='raw')
-
-def test_linked_cycle_self_reference_survives_with_pyobj_reference(self):
-p1, p1ref, r1, r1addr, check_alive = (
-self._rawrefcount_pair(42, create_immortal=True))
-r1.c_ob_refcnt += 2  # the pyobject is kept alive
-p1.next = p1
-check_alive(+2)
-self._collect(major=True)
-check_alive(+2)
-r1.c_ob_refcnt -= 1 # the external reference from pyobj is removed
-check_alive(+1)
-self._collect(major=True, expected_trigger=1)
-py.test.raises(RuntimeError, "p1.x")  # dead
-assert r1.c_ob_refcnt == 1  # in the pending list
-assert r1.c_ob_pypy_link == 0
-assert self.gc.rawrefcount_next_dead() == r1addr
-assert self.gc.rawrefcount_next_dead() == llmemory.NULL
-assert self.gc.rawrefcount_next_dead() == llmemory.NULL
-self.gc.check_no_more_rawrefcount_state()
-lltype.free(r1, flavor='raw')
-
-def test_linked_cycle_self_reference_survives_with_pypy_reference(self):
-p1, p1ref, r1, r1addr, check_alive = (
-self._rawrefcount_pair(42, create_immortal=True))
-r1.c_ob_refcnt += 1
-p1.next = p1
-self.stackroots.append(p1)
-check_alive(+1)
-self._collect(major=True)
-assert p1.x == 42
-assert self.trigger == []
-check_alive(+1)
-p1 = self.stackroots.pop()
-check_alive(+1)
-self._collect(major=True, expected_trigger=1)
-py.test.raises(RuntimeError, "p1.x")  # dead
-assert r1.c_ob_refcnt == 1
-assert r1.c_ob_pypy_link == 0
-assert self.gc.rawrefcount_next_dead() == r1addr
-self.gc.check_no_more_rawrefcount_state()
-lltype.free(r1, flavor='raw')
-
 dot_dir = os.path.join(os.path.realpath(os.path.dirname(__file__)), "dot")
 dot_files = [file for file in os.listdir(dot_dir) if file.endswith(".dot")]
 
+@py.test.mark.dont_track_allocations('intentionally keep objects alive, '
+ 'because we do the checks ourselves')
 @py.test.mark.parametrize("file", dot_files)
 def test_dots(self, file):
 from rpython.memory.gc.test.dot import pydot
@@ -488,6 +433,7 @@
 g = pydot.graph_from_dot_file(path)[0]
 nodes = {}
 
+# create objects from graph
 for n in g.get_nodes():
 name = n.get_name()
 attr = n.obj_dict['attributes']
@@ -512,6 +458,8 @@
 r.c_ob_refcnt = ext_refcnt
 nodes[name] = BorderNode(p, pref, r, raddr, check_alive, info)
 pass
+
+# add references between objects from graph
 for e in g.get_edges():
 source = nodes[e.get_source()]
 dest = nodes[e.get_destination()]
@@ -526,33 +474,36 @@
 else:
 assert False  # only 2 refs supported from pypy obj
 
+# quick self check, if traverse works properly
+dests_by_source = {}
+for e in g.get_edges():
+source = nodes[e.get_source()]
+dest = nodes[e.get_destination()]
+if source.info.type == "C" or dest.info.type == "C":
+if not dests_by_source.has_key(source):
+dests_by_source[source] = []
+dests_by_source[source].append(dest.r)
+for source in dests_by_source:
+dests_target = dests_by_source[source]
+def append(self, pyobj):
+dests_target.remove(pyobj)
+self.gc._rrc_visit_pyobj = append
+self.gc._rrc_traverse(source.raddr)
+assert len(dests_target) == 0
+
+ 

[pypy-commit] pypy cpyext-gc-cycle: Fixed cpyext test

2019-01-11 Thread stevie_92
Author: Stefan Beyer 
Branch: cpyext-gc-cycle
Changeset: r95609:860d9f8d29b6
Date: 2018-08-02 14:53 +0200
http://bitbucket.org/pypy/pypy/changeset/860d9f8d29b6/

Log:Fixed cpyext test

diff --git a/pypy/module/cpyext/test/test_cpyext.py 
b/pypy/module/cpyext/test/test_cpyext.py
--- a/pypy/module/cpyext/test/test_cpyext.py
+++ b/pypy/module/cpyext/test/test_cpyext.py
@@ -937,7 +937,7 @@
 if self.runappdirect:
 skip('cannot import module with undefined functions')
 
-# TODO: remove unnecessary stuff, add tests for gc_untrack, add asserts
+# TODO: remove unnecessary stuff, add gc_(un)track asserts
 init = """
 if (Py_IsInitialized()) {
 PyObject* m;
@@ -994,7 +994,7 @@
PyObject *kwds)
 {
 Cycle *self;
-self = (Cycle *)type->tp_alloc(type, 0);
+self = PyObject_GC_New(Cycle, type);
 if (self != NULL) {
 self->next = PyString_FromString("");
 if (self->next == NULL) {
@@ -1074,23 +1074,23 @@
 
 extern PyGC_Head *_pypy_rawrefcount_pyobj_list;
 
- static PyObject * Cycle_Create(Cycle *self, PyObject *val)
- {
- Cycle *c = PyObject_GC_New(Cycle, );
- if (c == NULL)
- return NULL;
- 
- Py_INCREF(val);
- c->next = val;
+static PyObject * Cycle_Create(Cycle *self, PyObject *val)
+{
+Cycle *c = (Cycle *)Cycle_new(, NULL, NULL);
+if (c == NULL)
+   return NULL;
+
+Py_INCREF(val);
+c->next = val;
 
- // TODO: check if _pypy_rawrefcount_pyobj_list contains c
+// TODO: check if _pypy_rawrefcount_pyobj_list contains c
 
- return (PyObject *)c;
- }
- static PyMethodDef module_methods[] = {
- {"create", (PyCFunction)Cycle_Create, METH_OLDARGS, ""},
- {NULL}  /* Sentinel */
- };
+return (PyObject *)c;
+}
+static PyMethodDef module_methods[] = {
+{"create", (PyCFunction)Cycle_Create, METH_OLDARGS, ""},
+{NULL}  /* Sentinel */
+};
 """
 module = self.import_module(name='cycle', init=init, body=body)
 
___
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit


[pypy-commit] pypy cpyext-gc-cycle: Directly call tp_traverse instead of via generic_cpy_call

2019-01-11 Thread stevie_92
Author: Stefan Beyer 
Branch: cpyext-gc-cycle
Changeset: r95601:fd6699184d11
Date: 2018-03-23 12:53 +0100
http://bitbucket.org/pypy/pypy/changeset/fd6699184d11/

Log:Directly call tp_traverse instead of via generic_cpy_call

diff --git a/pypy/module/cpyext/state.py b/pypy/module/cpyext/state.py
--- a/pypy/module/cpyext/state.py
+++ b/pypy/module/cpyext/state.py
@@ -83,9 +83,8 @@
 pyobj_dealloc_action = PyObjDeallocAction(space)
 self.dealloc_trigger = lambda: pyobj_dealloc_action.fire()
 
-def _rawrefcount_tp_traverse(space, pyobj_ptr, callback, args):
-from pypy.module.cpyext.api import (generic_cpy_call,
-PyObject)
+def _rawrefcount_tp_traverse(pyobj_ptr, callback, args):
+from pypy.module.cpyext.api import PyObject
 from pypy.module.cpyext.typeobjectdefs import visitproc
 # convert to pointers with correct types (PyObject)
 callback_addr = llmemory.cast_ptr_to_adr(callback)
@@ -95,12 +94,10 @@
 pyobj = llmemory.cast_adr_to_ptr(pyobj_addr, PyObject)
 # now call tp_traverse (if possible)
 if pyobj.c_ob_type and pyobj.c_ob_type.c_tp_traverse:
-generic_cpy_call(space, pyobj.c_ob_type.c_tp_traverse,
- pyobj,
- callback_ptr, args)
+pyobj.c_ob_type.c_tp_traverse(pyobj, callback_ptr,
+  args)
 self.tp_traverse = (lambda o, v, a:
-_rawrefcount_tp_traverse(self.space,
- o, v, a))
+_rawrefcount_tp_traverse(o, v, a))
 
 def build_api(self):
 """NOT_RPYTHON
___
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit


[pypy-commit] pypy unicode-utf8-py3: vastly speed up own tests

2019-01-11 Thread mattip
Author: Matti Picus 
Branch: unicode-utf8-py3
Changeset: r95618:cc276d4cd166
Date: 2019-01-11 14:05 +0200
http://bitbucket.org/pypy/pypy/changeset/cc276d4cd166/

Log:vastly speed up own tests

diff --git a/pypy/objspace/std/unicodeobject.py 
b/pypy/objspace/std/unicodeobject.py
--- a/pypy/objspace/std/unicodeobject.py
+++ b/pypy/objspace/std/unicodeobject.py
@@ -42,9 +42,10 @@
 self._index_storage = rutf8.null_storage()
 # XXX checking, remove before any performance measurments
 # ifdef not_running_in_benchmark
-if not we_are_translated():
-lgt = rutf8.codepoints_in_utf8(utf8str)
-assert lgt == length
+# if not we_are_translated():
+#print 'UnicodeObject.__init__'
+#lgt = rutf8.codepoints_in_utf8(utf8str)
+#assert lgt == length
 
 @staticmethod
 def from_utf8builder(builder):
___
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit


[pypy-commit] pypy unicode-utf8: remove untranslated check for unicode object creation

2019-01-11 Thread mattip
Author: Matti Picus 
Branch: unicode-utf8
Changeset: r95619:baef7e3e3ac0
Date: 2019-01-11 15:56 +0200
http://bitbucket.org/pypy/pypy/changeset/baef7e3e3ac0/

Log:remove untranslated check for unicode object creation

diff --git a/pypy/objspace/std/unicodeobject.py 
b/pypy/objspace/std/unicodeobject.py
--- a/pypy/objspace/std/unicodeobject.py
+++ b/pypy/objspace/std/unicodeobject.py
@@ -41,15 +41,6 @@
 self._utf8 = utf8str
 self._length = length
 self._index_storage = rutf8.null_storage()
-# XXX checking, remove before any performance measurments
-# ifdef not_running_in_benchmark
-if not we_are_translated():
-try:
-lgt = rutf8.check_utf8(utf8str, True)
-assert lgt == length
-except:
-# array.array can return invalid unicode
-pass
 
 @staticmethod
 def from_utf8builder(builder):
___
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit


[pypy-commit] pypy cpyext-gc-cycle: Removed unnecessary code

2019-01-11 Thread stevie_92
Author: Stefan Beyer 
Branch: cpyext-gc-cycle
Changeset: r95603:b74906a7ac4b
Date: 2018-05-10 11:12 +0200
http://bitbucket.org/pypy/pypy/changeset/b74906a7ac4b/

Log:Removed unnecessary code

diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py
--- a/pypy/module/cpyext/api.py
+++ b/pypy/module/cpyext/api.py
@@ -43,6 +43,7 @@
 from rpython.rlib import rstackovf
 from pypy.objspace.std.typeobject import W_TypeObject, find_best_base
 from pypy.module.cpyext.cparser import CTypeSpace
+from rpython.rlib.debug import ll_assert, debug_print, debug_start, debug_stop
 
 DEBUG_WRAPPER = True
 
@@ -974,6 +975,8 @@
 # we hope that malloc removal removes the newtuple() that is
 # inserted exactly here by the varargs specializer
 
+print "start to pypy"
+
 # see "Handling of the GIL" above (careful, we don't have the GIL here)
 tid = rthread.get_or_make_ident()
 _gil_auto = False
@@ -1085,6 +1088,9 @@
 rffi.stackcounter.stacks_counter -= 1
 
 _restore_gil_state(pygilstate_release, gilstate, gil_release, 
_gil_auto, tid)
+
+print "end to pypy"
+
 return retval
 
 wrapper_second_level._dont_inline_ = True
@@ -1773,8 +1779,10 @@
 
 preexist_error = PyErr_Occurred(space)
 try:
+print "start cpyext_call"
 # Call the function
 result = call_external_function(func, *boxed_args)
+print "end cpyext_call"
 finally:
 assert cpyext_glob_tid_ptr[0] == tid
 cpyext_glob_tid_ptr[0] = tid_before
diff --git a/rpython/config/translationoption.py 
b/rpython/config/translationoption.py
--- a/rpython/config/translationoption.py
+++ b/rpython/config/translationoption.py
@@ -105,6 +105,14 @@
  "asmgcc": [("translation.gctransformer", "framework"),
 ("translation.backend", "c")],
 }),
+ChoiceOption("cpyextgc", "Garbage Collection Strategy for cpyext",
+ ["boehm", "ref", "ref_trialdel", "none"],
+ default="ref",
+ requires={
+"boehm": [("translation.gc", "incminimark")],
+"ref_trialdel": [("translation.gc", "incminimark")],
+ },
+ cmdline="--cpyextgc"),
 
 # other noticeable options
 BoolOption("thread", "enable use of threading primitives",
diff --git a/rpython/translator/c/genc.py b/rpython/translator/c/genc.py
--- a/rpython/translator/c/genc.py
+++ b/rpython/translator/c/genc.py
@@ -177,6 +177,8 @@
 defines = defines.copy()
 if self.config.translation.countmallocs:
 defines['COUNT_OP_MALLOCS'] = 1
+if self.config.translation.cpyextgc == "boehm":
+defines['CPYEXT_BOEHM'] = 1
 if self.config.translation.sandbox:
 defines['RPY_SANDBOXED'] = 1
 if CBuilder.have___thread is None:
___
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit


[pypy-commit] pypy cpyext-gc-cycle: Implemented pyobj_list for rawrefcount (to be used in cpyext tests)

2019-01-11 Thread stevie_92
Author: Stefan Beyer 
Branch: cpyext-gc-cycle
Changeset: r95606:9e5001a6604b
Date: 2018-07-05 15:54 +0200
http://bitbucket.org/pypy/pypy/changeset/9e5001a6604b/

Log:Implemented pyobj_list for rawrefcount (to be used in cpyext tests)
Added own cpyext test file for GC-related tests

diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py
--- a/pypy/module/cpyext/api.py
+++ b/pypy/module/cpyext/api.py
@@ -1300,7 +1300,8 @@
 ctypes.c_void_p)
 
 # initialize the pyobj_list for the gc
-space.fromcache(State).C._PyPy_InitPyObjList()
+pyobj_list = space.fromcache(State).C._PyPy_InitPyObjList()
+rawrefcount._init_pyobj_list(pyobj_list)
 
 # we need to call this *after* the init code above, because it might
 # indirectly call some functions which are attached to pypyAPI (e.g., we
diff --git a/pypy/module/cpyext/state.py b/pypy/module/cpyext/state.py
--- a/pypy/module/cpyext/state.py
+++ b/pypy/module/cpyext/state.py
@@ -59,28 +59,23 @@
 def setup_rawrefcount(self):
 space = self.space
 if not self.space.config.translating:
-from pypy.module.cpyext.api import PyGC_HeadPtr
 def dealloc_trigger():
-from pypy.module.cpyext.pyobject import PyObject, decref
+from pypy.module.cpyext.pyobject import PyObject, decref, cts
 print 'dealloc_trigger...'
 while True:
 ob = rawrefcount.next_dead(PyObject)
 if not ob:
 break
-print 'deallocating PyObject', ob
+pto = ob.c_ob_type
+name = rffi.charp2str(cts.cast('char*', pto.c_tp_name))
+print 'deallocating PyObject', ob, 'of type', name
 decref(space, ob)
 print 'dealloc_trigger DONE'
 return "RETRY"
 def tp_traverse(obj_addr, callback, args):
 # TODO: implement
 pass
-# Warning: This list ist different than the list actually used
-# by the extension modules (see _PyPy_InitPyObjList).
-pyobj_list = lltype.malloc(PyGC_HeadPtr.TO,
-   flavor='raw', immortal=True, zero=True)
-pyobj_list.c_gc_next = rffi.cast(rffi.VOIDP, pyobj_list);
-pyobj_list.c_gc_next = rffi.cast(rffi.VOIDP, pyobj_list);
-rawrefcount.init(dealloc_trigger, tp_traverse, pyobj_list)
+rawrefcount.init(dealloc_trigger, tp_traverse)
 else:
 if space.config.translation.gc == "boehm":
 action = BoehmPyObjDeallocAction(space)
diff --git a/pypy/module/cpyext/test/test_cpyext_gc.py 
b/pypy/module/cpyext/test/test_cpyext_gc.py
new file mode 100644
--- /dev/null
+++ b/pypy/module/cpyext/test/test_cpyext_gc.py
@@ -0,0 +1,801 @@
+import sys
+import weakref
+
+import pytest
+
+from pypy.tool.cpyext.extbuild import (
+SystemCompilationInfo, HERE, get_sys_info_app)
+from pypy.interpreter.gateway import unwrap_spec, interp2app
+from rpython.rtyper.lltypesystem import lltype, ll2ctypes
+from pypy.module.cpyext import api
+from pypy.module.cpyext.state import State
+from rpython.tool.identity_dict import identity_dict
+from rpython.tool import leakfinder
+from rpython.rlib import rawrefcount
+from rpython.tool.udir import udir
+
+only_pypy ="config.option.runappdirect and '__pypy__' not in 
sys.builtin_module_names"
+
+@api.cpython_api([], api.PyObject)
+def PyPy_Crash1(space):
+1/0
+
+@api.cpython_api([], lltype.Signed, error=-1)
+def PyPy_Crash2(space):
+1/0
+
+class SpaceCompiler(SystemCompilationInfo):
+"""Extension compiler for regular (untranslated PyPy) mode"""
+def __init__(self, space, *args, **kwargs):
+self.space = space
+SystemCompilationInfo.__init__(self, *args, **kwargs)
+
+def load_module(self, mod, name):
+space = self.space
+api.load_extension_module(space, mod, name)
+return space.getitem(
+space.sys.get('modules'), space.wrap(name))
+
+
+def get_cpyext_info(space):
+from pypy.module.imp.importing import get_so_extension
+state = space.fromcache(State)
+api_library = state.api_lib
+if sys.platform == 'win32':
+libraries = [api_library]
+# '%s' undefined; assuming extern returning int
+compile_extra = ["/we4013"]
+# prevent linking with PythonXX.lib
+w_maj, w_min = space.fixedview(space.sys.get('version_info'), 5)[:2]
+link_extra = ["/NODEFAULTLIB:Python%d%d.lib" %
+(space.int_w(w_maj), space.int_w(w_min))]
+else:
+libraries = []
+if sys.platform.startswith('linux'):
+compile_extra = [
+"-Werror", "-g", "-O0", "-Wp,-U_FORTIFY_SOURCE", "-fPIC"]
+link_extra = ["-g"]
+else:
+compile_extra = link_extra = None
+return 

[pypy-commit] pypy cpyext-gc-cycle: Removed extra flags in cpython refcount

2019-01-11 Thread stevie_92
Author: Stefan Beyer 
Branch: cpyext-gc-cycle
Changeset: r95605:878ff32d88a1
Date: 2018-07-05 13:01 +0200
http://bitbucket.org/pypy/pypy/changeset/878ff32d88a1/

Log:Removed extra flags in cpython refcount Fixed tests in
test_rawrefcount and test_cpyext Removed references from rawrefcount
to cpyext Added some comments

diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py
--- a/pypy/module/cpyext/api.py
+++ b/pypy/module/cpyext/api.py
@@ -1787,10 +1787,10 @@
 
 preexist_error = PyErr_Occurred(space)
 try:
-print "start cpyext_call"
+#print "start cpyext_call"
 # Call the function
 result = call_external_function(func, *boxed_args)
-print "end cpyext_call"
+#print "end cpyext_call"
 finally:
 assert cpyext_glob_tid_ptr[0] == tid
 cpyext_glob_tid_ptr[0] = tid_before
diff --git a/pypy/module/cpyext/include/boolobject.h 
b/pypy/module/cpyext/include/boolobject.h
--- a/pypy/module/cpyext/include/boolobject.h
+++ b/pypy/module/cpyext/include/boolobject.h
@@ -13,8 +13,8 @@
 #define Py_True ((PyObject *) &_Py_TrueStruct)
 
 /* Macros for returning Py_True or Py_False, respectively */
-#define Py_RETURN_TRUE do { Py_INCREF(Py_True); return Py_True; } while(0)
-#define Py_RETURN_FALSE do { Py_INCREF(Py_False); return Py_False; } while(0)
+#define Py_RETURN_TRUE return Py_INCREF(Py_True), Py_True
+#define Py_RETURN_FALSE return Py_INCREF(Py_False), Py_False
 
 #ifdef __cplusplus
 }
diff --git a/pypy/module/cpyext/include/object.h 
b/pypy/module/cpyext/include/object.h
--- a/pypy/module/cpyext/include/object.h
+++ b/pypy/module/cpyext/include/object.h
@@ -2,7 +2,6 @@
 #define Py_OBJECT_H
 
 #include 
-#include 
 
 #ifdef __cplusplus
 extern "C" {
@@ -13,12 +12,7 @@
 #define PY_SSIZE_T_MAX ((Py_ssize_t)(((size_t)-1)>>1))
 #define PY_SSIZE_T_MIN (-PY_SSIZE_T_MAX-1)
 
-#define PY_REFCNT_FROM_PYPY (4L << ((long)(log(PY_SSIZE_T_MAX) / log(2) - 2)))
-#define PY_REFCNT_OVERFLOW (1L << ((long)(log(PY_SSIZE_T_MAX) / log(2) - 4) - 
1L))
-#define PY_REFCNT_MASK ((PY_REFCNT_OVERFLOW << 1L) - 1L)
-#define Py_RETURN_NONE return (PyObject *)(Py_None))->ob_refcnt & 
PY_REFCNT_OVERFLOW) == 0) ? \
-  ((PyObject *)(Py_None))->ob_refcnt++ : 
Py_IncRef((PyObject *)(Py_None))), Py_None
-
+#define Py_RETURN_NONE return Py_INCREF(Py_None), Py_None
 
 /*
 CPython has this for backwards compatibility with really old extensions, and 
now
@@ -40,20 +34,14 @@
 #define Py_XDECREF(ob)  (Py_DecRef((PyObject *)(ob)))
 #else
 /* Fast version */
-#define Py_INCREF(ob)   do {   
  \
-if (!(((PyObject *)(ob))->ob_refcnt & 
PY_REFCNT_OVERFLOW))   \
-((PyObject *)(ob))->ob_refcnt++;   
  \
-else   
  \
-Py_IncRef((PyObject *)(ob));   
 \
-} while (0)
-#define Py_DECREF(ob)   do {   
  \
-if PyObject *)(ob))->ob_refcnt & 
PY_REFCNT_OVERFLOW))\
-Py_DecRef((PyObject *)(ob));   
  \
-else if (--((PyObject *)(ob))->ob_refcnt & 
PY_REFCNT_MASK)   \
-;  
  \
-else   
  \
-_Py_Dealloc((PyObject *)(ob)); 
  \
-} while (0)
+#define Py_INCREF(ob)   (((PyObject *)(ob))->ob_refcnt++)
+#define Py_DECREF(op)   \
+do {\
+if (--((PyObject *)(op))->ob_refcnt != 0)   \
+;   \
+else\
+_Py_Dealloc((PyObject *)(op));  \
+} while (0)
 
 #define Py_XINCREF(op) do { if ((op) == NULL) ; else Py_INCREF(op); } while (0)
 #define Py_XDECREF(op) do { if ((op) == NULL) ; else Py_DECREF(op); } while (0)
@@ -73,8 +61,7 @@
 }  \
 } while (0)
 
-#define Py_REFCNT(ob) PyObject *)(ob))->ob_refcnt & PY_REFCNT_OVERFLOW == 
0) ?  \
-  (((PyObject*)(ob))->ob_refcnt & PY_REFCNT_MASK) : 
_Py_RefCnt_Overflow(ob))
+#define Py_REFCNT(ob)  (((PyObject*)(ob))->ob_refcnt)
 #define Py_TYPE(ob)(((PyObject*)(ob))->ob_type)
 #define Py_SIZE(ob)(((PyVarObject*)(ob))->ob_size)
 
diff --git a/pypy/module/cpyext/object.py b/pypy/module/cpyext/object.py
--- 

[pypy-commit] pypy cpyext-gc-cycle: Fixed cpyext test

2019-01-11 Thread stevie_92
Author: Stefan Beyer 
Branch: cpyext-gc-cycle
Changeset: r95608:ada4b64c0816
Date: 2018-08-02 10:59 +0200
http://bitbucket.org/pypy/pypy/changeset/ada4b64c0816/

Log:Fixed cpyext test

diff --git a/pypy/module/cpyext/test/test_cpyext.py 
b/pypy/module/cpyext/test/test_cpyext.py
--- a/pypy/module/cpyext/test/test_cpyext.py
+++ b/pypy/module/cpyext/test/test_cpyext.py
@@ -1069,6 +1069,7 @@
 (initproc)Cycle_init,  /* tp_init */
 0, /* tp_alloc */
 Cycle_new, /* tp_new */
+PyObject_GC_Del,   /* tp_free */
 };
 
 extern PyGC_Head *_pypy_rawrefcount_pyobj_list;
@@ -1078,6 +1079,8 @@
  Cycle *c = PyObject_GC_New(Cycle, );
  if (c == NULL)
  return NULL;
+ 
+ Py_INCREF(val);
  c->next = val;
 
  // TODO: check if _pypy_rawrefcount_pyobj_list contains c
@@ -1100,7 +1103,3 @@
 self.print_pyobj_list()
 c = module.create(Example(42))
 self.print_pyobj_list()
-
-# TODO: fix rawrefcount, so that the Cycle objects are properly added
-#   to the ALLOCATED list of leakfinder or alternatively not freed
-#   by collect
___
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit


[pypy-commit] pypy cpyext-gc-cycle: Fixed dot tests by allocating all PyPy objects old

2019-01-11 Thread stevie_92
Author: Stefan Beyer 
Branch: cpyext-gc-cycle
Changeset: r95616:ea95f4bc807f
Date: 2019-01-10 11:43 +0100
http://bitbucket.org/pypy/pypy/changeset/ea95f4bc807f/

Log:Fixed dot tests by allocating all PyPy objects old Add to stackroots
instead of immortal PyPy objects for dot tests Sorted dot tests

diff --git a/rpython/memory/gc/test/test_rawrefcount.py 
b/rpython/memory/gc/test/test_rawrefcount.py
--- a/rpython/memory/gc/test/test_rawrefcount.py
+++ b/rpython/memory/gc/test/test_rawrefcount.py
@@ -64,25 +64,16 @@
 refs.append(pyobj_to)
 pyobj_to.c_ob_refcnt += 1
 
-def _rawrefcount_pypyobj(self, intval, create_old=False,
- create_immortal=False, force_external=False):
-if create_immortal:
-p1 = lltype.malloc(S, immortal=True)
-else:
-saved = self.gc.nonlarge_max
-try:
-if force_external:
-self.gc.nonlarge_max = 1
-p1 = self.malloc(S)
-finally:
-self.gc.nonlarge_max = saved
+def _rawrefcount_pypyobj(self, intval, rooted=False, create_old=True):
+p1 = self.malloc(S)
 p1.x = intval
-if create_immortal:
-self.consider_constant(p1)
-elif create_old:
+
+if create_old:
 self.stackroots.append(p1)
 self._collect(major=False)
 p1 = self.stackroots.pop()
+if rooted:
+self.stackroots.append(p1)
 p1ref = lltype.cast_opaque_ptr(llmemory.GCREF, p1)
 
 def check_alive():
@@ -116,7 +107,7 @@
 
 def _rawrefcount_pair(self, intval, is_light=False, is_pyobj=False,
   create_old=False, create_immortal=False,
-  force_external=False):
+  rooted=False, force_external=False):
 if is_light:
 rc = REFCNT_FROM_PYPY_LIGHT
 else:
@@ -139,6 +130,8 @@
 self.stackroots.append(p1)
 self._collect(major=False)
 p1 = self.stackroots.pop()
+if rooted:
+self.stackroots.append(p1)
 p1ref = lltype.cast_opaque_ptr(llmemory.GCREF, p1)
 r1 = lltype.malloc(PYOBJ_HDR, flavor='raw',
immortal=create_immortal)
@@ -389,6 +382,7 @@
 
 dot_dir = os.path.join(os.path.realpath(os.path.dirname(__file__)), "dot")
 dot_files = [file for file in os.listdir(dot_dir) if file.endswith(".dot")]
+dot_files.sort()
 
 @py.test.mark.dont_track_allocations('intentionally keep objects alive, '
  'because we do the checks ourselves')
@@ -433,7 +427,8 @@
 g = pydot.graph_from_dot_file(path)[0]
 nodes = {}
 
-# create objects from graph
+# create objects from graph (always create old to prevent moving)
+i = 0
 for n in g.get_nodes():
 name = n.get_name()
 attr = n.obj_dict['attributes']
@@ -449,15 +444,18 @@
 nodes[name] = CPythonNode(r, raddr, check_alive, info)
 elif type == "P":
 p, pref, check_alive = \
-self._rawrefcount_pypyobj(42, create_immortal=rooted)
+self._rawrefcount_pypyobj(42 + i, rooted=rooted,
+  create_old=True)
 nodes[name] = PyPyNode(p, pref, check_alive, info)
+i += 1
 elif type == "B":
 p, pref, r, raddr, check_alive =\
-self._rawrefcount_pair(42, create_immortal=rooted)
+self._rawrefcount_pair(42 + i, rooted=rooted,
+   create_old=True)
 if ext_refcnt > 0:
 r.c_ob_refcnt = ext_refcnt
 nodes[name] = BorderNode(p, pref, r, raddr, check_alive, info)
-pass
+i += 1
 
 # add references between objects from graph
 for e in g.get_edges():
___
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit


[pypy-commit] pypy cpyext-gc-cycle: Added complex rawrefcount tests using dot files

2019-01-11 Thread stevie_92
Author: Stefan Beyer 
Branch: cpyext-gc-cycle
Changeset: r95614:2e7b85611e30
Date: 2018-12-21 11:55 +0100
http://bitbucket.org/pypy/pypy/changeset/2e7b85611e30/

Log:Added complex rawrefcount tests using dot files Adapted traverse
support in incminimark to support tests

diff too long, truncating to 2000 out of 9197 lines

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
@@ -3253,9 +3253,6 @@
 else:
 self._rrc_free(pyobject)
 
-def _rrc_visit_pyobj(self, pyobj):
-pass
-
 def _rrc_visit(pyobj, self_ptr):
 from rpython.rtyper.annlowlevel import cast_adr_to_nongc_instance
 #
@@ -3265,13 +3262,18 @@
 return rffi.cast(rffi.INT_real, 0)
 
 def _rrc_traverse(self, pyobject):
+from rpython.rlib.objectmodel import we_are_translated
 from rpython.rtyper.annlowlevel import (cast_nongc_instance_to_adr,
 llhelper)
 #
 pyobj = self._pyobj(pyobject)
-callback_ptr = llhelper(self.RAWREFCOUNT_VISIT,
-IncrementalMiniMarkGC._rrc_visit)
-self_ptr = rffi.cast(rffi.VOIDP, cast_nongc_instance_to_adr(self))
+if we_are_translated():
+callback_ptr = llhelper(self.RAWREFCOUNT_VISIT,
+IncrementalMiniMarkGC._rrc_visit)
+self_ptr = rffi.cast(rffi.VOIDP, cast_nongc_instance_to_adr(self))
+else:
+callback_ptr = self._rrc_visit_pyobj
+self_ptr = None
 self.rrc_tp_traverse(pyobj, callback_ptr, self_ptr)
 
 def _rrc_gc_list_init(self, pygclist):
diff --git a/rpython/memory/gc/test/__init__.py 
b/rpython/memory/gc/test/dot/__init__.py
copy from rpython/memory/gc/test/__init__.py
copy to rpython/memory/gc/test/dot/__init__.py
diff --git a/rpython/memory/gc/test/dot/dot_parser.py 
b/rpython/memory/gc/test/dot/dot_parser.py
new file mode 100644
--- /dev/null
+++ b/rpython/memory/gc/test/dot/dot_parser.py
@@ -0,0 +1,555 @@
+"""Graphviz's dot language parser.
+
+The dotparser parses GraphViz files in
+dot and dot files and transforms them
+into a class representation defined by `pydot`.
+
+Author: Michael Krause 
+Fixes by: Ero Carrera 
+"""
+from __future__ import division
+from __future__ import print_function
+import sys
+
+from pyparsing import (
+nestedExpr, Literal, CaselessLiteral,
+Word, OneOrMore,
+Forward,
+Group, Optional, Combine,
+restOfLine, cStyleComment, nums, alphanums,
+printables,
+ParseException, ParseResults, CharsNotIn,
+QuotedString)
+
+import pydot
+
+__author__ = ['Michael Krause', 'Ero Carrera']
+__license__ = 'MIT'
+
+
+PY3 = sys.version_info >= (3, 0, 0)
+if PY3:
+str_type = str
+else:
+str_type = basestring
+
+
+class P_AttrList(object):
+
+def __init__(self, toks):
+
+self.attrs = {}
+i = 0
+
+while i < len(toks):
+attrname = toks[i]
+if i+2 < len(toks) and toks[i+1] == '=':
+attrvalue = toks[i+2]
+i += 3
+else:
+attrvalue = None
+i += 1
+
+self.attrs[attrname] = attrvalue
+
+
+def __repr__(self):
+
+return "%s(%r)" % (self.__class__.__name__, self.attrs)
+
+
+
+class DefaultStatement(P_AttrList):
+
+def __init__(self, default_type, attrs):
+
+self.default_type = default_type
+self.attrs = attrs
+
+def __repr__(self):
+
+return "%s(%s, %r)" % (self.__class__.__name__,
+self.default_type, self.attrs)
+
+
+top_graphs = list()
+
+def push_top_graph_stmt(str, loc, toks):
+
+attrs = {}
+g = None
+
+for element in toks:
+
+if (isinstance(element, (ParseResults, tuple, list)) and
+len(element) == 1 and
+isinstance(element[0], str_type)):
+
+element = element[0]
+
+if element == 'strict':
+attrs['strict'] = True
+
+elif element in ['graph', 'digraph']:
+
+attrs = {}
+
+g = pydot.Dot(graph_type=element, **attrs)
+attrs['type'] = element
+
+top_graphs.append( g )
+
+elif isinstance( element, str_type):
+g.set_name( element )
+
+elif isinstance(element, pydot.Subgraph):
+
+g.obj_dict['attributes'].update( element.obj_dict['attributes'] )
+g.obj_dict['edges'].update( element.obj_dict['edges'] )
+g.obj_dict['nodes'].update( element.obj_dict['nodes'] )
+g.obj_dict['subgraphs'].update( element.obj_dict['subgraphs'] )
+
+g.set_parent_graph(g)
+
+elif isinstance(element, P_AttrList):
+attrs.update(element.attrs)
+
+elif isinstance(element, (ParseResults, list)):
+add_elements(g, element)
+
+else:
+

[pypy-commit] pypy unicode-utf8-py3: three XXX, will try to fix this weekend

2019-01-11 Thread cfbolz
Author: Carl Friedrich Bolz-Tereick 
Branch: unicode-utf8-py3
Changeset: r95620:1da3240effbd
Date: 2019-01-11 22:48 +0100
http://bitbucket.org/pypy/pypy/changeset/1da3240effbd/

Log:three XXX, will try to fix this weekend

diff --git a/pypy/objspace/std/dictmultiobject.py 
b/pypy/objspace/std/dictmultiobject.py
--- a/pypy/objspace/std/dictmultiobject.py
+++ b/pypy/objspace/std/dictmultiobject.py
@@ -1171,6 +1171,8 @@
 return self.space.utf8_w(wrapped)
 
 def is_correct_type(self, w_obj):
+# XXX the ascii restriction needs to be lifted, otherwise the
+# assumptions about get/setitem_str are just broken
 space = self.space
 return type(w_obj) is space.UnicodeObjectCls and w_obj.is_ascii()
 
@@ -1189,11 +1191,14 @@
 
 def setitem_str(self, w_dict, key, w_value):
 assert key is not None
+# XXX this is not valid! UnicodeDictStrategy can right now only store 
ascii, but
+# this path can lead to non-ascii utf8 strings ending up as keys
 self.unerase(w_dict.dstorage)[self.decodekey_str(key)] = w_value
 
 def getitem(self, w_dict, w_key):
 space = self.space
 # -- This is called extremely often.  Hack for performance --
+# XXX this shortcut looks wrong to me
 if type(w_key) is space.StringObjectCls:
  return self.getitem_str(w_dict, w_key.unwrap(space))
 # -- End of performance hack --
@@ -1201,6 +1206,7 @@
 
 def getitem_str(self, w_dict, key):
 assert key is not None
+# XXX why can't we just key here?
 return self.unerase(w_dict.dstorage).get(self.decodekey_str(key), None)
 
 def listview_utf8(self, w_dict):
___
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit