<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array"/>
  <modified type="array">
    <modified>
      <diff>@@ -1,4 +1,4 @@
-run setup.py test
+run setup.py --debug test
 bt
 continue
 bt</diff>
      <filename>go.comm</filename>
    </modified>
    <modified>
      <diff>@@ -13,13 +13,24 @@ scripts and functions respectively.  Borrows heavily from Claes Jacobssen's
 Javascript Perl module, in turn based on Mozilla's 'PerlConnect' Perl binding.
 &quot;&quot;&quot;,
 
+# I haven't the sligthest, but this appears to fix
+# all those EINTR errors. Pulled and adapted for OS X
+# from twisted bug #733
+import ctypes
+import signal
+libc = ctypes.CDLL(&quot;libc.dylib&quot;)
+libc.siginterrupt(signal.SIGCHLD, 0)
+
 import os
 import subprocess as sp
 import sys
+from distutils.dist import Distribution
 import ez_setup
 ez_setup.use_setuptools()
 from setuptools import setup, Extension
 
+DEBUG = &quot;--debug&quot; in sys.argv
+
 def find_sources(extensions=[&quot;.c&quot;, &quot;.cpp&quot;]):
     ret = []
     for dpath, dnames, fnames in os.walk(&quot;./spidermonkey&quot;):
@@ -67,6 +78,13 @@ def platform_config():
         &quot;-D_BSD_SOURCE&quot;,
         &quot;-Wno-strict-prototypes&quot;
     ])
+    if DEBUG:
+        config[&quot;extra_compile_args&quot;].extend([
+            &quot;-UNDEBG&quot;,
+            &quot;-DDEBUG&quot;,
+            &quot;-DJS_PARANOID_REQUEST&quot;
+        ])
+
 
     if sysname in [&quot;Linux&quot;, &quot;FreeBSD&quot;]:
         config[&quot;extra_compile_args&quot;].extend([
@@ -81,6 +99,9 @@ def platform_config():
 
     return config
 
+Distribution.global_options.append((&quot;debug&quot;, None,
+                    &quot;Build a DEBUG version of spidermonkey&quot;))
+
 setup(
     name = &quot;python-spidermonkey&quot;,
     version = &quot;0.0.5&quot;,</diff>
      <filename>setup.py</filename>
    </modified>
    <modified>
      <diff>@@ -40,7 +40,6 @@ Context_new(PyTypeObject* type, PyObject* args, PyObject* kwargs)
     self-&gt;classes = (PyDictObject*) PyDict_New();
     if(self-&gt;classes == NULL) goto error;
 
-
     self-&gt;objects = (PySetObject*) PySet_New(NULL);
     if(self-&gt;objects == NULL) goto error;
 
@@ -51,6 +50,8 @@ Context_new(PyTypeObject* type, PyObject* args, PyObject* kwargs)
         goto error;
     }
 
+    JS_BeginRequest(self-&gt;cx);
+
     self-&gt;root = JS_NewObject(self-&gt;cx, &amp;js_global_class, NULL, NULL);
     if(self-&gt;root == NULL)
     {
@@ -85,9 +86,12 @@ Context_new(PyTypeObject* type, PyObject* args, PyObject* kwargs)
     goto success;
 
 error:
+    if(self != NULL &amp;&amp; self-&gt;cx != NULL) JS_EndRequest(self-&gt;cx);
     Py_XDECREF(self);
+    self = NULL;
 
 success:
+    if(self != NULL &amp;&amp; self-&gt;cx != NULL) JS_EndRequest(self-&gt;cx);
     return (PyObject*) self;
 }
 
@@ -119,6 +123,8 @@ Context_add_global(Context* self, PyObject* args, PyObject* kwargs)
     jsid kid;
     jsval jsv;
 
+    JS_BeginRequest(self-&gt;cx);
+
     if(!PyArg_ParseTuple(args, &quot;OO&quot;, &amp;pykey, &amp;pyval)) goto error;
 
     jsk = py2js(self, pykey);
@@ -143,6 +149,7 @@ Context_add_global(Context* self, PyObject* args, PyObject* kwargs)
 
 error:
 success:
+    JS_EndRequest(self-&gt;cx);
     Py_RETURN_NONE;
 }
 
@@ -155,6 +162,8 @@ Context_rem_global(Context* self, PyObject* args, PyObject* kwargs)
     jsid kid;
     jsval jsv;
 
+    JS_BeginRequest(self-&gt;cx);
+
     if(!PyArg_ParseTuple(args, &quot;O&quot;, &amp;pykey)) goto error;
 
     jsk = py2js(self, pykey);
@@ -186,6 +195,7 @@ Context_rem_global(Context* self, PyObject* args, PyObject* kwargs)
 
 error:
 success:
+    JS_EndRequest(self-&gt;cx);
     return ret;
 }
 
