Browse files

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]
  • Loading branch information...
1 parent d3f9770 commit 786f808e62fd0a891ece4d60bff5626e2e1364cf Paul Davis committed May 10, 2009
Showing with 128 additions and 25 deletions.
  1. +1 −1 go.comm
  2. +21 −0 setup.py
  3. +15 −1 spidermonkey/context.c
  4. +30 −8 spidermonkey/jsarray.c
  5. +7 −1 spidermonkey/jsfunction.c
  6. +9 −3 spidermonkey/jsiterator.c
  7. +37 −10 spidermonkey/jsobject.c
  8. +4 −0 spidermonkey/pyiter.c
  9. +4 −1 spidermonkey/pyobject.c
View
2 go.comm
@@ -1,4 +1,4 @@
-run setup.py test
+run setup.py --debug test
bt
continue
bt
View
21 setup.py
@@ -13,13 +13,24 @@
Javascript Perl module, in turn based on Mozilla's 'PerlConnect' Perl binding.
""",
+# 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("libc.dylib")
+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 = "--debug" in sys.argv
+
def find_sources(extensions=[".c", ".cpp"]):
ret = []
for dpath, dnames, fnames in os.walk("./spidermonkey"):
@@ -67,6 +78,13 @@ def platform_config():
"-D_BSD_SOURCE",
"-Wno-strict-prototypes"
])
+ if DEBUG:
+ config["extra_compile_args"].extend([
+ "-UNDEBG",
+ "-DDEBUG",
+ "-DJS_PARANOID_REQUEST"
+ ])
+
if sysname in ["Linux", "FreeBSD"]:
config["extra_compile_args"].extend([
@@ -81,6 +99,9 @@ def platform_config():
return config
+Distribution.global_options.append(("debug", None,
+ "Build a DEBUG version of spidermonkey"))
+
setup(
name = "python-spidermonkey",
version = "0.0.5",
View
16 spidermonkey/context.c
@@ -40,7 +40,6 @@ Context_new(PyTypeObject* type, PyObject* args, PyObject* kwargs)
self->classes = (PyDictObject*) PyDict_New();
if(self->classes == NULL) goto error;
-
self->objects = (PySetObject*) PySet_New(NULL);
if(self->objects == NULL) goto error;
@@ -51,6 +50,8 @@ Context_new(PyTypeObject* type, PyObject* args, PyObject* kwargs)
goto error;
}
+ JS_BeginRequest(self->cx);
+
self->root = JS_NewObject(self->cx, &js_global_class, NULL, NULL);
if(self->root == NULL)
{
@@ -85,9 +86,12 @@ Context_new(PyTypeObject* type, PyObject* args, PyObject* kwargs)
goto success;
error:
+ if(self != NULL && self->cx != NULL) JS_EndRequest(self->cx);
Py_XDECREF(self);
+ self = NULL;
success:
+ if(self != NULL && self->cx != NULL) JS_EndRequest(self->cx);
return (PyObject*) self;
}
@@ -119,6 +123,8 @@ Context_add_global(Context* self, PyObject* args, PyObject* kwargs)
jsid kid;
jsval jsv;
+ JS_BeginRequest(self->cx);
+
if(!PyArg_ParseTuple(args, "OO", &pykey, &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->cx);
Py_RETURN_NONE;
}
@@ -155,6 +162,8 @@ Context_rem_global(Context* self, PyObject* args, PyObject* kwargs)
jsid kid;
jsval jsv;
+ JS_BeginRequest(self->cx);
+
if(!PyArg_ParseTuple(args, "O", &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->cx);
return ret;
}
@@ -201,6 +211,7 @@ Context_execute(Context* self, PyObject* args, PyObject* kwargs)
size_t slen;
jsval rval;
+ JS_BeginRequest(self->cx);
if(!PyArg_ParseTuple(args, "O", &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->cx);
JS_MaybeGC(self->cx);
goto success;
error:
+ JS_EndRequest(self->cx);
success:
return ret;
}
View
38 spidermonkey/jsarray.c
@@ -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->cx->cx);
+
if(!JS_GetArrayLength(self->cx->cx, self->obj, &length))
{
PyErr_SetString(PyExc_AttributeError, "Failed to get array length.");
- return -1;
+ goto done;
}
- return (Py_ssize_t) length;
+ ret = (Py_ssize_t) length;
+
+done:
+ JS_EndRequest(self->cx->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->cx->cx);
+
if(idx >= Array_length(self))
{
PyErr_SetString(PyExc_IndexError, "List index out of range.");
- return NULL;
+ goto done;
}
if(!JS_GetElement(self->cx->cx, self->obj, pos, &rval))
{
PyErr_SetString(PyExc_AttributeError, "Failed to get array item.");
- return NULL;
+ goto done;
}
- return js2py(self->cx, rval);
+ ret = js2py(self->cx, rval);
+
+done:
+ JS_EndRequest(self->cx->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->cx->cx);
+
pval = py2js(self->cx, val);
- if(pval == JSVAL_VOID) return -1;
+ if(pval == JSVAL_VOID) goto done;
if(!JS_SetElement(self->cx->cx, self->obj, pos, &pval))
{
PyErr_SetString(PyExc_AttributeError, "Failed to set array item.");
- return -1;
+ goto done;
}
- return 0;
+ ret = 0;
+
+done:
+ JS_EndRequest(self->cx->cx);
+ return ret;
}
PyObject*
View
8 spidermonkey/jsfunction.c
@@ -43,7 +43,9 @@ Function_dealloc(Function* self)
{
if(self->parent != JSVAL_VOID)
{
+ JS_BeginRequest(self->obj.cx->cx);
JS_RemoveRoot(self->obj.cx->cx, &(self->parent));
+ JS_EndRequest(self->obj.cx->cx);
}
ObjectType->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->obj.cx->cx);
+
argc = PySequence_Length(args);
if(argc < 0) goto error;
@@ -93,11 +97,13 @@ Function_call(Function* self, PyObject* args, PyObject* kwargs)
}
ret = js2py(self->obj.cx, rval);
+ JS_EndRequest(self->obj.cx->cx);
JS_MaybeGC(cx);
goto success;
error:
if(argv != NULL) free(argv);
+ JS_EndRequest(self->obj.cx->cx);
success:
Py_XDECREF(item);
return ret;
View
12 spidermonkey/jsiterator.c
@@ -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->cx);
// Build our new python object.
tpl = Py_BuildValue("(O)", cx);
@@ -43,6 +43,7 @@ Iterator_Wrap(Context* cx, JSObject* obj)
ret = NULL; // In case it was AddRoot
success:
Py_XDECREF(tpl);
+ JS_EndRequest(cx->cx);
return (PyObject*) ret;
}
@@ -79,7 +80,9 @@ Iterator_dealloc(Iterator* self)
{
if(self->iter != NULL)
{
+ JS_BeginRequest(self->cx->cx);
JS_RemoveRoot(self->cx->cx, &(self->root));
+ JS_EndRequest(self->cx->cx);
}
Py_XDECREF(self->cx);
@@ -92,6 +95,8 @@ Iterator_next(Iterator* self)
jsid propid;
jsval propname;
+ JS_BeginRequest(self->cx->cx);
+
if(!JS_NextProperty(self->cx->cx, self->iter, &propid))
{
PyErr_SetString(PyExc_RuntimeError, "Failed to iterate next JS prop.");
@@ -106,12 +111,13 @@ Iterator_next(Iterator* self)
if(propname != JSVAL_VOID)
{
- ret = js2py(self->cx->cx, propname);
+ ret = js2py(self->cx, propname);
}
// We return NULL with no error to signal completion.
done:
+ JS_EndRequest(self->cx->cx);
return ret;
}
View
47 spidermonkey/jsobject.c
@@ -23,6 +23,8 @@ make_object(PyTypeObject* type, Context* cx, jsval val)
jsval priv;
int found;
+ JS_BeginRequest(cx->cx);
+
// Unwrapping if its wrapped.
obj = JSVAL_TO_OBJECT(val);
klass = JS_GetClass(cx->cx, obj);
@@ -70,6 +72,7 @@ make_object(PyTypeObject* type, Context* cx, jsval val)
success:
Py_XDECREF(tpl);
+ JS_EndRequest(cx->cx);
return (PyObject*) ret;
}
@@ -113,7 +116,9 @@ Object_dealloc(Object* self)
{
if(self->val != JSVAL_VOID)
{
+ JS_BeginRequest(self->cx->cx);
JS_RemoveRoot(self->cx->cx, &(self->val));
+ JS_EndRequest(self->cx->cx);
}
Py_XDECREF(self->cx);
@@ -127,16 +132,20 @@ Object_repr(Object* self)
jschar* rchars = NULL;
size_t rlen;
+ JS_BeginRequest(self->cx->cx);
+
repr = JS_ValueToString(self->cx->cx, self->val);
if(repr == NULL)
{
PyErr_SetString(PyExc_RuntimeError, "Failed to convert to a string.");
+ JS_EndRequest(self->cx->cx);
return NULL;
}
rchars = JS_GetStringChars(repr);
rlen = JS_GetStringLength(repr);
+ JS_EndRequest(self->cx->cx);
return PyUnicode_Decode((const char*) rchars, rlen*2, "utf-16", "strict");
}
@@ -155,6 +164,7 @@ Object_length(Object* self)
prototype as per JS for ... in ... semantics.
*/
+ JS_BeginRequest(self->cx->cx);
cx = self->cx->cx;
iter = JS_NewPropertyIterator(cx, self->obj);
status = JS_NextProperty(cx, iter, &pid);
@@ -164,76 +174,90 @@ Object_length(Object* self)
status = JS_NextProperty(cx, iter, &pid);
}
+ JS_EndRequest(self->cx->cx);
return ret;
}
PyObject*
Object_getitem(Object* self, PyObject* key)
{
+ PyObject* ret = NULL;
jsval pval;
jsid pid;
+ JS_BeginRequest(self->cx->cx);
+
pval = py2js(self->cx, key);
if(pval == JSVAL_VOID) return NULL;
if(!JS_ValueToId(self->cx->cx, pval, &pid))
{
PyErr_SetString(PyExc_KeyError, "Failed to get property id.");
- return NULL;
+ goto done;
}
if(!js_GetProperty(self->cx->cx, self->obj, pid, &pval))
{
PyErr_SetString(PyExc_AttributeError, "Failed to get property.");
- return NULL;
+ goto done;
}
- return js2py_with_parent(self->cx, pval, self->val);
+ ret = js2py_with_parent(self->cx, pval, self->val);
+
+done:
+ JS_EndRequest(self->cx->cx);
+ return ret;
}
int
Object_setitem(Object* self, PyObject* key, PyObject* val)
{
+ int ret = -1;
jsval pval;
jsval vval;
jsid pid;
+ JS_BeginRequest(self->cx->cx);
+
pval = py2js(self->cx, key);
- if(pval == JSVAL_VOID) return -1;
+ if(pval == JSVAL_VOID) goto done;
if(!JS_ValueToId(self->cx->cx, pval, &pid))
{
PyErr_SetString(PyExc_KeyError, "Failed to get property id.");
- return -1;
+ goto done;
}
if(val != NULL)
{
vval = py2js(self->cx, val);
- if(vval == JSVAL_VOID) return -1;
+ if(vval == JSVAL_VOID) goto done;
if(!js_SetProperty(self->cx->cx, self->obj, pid, &vval))
{
PyErr_SetString(PyExc_AttributeError, "Failed to set property.");
- return -1;
+ goto done;
}
}
else
{
if(!js_DeleteProperty(self->cx->cx, self->obj, pid, &vval))
{
PyErr_SetString(PyExc_AttributeError, "Failed to delete property.");
- return -1;
+ goto done;
}
if(vval == JSVAL_VOID)
{
PyErr_SetString(PyExc_AttributeError, "Unable to delete property.");
- return -1;
+ goto done;
}
}
- return 0;
+ ret = 0;
+done:
+ JS_EndRequest(self->cx->cx);
+ return ret;
}
PyObject*
@@ -253,6 +277,8 @@ Object_rich_cmp(Object* self, PyObject* other, int op)
int rlen;
int cmp;
+ JS_BeginRequest(self->cx->cx);
+
if(!PyMapping_Check(other) && !PySequence_Check(other))
{
PyErr_SetString(PyExc_ValueError, "Invalid rhs operand.");
@@ -335,6 +361,7 @@ Object_rich_cmp(Object* self, PyObject* other, int op)
Py_XDECREF(otherval);
// Inc ref the true or false return
if(ret == Py_True || ret == Py_False) Py_INCREF(ret);
+ JS_EndRequest(self->cx->cx);
return ret;
}
View
4 spidermonkey/pyiter.c
@@ -29,6 +29,8 @@ finalize(JSContext* jscx, JSObject* jsobj)
PyObject* pyobj = NULL;
PyObject* pyiter = NULL;
+ JS_BeginRequest(jscx);
+
if(pycx == NULL)
{
fprintf(stderr, "*** NO PYTHON CONTEXT ***\n");
@@ -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);
}
View
5 spidermonkey/pyobject.c
@@ -205,15 +205,18 @@ 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.
fprintf(stderr, "*** NO PYTHON CONTEXT ***\n");
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

0 comments on commit 786f808

Please sign in to comment.