<div class="gmail_quote">2012/2/18 Stefan Behnel <span dir="ltr">&lt;<a href="mailto:stefan_ml@behnel.de">stefan_ml@behnel.de</a>&gt;</span><br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div id=":2zv">The weakref changes are really unfortunate as they appear in one of the<br>
most performance critical spots of lxml&#39;s API: on-the-fly proxy creation.<br>
<br>
I can understand why the original code won&#39;t work as is, but could you<br>
elaborate on why the weak references are needed? Maybe there is a faster<br>
way of doing this?<div class="yj6qo ajU"><div id=":309" class="ajR" tabindex="0"></div></div></div></blockquote></div><div><br></div><div>PyObject-&gt;ob_refcnt only counts the number of PyObject references to the object,</div>
<div>not eventual references held by other parts of the pypy interpreter.</div><div>For example, PyTuple_GetItem() often returns something with refcnt=1;</div><div>Two calls to &quot;PyObject *x = PyTuple_GetItem(tuple, 0); Py_DECREF(x);&quot; will</div>
<div>return different values for the x pointer.</div><div><br></div><div>But this model has issues with borrowed references.</div><div>For example, this code is valid CPython, but will crash with cpyext:</div><div>    PyObject *exc = PyErr_NewException(&quot;error&quot;, PyExc_StandardError, NULL);</div>
<div>    PyDict_SetItemString(module_dict, &quot;error&quot;, exc);</div><div>    Py_DECREF(exc);</div><div>    // exc is now a borrowed reference, but following line crash pypy:</div><div>    PyObject *another = PyErr_NewException(&quot;AnotherError&quot;, exc, NULL);</div>
<div><div>    PyDict_SetItemString(module_dict, &quot;AnotherError&quot;, another);</div><div>    Py_DECREF(exc);</div></div><div>In CPython, the code can continue using the created object: we don&#39;t own the reference,</div>
<div>exc is now a borrowed reference, valid as long as the containing dict is valid; The refcount</div><div>is 1 when the object is created, incremented when PyDict_SetItem stores it, and 1 again after DECREF.</div><div><br>
</div><div>PyPy does it differently: a dictionary does not store PyObject* pointers, but &quot;pypy objects&quot;</div><div>with no reference counting, and which address can change with a gc collection.</div><div>PyDict_SetItemString will not change exc-&gt;refcnt, which will remain 1, then Py_DECREF</div>
<div>will free the memory pointed by exc.</div><div>There are mechanisms to keep the reference a bit longer, for example PyTuple_GET_ITEM</div><div>will return a &quot;temporary&quot; reference that will be released when the tuple loses its last cpyext reference.</div>
<div><br></div><div>Another way to say this is that with cpyext, a borrowed reference has to borrow from</div><div>some other reference that you own. It can be a container, or in some cases the current</div><div>&quot;context&quot;, i.e. something that have the duration of the current C call.</div>
<div>Otherwise, weak references must be used instead.</div><div><div><div><br></div>-- <br>Amaury Forgeot d&#39;Arc<br>
</div></div>