@@ -201,6 +211,7 @@ Context_execute(Context* self, PyObject* args, PyObject* kwargs)
     size_t slen;
     jsval rval;
 
+    JS_BeginRequest(self-&gt;cx);
     if(!PyArg_ParseTuple(args, &quot;O&quot;, &amp;obj)) goto error;
     
     script = py2js_string_obj(self, obj);
@@ -228,10 +239,13 @@ Context_execute(Context* self, PyObject* args, PyObject* kwargs)
     }
 
     ret = js2py(self, rval);
+    
+    JS_EndRequest(self-&gt;cx);
     JS_MaybeGC(self-&gt;cx);
     goto success;
 
 error:
+    JS_EndRequest(self-&gt;cx);
 success:
     return ret;
 }</diff>
      <filename>spidermonkey/context.c</filename>
    </modified>
    <modified>
      <diff>@@ -17,53 +17,75 @@ js2py_array(Context* cx, jsval val)
 Py_ssize_t
 Array_length(Object* self)
 {
+    Py_ssize_t ret = -1;
     jsuint length;
+
+    JS_BeginRequest(self-&gt;cx-&gt;cx);
+
     if(!JS_GetArrayLength(self-&gt;cx-&gt;cx, self-&gt;obj, &amp;length))
     {
         PyErr_SetString(PyExc_AttributeError, &quot;Failed to get array length.&quot;);
-        return -1;
+        goto done;
     }
 
-    return (Py_ssize_t) length;
+     ret = (Py_ssize_t) length;
+    
+done:
+    JS_EndRequest(self-&gt;cx-&gt;cx);
+    return ret;
 }
 
 PyObject*
 Array_get_item(Object* self, Py_ssize_t idx)
 {
+    PyObject* ret = NULL;
     jsval rval;
     jsint pos = (jsint) idx;
 
+    JS_BeginRequest(self-&gt;cx-&gt;cx);
+
     if(idx &gt;= Array_length(self))
     {
         PyErr_SetString(PyExc_IndexError, &quot;List index out of range.&quot;);
-        return NULL;
+        goto done;
     }
 
     if(!JS_GetElement(self-&gt;cx-&gt;cx, self-&gt;obj, pos, &amp;rval))
     {
         PyErr_SetString(PyExc_AttributeError, &quot;Failed to get array item.&quot;);
-        return NULL;
+        goto done;
     }
 
-    return js2py(self-&gt;cx, rval);
+    ret = js2py(self-&gt;cx, rval);
+
+done:
+    JS_EndRequest(self-&gt;cx-&gt;cx);
+    return ret;
 }
 
 int
 Array_set_item(Object* self, Py_ssize_t idx, PyObject* val)
 {
+    int ret = -1;
     jsval pval;
     jsint pos = (jsint) idx;
 
+    JS_BeginRequest(self-&gt;cx-&gt;cx);
+
     pval = py2js(self-&gt;cx, val);
-    if(pval == JSVAL_VOID) return -1;
+    if(pval == JSVAL_VOID) goto done;
 
     if(!JS_SetElement(self-&gt;cx-&gt;cx, self-&gt;obj, pos, &amp;pval))
     {
         PyErr_SetString(PyExc_AttributeError, &quot;Failed to set array item.&quot;);
-        return -1;
+        goto done;
     }
 
-    return 0;
+    ret = 0;
+
+done:
+    JS_EndRequest(self-&gt;cx-&gt;cx);
+    return ret;
 }
 
 PyObject*</diff>
      <filename>spidermonkey/jsarray.c</filename>
    </modified>
    <modified>
      <diff>@@ -43,7 +43,9 @@ Function_dealloc(Function* self)
 {
     if(self-&gt;parent != JSVAL_VOID)
     {
+        JS_BeginRequest(self-&gt;obj.cx-&gt;cx);
         JS_RemoveRoot(self-&gt;obj.cx-&gt;cx, &amp;(self-&gt;parent));
+        JS_EndRequest(self-&gt;obj.cx-&gt;cx);
     }
 
     ObjectType-&gt;tp_dealloc((PyObject*) self);
@@ -61,7 +63,9 @@ Function_call(Function* self, PyObject* args, PyObject* kwargs)
     jsval func;
     jsval* argv = NULL;
     jsval rval;
-    
+
+    JS_BeginRequest(self-&gt;obj.cx-&gt;cx);
+
     argc = PySequence_Length(args);
     if(argc &lt; 0) goto error;
     
@@ -93,11 +97,13 @@ Function_call(Function* self, PyObject* args, PyObject* kwargs)
     }
 
     ret = js2py(self-&gt;obj.cx, rval);
