Skip to content

Commit

Permalink
Add JS_[Begin|End]Request semantics.
Browse files Browse the repository at this point in the history
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
Paul Davis committed May 10, 2009
1 parent d3f9770 commit 786f808
Show file tree
Hide file tree
Showing 9 changed files with 128 additions and 25 deletions.
2 changes: 1 addition & 1 deletion go.comm
@@ -1,4 +1,4 @@
run setup.py test
run setup.py --debug test
bt
continue
bt
21 changes: 21 additions & 0 deletions setup.py
Expand Up @@ -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"):
Expand Down Expand Up @@ -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([
Expand All @@ -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",
Expand Down
16 changes: 15 additions & 1 deletion spidermonkey/context.c
Expand Up @@ -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;

Expand All @@ -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)
{
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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);
Expand All @@ -143,6 +149,7 @@ Context_add_global(Context* self, PyObject* args, PyObject* kwargs)

error:
success:
JS_EndRequest(self->cx);
Py_RETURN_NONE;
}

Expand All @@ -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);
Expand Down Expand Up @@ -186,6 +195,7 @@ Context_rem_global(Context* self, PyObject* args, PyObject* kwargs)

error:
success:
JS_EndRequest(self->cx);
return ret;
}

Expand All @@ -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);
Expand Down Expand Up @@ -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;
}
Expand Down
38 changes: 30 additions & 8 deletions spidermonkey/jsarray.c
Expand Up @@ -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*
Expand Down
8 changes: 7 additions & 1 deletion spidermonkey/jsfunction.c
Expand Up @@ -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);
Expand All @@ -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;

Expand Down Expand Up @@ -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;
Expand Down
12 changes: 9 additions & 3 deletions spidermonkey/jsiterator.c
Expand Up @@ -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);
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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);
Expand All @@ -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.");
Expand All @@ -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;
}

Expand Down

0 comments on commit 786f808

Please sign in to comment.