# HG changeset patch # User Atul Varma # Date 1251684226 25200 # Node ID 1f9a5982db9c2e37c28298c5ba8d339d08e54c6f # Parent 3fadba04220142f77d8150bc78f31d3c4ab4cf3c Added a context.set_throw_hook() method. diff -r 3fadba042201 -r 1f9a5982db9c src/context.cpp --- a/src/context.cpp Sun Aug 30 17:07:38 2009 -0700 +++ b/src/context.cpp Sun Aug 30 19:03:46 2009 -0700 @@ -43,6 +43,33 @@ #include "jsdbgapi.h" #include "jsscript.h" +// This is the default throw hook for pymonkey-owned JS contexts, +// when they've defined one in Python. +static JSTrapStatus +PYM_throwHook(JSContext *cx, JSScript *script, jsbytecode *pc, jsval *rval, + void *closure) +{ + PYM_PyAutoEnsureGIL gil; + PYM_JSContextObject *context = (PYM_JSContextObject *) + JS_GetContextPrivate(cx); + + PyObject *callable = context->throwHook; + PyObject *args = PyTuple_Pack(1, (PyObject *) context); + if (args == NULL) { + JS_ReportOutOfMemory(cx); + return JSTRAP_CONTINUE; + } + PyObject *result = PyObject_Call(callable, args, NULL); + Py_DECREF(args); + if (result == NULL) { + PYM_pythonExceptionToJs(context); + return JSTRAP_CONTINUE; + } + + Py_DECREF(result); + return JSTRAP_CONTINUE; +} + // This is the default JSOperationCallback for pymonkey-owned JS contexts, // when they've defined one in Python. static JSBool @@ -92,6 +119,7 @@ PYM_traverse(PYM_JSContextObject *self, visitproc visit, void *arg) { Py_VISIT(self->opCallback); + Py_VISIT(self->throwHook); Py_VISIT(self->runtime); return 0; } @@ -100,6 +128,7 @@ PYM_clear(PYM_JSContextObject *self) { Py_CLEAR(self->opCallback); + Py_CLEAR(self->throwHook); Py_CLEAR(self->runtime); return 0; } @@ -630,6 +659,31 @@ } static PyObject * +PYM_setThrowHook(PYM_JSContextObject *self, PyObject *args) +{ + PYM_SANITY_CHECK(self->runtime); + PyObject *callable; + + if (!PyArg_ParseTuple(args, "O", &callable)) + return NULL; + + if (!PyCallable_Check(callable)) { + PyErr_SetString(PyExc_TypeError, "Callable must be callable"); + return NULL; + } + + self->hooks.throwHook = PYM_throwHook; + JS_SetContextDebugHooks(self->cx, &self->hooks); + + Py_INCREF(callable); + if (self->throwHook) + Py_DECREF(self->throwHook); + self->throwHook = callable; + + Py_RETURN_NONE; +} + +static PyObject * PYM_setOperationCallback(PYM_JSContextObject *self, PyObject *args) { PYM_SANITY_CHECK(self->runtime); @@ -701,6 +755,8 @@ {"set_operation_callback", (PyCFunction) PYM_setOperationCallback, METH_VARARGS, "Sets the operation callback for the context."}, + {"set_throw_hook", (PyCFunction) PYM_setThrowHook, METH_VARARGS, + "Sets the throw hook for the context."}, {"trigger_operation_callback", (PyCFunction) PYM_triggerOperationCallback, METH_VARARGS, "Triggers the operation callback for the context."}, @@ -765,8 +821,11 @@ if (context == NULL) return NULL; + memset(&context->hooks, 0, sizeof(context->hooks)); + context->weakrefs = NULL; context->opCallback = NULL; + context->throwHook = NULL; context->runtime = runtime; Py_INCREF(runtime); diff -r 3fadba042201 -r 1f9a5982db9c src/context.h --- a/src/context.h Sun Aug 30 17:07:38 2009 -0700 +++ b/src/context.h Sun Aug 30 19:03:46 2009 -0700 @@ -40,6 +40,7 @@ #include "runtime.h" #include +#include #include typedef struct { @@ -47,7 +48,9 @@ PYM_JSRuntimeObject *runtime; JSContext *cx; PyObject *opCallback; + PyObject *throwHook; PyObject *weakrefs; + JSDebugHooks hooks; } PYM_JSContextObject; extern PyTypeObject PYM_JSContextType; diff -r 3fadba042201 -r 1f9a5982db9c tests/test_pymonkey.py --- a/tests/test_pymonkey.py Sun Aug 30 17:07:38 2009 -0700 +++ b/tests/test_pymonkey.py Sun Aug 30 19:03:46 2009 -0700 @@ -232,6 +232,22 @@ '(function(){})', '', 1) self.assertEqual(cx.get_object_private(jsfunc), None) + def testThrowHookWorks(self): + timesCalled = [0] + def throwhook(cx): + timesCalled[0] += 1 + + cx = pymonkey.Runtime().new_context() + cx.set_throw_hook(throwhook) + self.assertRaises( + pymonkey.error, + cx.evaluate_script, + cx.new_object(), + '(function() { throw "hi"; })()', + '', 1 + ) + self.assertEqual(timesCalled[0], 2) + def testJsWrappedPythonFuncHasPrivate(self): def foo(cx, this, args): pass