+    JS_EndRequest(self-&gt;obj.cx-&gt;cx);
     JS_MaybeGC(cx);
     goto success;
 
 error:
     if(argv != NULL) free(argv);
+    JS_EndRequest(self-&gt;obj.cx-&gt;cx);
 success:
     Py_XDECREF(item);
     return ret;</diff>
      <filename>spidermonkey/jsfunction.c</filename>
    </modified>
    <modified>
      <diff>@@ -14,8 +14,8 @@ Iterator_Wrap(Context* cx, JSObject* obj)
     Iterator* self = NULL;
     PyObject* tpl = NULL;
     PyObject* ret = NULL;
-    JSObject* iter = NULL;
-    jsval priv;
+
+    JS_BeginRequest(cx-&gt;cx);
 
     // Build our new python object.
     tpl = Py_BuildValue(&quot;(O)&quot;, cx);
@@ -43,6 +43,7 @@ error:
     ret = NULL; // In case it was AddRoot
 success:
     Py_XDECREF(tpl);
+    JS_EndRequest(cx-&gt;cx);
     return (PyObject*) ret;
 }
 
@@ -79,7 +80,9 @@ Iterator_dealloc(Iterator* self)
 {
     if(self-&gt;iter != NULL)
     {
+        JS_BeginRequest(self-&gt;cx-&gt;cx);
         JS_RemoveRoot(self-&gt;cx-&gt;cx, &amp;(self-&gt;root));
+        JS_EndRequest(self-&gt;cx-&gt;cx);
     }
    
     Py_XDECREF(self-&gt;cx);
@@ -92,6 +95,8 @@ Iterator_next(Iterator* self)
     jsid propid;
     jsval propname;
 
+    JS_BeginRequest(self-&gt;cx-&gt;cx);
+
     if(!JS_NextProperty(self-&gt;cx-&gt;cx, self-&gt;iter, &amp;propid))
     {
         PyErr_SetString(PyExc_RuntimeError, &quot;Failed to iterate next JS prop.&quot;);
@@ -106,12 +111,13 @@ Iterator_next(Iterator* self)
 
     if(propname != JSVAL_VOID)
     {
-        ret = js2py(self-&gt;cx-&gt;cx, propname);
+        ret = js2py(self-&gt;cx, propname);
     }
 
     // We return NULL with no error to signal completion.
 
 done:
+    JS_EndRequest(self-&gt;cx-&gt;cx);
     return ret;
 }
 </diff>
      <filename>spidermonkey/jsiterator.c</filename>
    </modified>
    <modified>
      <diff>@@ -23,6 +23,8 @@ make_object(PyTypeObject* type, Context* cx, jsval val)
     jsval priv;
     int found;
 
+    JS_BeginRequest(cx-&gt;cx);
+
     // Unwrapping if its wrapped.
     obj = JSVAL_TO_OBJECT(val);
     klass = JS_GetClass(cx-&gt;cx, obj);
@@ -70,6 +72,7 @@ error:
 
 success:
     Py_XDECREF(tpl);
+    JS_EndRequest(cx-&gt;cx);
     return (PyObject*) ret;
 }
 
