Commits

Paul J. Davis  committed b2211e2

More RAII plzkthx.

Moving towards implementing simplifications using C++ RAII awesomeness.

  • Participants
  • Parent commits 3433175

Comments (0)

Files changed (16)

File spidermonkey/convert/array.cpp

-#include <spidermonkey.h>
+#include "convert.h"
 
 PyObject*
 js2py_array(Context* cx, jsval val)

File spidermonkey/convert/convert.cpp

  *
  */
 
-#include <spidermonkey.h>
+#include <jsapi.h>
+#include "convert.h"
+#include "python/python.h"
 
 jsval
 py2js(Context* cx, PyObject* obj)

File spidermonkey/convert/double.cpp

  *
  */
 
-#include <spidermonkey.h>
+#include "convert.h"
 
 jsval
 py2js_double(Context* cx, PyObject* obj)

File spidermonkey/convert/function.cpp

 
-#include <spidermonkey.h>
+#include "convert.h"
 
 PyObject*
 js2py_function(Context* cx, jsval val, jsval parent)

File spidermonkey/convert/integer.cpp

  *
  */
 
-#include <spidermonkey.h>
+#include "convert.h"
 
 jsval
 py2js_integer(Context* cx, PyObject* obj)

File spidermonkey/convert/object.cpp

 
-#include <spidermonkey.h>
+#include "convert.h"
+#include "javascript/javascript.h"
 
 jsval
 py2js_object(Context* cx, PyObject* pyobj)

File spidermonkey/convert/string.cpp

  *
  */
 
-#include <spidermonkey.h>
+#include "convert.h"
 
 JSString*
 py2js_string_obj(Context* cx, PyObject* str)

File spidermonkey/javascript/error.cpp

 #include <spidermonkey.h>
 #include "frameobject.h"
 
+JSBool
+js_error(JSContext* cx, const char* err)
+{
+    JS_ReportError(cx, err);
+    return JS_FALSE;
+}
+
 void
 add_frame(const char* srcfile, const char* funcname, int linenum)
 {
-    PyObject* src = NULL;
-    PyObject* func = NULL;
-    PyObject* glbl = NULL;
-    PyObject* tpl = NULL;
-    PyObject* str = NULL;
-    PyCodeObject* code = NULL;
-    PyFrameObject* frame = NULL;
+    PyObjectXDR src = PyString_FromString(srcfile);
+    PyObjectXDR func = PyString_FromString(funcname);
+    PyObjectXDR tpl = PyTuple_New(0);
+    PyObjectXDR str = PyString_FromString("");
 
-    src = PyString_FromString(srcfile);
-    if(src == NULL) goto error;
+    // This is a borrowed reference, hence no PyObjectXDR so we
+    // don't decref it.
+    PyPtr<PyObject> glbl = PyModule_GetDict(SpidermonkeyModule);
 
-    func = PyString_FromString(funcname);
-    if(func == NULL) goto error;
-    
-    glbl = PyModule_GetDict(SpidermonkeyModule);
-    if(glbl == NULL) goto error;
+    if(!src || !func || !glbl || !tpl || !str) return;
 
-    tpl = PyTuple_New(0);
-    if(tpl == NULL) goto error;
-
-    str = PyString_FromString("");
-    if(str == NULL) goto error;
-
-    code = PyCode_New(
+    PyCodeXDR code = PyCode_New(
         0,                      /*co_argcount*/
         0,                      /*co_nlocals*/
         0,                      /*co_stacksize*/
         0,                      /*co_flags*/
-        str,                    /*co_code*/
-        tpl,                    /*co_consts*/
-        tpl,                    /*co_names*/
-        tpl,                    /*co_varnames*/
-        tpl,                    /*co_freevars*/
-        tpl,                    /*co_cellvars*/
-        src,                    /*co_filename*/
-        func,                   /*co_name*/
+        str.get(),              /*co_code*/
+        tpl.get(),              /*co_consts*/
+        tpl.get(),              /*co_names*/
+        tpl.get(),              /*co_varnames*/
+        tpl.get(),              /*co_freevars*/
+        tpl.get(),              /*co_cellvars*/
+        src.get(),              /*co_filename*/
+        func.get(),             /*co_name*/
         linenum,                /*co_firstlineno*/
-        str                     /*co_lnotab*/
+        str.get()               /*co_lnotab*/
     );
-    if(code == NULL) goto error;
+    if(!code) return;
    
-    frame = PyFrame_New(PyThreadState_Get(), code, glbl, NULL);
-    if(frame == NULL) goto error;
+    PyFrameXDR frame = PyFrame_New(
+        PyThreadState_Get(), code.get(), glbl.get(), NULL
+    );
+    if(!frame) return;
     
     frame->f_lineno = linenum;
-    PyTraceBack_Here(frame);
-
-    goto success;
-    
-error:
-success:
-    Py_XDECREF(func);
-    Py_XDECREF(src);
-    Py_XDECREF(tpl);
-    Py_XDECREF(str);
-    Py_XDECREF(code);
-    Py_XDECREF(frame);
+    PyTraceBack_Here(frame.get());
 }
 
 void

File spidermonkey/javascript/global.cpp

 JSBool
 add_prop(JSContext* jscx, JSObject* jsobj, jsval key, jsval* rval)
 {
-    JSObject* obj = NULL;
+    if(JSVAL_IS_NULL(*rval) || !JSVAL_IS_OBJECT(*rval))
+        return JS_TRUE;
 
-    if(JSVAL_IS_NULL(*rval) || !JSVAL_IS_OBJECT(*rval)) return JS_TRUE;
+    if(JS_ObjectIsFunction(jscx, JSVAL_TO_OBJECT(*rval)))
+        return set_prop(jscx, jsobj, key, rval);
 
-    obj = JSVAL_TO_OBJECT(*rval);
-    if(JS_ObjectIsFunction(jscx, obj)) return set_prop(jscx, jsobj, key, rval);
     return JS_TRUE;
 }
 
 JSBool
 del_prop(JSContext* jscx, JSObject* jsobj, jsval key, jsval* rval)
 {
-    Context* pycx = NULL;
-    PyObject* pykey = NULL;
-    PyObject* pyval = NULL;
-    JSBool ret = JS_FALSE;
+    PyPtr<Context> pycx = (Context*) JS_GetContextPrivate(jscx);
+    if(!pycx) return js_error(jscx, "Failed to get Python context.");
 
-    pycx = (Context*) JS_GetContextPrivate(jscx);
-    if(pycx == NULL)
-    {
-        JS_ReportError(jscx, "Failed to get Python context.");
-        goto done;
-    }
+    if(pycx->pyglobal == NULL) return JS_TRUE;
+    if(!PyObject_HasAttrString(pycx->pyglobal, "__delitem__")) return JS_TRUE;
 
-    // Bail if there's no registered global handler.
-    if(pycx->pyglobal == NULL)
-    {
-        ret = JS_TRUE;
-        goto done;
-    }
+    PyObjectXDR pykey = js2py(pycx.get(), key);
+    if(!pykey) return js_error(jscx, "Failed to covert key.");
+
+    if(Context_has_access(pycx.get(), jscx, pycx->pyglobal, pykey.get()) <= 0)
+        return js_error(jscx, "Access denied.");
     
-    // Check access to python land.
-    if(Context_has_access(pycx, jscx, pycx->pyglobal, pykey) <= 0) goto done;
-
-    // Bail if the global doesn't have a __delitem__
-    if(!PyObject_HasAttrString(pycx->pyglobal, "__delitem__"))
-    {
-        ret = JS_TRUE;
-        goto done;
-    }
-
-    pykey = js2py(pycx, key);
-    if(pykey == NULL) goto done;
-
-    if(PyObject_DelItem(pycx->pyglobal, pykey) < 0) goto done;
-
-    ret = JS_TRUE;
-
-done:
-    Py_XDECREF(pykey);
-    Py_XDECREF(pyval);
-    return ret;
+    if(PyObject_DelItem(pycx->pyglobal, pykey.get()) < 0)
+        return js_error(jscx, "Failed to delete key.");
+    
+    return JS_TRUE;
 }
 
 JSBool
 get_prop(JSContext* jscx, JSObject* jsobj, jsval key, jsval* rval)
 {
-    Context* pycx = NULL;
-    PyObject* pykey = NULL;
-    PyObject* pyval = NULL;
-    JSBool ret = JS_FALSE;
+    PyPtr<Context> pycx = (Context*) JS_GetContextPrivate(jscx);
+    if(!pycx) return js_error(jscx, "Failed to get Python context.");
+    
+    if(pycx->pyglobal == NULL) return JS_TRUE;
+    
+    PyObjectXDR pykey = js2py(pycx.get(), key);
+    if(!pykey) return js_error(jscx, "Failed to convert key.");
+    
+    if(Context_has_access(pycx.get(), jscx, pycx->pyglobal, pykey.get()) <= 0)
+        return js_error(jscx, "Access denied.");
 
-    pycx = (Context*) JS_GetContextPrivate(jscx);
-    if(pycx == NULL)
-    {
-        JS_ReportError(jscx, "Failed to get Python context.");
-        goto done;
-    }
-
-    // Bail if there's no registered global handler.
-    if(pycx->pyglobal == NULL)
-    {
-        ret = JS_TRUE;
-        goto done;
-    }
-
-    pykey = js2py(pycx, key);
-    if(pykey == NULL) goto done;
-
-    if(Context_has_access(pycx, jscx, pycx->pyglobal, pykey) <= 0) goto done;
-
-    pyval = PyObject_GetItem(pycx->pyglobal, pykey);
-    if(pyval == NULL)
+    PyObjectXDR pyval = PyObject_GetItem(pycx->pyglobal, pykey.get());
+    if(!pyval)
     {
         if(PyErr_GivenExceptionMatches(PyErr_Occurred(), PyExc_KeyError))
         {
             PyErr_Clear();
-            ret = JS_TRUE;
+            return JS_TRUE;
         }
-        goto done;
+        return js_error(jscx, "Failed to get value.");
     }
 
-    *rval = py2js(pycx, pyval);
-    if(*rval == JSVAL_VOID) goto done;
-    ret = JS_TRUE;
-
-done:
-    Py_XDECREF(pykey);
-    Py_XDECREF(pyval);
-    return ret;
+    *rval = py2js(pycx.get(), pyval.get());
+    if(*rval == JSVAL_VOID)
+        return js_error(jscx, "Failed to convert value.");
+    
+    return JS_TRUE;
 }
 
 JSBool
 set_prop(JSContext* jscx, JSObject* jsobj, jsval key, jsval* rval)
 {
-    Context* pycx = NULL;
-    PyObject* pykey = NULL;
-    PyObject* pyval = NULL;
-    JSBool ret = JS_FALSE;
+    PyPtr<Context> pycx = (Context*) JS_GetContextPrivate(jscx);
+    if(!pycx) return js_error(jscx, "Failed to get Python context.");
+    
+    if(pycx->pyglobal == NULL) return JS_TRUE;
 
-    pycx = (Context*) JS_GetContextPrivate(jscx);
-    if(pycx == NULL)
-    {
-        JS_ReportError(jscx, "Failed to get Python context.");
-        goto done;
-    }
+    PyObjectXDR pykey = js2py(pycx.get(), key);
+    if(!pykey) return js_error(jscx, "Failed to convert key.");
 
-    // Bail if there's no registered global handler.
-    if(pycx->pyglobal == NULL)
-    {
-        ret = JS_TRUE;
-        goto done;
-    }
+    if(Context_has_access(pycx.get(), jscx, pycx->pyglobal, pykey.get()) <= 0)
+        return js_error(jscx, "Access denied.");
 
-    pykey = js2py(pycx, key);
-    if(pykey == NULL) goto done;
+    PyObjectXDR pyval = js2py(pycx.get(), *rval);
+    if(!pyval) return js_error(jscx, "Failed to convert value.");
 
-    if(Context_has_access(pycx, jscx, pycx->pyglobal, pykey) <= 0) goto done;
+    if(PyObject_SetItem(pycx->pyglobal, pykey.get(), pyval.get()) < 0)
+        return js_error(jscx, "Failed to set value.");
 
-    pyval = js2py(pycx, *rval);
-    if(pyval == NULL) goto done;
-
-    if(PyObject_SetItem(pycx->pyglobal, pykey, pyval) < 0) goto done;
-
-    ret = JS_TRUE;
-
-done:
-    Py_XDECREF(pykey);
-    Py_XDECREF(pyval);
-    return ret;
+    return JS_TRUE;
 }
 
 JSBool
 resolve(JSContext* jscx, JSObject* jsobj, jsval key)
 {
-    Context* pycx = NULL;
-    PyObject* pykey = NULL;
     jsid pid;
-    JSBool ret = JS_FALSE;
 
-    pycx = (Context*) JS_GetContextPrivate(jscx);
-    if(pycx == NULL)
-    {
-        JS_ReportError(jscx, "Failed to get Python context.");
-        goto done;
-    }
+    PyPtr<Context> pycx = (Context*) JS_GetContextPrivate(jscx);
+    if(!pycx) return js_error(jscx, "Failed to get Python context.");
 
-    // Bail if there's no registered global handler.
-    if(pycx->pyglobal == NULL)
-    {
-        ret = JS_TRUE;
-        goto done;
-    }
+    if(pycx->pyglobal == NULL) return JS_TRUE;
+    
+    PyObjectXDR pykey = js2py(pycx.get(), key);
+    if(!pykey) return js_error(jscx, "Failed to convert key.");
+    
+    if(Context_has_access(pycx.get(), jscx, pycx->pyglobal, pykey.get()) <= 0)
+        return js_error(jscx, "Access denied.");
 
-    pykey = js2py(pycx, key);
-    if(pykey == NULL) goto done;
-    
-    if(Context_has_access(pycx, jscx, pycx->pyglobal, pykey) <= 0) goto done;
-
-    if(!PyMapping_HasKey(pycx->pyglobal, pykey))
-    {
-        ret = JS_TRUE;
-        goto done;
-    }
+    if(!PyMapping_HasKey(pycx->pyglobal, pykey.get())) return JS_TRUE;
 
     if(!JS_ValueToId(jscx, key, &pid))
-    {
-        JS_ReportError(jscx, "Failed to convert property id.");
-        goto done;
-    }
+        return js_error(jscx, "Failed to convert property id.");
 
     if(!js_DefineProperty(jscx, pycx->jsglobal, pid, JSVAL_VOID, NULL, NULL,
                             JSPROP_SHARED, NULL))
-    {
-        JS_ReportError(jscx, "Failed to define property.");
-        goto done;
-    }
+        return js_error(jscx, "Failed to define property.");
 
-    ret = JS_TRUE;
-
-done:
-    Py_XDECREF(pykey);
-    return ret;
+    return JS_TRUE;
 }

File spidermonkey/javascript/iterator.cpp

 void
 finalize(JSContext* jscx, JSObject* jsobj)
 {
-    Context* pycx = (Context*) JS_GetContextPrivate(jscx);
-    PyObject* pyobj = NULL;
-    PyObject* pyiter = NULL;
-
-    JS_BeginRequest(jscx);
-
-    if(pycx == NULL)
+    PyPtr<Context> pycx = (Context*) JS_GetContextPrivate(jscx);
+    if(!pycx)
     {
         fprintf(stderr, "*** NO PYTHON CONTEXT ***\n");
-        JS_EndRequest(jscx);
         return;
     }
 
-    pyobj = get_js_slot(jscx, jsobj, 0);
-    Py_DECREF(pyobj);
+    JSRequest req(jscx);
 
-    pyiter = get_js_slot(jscx, jsobj, 1);
-    Py_DECREF(pyiter);
-
-    JS_EndRequest(jscx);
-
-    Py_DECREF(pycx);
+    Py_DECREF(get_js_slot(jscx, jsobj, 0));
+    Py_DECREF(get_js_slot(jscx, jsobj, 1));
+    Py_DECREF(pycx.get());
 }
 
 JSBool
 JSBool
 def_next(JSContext* jscx, JSObject* jsobj, uintN argc, jsval* argv, jsval* rval)
 {
-    Context* pycx = NULL;
-    PyObject* pyobj = NULL;
-    PyObject* iter = NULL;
-    PyObject* next = NULL;
-    PyObject* value = NULL;
-    JSBool ret = JS_FALSE;
-    JSBool foreach = JS_FALSE;
-
-    // For StopIteration throw
     JSObject* glbl = JS_GetGlobalObject(jscx);
     jsval exc = JSVAL_VOID;
+    
+    PyPtr<Context> pycx = (Context*) JS_GetContextPrivate(jscx);
+    if(!pycx) return js_error(jscx, "Failed to get Python context.");
 
-    pycx = (Context*) JS_GetContextPrivate(jscx);
-    if(pycx == NULL)
-    {
-        JS_ReportError(jscx, "Failed to get JS Context.");
-        goto done;
-    }
+    PyPtr<PyObject> iter = get_js_slot(jscx, jsobj, 1);
+    if(!PyIter_Check(iter.get()))
+        return js_error(jscx, "Object is not an iterator.");
+    
+    PyPtr<PyObject> pyobj = get_js_slot(jscx, jsobj, 0);
+    if(!pyobj) return js_error(jscx, "Failed to find iterated object.");
 
-    iter = get_js_slot(jscx, jsobj, 1);
-    if(!PyIter_Check(iter))
-    {
-        JS_ReportError(jscx, "Object is not an iterator.");
-        goto done;
-    }
-
-    pyobj = get_js_slot(jscx, jsobj, 0);
-    if(pyobj == NULL)
-    {
-        JS_ReportError(jscx, "Failed to find iterated object.");
-        goto done;
-    }
-
-    next = PyIter_Next(iter);
-    if(next == NULL && PyErr_Occurred())
-    {
-        goto done;
-    }
-    else if(next == NULL)
+    PyObjectXDR next = PyIter_Next(iter.get());
+    if(!next && PyErr_Occurred())
+        return js_error(jscx, "Failed to get iterator's next value.");
+    
+    // We're done iterating. Throw a StopIteration
+    if(!next)
     {
         if(JS_GetProperty(jscx, glbl, "StopIteration", &exc))
         {
             JS_SetPendingException(jscx, exc);
+            return JS_FALSE;
         }
-        else
-        {
-            JS_ReportError(jscx, "Failed to get StopIteration object.");
-        }
-        goto done;
+        
+        return js_error(jscx, "Failed to get StopIteration object.");
     }
 
+    JSBool foreach;
     if(!is_for_each(jscx, jsobj, &foreach))
+        return js_error(jscx, "Failed to get iterator flag.");
+
+    if(PyMapping_Check(pyobj.get()) && foreach)
     {
-        JS_ReportError(jscx, "Failed to get iterator flag.");
-        goto done;
-    }
-
-    if(PyMapping_Check(pyobj) && foreach)
-    {
-        value = PyObject_GetItem(pyobj, next);
-        if(value == NULL)
-        {
-            JS_ReportError(jscx, "Failed to get value in 'for each'");
-            goto done;
-        }
-        *rval = py2js(pycx, value);
+        PyObjectXDR value = PyObject_GetItem(pyobj.get(), next.get());
+        if(!value) return js_error(jscx, "Failed to get value in 'for each'");
+        *rval = py2js(pycx.get(), value.get());
     }
     else
     {
-        *rval = py2js(pycx, next);
+        *rval = py2js(pycx.get(), next.get());
     }
 
-    if(*rval != JSVAL_VOID) ret = JS_TRUE;
-
-done:
-    Py_XDECREF(next);
-    Py_XDECREF(value);
-    return ret;
+    if(*rval == JSVAL_VOID)
+        return js_error(jscx, "Failed to convert iterator value.");
+    
+    return JS_TRUE;
 }
 
 JSBool
 seq_next(JSContext* jscx, JSObject* jsobj, uintN argc, jsval* argv, jsval* rval)
-{
-    Context* pycx = NULL;
-    PyObject* pyobj = NULL;
-    PyObject* iter = NULL;
-    PyObject* next = NULL;
-    PyObject* value = NULL;
-    JSBool ret = JS_FALSE;
-    JSBool foreach = JS_FALSE;
-    long maxval = -1;
-    long currval = -1;
-    
-    // For StopIteration throw
+{    
     JSObject* glbl = JS_GetGlobalObject(jscx);
     jsval exc = JSVAL_VOID;
 
-    pycx = (Context*) JS_GetContextPrivate(jscx);
-    if(pycx == NULL)
-    {
-        JS_ReportError(jscx, "Failed to get JS Context.");
-        goto done;
-    }
+    PyPtr<Context> pycx = (Context*) JS_GetContextPrivate(jscx);
+    if(!pycx) return js_error(jscx, "Failed to get Python context.");
+    
+    PyPtr<PyObject> pyobj = get_js_slot(jscx, jsobj, 0);
+    if(!pyobj) return js_error(jscx, "Failed to get iterated object.");
+    if(!PySequence_Check(pyobj.get()))
+        return js_error(jscx, "Object is not a sequence.");
 
-    pyobj = get_js_slot(jscx, jsobj, 0);
-    if(!PySequence_Check(pyobj))
-    {
-        JS_ReportError(jscx, "Object is not a sequence.");
-        goto done;
-    }
+    long maxval = PyObject_Length(pyobj.get());
+    if(maxval < 0) return js_error(jscx, "Failed to get sequence length.");
 
-    maxval = PyObject_Length(pyobj);
-    if(maxval < 0) goto done;
+    PyPtr<PyObject> iter = get_js_slot(jscx, jsobj, 1);
+    if(!iter) return js_error(jscx, "Failed to get iteration state.");
+    if(!PyInt_Check(iter.get()))
+        return js_error(jscx, "Invalid iteration state object.");
 
-    iter = get_js_slot(jscx, jsobj, 1);
-    if(!PyInt_Check(iter))
-    {
-        JS_ReportError(jscx, "Object is not an integer.");
-        goto done;
-    }
+    long currval = PyInt_AsLong(iter.get());
+    if(currval == -1 && PyErr_Occurred())
+        return js_error(jscx, "Failed to get iteration state value.");
 
-    currval = PyInt_AsLong(iter);
-    if(currval == -1 && PyErr_Occurred())
-    {
-        goto done;
-    }
-    
     if(currval + 1 > maxval)
     {
         if(JS_GetProperty(jscx, glbl, "StopIteration", &exc))
         {
             JS_SetPendingException(jscx, exc);
+            return JS_FALSE;
         }
-        else
-        {
-            JS_ReportError(jscx, "Failed to get StopIteration object.");
-        }
-        goto done;
+        
+        return js_error(jscx, "Failed to get StopIteration object.");
     }
 
-    next = PyInt_FromLong(currval + 1);
-    if(next == NULL) goto done;
+    PyObjectXDR next = PyInt_FromLong(currval + 1);
+    if(!next) return js_error(jscx, "Failed to create next iterator value.");
 
-    if(!JS_SetReservedSlot(jscx, jsobj, 1, PRIVATE_TO_JSVAL(next)))
-    {
-        PyErr_SetString(PyExc_RuntimeError, "Failed to store base object.");
-        goto done;
-    }
+    // Swap iterator state.
+    if(!JS_SetReservedSlot(jscx, jsobj, 1, PRIVATE_TO_JSVAL(next.get())))
+        return js_error(jscx, "Failed to store iterator value.");
+    Py_INCREF(next.get());
+    Py_DECREF(iter.get());
 
+    JSBool foreach;
     if(!is_for_each(jscx, jsobj, &foreach))
-    {
-        JS_ReportError(jscx, "Failed to get iterator flag.");
-        goto done;
-    }
+        return js_error(jscx, "Failed to get iterator flag.");
 
     if(foreach)
     {
-        value = PyObject_GetItem(pyobj, iter);
-        if(value == NULL)
-        {
-            JS_ReportError(jscx, "Failed to get array element in 'for each'");
-            goto done;
-        }
-        *rval = py2js(pycx, value);
+        PyObjectXDR value = PyObject_GetItem(pyobj.get(), iter.get());
+        if(!value) return js_error(jscx, "Failed to get element in 'for each'");
+        *rval = py2js(pycx.get(), value.get());
     }
     else
     {
-        *rval = py2js(pycx, iter);
+        *rval = py2js(pycx.get(), iter.get());
     }
 
-    next = iter;
-    if(*rval != JSVAL_VOID) ret = JS_TRUE;
+    if(*rval == JSVAL_VOID)
+        return js_error(jscx, "Failed to convert iterator value.");
 
-done:
-    Py_XDECREF(next);
-    Py_XDECREF(value);
-    return ret;
+    return JS_TRUE;
 }
 
 JSBool
 new_py_def_iter(Context* cx, PyObject* obj, jsval* rval)
 {
-    PyObject* pyiter = NULL;
-    PyObject* attached = NULL;
-    JSObject* jsiter = NULL;
-    jsval jsv = JSVAL_VOID;
-    JSBool ret = JS_FALSE;
-
-    // Initialize the return value
     *rval = JSVAL_VOID;
 
-    pyiter = PyObject_GetIter(obj);
-    if(pyiter == NULL)
+    PyObjectXDR pyiter = PyObject_GetIter(obj);
+    if(!pyiter)
     {
         if(PyErr_GivenExceptionMatches(PyErr_Occurred(), PyExc_TypeError))
         {
             PyErr_Clear();
-            ret = JS_TRUE;
-            goto success;
+            return JS_TRUE;
         }
-        else
-        {
-            goto error;
-        }
+        
+        return JS_FALSE;
     }
 
-    jsiter = JS_NewObject(cx->cx, &js_iter_class, NULL, NULL);
-    if(jsiter == NULL) goto error;
+    JSObject* jsiter = JS_NewObject(cx->cx, &js_iter_class, NULL, NULL);
+    if(jsiter == NULL) return js_error(cx->cx, "Failed to create iterator.");
 
     if(!JS_DefineFunctions(cx->cx, jsiter, js_def_iter_functions))
-    {
-        PyErr_SetString(PyExc_RuntimeError, "Failed to define iter funcions.");
-        goto error;
-    }
+        return js_error(cx->cx, "Failed to define iterator functions.");
 
-    attached = obj;
-    Py_INCREF(attached);
-    jsv = PRIVATE_TO_JSVAL(attached);
+    PyObjectXDR attached = obj;
+    Py_INCREF(attached.get());
+
+    jsval jsv = PRIVATE_TO_JSVAL(attached.get());
     if(!JS_SetReservedSlot(cx->cx, jsiter, 0, jsv))
-    {
-        PyErr_SetString(PyExc_RuntimeError, "Failed to store base object.");
-        goto error;
-    }
-
-    jsv = PRIVATE_TO_JSVAL(pyiter);
+        return js_error(cx->cx, "Failed to store iterated object.");
+    
+    jsv = PRIVATE_TO_JSVAL(pyiter.get());
     if(!JS_SetReservedSlot(cx->cx, jsiter, 1, jsv))
-    {
-        PyErr_SetString(PyExc_RuntimeError, "Failed to store iter object.");
-        goto error;
-    }
+        return js_error(cx->cx, "Failed to store iterator object.");
 
     if(!JS_SetReservedSlot(cx->cx, jsiter, 2, JSVAL_FALSE))
-    {
-        PyErr_SetString(PyExc_RuntimeError, "Failed to store iterator flag.");
-        goto error;
-    }
+        return js_error(cx->cx, "Failed to store iterator flag.");
 
     Py_INCREF(cx);
     *rval = OBJECT_TO_JSVAL(jsiter);
-    ret = JS_TRUE;
-    goto success;
 
-error:
-    Py_XDECREF(pyiter);
-    Py_XDECREF(attached);
-success:
-    return ret;
+    // Keep attached alive on success.
+    attached.reset();
+    return JS_TRUE;
 }
 
 JSBool
 new_py_seq_iter(Context* cx, PyObject* obj, jsval* rval)
 {
-    PyObject* pyiter = NULL;
-    PyObject* attached = NULL;
-    JSObject* jsiter = NULL;
-    jsval jsv = JSVAL_VOID;
-    JSBool ret = JS_FALSE;
-
-    // Initialize the return value
     *rval = JSVAL_VOID;
 
     // Our counting state
-    pyiter = PyInt_FromLong(0);
-    if(pyiter == NULL) goto error;
+    PyObjectXDR pyiter = PyInt_FromLong(0);
+    if(!pyiter) return js_error(cx->cx, "Failed to create iterator state.");
 
-    jsiter = JS_NewObject(cx->cx, &js_iter_class, NULL, NULL);
-    if(jsiter == NULL) goto error;
+    JSObject* jsiter = JS_NewObject(cx->cx, &js_iter_class, NULL, NULL);
+    if(jsiter == NULL) return js_error(cx->cx, "Failed to create iterator.");
 
     if(!JS_DefineFunctions(cx->cx, jsiter, js_seq_iter_functions))
-    {
-        PyErr_SetString(PyExc_RuntimeError, "Failed to define iter funcions.");
-        goto error;
-    }
+        return js_error(cx->cx, "Failed to define iterator functions.");
 
-    attached = obj;
-    Py_INCREF(attached);
-    jsv = PRIVATE_TO_JSVAL(attached);
+    PyObjectXDR attached = obj;
+    Py_INCREF(attached.get());
+
+    jsval jsv = PRIVATE_TO_JSVAL(attached.get());
     if(!JS_SetReservedSlot(cx->cx, jsiter, 0, jsv))
-    {
-        PyErr_SetString(PyExc_RuntimeError, "Failed to store base object.");
-        goto error;
-    }
-
-    jsv = PRIVATE_TO_JSVAL(pyiter);
+        return js_error(cx->cx, "Failed to store iterated object.");
+    
+    jsv = PRIVATE_TO_JSVAL(pyiter.get());
     if(!JS_SetReservedSlot(cx->cx, jsiter, 1, jsv))
-    {
-        PyErr_SetString(PyExc_RuntimeError, "Failed to store iter object.");
-        goto error;
-    }
+        return js_error(cx->cx, "Failed to store iterator object.");
 
     if(!JS_SetReservedSlot(cx->cx, jsiter, 2, JSVAL_FALSE))
-    {
-        PyErr_SetString(PyExc_RuntimeError, "Failed to store iterator flag.");
-        goto error;
-    }
+        return js_error(cx->cx, "Failed to store iterator flag.");
 
     Py_INCREF(cx);
     *rval = OBJECT_TO_JSVAL(jsiter);
-    ret = JS_TRUE;
-    goto success;
-
-error:
-    Py_XDECREF(pyiter);
-    Py_XDECREF(attached);
-success:
-    return ret;
+    
+    // Keep attached alive on success.
+    return JS_TRUE;
 }
 
 JSBool
 new_py_iter(Context* cx, PyObject* obj, jsval* rval)
 {
     if(PySequence_Check(obj))
-    {
         return new_py_seq_iter(cx, obj, rval);
-    }
+
     return new_py_def_iter(cx, obj, rval);
 }

File spidermonkey/javascript/javascript.h

 #ifndef PYSM_JAVASCRIPT_H
 #define PYSM_JAVASCRIPT_H
 
-#include <spidermonkey.h>
+#include "python/python.h"
 
 extern JSClass js_global_class;
 
+JSBool js_error(JSContext* cx, const char* err);
+
 JSClass* create_class(Context* cx, PyObject* pyobj);
 JSBool new_py_iter(Context* cx, PyObject* obj, jsval* rval);
 void add_frame(const char* srcfile, const char* funcname, int linenum);

File spidermonkey/javascript/object.cpp

 #include <spidermonkey.h>
 #include <jsobj.h>
 
-/*
-    This is a fairly unsafe operation in so much as
-    I'm relying on JavaScript to never call one of
-    our callbacks on an object we didn't create.
-
-    Also, of note, we're not incref'ing the Python
-    object.
-*/
-PyObject*
-get_py_obj(JSContext* cx, JSObject* obj)
-{
-    jsval priv;
-
-    if(!JS_GetReservedSlot(cx, obj, 0, &priv))
-    {
-        PyErr_SetString(PyExc_RuntimeError, "Failed to get slot data.");
-        return NULL;
-    }
-
-    return (PyObject*) JSVAL_TO_PRIVATE(priv);
-}
+PyObject* get_py_obj(JSContext* cx, JSObject* obj);
+PyObject* mk_args_tpl(Context* pycx, JSContext* jscx, uintN argc, jsval* argv);
 
 JSBool
 js_add_prop(JSContext* jscx, JSObject* jsobj, jsval key, jsval* val)
 }
 
 JSBool
-js_del_prop(JSContext* jscx, JSObject* jsobj, jsval key, jsval* val)
+js_del_prop(JSContext* jscx, JSObject* jsobj, jsval key, jsval* rval)
 {
-    Context* pycx = NULL;
-    PyObject* pyobj = NULL;
-    PyObject* pykey = NULL;
-    JSBool ret = JS_FALSE;
+    PyPtr<Context> pycx = (Context*) JS_GetContextPrivate(jscx);
+    if(!pycx) return js_error(jscx, "Failed to get Python context.");
     
-    pycx = (Context*) JS_GetContextPrivate(jscx);
-    if(pycx == NULL)
-    {
-        PyErr_SetString(PyExc_RuntimeError, "Failed to get JS Context.");
-        goto error;
-    }
+    PyPtr<PyObject> pyobj = get_py_obj(jscx, jsobj);
+    if(!pyobj) return js_error(jscx, "Failed to get Python object.");
     
-    pyobj = get_py_obj(jscx, jsobj);
-    if(pyobj == NULL) goto error;
-    
-    pykey = js2py(pycx, key);
-    if(pykey == NULL) goto error;
+    PyObjectXDR pykey = js2py(pycx.get(), key);
+    if(!pykey) return js_error(jscx, "Failed to covert object key.");
 
-    if(Context_has_access(pycx, jscx, pyobj, pykey) <= 0) goto error;
+    if(Context_has_access(pycx.get(), jscx, pyobj.get(), pykey.get()) <= 0)
+        return js_error(jscx, "Access denied.");
 
-    if(PyObject_DelItem(pyobj, pykey) < 0)
+    if(PyObject_DelItem(pyobj.get(), pykey.get()) < 0)
     {
         PyErr_Clear();
-        if(PyObject_DelAttr(pyobj, pykey) < 0)
+        if(PyObject_DelAttr(pyobj.get(), pykey.get()) < 0)
         {
             PyErr_Clear();
-            *val = JSVAL_FALSE;
+            *rval = JSVAL_FALSE;
         }
     }
    
-    ret = JS_TRUE;
-    goto success;
-    
-error:
-success:
-    Py_XDECREF(pykey);
-    return ret;
+    return JS_TRUE;
 }
 
 JSBool
-js_get_prop(JSContext* jscx, JSObject* jsobj, jsval key, jsval* val)
+js_get_prop(JSContext* jscx, JSObject* jsobj, jsval key, jsval* rval)
 {
-    Context* pycx = NULL;
-    PyObject* pyobj = NULL;
-    PyObject* pykey = NULL;
-    PyObject* utf8 = NULL;
-    PyObject* pyval = NULL;
-    JSBool ret = JS_FALSE;
-    const char* data;
+    PyPtr<Context> pycx = (Context*) JS_GetContextPrivate(jscx);
+    if(!pycx) return js_error(jscx, "Failed to get Python context.");
 
-    pycx = (Context*) JS_GetContextPrivate(jscx);
-    if(pycx == NULL)
-    {
-        PyErr_SetString(PyExc_RuntimeError, "Failed to get JS Context.");
-        goto done;
-    }
+    PyPtr<PyObject> pyobj = get_py_obj(jscx, jsobj);
+    if(!pyobj) return js_error(jscx, "Failed to get Python object.");
     
-    pyobj = get_py_obj(jscx, jsobj);
-    if(pyobj == NULL) goto done;
+    PyObjectXDR pykey = js2py(pycx.get(), key);
+    if(!pykey) return js_error(jscx, "Failed to convert key.");
     
-    pykey = js2py(pycx, key);
-    if(pykey == NULL) goto done;
-
-    if(Context_has_access(pycx, jscx, pyobj, pykey) <= 0) goto done;
+    if(Context_has_access(pycx.get(), jscx, pyobj.get(), pykey.get()) <= 0)
+        return js_error(jscx, "Access denied.");
     
     // Yeah. It's ugly as sin.
-    if(PyString_Check(pykey) || PyUnicode_Check(pykey))
+    if(PyString_Check(pykey.get()) || PyUnicode_Check(pykey.get()))
     {
-        utf8 = PyUnicode_AsUTF8String(pykey);
-        if(utf8 == NULL) goto done;
+        PyObjectXDR utf8 = PyUnicode_AsUTF8String(pykey.get());
+        if(!utf8) return js_error(jscx, "Failed to convert string to UTF-8");
 
-        data = PyString_AsString(utf8);
-        if(data == NULL) goto done;
+        const char* data = PyString_AsString(utf8.get());
+        if(data == NULL)
+            return js_error(jscx, "Failed to convert string to buffer.");
 
         if(strcmp("__iterator__", data) == 0)
         {
-            if(!new_py_iter(pycx, pyobj, val)) goto done;
-            if(*val != JSVAL_VOID)
-            {
-                ret = JS_TRUE;
-                goto done;
-            }
+            if(!new_py_iter(pycx.get(), pyobj.get(), rval))
+                return JS_FALSE;
+            
+            if(*rval != JSVAL_VOID)
+                return JS_TRUE;
+
+            return JS_FALSE;
         }
     }
 
-    pyval = PyObject_GetItem(pyobj, pykey);
-    if(pyval == NULL)
-    {
+    PyObjectXDR pyval = PyObject_GetItem(pyobj.get(), pykey.get());
+    if(!pyval)
+    {        
         PyErr_Clear();
-        pyval = PyObject_GetAttr(pyobj, pykey);
-        if(pyval == NULL)
+        pyval = PyObject_GetAttr(pyobj.get(), pykey.get());
+        if(!pyval)
         {
             PyErr_Clear();
-            ret = JS_TRUE;
-            *val = JSVAL_VOID;
-            goto done;
+            *rval = JSVAL_VOID;
+            return JS_TRUE;
         }
     }
 
-    *val = py2js(pycx, pyval);
-    if(*val == JSVAL_VOID) goto done;
-    ret = JS_TRUE;
-
-done:
-    Py_XDECREF(pykey);
-    Py_XDECREF(pyval);
-    Py_XDECREF(utf8);
-
-    return ret;
+    *rval = py2js(pycx.get(), pyval.get());
+    if(*rval == JSVAL_VOID)
+        return JS_FALSE;
+    
+    return JS_TRUE;
 }
 
 JSBool
     Py_DECREF(pyobj);
 }
 
-PyObject*
-mk_args_tuple(Context* pycx, JSContext* jscx, uintN argc, jsval* argv)
-{
-    PyObject* tpl = NULL;
-    PyObject* tmp = NULL;
-    int idx;
-    
-    tpl = PyTuple_New(argc);
-    if(tpl == NULL)
-    {
-        JS_ReportError(jscx, "Failed to build args value.");
-        goto error;
-    }
-    
-    for(idx = 0; idx < argc; idx++)
-    {
-        tmp = js2py(pycx, argv[idx]);
-        if(tmp == NULL) goto error;
-        PyTuple_SET_ITEM(tpl, idx, tmp);
-    }
-
-    goto success;
-
-error:
-    Py_XDECREF(tpl);
-success:
-    return tpl;
-}
-
 JSBool
 js_call(JSContext* jscx, JSObject* jsobj, uintN argc, jsval* argv, jsval* rval)
 {
 
     if(Context_has_access(pycx, jscx, pyobj, attrcheck) <= 0) goto error;
 
-    tpl = mk_args_tuple(pycx, jscx, argc, argv);
+    tpl = mk_args_tpl(pycx, jscx, argc, argv);
     if(tpl == NULL) goto error;
     
     ret = PyObject_Call(pyobj, tpl, NULL);
 
     if(Context_has_access(pycx, jscx, pyobj, attrcheck) <= 0) goto error;
 
-    tpl = mk_args_tuple(pycx, jscx, argc, argv);
+    tpl = mk_args_tpl(pycx, jscx, argc, argv);
     if(tpl == NULL) goto error;
     
     ret = PyObject_CallObject(pyobj, tpl);
     return ret;
 }
 
+/*
+    This is a fairly unsafe operation in so much as
+    I'm relying on JavaScript to never call one of
+    our callbacks on an object we didn't create.
 
+    Also, of note, we're not incref'ing the Python
+    object.
+*/
+PyObject*
+get_py_obj(JSContext* cx, JSObject* obj)
+{
+    jsval priv;
 
+    if(!JS_GetReservedSlot(cx, obj, 0, &priv))
+    {
+        js_error(cx, "Failed to get object's slot data.");
+        return NULL;
+    }
+
+    return (PyObject*) JSVAL_TO_PRIVATE(priv);
+}
+
+PyObject*
+mk_args_tpl(Context* pycx, JSContext* jscx, uintN argc, jsval* argv)
+{
+    PyObject* tpl = NULL;
+    PyObject* tmp = NULL;
+    
+    tpl = PyTuple_New(argc);
+    if(tpl == NULL)
+    {
+        JS_ReportError(jscx, "Failed to build args value.");
+        goto error;
+    }
+    
+    for(unsigned int idx = 0; idx < argc; idx++)
+    {
+        tmp = js2py(pycx, argv[idx]);
+        if(tmp == NULL) goto error;
+        PyTuple_SET_ITEM(tpl, idx, tmp);
+    }
+
+    goto success;
+
+error:
+    Py_XDECREF(tpl);
+success:
+    return tpl;
+}

File spidermonkey/python/python.h

 #ifndef PYSM_PYTHON_H
 #define PYSM_PYTHON_H
 
+#include <Python.h>
+#include <jsapi.h>
+
 extern PyTypeObject _ArrayType;
 extern PyTypeObject _ContextType;
 extern PyTypeObject _FunctionType;
 extern PyTypeObject _ObjectType;
 extern PyTypeObject _RuntimeType;
 
+extern PyTypeObject* RuntimeType;
+extern PyTypeObject* ContextType;
+extern PyTypeObject* ClassType;
+extern PyTypeObject* ObjectType;
+extern PyTypeObject* ArrayType;
+extern PyTypeObject* FunctionType;
+extern PyTypeObject* IteratorType;
+extern PyTypeObject* HashCObjType;
+
 typedef struct {
     PyObject_HEAD
     JSRuntime* rt;

File spidermonkey/spidermonkey.h

 
 #include <jsapi.h>
 
+#ifdef __cplusplus
 #include "utils/utils.h"
+#endif
+
 #include "convert/convert.h"
 #include "javascript/javascript.h"
 #include "python/python.h"
 
 extern PyObject* SpidermonkeyModule;
-extern PyTypeObject* RuntimeType;
-extern PyTypeObject* ContextType;
-extern PyTypeObject* ClassType;
-extern PyTypeObject* ObjectType;
-extern PyTypeObject* ArrayType;
-extern PyTypeObject* FunctionType;
-extern PyTypeObject* IteratorType;
-extern PyTypeObject* HashCObjType;
 extern PyObject* JSError;
 
 #endif

File spidermonkey/utils/utils.cpp

 
 #include <spidermonkey.h>
 
-PyObjXDR::PyObjXDR(PyObject* p)
+JSRequest::JSRequest(JSContext* cx)
 {
-    this->data = p;
+    this->cx = cx;
+    JS_BeginRequest(cx);
 }
 
-PyObjXDR::~PyObjXDR()
+JSRequest::~JSRequest()
 {
-    Py_XDECREF(this->data);
-}
-
-PyObject*
-PyObjXDR::get()
-{
-    return this->data
-}
+    JS_EndRequest(cx);
+}

File spidermonkey/utils/utils.h

  *
  */
 
-#ifndef PYSM_CONVERT_H
-#define PYSM_CONVERT_H
+#ifndef PYSM_UTILS_H
+#define PYSM_UTILS_H
 
 #include <Python.h>
+#include <frameobject.h>
 
-class PyObjXDR {
+#include <iostream>
+
+template<class T> class PyPtr {
     public:
-        explicit PyObjXDR(PyObject* p = 0);
-        ~PyObjXDR();
+        PyPtr(T* p = 0)
+        {
+            this->data = p;
+        }
+        
+        ~PyPtr() {}
 
-        void reset(PyObject* p = 0);
+        T*
+        get() const
+        {
+            return this->data;
+        }
+        
+        void
+        reset()
+        {
+            this->data = NULL;
+        }
+
+        T*
+        operator->()
+        {
+            return this->data;
+        }
+        
+        PyPtr<T>&
+        operator=(T* p)
+        {
+            this->data = p;
+            return *this;
+        }
+        
+        PyPtr<T>&
+        operator=(PyPtr<T>& p)
+        {
+            this->data = p.data;
+            p.reset();
+            return *this;
+        }
     
-        PyObject* get() const;
-    
+        operator bool () const
+        {
+            return this->data != NULL;
+        }
+        
     protected:
-        PyObjXDR() {}
-    
+        T*   data;
+};
+
+template <class T> class PyXDR : public PyPtr<T> {
+    public:
+        PyXDR(T* p = 0)
+        {
+            this->data = p;
+        }
+        
+        ~PyXDR()
+        {
+            Py_XDECREF(this->data);
+        }
+        
+        PyXDR<T>&
+        operator=(T* p)
+        {
+            this->data = p;
+            return *this;
+        }
+};
+
+typedef PyXDR<PyObject> PyObjectXDR;
+typedef PyXDR<PyCodeObject> PyCodeXDR;
+typedef PyXDR<PyFrameObject> PyFrameXDR;
+
+
+// JS UTILS
+
+class JSRequest {
+    public:
+        JSRequest(JSContext* cx);
+        ~JSRequest();
     private:
-        PyObjXDR(const PyObjXDR&);
-        const PyObjXDR& operator=(const PyObjXDR&);
-        
-        PyObject*   data;
+        JSContext* cx;
 };
 
 #endif