@@ -113,7 +116,9 @@ Object_dealloc(Object* self)
 {
     if(self-&gt;val != JSVAL_VOID)
     {
+        JS_BeginRequest(self-&gt;cx-&gt;cx);
         JS_RemoveRoot(self-&gt;cx-&gt;cx, &amp;(self-&gt;val));
+        JS_EndRequest(self-&gt;cx-&gt;cx);
     }
    
     Py_XDECREF(self-&gt;cx);
@@ -127,16 +132,20 @@ Object_repr(Object* self)
     jschar* rchars = NULL;
     size_t rlen;
     
+    JS_BeginRequest(self-&gt;cx-&gt;cx);
+
     repr = JS_ValueToString(self-&gt;cx-&gt;cx, self-&gt;val);
     if(repr == NULL)
     {
         PyErr_SetString(PyExc_RuntimeError, &quot;Failed to convert to a string.&quot;);
+        JS_EndRequest(self-&gt;cx-&gt;cx);
         return NULL;
     }
 
     rchars = JS_GetStringChars(repr);
     rlen = JS_GetStringLength(repr);
 
+    JS_EndRequest(self-&gt;cx-&gt;cx);
     return PyUnicode_Decode((const char*) rchars, rlen*2, &quot;utf-16&quot;, &quot;strict&quot;);
 }
 
@@ -155,6 +164,7 @@ Object_length(Object* self)
         prototype as per JS for ... in ... semantics.
     */
     
+    JS_BeginRequest(self-&gt;cx-&gt;cx);
     cx = self-&gt;cx-&gt;cx;
     iter = JS_NewPropertyIterator(cx, self-&gt;obj);
     status = JS_NextProperty(cx, iter, &amp;pid);
@@ -164,58 +174,69 @@ Object_length(Object* self)
         status = JS_NextProperty(cx, iter, &amp;pid);
     }
 
+    JS_EndRequest(self-&gt;cx-&gt;cx);
     return ret;
 }
 
 PyObject*
 Object_getitem(Object* self, PyObject* key)
 {
+    PyObject* ret = NULL;
     jsval pval;
     jsid pid;
 
+    JS_BeginRequest(self-&gt;cx-&gt;cx);
+
     pval = py2js(self-&gt;cx, key);
     if(pval == JSVAL_VOID) return NULL;
    
     if(!JS_ValueToId(self-&gt;cx-&gt;cx, pval, &amp;pid))
     {
         PyErr_SetString(PyExc_KeyError, &quot;Failed to get property id.&quot;);
-        return NULL;
+        goto done;
     }
     
     if(!js_GetProperty(self-&gt;cx-&gt;cx, self-&gt;obj, pid, &amp;pval))
     {
         PyErr_SetString(PyExc_AttributeError, &quot;Failed to get property.&quot;);
-        return NULL;
+        goto done;
     }
 
-    return js2py_with_parent(self-&gt;cx, pval, self-&gt;val);
+    ret = js2py_with_parent(self-&gt;cx, pval, self-&gt;val);
+
+done:
+    JS_EndRequest(self-&gt;cx-&gt;cx);
+    return ret;
 }
 
 int
 Object_setitem(Object* self, PyObject* key, PyObject* val)
 {
+    int ret = -1;
     jsval pval;
     jsval vval;
     jsid pid;
 
+    JS_BeginRequest(self-&gt;cx-&gt;cx);
+
     pval = py2js(self-&gt;cx, key);
-    if(pval == JSVAL_VOID) return -1;
+    if(pval == JSVAL_VOID) goto done;
    
     if(!JS_ValueToId(self-&gt;cx-&gt;cx, pval, &amp;pid))
     {
         PyErr_SetString(PyExc_KeyError, &quot;Failed to get property id.&quot;);
-        return -1;
+        goto done;
     }
    
     if(val != NULL)
     {
         vval = py2js(self-&gt;cx, val);
-        if(vval == JSVAL_VOID) return -1;
+        if(vval == JSVAL_VOID) goto done;
 
         if(!js_SetProperty(self-&gt;cx-&gt;cx, self-&gt;obj, pid, &amp;vval))
         {
             PyErr_SetString(PyExc_AttributeError, &quot;Failed to set property.&quot;);
-            return -1;
+            goto done;
         }
     }
     else
@@ -223,17 +244,20 @@ Object_setitem(Object* self, PyObject* key, PyObject* val)
         if(!js_DeleteProperty(self-&gt;cx-&gt;cx, self-&gt;obj, pid, &amp;vval))
         {
             PyErr_SetString(PyExc_AttributeError, &quot;Failed to delete property.&quot;);
-            return -1;
+            goto done;
         }
 
         if(vval == JSVAL_VOID)
         {
             PyErr_SetString(PyExc_AttributeError, &quot;Unable to delete property.&quot;);
-            return -1;
+            goto done;
         }
     }
 
-    return 0;
+    ret = 0;
+done:
+    JS_EndRequest(self-&gt;cx-&gt;cx);
+    return ret;
 }
 
 PyObject*
@@ -253,6 +277,8 @@ Object_rich_cmp(Object* self, PyObject* other, int op)
     int rlen;
     int cmp;
 
+    JS_BeginRequest(self-&gt;cx-&gt;cx);
+
     if(!PyMapping_Check(other) &amp;&amp; !PySequence_Check(other))
     {
         PyErr_SetString(PyExc_ValueError, &quot;Invalid rhs operand.&quot;);
@@ -335,6 +361,7 @@ success:
     Py_XDECREF(otherval);
     // Inc ref the true or false return
     if(ret == Py_True || ret == Py_False) Py_INCREF(ret);
+    JS_EndRequest(self-&gt;cx-&gt;cx);
     return ret;
 }
 </diff>
      <filename>spidermonkey/jsobject.c</filename>
    </modified>
    <modified>
      <diff>@@ -29,6 +29,8 @@ finalize(JSContext* jscx, JSObject* jsobj)
     PyObject* pyobj = NULL;
     PyObject* pyiter = NULL;
 
+    JS_BeginRequest(jscx);
+
     if(pycx == NULL)
     {
         fprintf(stderr, &quot;*** NO PYTHON CONTEXT ***\n&quot;);
@@ -41,6 +43,8 @@ finalize(JSContext* jscx, JSObject* jsobj)
     pyiter = get_js_slot(jscx, jsobj, 1);
     Py_DECREF(pyiter);
 
+    JS_EndRequest(jscx);
+
     Py_DECREF(pycx);
 }
 </diff>
      <filename>spidermonkey/pyiter.c</filename>
    </modified>
    <modified>
      <diff>@@ -205,7 +205,7 @@ js_finalize(JSContext* jscx, JSObject* jsobj)
 {
     Context* pycx = (Context*) JS_GetContextPrivate(jscx);
     PyObject* pyobj = NULL;
-   
+  
     if(pycx == NULL)
     {
         // Not much else we can do but yell.
@@ -213,7 +213,10 @@ js_finalize(JSContext* jscx, JSObject* jsobj)
         return;
     }
 
+    JS_BeginRequest(jscx);
     pyobj = get_py_obj(jscx, jsobj);
+    JS_EndRequest(jscx);
+
     Py_DECREF(pyobj);
 
     // Technically, this could turn out to be nasty. If</diff>
      <filename>spidermonkey/pyobject.c</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>d3f9770b7b0894e68834c5071714811810e7e01e</id>
    </parent>
  </parents>
  <author>
    <name>Paul Davis</name>
    <email>davisp@davis-2318.local</email>
  </author>
  <url>http://github.com/defunkt/python-spidermonkey/commit/786f808e62fd0a891ece4d60bff5626e2e1364cf</url>
  <id>786f808e62fd0a891ece4d60bff5626e2e1364cf</id>
  <committed-date>2009-05-09T21:49:34-07:00</committed-date>
  <authored-date>2009-05-09T21:49:34-07:00</authored-date>
  <message>Add JS_[Begin|End]Request semantics.

This should wrap entries into the JS VM in JS_BeginRequest/JS_EndRequest calls.
I've added a setup.py debug flag to build spidermonkey in debug mode so that
calls into the VM requiring a request fail on an assert. To build in debug mode
you can do:

    python setup.py --debug $(ACTION)

I basically went through and added the calls where I thought they should go and
then turned on the debug build to get the ones I missed. Its quite possible I
still have some edge cases missing their required calls.

[#2 state:resolved]</message>
  <tree>397ffe5b9e2858d9ac2bb42d77d226b7f018d2ef</tree>
  <committer>
    <name>Paul Davis</name>
    <email>davisp@davis-2318.local</email>
  </committer>
</commit>
