changeset 117:ac8ca0ee7760

Moved all .cpp/.h files into 'src' dir and test suite into 'tests' dir.
author Atul Varma <varmaa@toolness.com>
date Mon, 17 Aug 2009 22:08:33 -0700
parents 06269ca0b36c
children 00e874d9a6a7
files context.cpp context.h function.cpp function.h object.cpp object.h pymonkey.cpp runtime.cpp runtime.h setup.py src/context.cpp src/context.h src/function.cpp src/function.h src/object.cpp src/object.h src/pymonkey.cpp src/runtime.cpp src/runtime.h src/undefined.cpp src/undefined.h src/utils.cpp src/utils.h test_pymonkey.py tests/test_pymonkey.py undefined.cpp undefined.h utils.cpp utils.h
diffstat 29 files changed, 2587 insertions(+), 2586 deletions(-) [+]
line wrap: on
line diff
--- a/context.cpp	Mon Aug 17 03:52:51 2009 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,553 +0,0 @@
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is Pymonkey.
- *
- * The Initial Developer of the Original Code is Mozilla.
- * Portions created by the Initial Developer are Copyright (C) 2007
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *   Atul Varma <atul@mozilla.com>
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-#include "context.h"
-#include "object.h"
-#include "function.h"
-#include "utils.h"
-
-// This is the default JSOperationCallback for pymonkey-owned JS contexts,
-// when they've defined one in Python.
-static JSBool
-PYM_operationCallback(JSContext *cx)
-{
-  PYM_PyAutoEnsureGIL gil;
-  PYM_JSContextObject *context = (PYM_JSContextObject *)
-    JS_GetContextPrivate(cx);
-
-  PyObject *callable = context->opCallback;
-  PyObject *args = PyTuple_Pack(1, (PyObject *) context);
-  if (args == NULL) {
-    JS_ReportOutOfMemory(cx);
-    return JS_FALSE;
-  }
-  PyObject *result = PyObject_Call(callable, args, NULL);
-  Py_DECREF(args);
-  if (result == NULL) {
-    PYM_pythonExceptionToJs(context);
-    return JS_FALSE;
-  }
-
-  Py_DECREF(result);
-  return JS_TRUE;
-}
-
-// This is the default JSErrorReporter for pymonkey-owned JS contexts.
-static void
-PYM_reportError(JSContext *cx, const char *message, JSErrorReport *report)
-{
-  PYM_PyAutoEnsureGIL gil;
-
-  // Convert JS warnings into Python warnings.
-  if (JSREPORT_IS_WARNING(report->flags)) {
-    if (report->filename)
-      PyErr_WarnExplicit(NULL, message, report->filename, report->lineno,
-                         NULL, NULL);
-    else
-      PyErr_Warn(NULL, message);
-  } else
-    // TODO: Not sure if this will ever get called, but we should know
-    // if it is.
-    PyErr_Warn(NULL, "A JS error was reported.");
-}
-
-static void
-PYM_JSContextDealloc(PYM_JSContextObject *self)
-{
-  if (self->opCallback) {
-    Py_DECREF(self->opCallback);
-    self->opCallback = NULL;
-  }
-
-  if (self->cx) {
-    JS_DestroyContext(self->cx);
-    self->cx = NULL;
-  }
-
-  Py_DECREF(self->runtime);
-  self->runtime = NULL;
-
-  self->ob_type->tp_free((PyObject *) self);
-}
-
-static PyObject *
-PYM_getRuntime(PYM_JSContextObject *self, PyObject *args)
-{
-  Py_INCREF(self->runtime);
-  return (PyObject *) self->runtime;
-}
-
-static PyObject *
-PYM_getObjectPrivate(PYM_JSContextObject *self, PyObject *args)
-{
-  PYM_SANITY_CHECK(self->runtime);
-  PYM_JSObject *object;
-
-  if (!PyArg_ParseTuple(args, "O!", &PYM_JSObjectType, &object))
-    return NULL;
-
-  PYM_ENSURE_RUNTIME_MATCH(self->runtime, object->runtime);
-
-  JSObject *obj = object->obj;
-
-  if (JS_ObjectIsFunction(self->cx, obj)) {
-    jsval functionHolder;
-    if (!JS_GetReservedSlot(self->cx, obj, 0, &functionHolder)) {
-      JS_ClearPendingException(self->cx);
-      Py_RETURN_NONE;
-    }
-    if (!JSVAL_IS_OBJECT(functionHolder))
-      Py_RETURN_NONE;
-    obj = JSVAL_TO_OBJECT(functionHolder);
-  }
-
-  JSClass *klass = JS_GET_CLASS(self->cx, obj);
-  if (klass != &PYM_JS_ObjectClass)
-    Py_RETURN_NONE;
-
-  PyObject *pyObject;
-
-  if (!PYM_JS_getPrivatePyObject(self->cx, obj, &pyObject)) {
-    PYM_jsExceptionToPython(self);
-    return NULL;
-  }
-
-  if (pyObject == NULL)
-    pyObject = Py_None;
-
-  Py_INCREF(pyObject);
-  return pyObject;
-}
-
-static PyObject *
-PYM_clearObjectPrivate(PYM_JSContextObject *self, PyObject *args)
-{
-  PYM_SANITY_CHECK(self->runtime);
-  PYM_JSObject *object;
-
-  if (!PyArg_ParseTuple(args, "O!", &PYM_JSObjectType, &object))
-    return NULL;
-
-  PYM_ENSURE_RUNTIME_MATCH(self->runtime, object->runtime);
-
-  JSObject *obj = object->obj;
-
-  if (JS_ObjectIsFunction(self->cx, obj)) {
-    jsval functionHolder;
-    if (!JS_GetReservedSlot(self->cx, obj, 0, &functionHolder)) {
-      JS_ClearPendingException(self->cx);
-      Py_RETURN_NONE;
-    }
-    if (!JSVAL_IS_OBJECT(functionHolder))
-      Py_RETURN_NONE;
-    obj = JSVAL_TO_OBJECT(functionHolder);
-  }
-
-  JSClass *klass = JS_GET_CLASS(self->cx, obj);
-  if (klass != &PYM_JS_ObjectClass)
-    Py_RETURN_NONE;
-
-  if (!PYM_JS_setPrivatePyObject(self->cx, obj, Py_None)) {
-    PYM_jsExceptionToPython(self);
-    return NULL;
-  }
-
-  Py_RETURN_NONE;
-}
-
-static PyObject *
-PYM_newObject(PYM_JSContextObject *self, PyObject *args)
-{
-  PYM_SANITY_CHECK(self->runtime);
-  PyObject *privateObj = NULL;
-
-  if (!PyArg_ParseTuple(args, "|O", &privateObj))
-    return NULL;
-
-  JSObject *obj = PYM_JS_newObject(self->cx, privateObj);
-  if (obj == NULL) {
-    PyErr_SetString(PYM_error, "PYM_JS_newObject() failed");
-    return NULL;
-  }
-
-  // If this fails, we don't need to worry about cleaning up
-  // obj because it'll get cleaned up at the next GC.
-  return (PyObject *) PYM_newJSObject(self, obj, NULL);
-}
-
-static PyObject *
-PYM_getProperty(PYM_JSContextObject *self, PyObject *args)
-{
-  PYM_SANITY_CHECK(self->runtime);
-  PYM_JSObject *object;
-  char *buffer = NULL;
-  int size;
-
-  if (!PyArg_ParseTuple(args, "O!es#", &PYM_JSObjectType, &object,
-                        "utf-16", &buffer, &size))
-    return NULL;
-
-  if (self->runtime != object->runtime) {
-    PyMem_Free(buffer);
-    PYM_ENSURE_RUNTIME_MATCH(self->runtime, object->runtime);
-  }
-
-  jsval val;
-  JSBool result;
-  Py_BEGIN_ALLOW_THREADS;
-  // Note that we're manipulating buffer and size here to get rid of
-  // the BOM.
-  result = JS_GetUCProperty(self->cx, object->obj, (jschar *) (buffer + 2),
-                            (size / 2) - 1, &val);
-  Py_END_ALLOW_THREADS;
-
-  PyMem_Free(buffer);
-
-  if (!result) {
-    PYM_jsExceptionToPython(self);
-    return NULL;
-  }
-
-  return PYM_jsvalToPyObject(self, val);
-}
-
-static PyObject *
-PYM_gc(PYM_JSContextObject *self, PyObject *args)
-{
-  PYM_SANITY_CHECK(self->runtime);
-  JS_GC(self->cx);
-  Py_RETURN_NONE;
-}
-
-static PyObject *
-PYM_initStandardClasses(PYM_JSContextObject *self, PyObject *args)
-{
-  PYM_SANITY_CHECK(self->runtime);
-  PYM_JSObject *object;
-
-  if (!PyArg_ParseTuple(args, "O!", &PYM_JSObjectType, &object))
-    return NULL;
-
-  PYM_ENSURE_RUNTIME_MATCH(self->runtime, object->runtime);
-
-  if (!JS_InitStandardClasses(self->cx, object->obj)) {
-    PyErr_SetString(PYM_error, "JS_InitStandardClasses() failed");
-    return NULL;
-  }
-
-  Py_RETURN_NONE;
-}
-
-static PyObject *
-PYM_evaluateScript(PYM_JSContextObject *self, PyObject *args)
-{
-  PYM_SANITY_CHECK(self->runtime);
-  PYM_JSObject *object;
-  const char *source;
-  int sourceLen;
-  const char *filename;
-  int lineNo;
-
-  if (!PyArg_ParseTuple(args, "O!s#si", &PYM_JSObjectType, &object,
-                        &source, &sourceLen, &filename, &lineNo))
-    return NULL;
-
-  PYM_ENSURE_RUNTIME_MATCH(self->runtime, object->runtime);
-
-  jsval rval;
-  JSBool result;
-  Py_BEGIN_ALLOW_THREADS;
-  result = JS_EvaluateScript(self->cx, object->obj, source, sourceLen,
-                             filename, lineNo, &rval);
-  Py_END_ALLOW_THREADS;
-
-  if (!result) {
-    PYM_jsExceptionToPython(self);
-    return NULL;
-  }
-
-  PyObject *pyRval = PYM_jsvalToPyObject(self, rval);
-  return pyRval;
-}
-
-static PyObject *
-PYM_defineProperty(PYM_JSContextObject *self, PyObject *args)
-{
-  PYM_SANITY_CHECK(self->runtime);
-  PYM_JSObject *object;
-  PyObject *value;
-  char *name = NULL;
-  int namelen;
-
-  if (!PyArg_ParseTuple(args, "O!es#O", &PYM_JSObjectType, &object,
-                        "utf-16", &name, &namelen, &value))
-    return NULL;
-
-  if (self->runtime != object->runtime) {
-    PyMem_Free(name);
-    PYM_ENSURE_RUNTIME_MATCH(self->runtime, object->runtime);
-  }
-
-  jsval jsValue;
-
-  if (PYM_pyObjectToJsval(self, value, &jsValue) == -1) {
-    PyMem_Free(name);
-    return NULL;
-  }
-
-  // Note that we're manipulating buffer and size here to get rid of
-  // the BOM.
-  if (!JS_DefineUCProperty(self->cx, object->obj, (jschar *) (name + 2),
-                           (namelen / 2) - 1, jsValue, NULL, NULL,
-                           JSPROP_ENUMERATE)) {
-    // TODO: There's probably an exception pending on self->cx,
-    // what should we do about it?
-    PyMem_Free(name);
-    PyErr_SetString(PYM_error, "JS_DefineProperty() failed");
-    return NULL;
-  }
-
-  PyMem_Free(name);
-  Py_RETURN_NONE;
-}
-
-static PyObject *
-PYM_callFunction(PYM_JSContextObject *self, PyObject *args)
-{
-  PYM_SANITY_CHECK(self->runtime);
-  PYM_JSObject *obj;
-  PYM_JSFunction *fun;
-  PyObject *funcArgs;
-
-  if (!PyArg_ParseTuple(args, "O!O!O!", &PYM_JSObjectType, &obj,
-                        &PYM_JSFunctionType, &fun,
-                        &PyTuple_Type, &funcArgs))
-    return NULL;
-
-  PYM_ENSURE_RUNTIME_MATCH(self->runtime, obj->runtime);
-  PYM_ENSURE_RUNTIME_MATCH(self->runtime, fun->base.runtime);
-
-  uintN argc = PyTuple_Size(funcArgs);
-
-  jsval *argv = (jsval *) PyMem_Malloc(sizeof(jsval) * argc);
-  if (argv == NULL)
-    return PyErr_NoMemory();
-
-  jsval *currArg = argv;
-
-  for (unsigned int i = 0; i < argc; i++) {
-    PyObject *item = PyTuple_GET_ITEM(funcArgs, i);
-    if (item == NULL ||
-        PYM_pyObjectToJsval(self, item, currArg) == -1) {
-      PyMem_Free(argv);
-      return NULL;
-    }
-    currArg++;
-  }
-
-  jsval rval;
-
-  // TODO: This assumes that a JSFunction * is actually a subclass of
-  // a JSObject *, which may or may not be regarded as an implementation
-  // detail.
-  JSBool result;
-  Py_BEGIN_ALLOW_THREADS;
-  result = JS_CallFunction(self->cx, obj->obj,
-                           (JSFunction *) fun->base.obj,
-                           argc, argv, &rval);
-  Py_END_ALLOW_THREADS;
-
-  PyMem_Free(argv);
-
-  if (!result) {
-    PYM_jsExceptionToPython(self);
-    return NULL;
-  }
-
-  return PYM_jsvalToPyObject(self, rval);
-}
-
-static PyObject *
-PYM_newFunction(PYM_JSContextObject *self, PyObject *args)
-{
-  PYM_SANITY_CHECK(self->runtime);
-  PyObject *callable;
-  const char *name;
-
-  if (!PyArg_ParseTuple(args, "Os", &callable, &name))
-    return NULL;
-
-  return (PyObject *) PYM_newJSFunctionFromCallable(self, callable, name);
-}
-
-static PyObject *
-PYM_setOperationCallback(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;
-  }
-
-  JS_SetOperationCallback(self->cx, PYM_operationCallback);
-
-  Py_INCREF(callable);
-  if (self->opCallback)
-    Py_DECREF(self->opCallback);
-  self->opCallback = callable;
-
-  Py_RETURN_NONE;
-}
-
-static PyObject *
-PYM_triggerOperationCallback(PYM_JSContextObject *self, PyObject *args)
-{
-  JS_TriggerOperationCallback(self->cx);
-  Py_RETURN_NONE;
-}
-
-static PyMethodDef PYM_JSContextMethods[] = {
-  {"get_runtime", (PyCFunction) PYM_getRuntime, METH_VARARGS,
-   "Get the JavaScript runtime associated with this context."},
-  {"new_object", (PyCFunction) PYM_newObject, METH_VARARGS,
-   "Create a new JavaScript object."},
-  {"init_standard_classes",
-   (PyCFunction) PYM_initStandardClasses, METH_VARARGS,
-   "Add standard classes and functions to the given object."},
-  {"evaluate_script",
-   (PyCFunction) PYM_evaluateScript, METH_VARARGS,
-   "Evaluate the given JavaScript code in the context of the given "
-   "global object, using the given filename"
-   "and line number information."},
-  {"call_function",
-   (PyCFunction) PYM_callFunction, METH_VARARGS,
-   "Calls a JS function."},
-  {"new_function",
-   (PyCFunction) PYM_newFunction, METH_VARARGS,
-   "Creates a new function callable from JS."},
-  {"define_property",
-   (PyCFunction) PYM_defineProperty, METH_VARARGS,
-   "Defines a property on an object."},
-  {"get_property", (PyCFunction) PYM_getProperty, METH_VARARGS,
-   "Gets the given property for the given JavaScript object."},
-  {"gc", (PyCFunction) PYM_gc, METH_VARARGS,
-   "Performs garbage collection on the context's runtime."},
-  {"set_operation_callback", (PyCFunction) PYM_setOperationCallback,
-   METH_VARARGS,
-   "Sets the operation callback for the context."},
-  {"trigger_operation_callback", (PyCFunction) PYM_triggerOperationCallback,
-   METH_VARARGS,
-   "Triggers the operation callback for the context."},
-  {"get_object_private", (PyCFunction) PYM_getObjectPrivate, METH_VARARGS,
-   "Returns the private Python object stored in the JavaScript object."},
-  {"clear_object_private", (PyCFunction) PYM_clearObjectPrivate, METH_VARARGS,
-   "Clears any private Python object stored in the JavaScript object."},
-  {NULL, NULL, 0, NULL}
-};
-
-PyTypeObject PYM_JSContextType = {
-  PyObject_HEAD_INIT(NULL)
-  0,                           /*ob_size*/
-  "pymonkey.Context",          /*tp_name*/
-  sizeof(PYM_JSContextObject), /*tp_basicsize*/
-  0,                           /*tp_itemsize*/
-  /*tp_dealloc*/
-  (destructor) PYM_JSContextDealloc,
-  0,                           /*tp_print*/
-  0,                           /*tp_getattr*/
-  0,                           /*tp_setattr*/
-  0,                           /*tp_compare*/
-  0,                           /*tp_repr*/
-  0,                           /*tp_as_number*/
-  0,                           /*tp_as_sequence*/
-  0,                           /*tp_as_mapping*/
-  0,                           /*tp_hash */
-  0,                           /*tp_call*/
-  0,                           /*tp_str*/
-  0,                           /*tp_getattro*/
-  0,                           /*tp_setattro*/
-  0,                           /*tp_as_buffer*/
-  Py_TPFLAGS_DEFAULT,          /*tp_flags*/
-  /* tp_doc */
-  "JavaScript Context.",
-  0,		               /* tp_traverse */
-  0,		               /* tp_clear */
-  0,		               /* tp_richcompare */
-  0,		               /* tp_weaklistoffset */
-  0,		               /* tp_iter */
-  0,		               /* tp_iternext */
-  PYM_JSContextMethods,        /* tp_methods */
-  0,                           /* tp_members */
-  0,                           /* tp_getset */
-  0,                           /* tp_base */
-  0,                           /* tp_dict */
-  0,                           /* tp_descr_get */
-  0,                           /* tp_descr_set */
-  0,                           /* tp_dictoffset */
-  0,                           /* tp_init */
-  0,                           /* tp_alloc */
-  0,                           /* tp_new */
-};
-
-extern PYM_JSContextObject *
-PYM_newJSContextObject(PYM_JSRuntimeObject *runtime, JSContext *cx)
-{
-  PYM_JSContextObject *context = PyObject_New(PYM_JSContextObject,
-                                              &PYM_JSContextType);
-  if (context == NULL)
-    return NULL;
-
-  context->opCallback = NULL;
-  context->runtime = runtime;
-  Py_INCREF(runtime);
-
-  context->cx = cx;
-  JS_SetContextPrivate(cx, context);
-  JS_SetErrorReporter(cx, PYM_reportError);
-
-#ifdef JS_GC_ZEAL
-  // TODO: Consider exposing JS_SetGCZeal() to Python instead of
-  // hard-coding it here.
-  JS_SetGCZeal(cx, 2);
-#endif
-
-  return context;
-}
--- a/context.h	Mon Aug 17 03:52:51 2009 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,58 +0,0 @@
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is Pymonkey.
- *
- * The Initial Developer of the Original Code is Mozilla.
- * Portions created by the Initial Developer are Copyright (C) 2007
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *   Atul Varma <atul@mozilla.com>
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-#ifndef PYM_CONTEXT_H
-#define PYM_CONTEXT_H
-
-#include "runtime.h"
-
-#include <jsapi.h>
-#include <Python.h>
-
-typedef struct {
-  PyObject_HEAD
-  PYM_JSRuntimeObject *runtime;
-  JSContext *cx;
-  PyObject *opCallback;
-} PYM_JSContextObject;
-
-extern PyTypeObject PYM_JSContextType;
-
-extern PYM_JSContextObject *
-PYM_newJSContextObject(PYM_JSRuntimeObject *runtime,
-                       JSContext *cx);
-
-#endif
--- a/function.cpp	Mon Aug 17 03:52:51 2009 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,224 +0,0 @@
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is Pymonkey.
- *
- * The Initial Developer of the Original Code is Mozilla.
- * Portions created by the Initial Developer are Copyright (C) 2007
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *   Atul Varma <atul@mozilla.com>
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-#include "function.h"
-#include "utils.h"
-
-static void
-PYM_JSFunctionDealloc(PYM_JSFunction *self)
-{
-  PYM_JSObjectType.tp_dealloc((PyObject *) self);
-}
-
-static JSBool
-PYM_dispatchJSFunctionToPython(JSContext *cx,
-                               JSObject *obj,
-                               uintN argc,
-                               jsval *argv,
-                               jsval *rval)
-{
-  PYM_PyAutoEnsureGIL gil;
-  jsval callee = JS_ARGV_CALLEE(argv);
-  jsval functionHolder;
-  if (!JS_GetReservedSlot(cx, JSVAL_TO_OBJECT(callee), 0, &functionHolder))
-    return JS_FALSE;
-
-  PyObject *callable;
-  if (!PYM_JS_getPrivatePyObject(cx, JSVAL_TO_OBJECT(functionHolder),
-                                 &callable))
-    return JS_FALSE;
-
-  if (callable == Py_None) {
-    JS_ReportError(cx, "Wrapped Python function no longer exists");
-    return JS_FALSE;
-  }
-
-  PYM_JSContextObject *context = (PYM_JSContextObject *)
-    JS_GetContextPrivate(cx);
-
-  jsval thisArg = OBJECT_TO_JSVAL(obj);
-  PyObject *pyThisArg = PYM_jsvalToPyObject(context, thisArg);
-  if (pyThisArg == NULL) {
-    PYM_pythonExceptionToJs(context);
-    return JS_FALSE;
-  }
-
-  PyObject *funcArgs = PyTuple_New(argc);
-  if (funcArgs == NULL) {
-    Py_DECREF(pyThisArg);
-    JS_ReportOutOfMemory(cx);
-    return JS_FALSE;
-  }
-
-  for (unsigned int i = 0; i < argc; i++) {
-    PyObject *arg = PYM_jsvalToPyObject(context, argv[i]);
-    if (arg == NULL || PyTuple_SetItem(funcArgs, i, arg)) {
-      if (arg)
-        Py_DECREF(arg);
-      Py_DECREF(funcArgs);
-      Py_DECREF(pyThisArg);
-      PYM_pythonExceptionToJs(context);
-      return JS_FALSE;
-    }
-  }
-
-  PyObject *args = PyTuple_Pack(3,
-                                (PyObject *) context,
-                                pyThisArg,
-                                funcArgs);
-  Py_DECREF(pyThisArg);
-  Py_DECREF(funcArgs);
-  if (args == NULL) {
-    JS_ReportOutOfMemory(cx);
-    return JS_FALSE;
-  }
-
-  PyObject *result = PyObject_Call(callable, args, NULL);
-  Py_DECREF(args);
-  if (result == NULL) {
-    PYM_pythonExceptionToJs(context);
-    return JS_FALSE;
-  }
-
-  int error = PYM_pyObjectToJsval(context, result, rval);
-  Py_DECREF(result);
-
-  if (error) {
-    PYM_pythonExceptionToJs(context);
-    return JS_FALSE;
-  }
-
-  return JS_TRUE;
-}
-
-PyTypeObject PYM_JSFunctionType = {
-  PyObject_HEAD_INIT(NULL)
-  0,                           /*ob_size*/
-  "pymonkey.Function",         /*tp_name*/
-  sizeof(PYM_JSFunction),      /*tp_basicsize*/
-  0,                           /*tp_itemsize*/
-  /*tp_dealloc*/
-  (destructor) PYM_JSFunctionDealloc,
-  0,                           /*tp_print*/
-  0,                           /*tp_getattr*/
-  0,                           /*tp_setattr*/
-  0,                           /*tp_compare*/
-  0,                           /*tp_repr*/
-  0,                           /*tp_as_number*/
-  0,                           /*tp_as_sequence*/
-  0,                           /*tp_as_mapping*/
-  0,                           /*tp_hash */
-  0,                           /*tp_call*/
-  0,                           /*tp_str*/
-  0,                           /*tp_getattro*/
-  0,                           /*tp_setattro*/
-  0,                           /*tp_as_buffer*/
-  /*tp_flags*/
-  Py_TPFLAGS_DEFAULT,
-  /* tp_doc */
-  "JavaScript Function.",
-  0,		               /* tp_traverse */
-  0,		               /* tp_clear */
-  0,		               /* tp_richcompare */
-  0,                           /* tp_weaklistoffset */
-  0,		               /* tp_iter */
-  0,		               /* tp_iternext */
-  0,                           /* tp_methods */
-  0,                           /* tp_members */
-  0,                           /* tp_getset */
-  0,                           /* tp_base */
-  0,                           /* tp_dict */
-  0,                           /* tp_descr_get */
-  0,                           /* tp_descr_set */
-  0,                           /* tp_dictoffset */
-  0,                           /* tp_init */
-  0,                           /* tp_alloc */
-  0,                           /* tp_new */
-};
-
-PYM_JSFunction *
-PYM_newJSFunctionFromCallable(PYM_JSContextObject *context,
-                              PyObject *callable,
-                              const char *name)
-{
-  if (!PyCallable_Check(callable)) {
-    PyErr_SetString(PyExc_TypeError, "Callable must be callable");
-    return NULL;
-  }
-
-  JSFunction *func = JS_NewFunction(context->cx,
-                                    PYM_dispatchJSFunctionToPython, 0,
-                                    0, NULL, name);
-
-  if (func == NULL) {
-    PyErr_SetString(PYM_error, "JS_DefineFunction() failed");
-    return NULL;
-  }
-
-  JSObject *funcObj = JS_GetFunctionObject(func);
-
-  if (funcObj == NULL) {
-    PyErr_SetString(PYM_error, "JS_GetFunctionObject() failed");
-    return NULL;
-  }
-
-  PYM_JSFunction *object = PyObject_New(PYM_JSFunction,
-                                        &PYM_JSFunctionType);
-  if (object == NULL)
-    return NULL;
-
-  if (PYM_newJSObject(context, funcObj,
-                      (PYM_JSObject *) object) == NULL)
-    // Note that our object's reference count will have already
-    // been decremented by PYM_newJSObject().
-    return NULL;
-
-  JSObject *functionHolder = PYM_JS_newObject(context->cx, callable);
-  if (functionHolder == NULL) {
-    Py_DECREF((PyObject *) object);
-    PyErr_SetString(PYM_error, "PYM_JS_newObject() failed");
-    return NULL;
-  }
-
-  if (!JS_SetReservedSlot(context->cx, funcObj, 0,
-                          OBJECT_TO_JSVAL(functionHolder))) {
-    Py_DECREF((PyObject *) object);
-    PyErr_SetString(PYM_error, "JS_SetReservedSlot() failed");
-    return NULL;
-  }
-
-  return object;
-}
--- a/function.h	Mon Aug 17 03:52:51 2009 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,57 +0,0 @@
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is Pymonkey.
- *
- * The Initial Developer of the Original Code is Mozilla.
- * Portions created by the Initial Developer are Copyright (C) 2007
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *   Atul Varma <atul@mozilla.com>
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-#ifndef PYM_FUNCTION_H
-#define PYM_FUNCTION_H
-
-#include "object.h"
-#include "context.h"
-
-#include <jsapi.h>
-#include <Python.h>
-
-typedef struct {
-  PYM_JSObject base;
-} PYM_JSFunction;
-
-extern PyTypeObject PYM_JSFunctionType;
-
-extern PYM_JSFunction *
-PYM_newJSFunctionFromCallable(PYM_JSContextObject *context,
-                              PyObject *callable,
-                              const char *name);
-
-#endif
--- a/object.cpp	Mon Aug 17 03:52:51 2009 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,238 +0,0 @@
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is Pymonkey.
- *
- * The Initial Developer of the Original Code is Mozilla.
- * Portions created by the Initial Developer are Copyright (C) 2007
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *   Atul Varma <atul@mozilla.com>
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-#include "object.h"
-#include "function.h"
-#include "runtime.h"
-#include "utils.h"
-
-JSObject *
-PYM_JS_newObject(JSContext *cx, PyObject *pyObject)
-{
-  JSObject *obj = JS_NewObject(cx, &PYM_JS_ObjectClass, NULL, NULL);
-  if (obj) {
-    if (!JS_SetPrivate(cx, obj, pyObject))
-      return NULL;
-    Py_XINCREF(pyObject);
-  }
-  return obj;
-}
-
-JSBool
-PYM_JS_setPrivatePyObject(JSContext *cx, JSObject *obj, PyObject *pyObject)
-{
-  PyObject *old;
-  if (!PYM_JS_getPrivatePyObject(cx, obj, &old))
-    return JS_FALSE;
-  if (!JS_SetPrivate(cx, obj, pyObject))
-    return JS_FALSE;
-  Py_INCREF(pyObject);
-  Py_XDECREF(old);
-  return JS_TRUE;
-}
-
-JSBool
-PYM_JS_getPrivatePyObject(JSContext *cx, JSObject *obj, PyObject **pyObject)
-{
-  JSClass *klass = JS_GET_CLASS(cx, obj);
-  if (klass != &PYM_JS_ObjectClass) {
-    JS_ReportError(cx, "Object is not an instance of PymonkeyObject");
-    return JS_FALSE;
-  }
-
-  *pyObject = (PyObject *) JS_GetPrivate(cx, obj);
-  return JS_TRUE;
-}
-
-static void
-PYM_JS_finalizeObject(JSContext *cx, JSObject *obj)
-{
-  PYM_PyAutoEnsureGIL gil;
-  PyObject *pyObject;
-  // TODO: What if this fails?
-  if (PYM_JS_getPrivatePyObject(cx, obj, &pyObject))
-    Py_XDECREF(pyObject);
-}
-
-// This one-size-fits-all JSClass is used for any JS objects created
-// in Python.  It can hold a reference to a Python object for as long as
-// its parent JS object is accessible from JS-land. As soon as it's
-// garbage collected by the JS interpreter, it releases its reference on
-// the Python object.
-JSClass PYM_JS_ObjectClass = {
-  "PymonkeyObject", JSCLASS_GLOBAL_FLAGS | JSCLASS_HAS_PRIVATE,
-  JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
-  JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, PYM_JS_finalizeObject,
-  JSCLASS_NO_OPTIONAL_MEMBERS
-};
-
-static void
-PYM_JSObjectDealloc(PYM_JSObject *self)
-{
-  if (self->obj) {
-    JS_DHashTableOperate(&self->runtime->objects,
-                         (void *) self->obj,
-                         JS_DHASH_REMOVE);
-
-    // JS_RemoveRoot() always returns JS_TRUE, so don't
-    // bother checking its return value.
-    JS_RemoveRootRT(self->runtime->rt, &self->obj);
-    self->obj = NULL;
-  }
-
-  if (self->runtime) {
-    Py_DECREF(self->runtime);
-    self->runtime = NULL;
-  }
-
-  self->ob_type->tp_free((PyObject *) self);
-}
-
-static PyObject *
-PYM_getRuntime(PYM_JSObject *self, PyObject *args)
-{
-  Py_INCREF(self->runtime);
-  return (PyObject *) self->runtime;
-}
-
-static PyMethodDef PYM_JSObjectMethods[] = {
-  {"get_runtime", (PyCFunction) PYM_getRuntime, METH_VARARGS,
-   "Get the JavaScript runtime associated with this object."},
-  {NULL, NULL, 0, NULL}
-};
-
-PyTypeObject PYM_JSObjectType = {
-  PyObject_HEAD_INIT(NULL)
-  0,                           /*ob_size*/
-  "pymonkey.Object",           /*tp_name*/
-  sizeof(PYM_JSObject),        /*tp_basicsize*/
-  0,                           /*tp_itemsize*/
-  /*tp_dealloc*/
-  (destructor) PYM_JSObjectDealloc,
-  0,                           /*tp_print*/
-  0,                           /*tp_getattr*/
-  0,                           /*tp_setattr*/
-  0,                           /*tp_compare*/
-  0,                           /*tp_repr*/
-  0,                           /*tp_as_number*/
-  0,                           /*tp_as_sequence*/
-  0,                           /*tp_as_mapping*/
-  0,                           /*tp_hash */
-  0,                           /*tp_call*/
-  0,                           /*tp_str*/
-  0,                           /*tp_getattro*/
-  0,                           /*tp_setattro*/
-  0,                           /*tp_as_buffer*/
-  /*tp_flags*/
-  Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
-  /* tp_doc */
-  "JavaScript Object.",
-  0,		               /* tp_traverse */
-  0,		               /* tp_clear */
-  0,		               /* tp_richcompare */
-  0,                           /* tp_weaklistoffset */
-  0,		               /* tp_iter */
-  0,		               /* tp_iternext */
-  PYM_JSObjectMethods,         /* tp_methods */
-  0,                           /* tp_members */
-  0,                           /* tp_getset */
-  0,                           /* tp_base */
-  0,                           /* tp_dict */
-  0,                           /* tp_descr_get */
-  0,                           /* tp_descr_set */
-  0,                           /* tp_dictoffset */
-  0,                           /* tp_init */
-  0,                           /* tp_alloc */
-  0,                           /* tp_new */
-};
-
-PYM_JSObject *PYM_newJSObject(PYM_JSContextObject *context,
-                              JSObject *obj,
-                              PYM_JSObject *subclass) {
-  PYM_JSRuntimeObject *runtime = context->runtime;
-  PYM_HashEntry *cached = (PYM_HashEntry *) JS_DHashTableOperate(
-    &runtime->objects,
-    (void *) obj,
-    JS_DHASH_LOOKUP
-    );
-
-  if (JS_DHASH_ENTRY_IS_BUSY((JSDHashEntryHdr *) cached)) {
-    Py_INCREF((PyObject *) cached->value);
-    return (PYM_JSObject *) cached->value;
-  }
-
-  PYM_JSObject *object;
-
-  if (subclass)
-    object = subclass;
-  else {
-    if (JS_ObjectIsFunction(context->cx, obj)) {
-      PYM_JSFunction *func = PyObject_New(PYM_JSFunction,
-                                          &PYM_JSFunctionType);
-      object = (PYM_JSObject *) func;
-    } else
-      object = PyObject_New(PYM_JSObject,
-                            &PYM_JSObjectType);
-  }
-
-  if (object == NULL)
-    return NULL;
-
-  object->runtime = NULL;
-  object->obj = NULL;
-
-  cached = (PYM_HashEntry *) JS_DHashTableOperate(&runtime->objects,
-                                                  (void *) obj,
-                                                  JS_DHASH_ADD);
-  if (cached == NULL) {
-    Py_DECREF(object);
-    PyErr_SetString(PYM_error, "JS_DHashTableOperate() failed");
-    return NULL;
-  }
-
-  cached->base.key = (void *) obj;
-  cached->value = object;
-
-  object->runtime = context->runtime;
-  Py_INCREF(object->runtime);
-
-  object->obj = obj;
-
-  JS_AddNamedRootRT(object->runtime->rt, &object->obj,
-                    "Pymonkey-Generated Object");
-
-  return object;
-}
--- a/object.h	Mon Aug 17 03:52:51 2009 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,68 +0,0 @@
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is Pymonkey.
- *
- * The Initial Developer of the Original Code is Mozilla.
- * Portions created by the Initial Developer are Copyright (C) 2007
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *   Atul Varma <atul@mozilla.com>
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-#ifndef PYM_OBJECT_H
-#define PYM_OBJECT_H
-
-#include "context.h"
-
-#include <jsapi.h>
-#include <Python.h>
-
-extern JSObject *
-PYM_JS_newObject(JSContext *cx, PyObject *pyObject);
-
-extern JSBool
-PYM_JS_setPrivatePyObject(JSContext *cx, JSObject *obj, PyObject *pyObject);
-
-extern JSBool
-PYM_JS_getPrivatePyObject(JSContext *cx, JSObject *obj, PyObject **pyObject);
-
-extern JSClass PYM_JS_ObjectClass;
-
-typedef struct {
-  PyObject_HEAD
-  PYM_JSRuntimeObject *runtime;
-  JSObject *obj;
-} PYM_JSObject;
-
-extern PyTypeObject PYM_JSObjectType;
-
-extern PYM_JSObject *
-PYM_newJSObject(PYM_JSContextObject *context, JSObject *obj,
-                PYM_JSObject *subclass);
-
-#endif
--- a/pymonkey.cpp	Mon Aug 17 03:52:51 2009 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,94 +0,0 @@
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is Pymonkey.
- *
- * The Initial Developer of the Original Code is Mozilla.
- * Portions created by the Initial Developer are Copyright (C) 2007
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *   Atul Varma <atul@mozilla.com>
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-#include "undefined.h"
-#include "runtime.h"
-#include "context.h"
-#include "object.h"
-#include "function.h"
-#include "utils.h"
-
-static PyMethodDef PYM_methods[] = {
-  {NULL, NULL, 0, NULL}
-};
-
-PyMODINIT_FUNC
-initpymonkey(void)
-{
-  PyObject *module;
-
-  module = Py_InitModule("pymonkey", PYM_methods);
-  if (module == NULL)
-    return;
-
-  if (PyType_Ready(&PYM_undefinedType) < 0)
-    return;
-
-  PYM_undefined = PyObject_New(PYM_undefinedObject, &PYM_undefinedType);
-  if (PYM_undefined == NULL)
-    return;
-  Py_INCREF(PYM_undefined);
-  PyModule_AddObject(module, "undefined", (PyObject *) PYM_undefined);
-
-  PYM_error = PyErr_NewException("pymonkey.error", NULL, NULL);
-  Py_INCREF(PYM_error);
-  PyModule_AddObject(module, "error", PYM_error);
-
-  if (!PyType_Ready(&PYM_JSRuntimeType) < 0)
-    return;
-
-  Py_INCREF(&PYM_JSRuntimeType);
-  PyModule_AddObject(module, "Runtime", (PyObject *) &PYM_JSRuntimeType);
-
-  if (!PyType_Ready(&PYM_JSContextType) < 0)
-    return;
-
-  Py_INCREF(&PYM_JSContextType);
-  PyModule_AddObject(module, "Context", (PyObject *) &PYM_JSContextType);
-
-  if (!PyType_Ready(&PYM_JSObjectType) < 0)
-    return;
-
-  Py_INCREF(&PYM_JSObjectType);
-  PyModule_AddObject(module, "Object", (PyObject *) &PYM_JSObjectType);
-
-  PYM_JSFunctionType.tp_base = &PYM_JSObjectType;
-  if (!PyType_Ready(&PYM_JSFunctionType) < 0)
-    return;
-
-  Py_INCREF(&PYM_JSFunctionType);
-  PyModule_AddObject(module, "Function", (PyObject *) &PYM_JSFunctionType);
-}
--- a/runtime.cpp	Mon Aug 17 03:52:51 2009 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,177 +0,0 @@
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is Pymonkey.
- *
- * The Initial Developer of the Original Code is Mozilla.
- * Portions created by the Initial Developer are Copyright (C) 2007
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *   Atul Varma <atul@mozilla.com>
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-#include "runtime.h"
-#include "context.h"
-#include "utils.h"
-
-static PyObject *
-PYM_JSRuntimeNew(PyTypeObject *type, PyObject *args,
-                 PyObject *kwds)
-{
-  PYM_JSRuntimeObject *self;
-
-  self = (PYM_JSRuntimeObject *) type->tp_alloc(type, 0);
-  if (self != NULL) {
-    self->thread = PyThread_get_thread_ident();
-    self->rt = NULL;
-    self->cx = NULL;
-    self->objects.ops = NULL;
-
-    if (!JS_DHashTableInit(&self->objects,
-                           JS_DHashGetStubOps(),
-                           NULL,
-                           sizeof(PYM_HashEntry),
-                           JS_DHASH_DEFAULT_CAPACITY(100))) {
-      PyErr_SetString(PYM_error, "JS_DHashTableInit() failed");
-      type->tp_dealloc((PyObject *) self);
-      self = NULL;
-    }
-
-    if (self != NULL) {
-      self->rt = JS_NewRuntime(8L * 1024L * 1024L);
-      if (!self->rt) {
-        PyErr_SetString(PYM_error, "JS_NewRuntime() failed");
-        type->tp_dealloc((PyObject *) self);
-        self = NULL;
-      } else {
-        self->cx = JS_NewContext(self->rt, 8192);
-        if (!self->cx) {
-          PyErr_SetString(PYM_error, "JS_NewContext() failed");
-          type->tp_dealloc((PyObject *) self);
-          self = NULL;
-        }
-      }
-    }
-  }
-
-  return (PyObject *) self;
-}
-
-static void
-PYM_JSRuntimeDealloc(PYM_JSRuntimeObject *self)
-{
-  if (self->objects.ops) {
-    JS_DHashTableFinish(&self->objects);
-    self->objects.ops = NULL;
-  }
-
-  if (self->cx) {
-    // Note that this will also force GC of any remaining objects
-    // in the runtime.
-    JS_DestroyContext(self->cx);
-    self->cx = NULL;
-  }
-
-  if (self->rt) {
-    JS_DestroyRuntime(self->rt);
-    self->rt = NULL;
-  }
-
-  self->ob_type->tp_free((PyObject *) self);
-}
-
-static PyObject *
-PYM_newContext(PYM_JSRuntimeObject *self, PyObject *args)
-{
-  PYM_SANITY_CHECK(self);
-  JSContext *cx = JS_NewContext(self->rt, 8192);
-  if (cx == NULL) {
-    PyErr_SetString(PYM_error, "JS_NewContext() failed");
-    return NULL;
-  }
-
-  JS_SetOptions(cx, JSOPTION_VAROBJFIX | JSOPTION_DONT_REPORT_UNCAUGHT |
-                JSOPTION_ATLINE | JSOPTION_STRICT);
-  JS_SetVersion(cx, JSVERSION_LATEST);
-
-  PyObject *retval = (PyObject *) PYM_newJSContextObject(self, cx);
-
-  if (retval == NULL)
-    JS_DestroyContext(cx);
-
-  return retval;
-}
-
-static PyMethodDef PYM_JSRuntimeMethods[] = {
-  {"new_context", (PyCFunction) PYM_newContext, METH_VARARGS,
-   "Create a new JavaScript context."},
-  {NULL, NULL, 0, NULL}
-};
-
-PyTypeObject PYM_JSRuntimeType = {
-  PyObject_HEAD_INIT(NULL)
-  0,                           /*ob_size*/
-  "pymonkey.Runtime",          /*tp_name*/
-  sizeof(PYM_JSRuntimeObject), /*tp_basicsize*/
-  0,                           /*tp_itemsize*/
-  /*tp_dealloc*/
-  (destructor) PYM_JSRuntimeDealloc,
-  0,                           /*tp_print*/
-  0,                           /*tp_getattr*/
-  0,                           /*tp_setattr*/
-  0,                           /*tp_compare*/
-  0,                           /*tp_repr*/
-  0,                           /*tp_as_number*/
-  0,                           /*tp_as_sequence*/
-  0,                           /*tp_as_mapping*/
-  0,                           /*tp_hash */
-  0,                           /*tp_call*/
-  0,                           /*tp_str*/
-  0,                           /*tp_getattro*/
-  0,                           /*tp_setattro*/
-  0,                           /*tp_as_buffer*/
-  Py_TPFLAGS_DEFAULT,          /*tp_flags*/
-  /* tp_doc */
-  "JavaScript Runtime.",
-  0,		               /* tp_traverse */
-  0,		               /* tp_clear */
-  0,		               /* tp_richcompare */
-  0,		               /* tp_weaklistoffset */
-  0,		               /* tp_iter */
-  0,		               /* tp_iternext */
-  PYM_JSRuntimeMethods,        /* tp_methods */
-  0,                           /* tp_members */
-  0,                           /* tp_getset */
-  0,                           /* tp_base */
-  0,                           /* tp_dict */
-  0,                           /* tp_descr_get */
-  0,                           /* tp_descr_set */
-  0,                           /* tp_dictoffset */
-  0,                           /* tp_init */
-  0,                           /* tp_alloc */
-  PYM_JSRuntimeNew,            /* tp_new */
-};
--- a/runtime.h	Mon Aug 17 03:52:51 2009 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,67 +0,0 @@
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is Pymonkey.
- *
- * The Initial Developer of the Original Code is Mozilla.
- * Portions created by the Initial Developer are Copyright (C) 2007
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *   Atul Varma <atul@mozilla.com>
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-#ifndef PYM_RUNTIME_H
-#define PYM_RUNTIME_H
-
-#include <jsapi.h>
-#include <jsdhash.h>
-#include <Python.h>
-#include <pythread.h>
-
-#define PYM_SANITY_CHECK(runtime) \
-  if (PyThread_get_thread_ident() != runtime->thread) {               \
-    PyErr_SetString(PYM_error, "Function called from wrong thread"); \
-    return NULL; \
-  }
-
-#define PYM_ENSURE_RUNTIME_MATCH(runtime1, runtime2) \
-  if (runtime1 != runtime2) { \
-    PyErr_SetString(PyExc_ValueError, "JS runtime mismatch"); \
-    return NULL; \
-  }
-
-typedef struct {
-  PyObject_HEAD
-  JSRuntime *rt;
-  JSContext *cx;
-  JSDHashTable objects;
-  long thread;
-} PYM_JSRuntimeObject;
-
-extern PyTypeObject PYM_JSRuntimeType;
-
-#endif
--- a/setup.py	Mon Aug 17 03:52:51 2009 -0700
+++ b/setup.py	Mon Aug 17 22:08:33 2009 -0700
@@ -92,7 +92,8 @@
 
 setup_options['ext_modules'] = [
     distutils.core.Extension('pymonkey',
-                             SOURCE_FILES,
+                             [os.path.join("src", filename)
+                              for filename in SOURCE_FILES],
                              **ext_options)
     ]
 
@@ -228,7 +229,7 @@
 
     result = subprocess.call(
         [sys.executable,
-         "test_pymonkey.py"],
+         os.path.join("tests", "test_pymonkey.py")],
         env = new_env
         )
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/context.cpp	Mon Aug 17 22:08:33 2009 -0700
@@ -0,0 +1,553 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Pymonkey.
+ *
+ * The Initial Developer of the Original Code is Mozilla.
+ * Portions created by the Initial Developer are Copyright (C) 2007
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Atul Varma <atul@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "context.h"
+#include "object.h"
+#include "function.h"
+#include "utils.h"
+
+// This is the default JSOperationCallback for pymonkey-owned JS contexts,
+// when they've defined one in Python.
+static JSBool
+PYM_operationCallback(JSContext *cx)
+{
+  PYM_PyAutoEnsureGIL gil;
+  PYM_JSContextObject *context = (PYM_JSContextObject *)
+    JS_GetContextPrivate(cx);
+
+  PyObject *callable = context->opCallback;
+  PyObject *args = PyTuple_Pack(1, (PyObject *) context);
+  if (args == NULL) {
+    JS_ReportOutOfMemory(cx);
+    return JS_FALSE;
+  }
+  PyObject *result = PyObject_Call(callable, args, NULL);
+  Py_DECREF(args);
+  if (result == NULL) {
+    PYM_pythonExceptionToJs(context);
+    return JS_FALSE;
+  }
+
+  Py_DECREF(result);
+  return JS_TRUE;
+}
+
+// This is the default JSErrorReporter for pymonkey-owned JS contexts.
+static void
+PYM_reportError(JSContext *cx, const char *message, JSErrorReport *report)
+{
+  PYM_PyAutoEnsureGIL gil;
+
+  // Convert JS warnings into Python warnings.
+  if (JSREPORT_IS_WARNING(report->flags)) {
+    if (report->filename)
+      PyErr_WarnExplicit(NULL, message, report->filename, report->lineno,
+                         NULL, NULL);
+    else
+      PyErr_Warn(NULL, message);
+  } else
+    // TODO: Not sure if this will ever get called, but we should know
+    // if it is.
+    PyErr_Warn(NULL, "A JS error was reported.");
+}
+
+static void
+PYM_JSContextDealloc(PYM_JSContextObject *self)
+{
+  if (self->opCallback) {
+    Py_DECREF(self->opCallback);
+    self->opCallback = NULL;
+  }
+
+  if (self->cx) {
+    JS_DestroyContext(self->cx);
+    self->cx = NULL;
+  }
+
+  Py_DECREF(self->runtime);
+  self->runtime = NULL;
+
+  self->ob_type->tp_free((PyObject *) self);
+}
+
+static PyObject *
+PYM_getRuntime(PYM_JSContextObject *self, PyObject *args)
+{
+  Py_INCREF(self->runtime);
+  return (PyObject *) self->runtime;
+}
+
+static PyObject *
+PYM_getObjectPrivate(PYM_JSContextObject *self, PyObject *args)
+{
+  PYM_SANITY_CHECK(self->runtime);
+  PYM_JSObject *object;
+
+  if (!PyArg_ParseTuple(args, "O!", &PYM_JSObjectType, &object))
+    return NULL;
+
+  PYM_ENSURE_RUNTIME_MATCH(self->runtime, object->runtime);
+
+  JSObject *obj = object->obj;
+
+  if (JS_ObjectIsFunction(self->cx, obj)) {
+    jsval functionHolder;
+    if (!JS_GetReservedSlot(self->cx, obj, 0, &functionHolder)) {
+      JS_ClearPendingException(self->cx);
+      Py_RETURN_NONE;
+    }
+    if (!JSVAL_IS_OBJECT(functionHolder))
+      Py_RETURN_NONE;
+    obj = JSVAL_TO_OBJECT(functionHolder);
+  }
+
+  JSClass *klass = JS_GET_CLASS(self->cx, obj);
+  if (klass != &PYM_JS_ObjectClass)
+    Py_RETURN_NONE;
+
+  PyObject *pyObject;
+
+  if (!PYM_JS_getPrivatePyObject(self->cx, obj, &pyObject)) {
+    PYM_jsExceptionToPython(self);
+    return NULL;
+  }
+
+  if (pyObject == NULL)
+    pyObject = Py_None;
+
+  Py_INCREF(pyObject);
+  return pyObject;
+}
+
+static PyObject *
+PYM_clearObjectPrivate(PYM_JSContextObject *self, PyObject *args)
+{
+  PYM_SANITY_CHECK(self->runtime);
+  PYM_JSObject *object;
+
+  if (!PyArg_ParseTuple(args, "O!", &PYM_JSObjectType, &object))
+    return NULL;
+
+  PYM_ENSURE_RUNTIME_MATCH(self->runtime, object->runtime);
+
+  JSObject *obj = object->obj;
+
+  if (JS_ObjectIsFunction(self->cx, obj)) {
+    jsval functionHolder;
+    if (!JS_GetReservedSlot(self->cx, obj, 0, &functionHolder)) {
+      JS_ClearPendingException(self->cx);
+      Py_RETURN_NONE;
+    }
+    if (!JSVAL_IS_OBJECT(functionHolder))
+      Py_RETURN_NONE;
+    obj = JSVAL_TO_OBJECT(functionHolder);
+  }
+
+  JSClass *klass = JS_GET_CLASS(self->cx, obj);
+  if (klass != &PYM_JS_ObjectClass)
+    Py_RETURN_NONE;
+
+  if (!PYM_JS_setPrivatePyObject(self->cx, obj, Py_None)) {
+    PYM_jsExceptionToPython(self);
+    return NULL;
+  }
+
+  Py_RETURN_NONE;
+}
+
+static PyObject *
+PYM_newObject(PYM_JSContextObject *self, PyObject *args)
+{
+  PYM_SANITY_CHECK(self->runtime);
+  PyObject *privateObj = NULL;
+
+  if (!PyArg_ParseTuple(args, "|O", &privateObj))
+    return NULL;
+
+  JSObject *obj = PYM_JS_newObject(self->cx, privateObj);
+  if (obj == NULL) {
+    PyErr_SetString(PYM_error, "PYM_JS_newObject() failed");
+    return NULL;
+  }
+
+  // If this fails, we don't need to worry about cleaning up
+  // obj because it'll get cleaned up at the next GC.
+  return (PyObject *) PYM_newJSObject(self, obj, NULL);
+}
+
+static PyObject *
+PYM_getProperty(PYM_JSContextObject *self, PyObject *args)
+{
+  PYM_SANITY_CHECK(self->runtime);
+  PYM_JSObject *object;
+  char *buffer = NULL;
+  int size;
+
+  if (!PyArg_ParseTuple(args, "O!es#", &PYM_JSObjectType, &object,
+                        "utf-16", &buffer, &size))
+    return NULL;
+
+  if (self->runtime != object->runtime) {
+    PyMem_Free(buffer);
+    PYM_ENSURE_RUNTIME_MATCH(self->runtime, object->runtime);
+  }
+
+  jsval val;
+  JSBool result;
+  Py_BEGIN_ALLOW_THREADS;
+  // Note that we're manipulating buffer and size here to get rid of
+  // the BOM.
+  result = JS_GetUCProperty(self->cx, object->obj, (jschar *) (buffer + 2),
+                            (size / 2) - 1, &val);
+  Py_END_ALLOW_THREADS;
+
+  PyMem_Free(buffer);
+
+  if (!result) {
+    PYM_jsExceptionToPython(self);
+    return NULL;
+  }
+
+  return PYM_jsvalToPyObject(self, val);
+}
+
+static PyObject *
+PYM_gc(PYM_JSContextObject *self, PyObject *args)
+{
+  PYM_SANITY_CHECK(self->runtime);
+  JS_GC(self->cx);
+  Py_RETURN_NONE;
+}
+
+static PyObject *
+PYM_initStandardClasses(PYM_JSContextObject *self, PyObject *args)
+{
+  PYM_SANITY_CHECK(self->runtime);
+  PYM_JSObject *object;
+
+  if (!PyArg_ParseTuple(args, "O!", &PYM_JSObjectType, &object))
+    return NULL;
+
+  PYM_ENSURE_RUNTIME_MATCH(self->runtime, object->runtime);
+
+  if (!JS_InitStandardClasses(self->cx, object->obj)) {
+    PyErr_SetString(PYM_error, "JS_InitStandardClasses() failed");
+    return NULL;
+  }
+
+  Py_RETURN_NONE;
+}
+
+static PyObject *
+PYM_evaluateScript(PYM_JSContextObject *self, PyObject *args)
+{
+  PYM_SANITY_CHECK(self->runtime);
+  PYM_JSObject *object;
+  const char *source;
+  int sourceLen;
+  const char *filename;
+  int lineNo;
+
+  if (!PyArg_ParseTuple(args, "O!s#si", &PYM_JSObjectType, &object,
+                        &source, &sourceLen, &filename, &lineNo))
+    return NULL;
+
+  PYM_ENSURE_RUNTIME_MATCH(self->runtime, object->runtime);
+
+  jsval rval;
+  JSBool result;
+  Py_BEGIN_ALLOW_THREADS;
+  result = JS_EvaluateScript(self->cx, object->obj, source, sourceLen,
+                             filename, lineNo, &rval);
+  Py_END_ALLOW_THREADS;
+
+  if (!result) {
+    PYM_jsExceptionToPython(self);
+    return NULL;
+  }
+
+  PyObject *pyRval = PYM_jsvalToPyObject(self, rval);
+  return pyRval;
+}
+
+static PyObject *
+PYM_defineProperty(PYM_JSContextObject *self, PyObject *args)
+{
+  PYM_SANITY_CHECK(self->runtime);
+  PYM_JSObject *object;
+  PyObject *value;
+  char *name = NULL;
+  int namelen;
+
+  if (!PyArg_ParseTuple(args, "O!es#O", &PYM_JSObjectType, &object,
+                        "utf-16", &name, &namelen, &value))
+    return NULL;
+
+  if (self->runtime != object->runtime) {
+    PyMem_Free(name);
+    PYM_ENSURE_RUNTIME_MATCH(self->runtime, object->runtime);
+  }
+
+  jsval jsValue;
+
+  if (PYM_pyObjectToJsval(self, value, &jsValue) == -1) {
+    PyMem_Free(name);
+    return NULL;
+  }
+
+  // Note that we're manipulating buffer and size here to get rid of
+  // the BOM.
+  if (!JS_DefineUCProperty(self->cx, object->obj, (jschar *) (name + 2),
+                           (namelen / 2) - 1, jsValue, NULL, NULL,
+                           JSPROP_ENUMERATE)) {
+    // TODO: There's probably an exception pending on self->cx,
+    // what should we do about it?
+    PyMem_Free(name);
+    PyErr_SetString(PYM_error, "JS_DefineProperty() failed");
+    return NULL;
+  }
+
+  PyMem_Free(name);
+  Py_RETURN_NONE;
+}
+
+static PyObject *
+PYM_callFunction(PYM_JSContextObject *self, PyObject *args)
+{
+  PYM_SANITY_CHECK(self->runtime);
+  PYM_JSObject *obj;
+  PYM_JSFunction *fun;
+  PyObject *funcArgs;
+
+  if (!PyArg_ParseTuple(args, "O!O!O!", &PYM_JSObjectType, &obj,
+                        &PYM_JSFunctionType, &fun,
+                        &PyTuple_Type, &funcArgs))
+    return NULL;
+
+  PYM_ENSURE_RUNTIME_MATCH(self->runtime, obj->runtime);
+  PYM_ENSURE_RUNTIME_MATCH(self->runtime, fun->base.runtime);
+
+  uintN argc = PyTuple_Size(funcArgs);
+
+  jsval *argv = (jsval *) PyMem_Malloc(sizeof(jsval) * argc);
+  if (argv == NULL)
+    return PyErr_NoMemory();
+
+  jsval *currArg = argv;
+
+  for (unsigned int i = 0; i < argc; i++) {
+    PyObject *item = PyTuple_GET_ITEM(funcArgs, i);
+    if (item == NULL ||
+        PYM_pyObjectToJsval(self, item, currArg) == -1) {
+      PyMem_Free(argv);
+      return NULL;
+    }
+    currArg++;
+  }
+
+  jsval rval;
+
+  // TODO: This assumes that a JSFunction * is actually a subclass of
+  // a JSObject *, which may or may not be regarded as an implementation
+  // detail.
+  JSBool result;
+  Py_BEGIN_ALLOW_THREADS;
+  result = JS_CallFunction(self->cx, obj->obj,
+                           (JSFunction *) fun->base.obj,
+                           argc, argv, &rval);
+  Py_END_ALLOW_THREADS;
+
+  PyMem_Free(argv);
+
+  if (!result) {
+    PYM_jsExceptionToPython(self);
+    return NULL;
+  }
+
+  return PYM_jsvalToPyObject(self, rval);
+}
+
+static PyObject *
+PYM_newFunction(PYM_JSContextObject *self, PyObject *args)
+{
+  PYM_SANITY_CHECK(self->runtime);
+  PyObject *callable;
+  const char *name;
+
+  if (!PyArg_ParseTuple(args, "Os", &callable, &name))
+    return NULL;
+
+  return (PyObject *) PYM_newJSFunctionFromCallable(self, callable, name);
+}
+
+static PyObject *
+PYM_setOperationCallback(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;
+  }
+
+  JS_SetOperationCallback(self->cx, PYM_operationCallback);
+
+  Py_INCREF(callable);
+  if (self->opCallback)
+    Py_DECREF(self->opCallback);
+  self->opCallback = callable;
+
+  Py_RETURN_NONE;
+}
+
+static PyObject *
+PYM_triggerOperationCallback(PYM_JSContextObject *self, PyObject *args)
+{
+  JS_TriggerOperationCallback(self->cx);
+  Py_RETURN_NONE;
+}
+
+static PyMethodDef PYM_JSContextMethods[] = {
+  {"get_runtime", (PyCFunction) PYM_getRuntime, METH_VARARGS,
+   "Get the JavaScript runtime associated with this context."},
+  {"new_object", (PyCFunction) PYM_newObject, METH_VARARGS,
+   "Create a new JavaScript object."},
+  {"init_standard_classes",
+   (PyCFunction) PYM_initStandardClasses, METH_VARARGS,
+   "Add standard classes and functions to the given object."},
+  {"evaluate_script",
+   (PyCFunction) PYM_evaluateScript, METH_VARARGS,
+   "Evaluate the given JavaScript code in the context of the given "
+   "global object, using the given filename"
+   "and line number information."},
+  {"call_function",
+   (PyCFunction) PYM_callFunction, METH_VARARGS,
+   "Calls a JS function."},
+  {"new_function",
+   (PyCFunction) PYM_newFunction, METH_VARARGS,
+   "Creates a new function callable from JS."},
+  {"define_property",
+   (PyCFunction) PYM_defineProperty, METH_VARARGS,
+   "Defines a property on an object."},
+  {"get_property", (PyCFunction) PYM_getProperty, METH_VARARGS,
+   "Gets the given property for the given JavaScript object."},
+  {"gc", (PyCFunction) PYM_gc, METH_VARARGS,
+   "Performs garbage collection on the context's runtime."},
+  {"set_operation_callback", (PyCFunction) PYM_setOperationCallback,
+   METH_VARARGS,
+   "Sets the operation callback for the context."},
+  {"trigger_operation_callback", (PyCFunction) PYM_triggerOperationCallback,
+   METH_VARARGS,
+   "Triggers the operation callback for the context."},
+  {"get_object_private", (PyCFunction) PYM_getObjectPrivate, METH_VARARGS,
+   "Returns the private Python object stored in the JavaScript object."},
+  {"clear_object_private", (PyCFunction) PYM_clearObjectPrivate, METH_VARARGS,
+   "Clears any private Python object stored in the JavaScript object."},
+  {NULL, NULL, 0, NULL}
+};
+
+PyTypeObject PYM_JSContextType = {
+  PyObject_HEAD_INIT(NULL)
+  0,                           /*ob_size*/
+  "pymonkey.Context",          /*tp_name*/
+  sizeof(PYM_JSContextObject), /*tp_basicsize*/
+  0,                           /*tp_itemsize*/
+  /*tp_dealloc*/
+  (destructor) PYM_JSContextDealloc,
+  0,                           /*tp_print*/
+  0,                           /*tp_getattr*/
+  0,                           /*tp_setattr*/
+  0,                           /*tp_compare*/
+  0,                           /*tp_repr*/
+  0,                           /*tp_as_number*/
+  0,                           /*tp_as_sequence*/
+  0,                           /*tp_as_mapping*/
+  0,                           /*tp_hash */
+  0,                           /*tp_call*/
+  0,                           /*tp_str*/
+  0,                           /*tp_getattro*/
+  0,                           /*tp_setattro*/
+  0,                           /*tp_as_buffer*/
+  Py_TPFLAGS_DEFAULT,          /*tp_flags*/
+  /* tp_doc */
+  "JavaScript Context.",
+  0,		               /* tp_traverse */
+  0,		               /* tp_clear */
+  0,		               /* tp_richcompare */
+  0,		               /* tp_weaklistoffset */
+  0,		               /* tp_iter */
+  0,		               /* tp_iternext */
+  PYM_JSContextMethods,        /* tp_methods */
+  0,                           /* tp_members */
+  0,                           /* tp_getset */
+  0,                           /* tp_base */
+  0,                           /* tp_dict */
+  0,                           /* tp_descr_get */
+  0,                           /* tp_descr_set */
+  0,                           /* tp_dictoffset */
+  0,                           /* tp_init */
+  0,                           /* tp_alloc */
+  0,                           /* tp_new */
+};
+
+extern PYM_JSContextObject *
+PYM_newJSContextObject(PYM_JSRuntimeObject *runtime, JSContext *cx)
+{
+  PYM_JSContextObject *context = PyObject_New(PYM_JSContextObject,
+                                              &PYM_JSContextType);
+  if (context == NULL)
+    return NULL;
+
+  context->opCallback = NULL;
+  context->runtime = runtime;
+  Py_INCREF(runtime);
+
+  context->cx = cx;
+  JS_SetContextPrivate(cx, context);
+  JS_SetErrorReporter(cx, PYM_reportError);
+
+#ifdef JS_GC_ZEAL
+  // TODO: Consider exposing JS_SetGCZeal() to Python instead of
+  // hard-coding it here.
+  JS_SetGCZeal(cx, 2);
+#endif
+
+  return context;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/context.h	Mon Aug 17 22:08:33 2009 -0700
@@ -0,0 +1,58 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Pymonkey.
+ *
+ * The Initial Developer of the Original Code is Mozilla.
+ * Portions created by the Initial Developer are Copyright (C) 2007
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Atul Varma <atul@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef PYM_CONTEXT_H
+#define PYM_CONTEXT_H
+
+#include "runtime.h"
+
+#include <jsapi.h>
+#include <Python.h>
+
+typedef struct {
+  PyObject_HEAD
+  PYM_JSRuntimeObject *runtime;
+  JSContext *cx;
+  PyObject *opCallback;
+} PYM_JSContextObject;
+
+extern PyTypeObject PYM_JSContextType;
+
+extern PYM_JSContextObject *
+PYM_newJSContextObject(PYM_JSRuntimeObject *runtime,
+                       JSContext *cx);
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/function.cpp	Mon Aug 17 22:08:33 2009 -0700
@@ -0,0 +1,224 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Pymonkey.
+ *
+ * The Initial Developer of the Original Code is Mozilla.
+ * Portions created by the Initial Developer are Copyright (C) 2007
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Atul Varma <atul@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "function.h"
+#include "utils.h"
+
+static void
+PYM_JSFunctionDealloc(PYM_JSFunction *self)
+{
+  PYM_JSObjectType.tp_dealloc((PyObject *) self);
+}
+
+static JSBool
+PYM_dispatchJSFunctionToPython(JSContext *cx,
+                               JSObject *obj,
+                               uintN argc,
+                               jsval *argv,
+                               jsval *rval)
+{
+  PYM_PyAutoEnsureGIL gil;
+  jsval callee = JS_ARGV_CALLEE(argv);
+  jsval functionHolder;
+  if (!JS_GetReservedSlot(cx, JSVAL_TO_OBJECT(callee), 0, &functionHolder))
+    return JS_FALSE;
+
+  PyObject *callable;
+  if (!PYM_JS_getPrivatePyObject(cx, JSVAL_TO_OBJECT(functionHolder),
+                                 &callable))
+    return JS_FALSE;
+
+  if (callable == Py_None) {
+    JS_ReportError(cx, "Wrapped Python function no longer exists");
+    return JS_FALSE;
+  }
+
+  PYM_JSContextObject *context = (PYM_JSContextObject *)
+    JS_GetContextPrivate(cx);
+
+  jsval thisArg = OBJECT_TO_JSVAL(obj);
+  PyObject *pyThisArg = PYM_jsvalToPyObject(context, thisArg);
+  if (pyThisArg == NULL) {
+    PYM_pythonExceptionToJs(context);
+    return JS_FALSE;
+  }
+
+  PyObject *funcArgs = PyTuple_New(argc);
+  if (funcArgs == NULL) {
+    Py_DECREF(pyThisArg);
+    JS_ReportOutOfMemory(cx);
+    return JS_FALSE;
+  }
+
+  for (unsigned int i = 0; i < argc; i++) {
+    PyObject *arg = PYM_jsvalToPyObject(context, argv[i]);
+    if (arg == NULL || PyTuple_SetItem(funcArgs, i, arg)) {
+      if (arg)
+        Py_DECREF(arg);
+      Py_DECREF(funcArgs);
+      Py_DECREF(pyThisArg);
+      PYM_pythonExceptionToJs(context);
+      return JS_FALSE;
+    }
+  }
+
+  PyObject *args = PyTuple_Pack(3,
+                                (PyObject *) context,
+                                pyThisArg,
+                                funcArgs);
+  Py_DECREF(pyThisArg);
+  Py_DECREF(funcArgs);
+  if (args == NULL) {
+    JS_ReportOutOfMemory(cx);
+    return JS_FALSE;
+  }
+
+  PyObject *result = PyObject_Call(callable, args, NULL);
+  Py_DECREF(args);
+  if (result == NULL) {
+    PYM_pythonExceptionToJs(context);
+    return JS_FALSE;
+  }
+
+  int error = PYM_pyObjectToJsval(context, result, rval);
+  Py_DECREF(result);
+
+  if (error) {
+    PYM_pythonExceptionToJs(context);
+    return JS_FALSE;
+  }
+
+  return JS_TRUE;
+}
+
+PyTypeObject PYM_JSFunctionType = {
+  PyObject_HEAD_INIT(NULL)
+  0,                           /*ob_size*/
+  "pymonkey.Function",         /*tp_name*/
+  sizeof(PYM_JSFunction),      /*tp_basicsize*/
+  0,                           /*tp_itemsize*/
+  /*tp_dealloc*/
+  (destructor) PYM_JSFunctionDealloc,
+  0,                           /*tp_print*/
+  0,                           /*tp_getattr*/
+  0,                           /*tp_setattr*/
+  0,                           /*tp_compare*/
+  0,                           /*tp_repr*/
+  0,                           /*tp_as_number*/
+  0,                           /*tp_as_sequence*/
+  0,                           /*tp_as_mapping*/
+  0,                           /*tp_hash */
+  0,                           /*tp_call*/
+  0,                           /*tp_str*/
+  0,                           /*tp_getattro*/
+  0,                           /*tp_setattro*/
+  0,                           /*tp_as_buffer*/
+  /*tp_flags*/
+  Py_TPFLAGS_DEFAULT,
+  /* tp_doc */
+  "JavaScript Function.",
+  0,		               /* tp_traverse */
+  0,		               /* tp_clear */
+  0,		               /* tp_richcompare */
+  0,                           /* tp_weaklistoffset */
+  0,		               /* tp_iter */
+  0,		               /* tp_iternext */
+  0,                           /* tp_methods */
+  0,                           /* tp_members */
+  0,                           /* tp_getset */
+  0,                           /* tp_base */
+  0,                           /* tp_dict */
+  0,                           /* tp_descr_get */
+  0,                           /* tp_descr_set */
+  0,                           /* tp_dictoffset */
+  0,                           /* tp_init */
+  0,                           /* tp_alloc */
+  0,                           /* tp_new */
+};
+
+PYM_JSFunction *
+PYM_newJSFunctionFromCallable(PYM_JSContextObject *context,
+                              PyObject *callable,
+                              const char *name)
+{
+  if (!PyCallable_Check(callable)) {
+    PyErr_SetString(PyExc_TypeError, "Callable must be callable");
+    return NULL;
+  }
+
+  JSFunction *func = JS_NewFunction(context->cx,
+                                    PYM_dispatchJSFunctionToPython, 0,
+                                    0, NULL, name);
+
+  if (func == NULL) {
+    PyErr_SetString(PYM_error, "JS_DefineFunction() failed");
+    return NULL;
+  }
+
+  JSObject *funcObj = JS_GetFunctionObject(func);
+
+  if (funcObj == NULL) {
+    PyErr_SetString(PYM_error, "JS_GetFunctionObject() failed");
+    return NULL;
+  }
+
+  PYM_JSFunction *object = PyObject_New(PYM_JSFunction,
+                                        &PYM_JSFunctionType);
+  if (object == NULL)
+    return NULL;
+
+  if (PYM_newJSObject(context, funcObj,
+                      (PYM_JSObject *) object) == NULL)
+    // Note that our object's reference count will have already
+    // been decremented by PYM_newJSObject().
+    return NULL;
+
+  JSObject *functionHolder = PYM_JS_newObject(context->cx, callable);
+  if (functionHolder == NULL) {
+    Py_DECREF((PyObject *) object);
+    PyErr_SetString(PYM_error, "PYM_JS_newObject() failed");
+    return NULL;
+  }
+
+  if (!JS_SetReservedSlot(context->cx, funcObj, 0,
+                          OBJECT_TO_JSVAL(functionHolder))) {
+    Py_DECREF((PyObject *) object);
+    PyErr_SetString(PYM_error, "JS_SetReservedSlot() failed");
+    return NULL;
+  }
+
+  return object;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/function.h	Mon Aug 17 22:08:33 2009 -0700
@@ -0,0 +1,57 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Pymonkey.
+ *
+ * The Initial Developer of the Original Code is Mozilla.
+ * Portions created by the Initial Developer are Copyright (C) 2007
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Atul Varma <atul@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef PYM_FUNCTION_H
+#define PYM_FUNCTION_H
+
+#include "object.h"
+#include "context.h"
+
+#include <jsapi.h>
+#include <Python.h>
+
+typedef struct {
+  PYM_JSObject base;
+} PYM_JSFunction;
+
+extern PyTypeObject PYM_JSFunctionType;
+
+extern PYM_JSFunction *
+PYM_newJSFunctionFromCallable(PYM_JSContextObject *context,
+                              PyObject *callable,
+                              const char *name);
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/object.cpp	Mon Aug 17 22:08:33 2009 -0700
@@ -0,0 +1,238 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Pymonkey.
+ *
+ * The Initial Developer of the Original Code is Mozilla.
+ * Portions created by the Initial Developer are Copyright (C) 2007
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Atul Varma <atul@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "object.h"
+#include "function.h"
+#include "runtime.h"
+#include "utils.h"
+
+JSObject *
+PYM_JS_newObject(JSContext *cx, PyObject *pyObject)
+{
+  JSObject *obj = JS_NewObject(cx, &PYM_JS_ObjectClass, NULL, NULL);
+  if (obj) {
+    if (!JS_SetPrivate(cx, obj, pyObject))
+      return NULL;
+    Py_XINCREF(pyObject);
+  }
+  return obj;
+}
+
+JSBool
+PYM_JS_setPrivatePyObject(JSContext *cx, JSObject *obj, PyObject *pyObject)
+{
+  PyObject *old;
+  if (!PYM_JS_getPrivatePyObject(cx, obj, &old))
+    return JS_FALSE;
+  if (!JS_SetPrivate(cx, obj, pyObject))
+    return JS_FALSE;
+  Py_INCREF(pyObject);
+  Py_XDECREF(old);
+  return JS_TRUE;
+}
+
+JSBool
+PYM_JS_getPrivatePyObject(JSContext *cx, JSObject *obj, PyObject **pyObject)
+{
+  JSClass *klass = JS_GET_CLASS(cx, obj);
+  if (klass != &PYM_JS_ObjectClass) {
+    JS_ReportError(cx, "Object is not an instance of PymonkeyObject");
+    return JS_FALSE;
+  }
+
+  *pyObject = (PyObject *) JS_GetPrivate(cx, obj);
+  return JS_TRUE;
+}
+
+static void
+PYM_JS_finalizeObject(JSContext *cx, JSObject *obj)
+{
+  PYM_PyAutoEnsureGIL gil;
+  PyObject *pyObject;
+  // TODO: What if this fails?
+  if (PYM_JS_getPrivatePyObject(cx, obj, &pyObject))
+    Py_XDECREF(pyObject);
+}
+
+// This one-size-fits-all JSClass is used for any JS objects created
+// in Python.  It can hold a reference to a Python object for as long as
+// its parent JS object is accessible from JS-land. As soon as it's
+// garbage collected by the JS interpreter, it releases its reference on
+// the Python object.
+JSClass PYM_JS_ObjectClass = {
+  "PymonkeyObject", JSCLASS_GLOBAL_FLAGS | JSCLASS_HAS_PRIVATE,
+  JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
+  JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, PYM_JS_finalizeObject,
+  JSCLASS_NO_OPTIONAL_MEMBERS
+};
+
+static void
+PYM_JSObjectDealloc(PYM_JSObject *self)
+{
+  if (self->obj) {
+    JS_DHashTableOperate(&self->runtime->objects,
+                         (void *) self->obj,
+                         JS_DHASH_REMOVE);
+
+    // JS_RemoveRoot() always returns JS_TRUE, so don't
+    // bother checking its return value.
+    JS_RemoveRootRT(self->runtime->rt, &self->obj);
+    self->obj = NULL;
+  }
+
+  if (self->runtime) {
+    Py_DECREF(self->runtime);
+    self->runtime = NULL;
+  }
+
+  self->ob_type->tp_free((PyObject *) self);
+}
+
+static PyObject *
+PYM_getRuntime(PYM_JSObject *self, PyObject *args)
+{
+  Py_INCREF(self->runtime);
+  return (PyObject *) self->runtime;
+}
+
+static PyMethodDef PYM_JSObjectMethods[] = {
+  {"get_runtime", (PyCFunction) PYM_getRuntime, METH_VARARGS,
+   "Get the JavaScript runtime associated with this object."},
+  {NULL, NULL, 0, NULL}
+};
+
+PyTypeObject PYM_JSObjectType = {
+  PyObject_HEAD_INIT(NULL)
+  0,                           /*ob_size*/
+  "pymonkey.Object",           /*tp_name*/
+  sizeof(PYM_JSObject),        /*tp_basicsize*/
+  0,                           /*tp_itemsize*/
+  /*tp_dealloc*/
+  (destructor) PYM_JSObjectDealloc,
+  0,                           /*tp_print*/
+  0,                           /*tp_getattr*/
+  0,                           /*tp_setattr*/
+  0,                           /*tp_compare*/
+  0,                           /*tp_repr*/
+  0,                           /*tp_as_number*/
+  0,                           /*tp_as_sequence*/
+  0,                           /*tp_as_mapping*/
+  0,                           /*tp_hash */
+  0,                           /*tp_call*/
+  0,                           /*tp_str*/
+  0,                           /*tp_getattro*/
+  0,                           /*tp_setattro*/
+  0,                           /*tp_as_buffer*/
+  /*tp_flags*/
+  Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+  /* tp_doc */
+  "JavaScript Object.",
+  0,		               /* tp_traverse */
+  0,		               /* tp_clear */
+  0,		               /* tp_richcompare */
+  0,                           /* tp_weaklistoffset */
+  0,		               /* tp_iter */
+  0,		               /* tp_iternext */
+  PYM_JSObjectMethods,         /* tp_methods */
+  0,                           /* tp_members */
+  0,                           /* tp_getset */
+  0,                           /* tp_base */
+  0,                           /* tp_dict */
+  0,                           /* tp_descr_get */
+  0,                           /* tp_descr_set */
+  0,                           /* tp_dictoffset */
+  0,                           /* tp_init */
+  0,                           /* tp_alloc */
+  0,                           /* tp_new */
+};
+
+PYM_JSObject *PYM_newJSObject(PYM_JSContextObject *context,
+                              JSObject *obj,
+                              PYM_JSObject *subclass) {
+  PYM_JSRuntimeObject *runtime = context->runtime;
+  PYM_HashEntry *cached = (PYM_HashEntry *) JS_DHashTableOperate(
+    &runtime->objects,
+    (void *) obj,
+    JS_DHASH_LOOKUP
+    );
+
+  if (JS_DHASH_ENTRY_IS_BUSY((JSDHashEntryHdr *) cached)) {
+    Py_INCREF((PyObject *) cached->value);
+    return (PYM_JSObject *) cached->value;
+  }
+
+  PYM_JSObject *object;
+
+  if (subclass)
+    object = subclass;
+  else {
+    if (JS_ObjectIsFunction(context->cx, obj)) {
+      PYM_JSFunction *func = PyObject_New(PYM_JSFunction,
+                                          &PYM_JSFunctionType);
+      object = (PYM_JSObject *) func;
+    } else
+      object = PyObject_New(PYM_JSObject,
+                            &PYM_JSObjectType);
+  }
+
+  if (object == NULL)
+    return NULL;
+
+  object->runtime = NULL;
+  object->obj = NULL;
+
+  cached = (PYM_HashEntry *) JS_DHashTableOperate(&runtime->objects,
+                                                  (void *) obj,
+                                                  JS_DHASH_ADD);
+  if (cached == NULL) {
+    Py_DECREF(object);
+    PyErr_SetString(PYM_error, "JS_DHashTableOperate() failed");
+    return NULL;
+  }
+
+  cached->base.key = (void *) obj;
+  cached->value = object;
+
+  object->runtime = context->runtime;
+  Py_INCREF(object->runtime);
+
+  object->obj = obj;
+
+  JS_AddNamedRootRT(object->runtime->rt, &object->obj,
+                    "Pymonkey-Generated Object");
+
+  return object;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/object.h	Mon Aug 17 22:08:33 2009 -0700
@@ -0,0 +1,68 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Pymonkey.
+ *
+ * The Initial Developer of the Original Code is Mozilla.
+ * Portions created by the Initial Developer are Copyright (C) 2007
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Atul Varma <atul@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef PYM_OBJECT_H
+#define PYM_OBJECT_H
+
+#include "context.h"
+
+#include <jsapi.h>
+#include <Python.h>
+
+extern JSObject *
+PYM_JS_newObject(JSContext *cx, PyObject *pyObject);
+
+extern JSBool
+PYM_JS_setPrivatePyObject(JSContext *cx, JSObject *obj, PyObject *pyObject);
+
+extern JSBool
+PYM_JS_getPrivatePyObject(JSContext *cx, JSObject *obj, PyObject **pyObject);
+
+extern JSClass PYM_JS_ObjectClass;
+
+typedef struct {
+  PyObject_HEAD
+  PYM_JSRuntimeObject *runtime;
+  JSObject *obj;
+} PYM_JSObject;
+
+extern PyTypeObject PYM_JSObjectType;
+
+extern PYM_JSObject *
+PYM_newJSObject(PYM_JSContextObject *context, JSObject *obj,
+                PYM_JSObject *subclass);
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/pymonkey.cpp	Mon Aug 17 22:08:33 2009 -0700
@@ -0,0 +1,94 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Pymonkey.
+ *
+ * The Initial Developer of the Original Code is Mozilla.
+ * Portions created by the Initial Developer are Copyright (C) 2007
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Atul Varma <atul@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "undefined.h"
+#include "runtime.h"
+#include "context.h"
+#include "object.h"
+#include "function.h"
+#include "utils.h"
+
+static PyMethodDef PYM_methods[] = {
+  {NULL, NULL, 0, NULL}
+};
+
+PyMODINIT_FUNC
+initpymonkey(void)
+{
+  PyObject *module;
+
+  module = Py_InitModule("pymonkey", PYM_methods);
+  if (module == NULL)
+    return;
+
+  if (PyType_Ready(&PYM_undefinedType) < 0)
+    return;
+
+  PYM_undefined = PyObject_New(PYM_undefinedObject, &PYM_undefinedType);
+  if (PYM_undefined == NULL)
+    return;
+  Py_INCREF(PYM_undefined);
+  PyModule_AddObject(module, "undefined", (PyObject *) PYM_undefined);
+
+  PYM_error = PyErr_NewException("pymonkey.error", NULL, NULL);
+  Py_INCREF(PYM_error);
+  PyModule_AddObject(module, "error", PYM_error);
+
+  if (!PyType_Ready(&PYM_JSRuntimeType) < 0)
+    return;
+
+  Py_INCREF(&PYM_JSRuntimeType);
+  PyModule_AddObject(module, "Runtime", (PyObject *) &PYM_JSRuntimeType);
+
+  if (!PyType_Ready(&PYM_JSContextType) < 0)
+    return;
+
+  Py_INCREF(&PYM_JSContextType);
+  PyModule_AddObject(module, "Context", (PyObject *) &PYM_JSContextType);
+
+  if (!PyType_Ready(&PYM_JSObjectType) < 0)
+    return;
+
+  Py_INCREF(&PYM_JSObjectType);
+  PyModule_AddObject(module, "Object", (PyObject *) &PYM_JSObjectType);
+
+  PYM_JSFunctionType.tp_base = &PYM_JSObjectType;
+  if (!PyType_Ready(&PYM_JSFunctionType) < 0)
+    return;
+
+  Py_INCREF(&PYM_JSFunctionType);
+  PyModule_AddObject(module, "Function", (PyObject *) &PYM_JSFunctionType);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/runtime.cpp	Mon Aug 17 22:08:33 2009 -0700
@@ -0,0 +1,177 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Pymonkey.
+ *
+ * The Initial Developer of the Original Code is Mozilla.
+ * Portions created by the Initial Developer are Copyright (C) 2007
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Atul Varma <atul@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "runtime.h"
+#include "context.h"
+#include "utils.h"
+
+static PyObject *
+PYM_JSRuntimeNew(PyTypeObject *type, PyObject *args,
+                 PyObject *kwds)
+{
+  PYM_JSRuntimeObject *self;
+
+  self = (PYM_JSRuntimeObject *) type->tp_alloc(type, 0);
+  if (self != NULL) {
+    self->thread = PyThread_get_thread_ident();
+    self->rt = NULL;
+    self->cx = NULL;
+    self->objects.ops = NULL;
+
+    if (!JS_DHashTableInit(&self->objects,
+                           JS_DHashGetStubOps(),
+                           NULL,
+                           sizeof(PYM_HashEntry),
+                           JS_DHASH_DEFAULT_CAPACITY(100))) {
+      PyErr_SetString(PYM_error, "JS_DHashTableInit() failed");
+      type->tp_dealloc((PyObject *) self);
+      self = NULL;
+    }
+
+    if (self != NULL) {
+      self->rt = JS_NewRuntime(8L * 1024L * 1024L);
+      if (!self->rt) {
+        PyErr_SetString(PYM_error, "JS_NewRuntime() failed");
+        type->tp_dealloc((PyObject *) self);
+        self = NULL;
+      } else {
+        self->cx = JS_NewContext(self->rt, 8192);
+        if (!self->cx) {
+          PyErr_SetString(PYM_error, "JS_NewContext() failed");
+          type->tp_dealloc((PyObject *) self);
+          self = NULL;
+        }
+      }
+    }
+  }
+
+  return (PyObject *) self;
+}
+
+static void
+PYM_JSRuntimeDealloc(PYM_JSRuntimeObject *self)
+{
+  if (self->objects.ops) {
+    JS_DHashTableFinish(&self->objects);
+    self->objects.ops = NULL;
+  }
+
+  if (self->cx) {
+    // Note that this will also force GC of any remaining objects
+    // in the runtime.
+    JS_DestroyContext(self->cx);
+    self->cx = NULL;
+  }
+
+  if (self->rt) {
+    JS_DestroyRuntime(self->rt);
+    self->rt = NULL;
+  }
+
+  self->ob_type->tp_free((PyObject *) self);
+}
+
+static PyObject *
+PYM_newContext(PYM_JSRuntimeObject *self, PyObject *args)
+{
+  PYM_SANITY_CHECK(self);
+  JSContext *cx = JS_NewContext(self->rt, 8192);
+  if (cx == NULL) {
+    PyErr_SetString(PYM_error, "JS_NewContext() failed");
+    return NULL;
+  }
+
+  JS_SetOptions(cx, JSOPTION_VAROBJFIX | JSOPTION_DONT_REPORT_UNCAUGHT |
+                JSOPTION_ATLINE | JSOPTION_STRICT);
+  JS_SetVersion(cx, JSVERSION_LATEST);
+
+  PyObject *retval = (PyObject *) PYM_newJSContextObject(self, cx);
+
+  if (retval == NULL)
+    JS_DestroyContext(cx);
+
+  return retval;
+}
+
+static PyMethodDef PYM_JSRuntimeMethods[] = {
+  {"new_context", (PyCFunction) PYM_newContext, METH_VARARGS,
+   "Create a new JavaScript context."},
+  {NULL, NULL, 0, NULL}
+};
+
+PyTypeObject PYM_JSRuntimeType = {
+  PyObject_HEAD_INIT(NULL)
+  0,                           /*ob_size*/
+  "pymonkey.Runtime",          /*tp_name*/
+  sizeof(PYM_JSRuntimeObject), /*tp_basicsize*/
+  0,                           /*tp_itemsize*/
+  /*tp_dealloc*/
+  (destructor) PYM_JSRuntimeDealloc,
+  0,                           /*tp_print*/
+  0,                           /*tp_getattr*/
+  0,                           /*tp_setattr*/
+  0,                           /*tp_compare*/
+  0,                           /*tp_repr*/
+  0,                           /*tp_as_number*/
+  0,                           /*tp_as_sequence*/
+  0,                           /*tp_as_mapping*/
+  0,                           /*tp_hash */
+  0,                           /*tp_call*/
+  0,                           /*tp_str*/
+  0,                           /*tp_getattro*/
+  0,                           /*tp_setattro*/
+  0,                           /*tp_as_buffer*/
+  Py_TPFLAGS_DEFAULT,          /*tp_flags*/
+  /* tp_doc */
+  "JavaScript Runtime.",
+  0,		               /* tp_traverse */
+  0,		               /* tp_clear */
+  0,		               /* tp_richcompare */
+  0,		               /* tp_weaklistoffset */
+  0,		               /* tp_iter */
+  0,		               /* tp_iternext */
+  PYM_JSRuntimeMethods,        /* tp_methods */
+  0,                           /* tp_members */
+  0,                           /* tp_getset */
+  0,                           /* tp_base */
+  0,                           /* tp_dict */
+  0,                           /* tp_descr_get */
+  0,                           /* tp_descr_set */
+  0,                           /* tp_dictoffset */
+  0,                           /* tp_init */
+  0,                           /* tp_alloc */
+  PYM_JSRuntimeNew,            /* tp_new */
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/runtime.h	Mon Aug 17 22:08:33 2009 -0700
@@ -0,0 +1,67 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Pymonkey.
+ *
+ * The Initial Developer of the Original Code is Mozilla.
+ * Portions created by the Initial Developer are Copyright (C) 2007
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Atul Varma <atul@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef PYM_RUNTIME_H
+#define PYM_RUNTIME_H
+
+#include <jsapi.h>
+#include <jsdhash.h>
+#include <Python.h>
+#include <pythread.h>
+
+#define PYM_SANITY_CHECK(runtime) \
+  if (PyThread_get_thread_ident() != runtime->thread) {               \
+    PyErr_SetString(PYM_error, "Function called from wrong thread"); \
+    return NULL; \
+  }
+
+#define PYM_ENSURE_RUNTIME_MATCH(runtime1, runtime2) \
+  if (runtime1 != runtime2) { \
+    PyErr_SetString(PyExc_ValueError, "JS runtime mismatch"); \
+    return NULL; \
+  }
+
+typedef struct {
+  PyObject_HEAD
+  JSRuntime *rt;
+  JSContext *cx;
+  JSDHashTable objects;
+  long thread;
+} PYM_JSRuntimeObject;
+
+extern PyTypeObject PYM_JSRuntimeType;
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/undefined.cpp	Mon Aug 17 22:08:33 2009 -0700
@@ -0,0 +1,82 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Pymonkey.
+ *
+ * The Initial Developer of the Original Code is Mozilla.
+ * Portions created by the Initial Developer are Copyright (C) 2007
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Atul Varma <atul@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "undefined.h"
+
+static Py_ssize_t PYM_undefinedLength(PyObject *o) {
+  return 0;
+};
+
+static PyMappingMethods PYM_undefinedAsMapping = {
+  PYM_undefinedLength,         /*mp_length*/
+  0,                           /*mp_subscript*/
+  0                            /*mp_ass_subscript*/
+};
+
+static PyObject *PYM_undefinedRepr(PyObject *o) {
+  return PyString_FromString("pymonkey.undefined");
+}
+
+// TODO: We should make this behave as much like JavaScript's
+// "undefined" value as possible; e.g., its string value should
+// be "undefined", the singleton should be falsy, etc.
+PyTypeObject PYM_undefinedType = {
+  PyObject_HEAD_INIT(NULL)
+  0,                           /*ob_size*/
+  "pymonkey.undefined",        /*tp_name*/
+  sizeof(PYM_undefinedObject), /*tp_basicsize*/
+  0,                           /*tp_itemsize*/
+  0,                           /*tp_dealloc*/
+  0,                           /*tp_print*/
+  0,                           /*tp_getattr*/
+  0,                           /*tp_setattr*/
+  0,                           /*tp_compare*/
+  PYM_undefinedRepr,           /*tp_repr*/
+  0,                           /*tp_as_number*/
+  0,                           /*tp_as_sequence*/
+  &PYM_undefinedAsMapping,     /*tp_as_mapping*/
+  0,                           /*tp_hash */
+  0,                           /*tp_call*/
+  PYM_undefinedRepr,           /*tp_str*/
+  0,                           /*tp_getattro*/
+  0,                           /*tp_setattro*/
+  0,                           /*tp_as_buffer*/
+  Py_TPFLAGS_DEFAULT,          /*tp_flags*/
+  /* tp_doc */
+  "Pythonic equivalent of JavaScript's 'undefined' value",
+};
+
+PYM_undefinedObject *PYM_undefined;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/undefined.h	Mon Aug 17 22:08:33 2009 -0700
@@ -0,0 +1,53 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Pymonkey.
+ *
+ * The Initial Developer of the Original Code is Mozilla.
+ * Portions created by the Initial Developer are Copyright (C) 2007
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Atul Varma <atul@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef PYM_UNDEFINED_H
+#define PYM_UNDEFINED_H
+
+#include <Python.h>
+
+#define Py_RETURN_UNDEFINED  { Py_INCREF(PYM_undefined);        \
+                               return (PyObject *) PYM_undefined; }
+
+typedef struct {
+  PyObject_HEAD
+} PYM_undefinedObject;
+
+extern PyTypeObject PYM_undefinedType;
+
+extern PYM_undefinedObject *PYM_undefined;
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/utils.cpp	Mon Aug 17 22:08:33 2009 -0700
@@ -0,0 +1,257 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Pymonkey.
+ *
+ * The Initial Developer of the Original Code is Mozilla.
+ * Portions created by the Initial Developer are Copyright (C) 2007
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Atul Varma <atul@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "utils.h"
+#include "undefined.h"
+#include "object.h"
+
+PyObject *PYM_error;
+
+static int
+PYM_doubleToJsval(PYM_JSContextObject *context,
+                  double number,
+                  jsval *rval)
+{
+  jsdouble *numberAsJsdouble = JS_NewDouble(context->cx, number);
+  if (numberAsJsdouble == NULL) {
+    PyErr_SetString(PYM_error, "JS_NewDouble() failed");
+    return -1;
+  }
+  *rval = DOUBLE_TO_JSVAL(numberAsJsdouble);
+  return 0;
+}
+
+int
+PYM_pyObjectToJsval(PYM_JSContextObject *context,
+                    PyObject *object,
+                    jsval *rval)
+{
+  if (PyString_Check(object) || PyUnicode_Check(object)) {
+    PyObject *unicode;
+    if (PyString_Check(object)) {
+      unicode = PyUnicode_FromObject(object);
+      if (unicode == NULL)
+        return -1;
+    } else {
+      unicode = object;
+      Py_INCREF(unicode);
+    }
+
+    PyObject *string = PyUnicode_AsUTF16String(unicode);
+    Py_DECREF(unicode);
+    if (string == NULL)
+      return -1;
+
+    char *buffer = PyString_AS_STRING(string);
+    Py_ssize_t size = PyString_GET_SIZE(string);
+
+    // Note that we're manipulating buffer and size here to get rid of
+    // the BOM.
+    JSString *jsString = JS_NewUCStringCopyN(context->cx,
+                                             (const jschar *) (buffer + 2),
+                                             (size / 2) - 1);
+    Py_DECREF(string);
+    if (jsString == NULL) {
+      PyErr_SetString(PYM_error, "JS_NewUCStringCopyN() failed");
+      return -1;
+    }
+
+    *rval = STRING_TO_JSVAL(jsString);
+    return 0;
+  }
+
+  if (PyInt_Check(object)) {
+    long number = PyInt_AS_LONG(object);
+    if (INT_FITS_IN_JSVAL(number)) {
+      *rval = INT_TO_JSVAL(number);
+      return 0;
+    } else
+      return PYM_doubleToJsval(context, number, rval);
+  }
+
+  if (PyFloat_Check(object))
+    return PYM_doubleToJsval(context, PyFloat_AS_DOUBLE(object), rval);
+
+  if (PyObject_TypeCheck(object, &PYM_JSObjectType)) {
+    PYM_JSObject *jsObject = (PYM_JSObject *) object;
+    JSRuntime *rt = JS_GetRuntime(context->cx);
+    if (rt != jsObject->runtime->rt) {
+      PyErr_SetString(PyExc_ValueError,
+                      "JS object and JS context are from different "
+                      "JS runtimes");
+      return -1;
+    }
+    *rval = OBJECT_TO_JSVAL(jsObject->obj);
+    return 0;
+  }
+
+  if (object == Py_True) {
+    *rval = JSVAL_TRUE;
+    return 0;
+  }
+
+  if (object == Py_False) {
+    *rval = JSVAL_FALSE;
+    return 0;
+  }
+
+  if (object == Py_None) {
+    *rval = JSVAL_NULL;
+    return 0;
+  }
+
+  // TODO: Support more types.
+  PyErr_SetString(PyExc_NotImplementedError,
+                  "Data type conversion not implemented.");
+  return -1;
+}
+
+PyObject *
+PYM_jsvalToPyObject(PYM_JSContextObject *context,
+                    jsval value) {
+  if (JSVAL_IS_INT(value))
+    return PyInt_FromLong(JSVAL_TO_INT(value));
+
+  if (JSVAL_IS_DOUBLE(value)) {
+    jsdouble *doubleRef = JSVAL_TO_DOUBLE(value);
+    return PyFloat_FromDouble(*doubleRef);
+  }
+
+  if (value == JSVAL_FALSE)
+    Py_RETURN_FALSE;
+
+  if (value == JSVAL_TRUE)
+    Py_RETURN_TRUE;
+
+  if (JSVAL_IS_NULL(value))
+    Py_RETURN_NONE;
+
+  if (JSVAL_IS_VOID(value))
+    Py_RETURN_UNDEFINED;
+
+  if (JSVAL_IS_STRING(value)) {
+    // Strings in JS are funky: think of them as 16-bit versions of
+    // Python 2.x's 'str' type.  Whether or not they're valid UTF-16
+    // is entirely up to the client code.
+
+    // TODO: Instead of ignoring errors, consider actually treating
+    // the string as a raw character buffer.
+    JSString *str = JSVAL_TO_STRING(value);
+    const char *chars = (const char *) JS_GetStringChars(str);
+    size_t length = JS_GetStringLength(str);
+
+    // We're multiplying length by two since Python wants the number
+    // of bytes, not the number of 16-bit characters.
+    return PyUnicode_DecodeUTF16(chars, length * 2, "ignore", NULL);
+  }
+
+  if (JSVAL_IS_OBJECT(value))
+    return (PyObject *) PYM_newJSObject(context, JSVAL_TO_OBJECT(value),
+                                        NULL);
+
+  // TODO: Support more types.
+  PyErr_SetString(PyExc_NotImplementedError,
+                  "Data type conversion not implemented.");
+  return NULL;
+}
+
+void
+PYM_pythonExceptionToJs(PYM_JSContextObject *context)
+{
+  PyObject *type;
+  PyObject *value;
+  PyObject *traceback;
+
+  PyErr_Fetch(&type, &value, &traceback);
+
+  if (type == PYM_error && value &&
+      PyObject_HasAttrString(value, "message")) {
+    jsval val;
+    PyObject *message = PyObject_GetAttrString(value, "message");
+    if (message && PYM_pyObjectToJsval(context, message, &val) == 0) {
+      JS_SetPendingException(context->cx, val);
+    } else
+      JS_ReportError(context->cx,
+                     "Python exception occurred, but exception "
+                     "couldn't be converted");
+    Py_XDECREF(message);
+  } else {
+    if (value) {
+      JSObject *exception = PYM_JS_newObject(context->cx, value);
+      if (exception)
+        JS_SetPendingException(context->cx, OBJECT_TO_JSVAL(exception));
+      else
+        JS_ReportOutOfMemory(context->cx);
+    } else
+      JS_ReportError(context->cx, "Python exception occurred");
+  }
+
+  Py_XDECREF(type);
+  Py_XDECREF(value);
+  Py_XDECREF(traceback);
+}
+
+void
+PYM_jsExceptionToPython(PYM_JSContextObject *context)
+{
+  if (!JS_IsExceptionPending(context->cx) &&
+      PyErr_Occurred())
+    return;
+
+  jsval val;
+  if (JS_GetPendingException(context->cx, &val)) {
+    PyObject *obj = PYM_jsvalToPyObject(context, val);
+    if (obj) {
+      PyErr_SetObject(PYM_error, obj);
+      Py_DECREF(obj);
+    } else {
+      PyErr_Clear();
+
+      JSString *str = NULL;
+
+      Py_BEGIN_ALLOW_THREADS;
+      str = JS_ValueToString(context->cx, val);
+      Py_END_ALLOW_THREADS;
+
+      if (str != NULL) {
+        const char *chars = JS_GetStringBytes(str);
+        PyErr_SetString(PYM_error, chars);
+      } else
+        PyErr_SetString(PYM_error, "JS exception occurred");
+    }
+  } else
+    PyErr_SetString(PYM_error, "JS_GetPendingException() failed");
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/utils.h	Mon Aug 17 22:08:33 2009 -0700
@@ -0,0 +1,81 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Pymonkey.
+ *
+ * The Initial Developer of the Original Code is Mozilla.
+ * Portions created by the Initial Developer are Copyright (C) 2007
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Atul Varma <atul@mozilla.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef PYM_UTILS_H
+#define PYM_UTILS_H
+
+#include "context.h"
+
+#include <jsapi.h>
+#include <jsdhash.h>
+#include <Python.h>
+
+class PYM_PyAutoEnsureGIL {
+public:
+  PYM_PyAutoEnsureGIL() {
+    state = PyGILState_Ensure();
+  }
+
+  ~PYM_PyAutoEnsureGIL() {
+    PyGILState_Release(state);
+  }
+
+protected:
+  PyGILState_STATE state;
+};
+
+typedef struct {
+  JSDHashEntryStub base;
+  void *value;
+} PYM_HashEntry;
+
+extern PyObject *PYM_error;
+
+extern int
+PYM_pyObjectToJsval(PYM_JSContextObject *context,
+                    PyObject *object,
+                    jsval *rval);
+
+extern PyObject *
+PYM_jsvalToPyObject(PYM_JSContextObject *context, jsval value);
+
+extern void
+PYM_pythonExceptionToJs(PYM_JSContextObject *context);
+
+void
+PYM_jsExceptionToPython(PYM_JSContextObject *context);
+
+#endif
--- a/test_pymonkey.py	Mon Aug 17 03:52:51 2009 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,575 +0,0 @@
-import sys
-import unittest
-import weakref
-import time
-import threading
-
-import pymonkey
-
-class PymonkeyTests(unittest.TestCase):
-    def _evaljs(self, code):
-        rt = pymonkey.Runtime()
-        cx = rt.new_context()
-        obj = cx.new_object()
-        cx.init_standard_classes(obj)
-        return cx.evaluate_script(obj, code, '<string>', 1)
-
-    def _evalJsWrappedPyFunc(self, func, code):
-        cx = pymonkey.Runtime().new_context()
-        obj = cx.new_object()
-        cx.init_standard_classes(obj)
-        jsfunc = cx.new_function(func, func.__name__)
-        cx.define_property(obj, func.__name__, jsfunc)
-        return cx.evaluate_script(obj, code, '<string>', 1)
-
-    def assertRaises(self, exctype, func, *args):
-        was_raised = False
-        try:
-            func(*args)
-        except exctype, e:
-            self.last_exception = e
-            was_raised = True
-        self.assertTrue(was_raised)
-
-    def testThreadSafetyExceptionIsRaised(self):
-        stuff = {}
-        def make_runtime():
-            stuff['rt'] = pymonkey.Runtime()
-        thread = threading.Thread(target = make_runtime)
-        thread.start()
-        thread.join()
-        self.assertRaises(pymonkey.error,
-                          stuff['rt'].new_context)
-        self.assertEqual(self.last_exception.args[0],
-                         'Function called from wrong thread')
-
-    def testClearObjectPrivateWorks(self):
-        class Foo(object):
-            pass
-        pyobj = Foo()
-        cx = pymonkey.Runtime().new_context()
-        obj = cx.new_object(pyobj)
-        pyobj = weakref.ref(pyobj)
-        self.assertEqual(pyobj(), cx.get_object_private(obj))
-        cx.clear_object_private(obj)
-        self.assertEqual(cx.get_object_private(obj), None)
-        self.assertEqual(pyobj(), None)
-
-    def testGetObjectPrivateWorks(self):
-        class Foo(object):
-            pass
-        pyobj = Foo()
-        cx = pymonkey.Runtime().new_context()
-        obj = cx.new_object(pyobj)
-        pyobj = weakref.ref(pyobj)
-        self.assertEqual(pyobj(), cx.get_object_private(obj))
-        del obj
-        del cx
-        self.assertEqual(pyobj(), None)
-
-    def testOperationCallbackIsCalled(self):
-        def opcb(cx):
-            raise Exception("stop eet!")
-
-        cx = pymonkey.Runtime().new_context()
-        cx.set_operation_callback(opcb)
-        obj = cx.new_object()
-        cx.init_standard_classes(obj)
-
-        def watchdog():
-            time.sleep(0.1)
-            cx.trigger_operation_callback()
-
-        thread = threading.Thread(target = watchdog)
-        thread.start()
-
-        self.assertRaises(
-            pymonkey.error,
-            cx.evaluate_script,
-            obj, 'while (1) {}', '<string>', 1
-            )
-
-    def testUndefinedStrIsUndefined(self):
-        self.assertEqual(str(pymonkey.undefined),
-                         "pymonkey.undefined")
-
-    def testJsWrappedPythonFuncHasPrivate(self):
-        def foo(cx, this, args):
-            pass
-
-        cx = pymonkey.Runtime().new_context()
-        jsfunc = cx.new_function(foo, foo.__name__)
-        self.assertEqual(cx.get_object_private(jsfunc), foo)
-
-    def testJsWrappedPythonFuncIsNotGCd(self):
-        def define(cx, obj):
-            def func(cx, this, args):
-                return u'func was called'
-            jsfunc = cx.new_function(func, func.__name__)
-            cx.define_property(obj, func.__name__, jsfunc)
-            return weakref.ref(func)
-        rt = pymonkey.Runtime()
-        cx = rt.new_context()
-        obj = cx.new_object()
-        cx.init_standard_classes(obj)
-        ref = define(cx, obj)
-        cx.gc()
-        self.assertNotEqual(ref(), None)
-        result = cx.evaluate_script(obj, 'func()', '<string>', 1)
-        self.assertEqual(result, u'func was called')
-
-        # Now ensure that the wrapped function is GC'd when it's
-        # no longer reachable from JS space.
-        cx.define_property(obj, 'func', 0)
-        cx.gc()
-        self.assertEqual(ref(), None)
-
-    def testCircularJsWrappedPythonFuncIsGCdIfPrivateCleared(self):
-        def define(cx, obj):
-            rt = cx.get_runtime()
-            def func(cx, this, args):
-                # Oh noes, a circular reference is born!
-                rt
-            jsfunc = cx.new_function(func, func.__name__)
-            cx.define_property(obj, func.__name__, jsfunc)
-            return (jsfunc, weakref.ref(func))
-        rt = pymonkey.Runtime()
-        cx = rt.new_context()
-        obj = cx.new_object()
-        cx.init_standard_classes(obj)
-        jsfunc, ref = define(cx, obj)
-
-        # This will break the circular reference.
-        cx.clear_object_private(jsfunc)
-
-        del jsfunc
-        del rt
-        del cx
-        del obj
-        self.assertEqual(ref(), None)
-
-    def testJsWrappedPythonFuncIsGCdAtRuntimeDestruction(self):
-        def define(cx, obj):
-            def func(cx, this, args):
-                return u'func was called'
-            jsfunc = cx.new_function(func, func.__name__)
-            cx.define_property(obj, func.__name__, jsfunc)
-            return weakref.ref(func)
-        rt = pymonkey.Runtime()
-        cx = rt.new_context()
-        obj = cx.new_object()
-        cx.init_standard_classes(obj)
-        ref = define(cx, obj)
-        del rt
-        del cx
-        del obj
-        self.assertEqual(ref(), None)
-
-    def testJsWrappedPythonFuncThrowsExcIfPrivateCleared(self):
-        def func(cx, this, args):
-            return True
-
-        code = "func()"
-        cx = pymonkey.Runtime().new_context()
-        obj = cx.new_object()
-        cx.init_standard_classes(obj)
-        jsfunc = cx.new_function(func, func.__name__)
-        cx.define_property(obj, func.__name__, jsfunc)
-        cx.clear_object_private(jsfunc)
-        self.assertRaises(pymonkey.error,
-                          cx.evaluate_script,
-                          obj, code, '<string>', 1)
-        self.assertEqual(
-            self._tostring(cx, self.last_exception.args[0]),
-            "Error: Wrapped Python function no longer exists"
-            )
-
-    def testJsWrappedPythonFuncPassesContext(self):
-        contexts = []
-
-        def func(cx, this, args):
-            contexts.append(cx)
-            return True
-
-        code = "func()"
-        cx = pymonkey.Runtime().new_context()
-        obj = cx.new_object()
-        cx.init_standard_classes(obj)
-        jsfunc = cx.new_function(func, func.__name__)
-        cx.define_property(obj, func.__name__, jsfunc)
-        cx.evaluate_script(obj, code, '<string>', 1)
-        self.assertEqual(contexts[0], cx)
-
-    def testJsWrappedPythonFuncPassesThisArg(self):
-        thisObjs = []
-
-        def func(cx, this, args):
-            thisObjs.append(this)
-            return True
-
-        code = "func()"
-        cx = pymonkey.Runtime().new_context()
-        obj = cx.new_object()
-        cx.init_standard_classes(obj)
-        jsfunc = cx.new_function(func, func.__name__)
-        cx.define_property(obj, func.__name__, jsfunc)
-        cx.evaluate_script(obj, code, '<string>', 1)
-        self.assertEqual(thisObjs[0], obj)
-
-    def testJsWrappedPythonFuncPassesFuncArgs(self):
-        funcArgs = []
-
-        def func(cx, this, args):
-            funcArgs.append(args)
-            return True
-
-        cx = pymonkey.Runtime().new_context()
-        obj = cx.new_object()
-        cx.init_standard_classes(obj)
-        jsfunc = cx.new_function(func, func.__name__)
-        cx.define_property(obj, func.__name__, jsfunc)
-
-        cx.evaluate_script(obj, "func()", '<string>', 1)
-        self.assertEqual(len(funcArgs[0]), 0)
-        self.assertTrue(isinstance(funcArgs[0], tuple))
-
-        cx.evaluate_script(obj, "func(1, 'foo')", '<string>', 1)
-        self.assertEqual(len(funcArgs[1]), 2)
-        self.assertEqual(funcArgs[1][0], 1)
-        self.assertEqual(funcArgs[1][1], u'foo')
-
-    def testJsWrappedPythonFunctionReturnsUnicodeWithEmbeddedNULs(self):
-        def hai2u(cx, this, args):
-            return args[0] + u"o hai"
-        self.assertEqual(self._evalJsWrappedPyFunc(hai2u,
-                                                   'hai2u("blah\x00 ")'),
-                         u"blah\x00 o hai")
-
-    def testJsWrappedPythonFunctionReturnsString(self):
-        def hai2u(cx, this, args):
-            return "o hai"
-        self.assertEqual(self._evalJsWrappedPyFunc(hai2u, 'hai2u()'),
-                         "o hai")
-
-    def testJsWrappedPythonFunctionReturnsUnicode(self):
-        def hai2u(cx, this, args):
-            return u"o hai\u2026"
-        self.assertEqual(self._evalJsWrappedPyFunc(hai2u, 'hai2u()'),
-                         u"o hai\u2026")
-
-    def testJsWrappedPythonFunctionThrowsJsException(self):
-        def hai2u(cx, this, args):
-            raise pymonkey.error(u"blarg")
-        self.assertRaises(pymonkey.error,
-                          self._evalJsWrappedPyFunc,
-                          hai2u, 'hai2u()')
-        self.assertEqual(self.last_exception.args[0], u"blarg")
-
-    def testJsWrappedPythonFunctionThrowsPyException(self):
-        thecx = []
-        def hai2u(cx, this, args):
-            thecx.append(cx)
-            raise Exception("hello")
-        self.assertRaises(pymonkey.error,
-                          self._evalJsWrappedPyFunc,
-                          hai2u, 'hai2u()')
-        exc = thecx[0].get_object_private(self.last_exception.args[0])
-        self.assertEqual(exc.args[0], "hello")
-
-    def testJsWrappedPythonFunctionReturnsNone(self):
-        def hai2u(cx, this, args):
-            pass
-        self.assertEqual(self._evalJsWrappedPyFunc(hai2u, 'hai2u()'),
-                         None)
-
-    def testJsWrappedPythonFunctionReturnsTrue(self):
-        def hai2u(cx, this, args):
-            return True
-        self.assertEqual(self._evalJsWrappedPyFunc(hai2u, 'hai2u()'),
-                         True)
-
-    def testJsWrappedPythonFunctionReturnsFalse(self):
-        def hai2u(cx, this, args):
-            return False
-        self.assertEqual(self._evalJsWrappedPyFunc(hai2u, 'hai2u()'),
-                         False)
-
-    def testJsWrappedPythonFunctionReturnsSmallInt(self):
-        def hai2u(cx, this, args):
-            return 5
-        self.assertEqual(self._evalJsWrappedPyFunc(hai2u, 'hai2u()'),
-                         5)
-
-    def testJsWrappedPythonFunctionReturnsFloat(self):
-        def hai2u(cx, this, args):
-            return 5.1
-        self.assertEqual(self._evalJsWrappedPyFunc(hai2u, 'hai2u()'),
-                         5.1)
-
-    def testJsWrappedPythonFunctionReturnsNegativeInt(self):
-        def hai2u(cx, this, args):
-            return -5
-        self.assertEqual(self._evalJsWrappedPyFunc(hai2u, 'hai2u()'),
-                         -5)
-
-    def testJsWrappedPythonFunctionReturnsBigInt(self):
-        def hai2u(cx, this, args):
-            return 2147483647
-        self.assertEqual(self._evalJsWrappedPyFunc(hai2u, 'hai2u()'),
-                         2147483647)
-
-    def testDefinePropertyWorksWithUnicodePropertyNames(self):
-        cx = pymonkey.Runtime().new_context()
-        obj = cx.new_object()
-        cx.init_standard_classes(obj)
-        foo = cx.new_object()
-        cx.define_property(obj, u"foo\u2026", foo)
-        self.assertEqual(
-            cx.get_property(obj, u"foo\u2026"),
-            foo
-            )
-
-    def testDefinePropertyWorksWithObject(self):
-        cx = pymonkey.Runtime().new_context()
-        obj = cx.new_object()
-        cx.init_standard_classes(obj)
-        foo = cx.new_object()
-        cx.define_property(obj, "foo", foo)
-        self.assertEqual(
-            cx.evaluate_script(obj, 'foo', '<string>', 1),
-            foo
-            )
-
-    def testDefinePropertyWorksWithString(self):
-        cx = pymonkey.Runtime().new_context()
-        obj = cx.new_object()
-        cx.init_standard_classes(obj)
-        foo = cx.new_object()
-        cx.define_property(obj, "foo", u"hello")
-        self.assertEqual(
-            cx.evaluate_script(obj, 'foo', '<string>', 1),
-            u"hello"
-            )
-
-    def testObjectIsIdentityPreserving(self):
-        cx = pymonkey.Runtime().new_context()
-        obj = cx.new_object()
-        cx.init_standard_classes(obj)
-        cx.evaluate_script(obj, 'var foo = {bar: 1}', '<string>', 1)
-        self.assertTrue(isinstance(cx.get_property(obj, u"foo"),
-                                   pymonkey.Object))
-        self.assertTrue(cx.get_property(obj, u"foo") is
-                        cx.get_property(obj, "foo"))
-
-    def testObjectGetattrThrowsException(self):
-        cx = pymonkey.Runtime().new_context()
-        obj = cx.new_object()
-        cx.init_standard_classes(obj)
-        result = cx.evaluate_script(obj, '({get foo() { throw "blah"; }})',
-                                    '<string>', 1)
-        self.assertRaises(pymonkey.error,
-                          cx.get_property,
-                          result,
-                          u"foo")
-        self.assertEqual(self.last_exception.args[0], u"blah")
-
-    def testInfiniteRecursionRaisesError(self):
-        cx = pymonkey.Runtime().new_context()
-        obj = cx.new_object()
-        cx.init_standard_classes(obj)
-        self.assertRaises(
-            pymonkey.error,
-            cx.evaluate_script,
-            obj, '(function foo() { foo(); })();', '<string>', 1
-            )
-        self.assertEqual(
-            self._tostring(cx, self.last_exception.args[0]),
-            "InternalError: too much recursion"
-            )
-
-    def testObjectGetattrWorks(self):
-        cx = pymonkey.Runtime().new_context()
-        obj = cx.new_object()
-        cx.init_standard_classes(obj)
-        cx.evaluate_script(obj, 'var boop = 5', '<string>', 1)
-        cx.evaluate_script(obj, 'this["blarg\u2026"] = 5', '<string>', 1)
-        self.assertEqual(cx.get_property(obj, u"beans"),
-                         pymonkey.undefined)
-        self.assertEqual(cx.get_property(obj, u"blarg\u2026"), 5)
-        self.assertEqual(cx.get_property(obj, u"boop"), 5)
-
-    def testContextIsInstance(self):
-        cx = pymonkey.Runtime().new_context()
-        self.assertTrue(isinstance(cx, pymonkey.Context))
-
-    def testContextTypeCannotBeInstantiated(self):
-        self.assertRaises(TypeError, pymonkey.Context)
-
-    def testObjectIsInstance(self):
-        obj = pymonkey.Runtime().new_context().new_object()
-        self.assertTrue(isinstance(obj, pymonkey.Object))
-        self.assertFalse(isinstance(obj, pymonkey.Function))
-
-    def testObjectTypeCannotBeInstantiated(self):
-        self.assertRaises(TypeError, pymonkey.Object)
-
-    def testFunctionIsInstance(self):
-        def boop():
-            pass
-        obj = pymonkey.Runtime().new_context().new_function(boop, "boop")
-        self.assertTrue(isinstance(obj, pymonkey.Object))
-        self.assertTrue(isinstance(obj, pymonkey.Function))
-
-    def testFunctionTypeCannotBeInstantiated(self):
-        self.assertRaises(TypeError, pymonkey.Function)
-
-    def testObjectGetRuntimeWorks(self):
-        rt = pymonkey.Runtime()
-        obj = rt.new_context().new_object()
-        self.assertEqual(obj.get_runtime(), rt)
-
-    def testContextGetRuntimeWorks(self):
-        rt = pymonkey.Runtime()
-        cx = rt.new_context()
-        self.assertEqual(cx.get_runtime(), rt)
-
-    def testUndefinedCannotBeInstantiated(self):
-        self.assertRaises(TypeError, pymonkey.undefined)
-
-    def testEvaluateThrowsException(self):
-        cx = pymonkey.Runtime().new_context()
-        obj = cx.new_object()
-        self.assertRaises(pymonkey.error,
-                          cx.evaluate_script,
-                          obj, 'hai2u()', '<string>', 1)
-        self.assertEqual(self._tostring(cx,
-                                        self.last_exception.args[0]),
-                         'ReferenceError: hai2u is not defined')
-
-    def testEvaluateReturnsUndefined(self):
-        retval = self._evaljs("")
-        self.assertTrue(retval is pymonkey.undefined)
-
-    def testEvaludateReturnsUnicodeWithEmbeddedNULs(self):
-        retval = self._evaljs("'\x00hi'")
-        self.assertEqual(retval, u'\x00hi')
-
-    def testEvaluateReturnsSMPUnicode(self):
-        # This is 'LINEAR B SYLLABLE B008 A', in the supplementary
-        # multilingual plane (SMP).
-        retval = self._evaljs("'\uD800\uDC00'")
-        self.assertEqual(retval, u'\U00010000')
-        self.assertEqual(retval.encode('utf-16'),
-                         '\xff\xfe\x00\xd8\x00\xdc')
-
-    def testEvaluateReturnsBMPUnicode(self):
-        retval = self._evaljs("'o hai\u2026'")
-        self.assertTrue(type(retval) == unicode)
-        self.assertEqual(retval, u'o hai\u2026')
-
-    def testEvaluateReturnsObject(self):
-        cx = pymonkey.Runtime().new_context()
-        obj = cx.new_object()
-        cx.init_standard_classes(obj)
-        obj = cx.evaluate_script(obj, '({boop: 1})', '<string>', 1)
-        self.assertTrue(isinstance(obj, pymonkey.Object))
-        self.assertEqual(cx.get_property(obj, u"boop"), 1)
-
-    def testEvaluateReturnsFunction(self):
-        cx = pymonkey.Runtime().new_context()
-        obj = cx.new_object()
-        cx.init_standard_classes(obj)
-        obj = cx.evaluate_script(obj, '(function boop() { return 1; })',
-                                 '<string>', 1)
-        self.assertTrue(isinstance(obj, pymonkey.Function))
-
-    def testJsExceptionStateIsClearedAfterExceptionIsCaught(self):
-        cx = pymonkey.Runtime().new_context()
-        obj = cx.new_object()
-        self.assertRaises(pymonkey.error,
-                          cx.evaluate_script,
-                          obj, 'blah()', '<string>', 1)
-        self.assertEqual(cx.evaluate_script(obj, '5+3', '<string>', 1),
-                         8)
-
-    def testCallFunctionRaisesErrorOnBadFuncArgs(self):
-        cx = pymonkey.Runtime().new_context()
-        obj = cx.new_object()
-        obj = cx.evaluate_script(
-            obj,
-            '(function boop(a, b) { return a+b+this.c; })',
-            '<string>', 1
-            )
-        self.assertRaises(
-            NotImplementedError,
-            cx.call_function,
-            obj, obj, (1, self)
-            )
-
-    def _tostring(self, cx, obj):
-        return cx.call_function(obj,
-                                cx.get_property(obj, u"toString"),
-                                ())
-
-    def testCallFunctionRaisesErrorFromJS(self):
-        cx = pymonkey.Runtime().new_context()
-        obj = cx.new_object()
-        obj = cx.evaluate_script(
-            obj,
-            '(function boop(a, b) { blarg(); })',
-            '<string>', 1
-            )
-        self.assertRaises(pymonkey.error,
-                          cx.call_function,
-                          obj, obj, (1,))
-        self.assertEqual(self._tostring(cx,
-                                        self.last_exception.args[0]),
-                         'ReferenceError: blarg is not defined')
-
-    def testInitStandardClassesRaisesExcOnRuntimeMismatch(self):
-        cx2 = pymonkey.Runtime().new_context()
-        cx = pymonkey.Runtime().new_context()
-        obj = cx.new_object()
-        self.assertRaises(ValueError,
-                          cx2.init_standard_classes,
-                          obj)
-        self.assertEqual(self.last_exception.args[0],
-                         'JS runtime mismatch')
-
-    def testCallFunctionWorks(self):
-        cx = pymonkey.Runtime().new_context()
-        obj = cx.new_object()
-        thisArg = cx.new_object()
-        cx.define_property(thisArg, "c", 3)
-        cx.init_standard_classes(obj)
-        obj = cx.evaluate_script(
-            obj,
-            '(function boop(a, b) { return a+b+this.c; })',
-            '<string>', 1
-            )
-        self.assertEqual(cx.call_function(thisArg, obj, (1,2)), 6)
-
-    def testEvaluateReturnsTrue(self):
-        self.assertTrue(self._evaljs('true') is True)
-
-    def testEvaluateReturnsFalse(self):
-        self.assertTrue(self._evaljs('false') is False)
-
-    def testEvaluateReturnsNone(self):
-        self.assertTrue(self._evaljs('null') is None)
-
-    def testEvaluateReturnsIntegers(self):
-        self.assertEqual(self._evaljs('1+3'), 4)
-
-    def testEvaluateReturnsNegativeIntegers(self):
-        self.assertEqual(self._evaljs('-5'), -5)
-
-    def testEvaluateReturnsBigIntegers(self):
-        self.assertEqual(self._evaljs('2147483647*2'),
-                         2147483647*2)
-
-    def testEvaluateReturnsFloats(self):
-        self.assertEqual(self._evaljs('1.1+3'), 4.1)
-
-if __name__ == '__main__':
-    unittest.main()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test_pymonkey.py	Mon Aug 17 22:08:33 2009 -0700
@@ -0,0 +1,575 @@
+import sys
+import unittest
+import weakref
+import time
+import threading
+
+import pymonkey
+
+class PymonkeyTests(unittest.TestCase):
+    def _evaljs(self, code):
+        rt = pymonkey.Runtime()
+        cx = rt.new_context()
+        obj = cx.new_object()
+        cx.init_standard_classes(obj)
+        return cx.evaluate_script(obj, code, '<string>', 1)
+
+    def _evalJsWrappedPyFunc(self, func, code):
+        cx = pymonkey.Runtime().new_context()
+        obj = cx.new_object()
+        cx.init_standard_classes(obj)
+        jsfunc = cx.new_function(func, func.__name__)
+        cx.define_property(obj, func.__name__, jsfunc)
+        return cx.evaluate_script(obj, code, '<string>', 1)
+
+    def assertRaises(self, exctype, func, *args):
+        was_raised = False
+        try:
+            func(*args)
+        except exctype, e:
+            self.last_exception = e
+            was_raised = True
+        self.assertTrue(was_raised)
+
+    def testThreadSafetyExceptionIsRaised(self):
+        stuff = {}
+        def make_runtime():
+            stuff['rt'] = pymonkey.Runtime()
+        thread = threading.Thread(target = make_runtime)
+        thread.start()
+        thread.join()
+        self.assertRaises(pymonkey.error,
+                          stuff['rt'].new_context)
+        self.assertEqual(self.last_exception.args[0],
+                         'Function called from wrong thread')
+
+    def testClearObjectPrivateWorks(self):
+        class Foo(object):
+            pass
+        pyobj = Foo()
+        cx = pymonkey.Runtime().new_context()
+        obj = cx.new_object(pyobj)
+        pyobj = weakref.ref(pyobj)
+        self.assertEqual(pyobj(), cx.get_object_private(obj))
+        cx.clear_object_private(obj)
+        self.assertEqual(cx.get_object_private(obj), None)
+        self.assertEqual(pyobj(), None)
+
+    def testGetObjectPrivateWorks(self):
+        class Foo(object):
+            pass
+        pyobj = Foo()
+        cx = pymonkey.Runtime().new_context()
+        obj = cx.new_object(pyobj)
+        pyobj = weakref.ref(pyobj)
+        self.assertEqual(pyobj(), cx.get_object_private(obj))
+        del obj
+        del cx
+        self.assertEqual(pyobj(), None)
+
+    def testOperationCallbackIsCalled(self):
+        def opcb(cx):
+            raise Exception("stop eet!")
+
+        cx = pymonkey.Runtime().new_context()
+        cx.set_operation_callback(opcb)
+        obj = cx.new_object()
+        cx.init_standard_classes(obj)
+
+        def watchdog():
+            time.sleep(0.1)
+            cx.trigger_operation_callback()
+
+        thread = threading.Thread(target = watchdog)
+        thread.start()
+
+        self.assertRaises(
+            pymonkey.error,
+            cx.evaluate_script,
+            obj, 'while (1) {}', '<string>', 1
+            )
+
+    def testUndefinedStrIsUndefined(self):
+        self.assertEqual(str(pymonkey.undefined),
+                         "pymonkey.undefined")
+
+    def testJsWrappedPythonFuncHasPrivate(self):
+        def foo(cx, this, args):
+            pass
+
+        cx = pymonkey.Runtime().new_context()
+        jsfunc = cx.new_function(foo, foo.__name__)
+        self.assertEqual(cx.get_object_private(jsfunc), foo)
+
+    def testJsWrappedPythonFuncIsNotGCd(self):
+        def define(cx, obj):
+            def func(cx, this, args):
+                return u'func was called'
+            jsfunc = cx.new_function(func, func.__name__)
+            cx.define_property(obj, func.__name__, jsfunc)
+            return weakref.ref(func)
+        rt = pymonkey.Runtime()
+        cx = rt.new_context()
+        obj = cx.new_object()
+        cx.init_standard_classes(obj)
+        ref = define(cx, obj)
+        cx.gc()
+        self.assertNotEqual(ref(), None)
+        result = cx.evaluate_script(obj, 'func()', '<string>', 1)
+        self.assertEqual(result, u'func was called')
+
+        # Now ensure that the wrapped function is GC'd when it's
+        # no longer reachable from JS space.
+        cx.define_property(obj, 'func', 0)
+        cx.gc()
+        self.assertEqual(ref(), None)
+
+    def testCircularJsWrappedPythonFuncIsGCdIfPrivateCleared(self):
+        def define(cx, obj):
+            rt = cx.get_runtime()
+            def func(cx, this, args):
+                # Oh noes, a circular reference is born!
+                rt
+            jsfunc = cx.new_function(func, func.__name__)
+            cx.define_property(obj, func.__name__, jsfunc)
+            return (jsfunc, weakref.ref(func))
+        rt = pymonkey.Runtime()
+        cx = rt.new_context()
+        obj = cx.new_object()
+        cx.init_standard_classes(obj)
+        jsfunc, ref = define(cx, obj)
+
+        # This will break the circular reference.
+        cx.clear_object_private(jsfunc)
+
+        del jsfunc
+        del rt
+        del cx
+        del obj
+        self.assertEqual(ref(), None)
+
+    def testJsWrappedPythonFuncIsGCdAtRuntimeDestruction(self):
+        def define(cx, obj):
+            def func(cx, this, args):
+                return u'func was called'
+            jsfunc = cx.new_function(func, func.__name__)
+            cx.define_property(obj, func.__name__, jsfunc)
+            return weakref.ref(func)
+        rt = pymonkey.Runtime()
+        cx = rt.new_context()
+        obj = cx.new_object()
+        cx.init_standard_classes(obj)
+        ref = define(cx, obj)
+        del rt
+        del cx
+        del obj
+        self.assertEqual(ref(), None)
+
+    def testJsWrappedPythonFuncThrowsExcIfPrivateCleared(self):
+        def func(cx, this, args):
+            return True
+
+        code = "func()"
+        cx = pymonkey.Runtime().new_context()
+        obj = cx.new_object()
+        cx.init_standard_classes(obj)
+        jsfunc = cx.new_function(func, func.__name__)
+        cx.define_property(obj, func.__name__, jsfunc)
+        cx.clear_object_private(jsfunc)
+        self.assertRaises(pymonkey.error,
+                          cx.evaluate_script,
+                          obj, code, '<string>', 1)
+        self.assertEqual(
+            self._tostring(cx, self.last_exception.args[0]),
+            "Error: Wrapped Python function no longer exists"
+            )
+
+    def testJsWrappedPythonFuncPassesContext(self):
+        contexts = []
+
+        def func(cx, this, args):
+            contexts.append(cx)
+            return True
+
+        code = "func()"
+        cx = pymonkey.Runtime().new_context()
+        obj = cx.new_object()
+        cx.init_standard_classes(obj)
+        jsfunc = cx.new_function(func, func.__name__)
+        cx.define_property(obj, func.__name__, jsfunc)
+        cx.evaluate_script(obj, code, '<string>', 1)
+        self.assertEqual(contexts[0], cx)
+
+    def testJsWrappedPythonFuncPassesThisArg(self):
+        thisObjs = []
+
+        def func(cx, this, args):
+            thisObjs.append(this)
+            return True
+
+        code = "func()"
+        cx = pymonkey.Runtime().new_context()
+        obj = cx.new_object()
+        cx.init_standard_classes(obj)
+        jsfunc = cx.new_function(func, func.__name__)
+        cx.define_property(obj, func.__name__, jsfunc)
+        cx.evaluate_script(obj, code, '<string>', 1)
+        self.assertEqual(thisObjs[0], obj)
+
+    def testJsWrappedPythonFuncPassesFuncArgs(self):
+        funcArgs = []
+
+        def func(cx, this, args):
+            funcArgs.append(args)
+            return True
+
+        cx = pymonkey.Runtime().new_context()
+        obj = cx.new_object()
+        cx.init_standard_classes(obj)
+        jsfunc = cx.new_function(func, func.__name__)
+        cx.define_property(obj, func.__name__, jsfunc)
+
+        cx.evaluate_script(obj, "func()", '<string>', 1)
+        self.assertEqual(len(funcArgs[0]), 0)
+        self.assertTrue(isinstance(funcArgs[0], tuple))
+
+        cx.evaluate_script(obj, "func(1, 'foo')", '<string>', 1)
+        self.assertEqual(len(funcArgs[1]), 2)
+        self.assertEqual(funcArgs[1][0], 1)
+        self.assertEqual(funcArgs[1][1], u'foo')
+
+    def testJsWrappedPythonFunctionReturnsUnicodeWithEmbeddedNULs(self):
+        def hai2u(cx, this, args):
+            return args[0] + u"o hai"
+        self.assertEqual(self._evalJsWrappedPyFunc(hai2u,
+                                                   'hai2u("blah\x00 ")'),
+                         u"blah\x00 o hai")
+
+    def testJsWrappedPythonFunctionReturnsString(self):
+        def hai2u(cx, this, args):
+            return "o hai"
+        self.assertEqual(self._evalJsWrappedPyFunc(hai2u, 'hai2u()'),
+                         "o hai")
+
+    def testJsWrappedPythonFunctionReturnsUnicode(self):
+        def hai2u(cx, this, args):
+            return u"o hai\u2026"
+        self.assertEqual(self._evalJsWrappedPyFunc(hai2u, 'hai2u()'),
+                         u"o hai\u2026")
+
+    def testJsWrappedPythonFunctionThrowsJsException(self):
+        def hai2u(cx, this, args):
+            raise pymonkey.error(u"blarg")
+        self.assertRaises(pymonkey.error,
+                          self._evalJsWrappedPyFunc,
+                          hai2u, 'hai2u()')
+        self.assertEqual(self.last_exception.args[0], u"blarg")
+
+    def testJsWrappedPythonFunctionThrowsPyException(self):
+        thecx = []
+        def hai2u(cx, this, args):
+            thecx.append(cx)
+            raise Exception("hello")
+        self.assertRaises(pymonkey.error,
+                          self._evalJsWrappedPyFunc,
+                          hai2u, 'hai2u()')
+        exc = thecx[0].get_object_private(self.last_exception.args[0])
+        self.assertEqual(exc.args[0], "hello")
+
+    def testJsWrappedPythonFunctionReturnsNone(self):
+        def hai2u(cx, this, args):
+            pass
+        self.assertEqual(self._evalJsWrappedPyFunc(hai2u, 'hai2u()'),
+                         None)
+
+    def testJsWrappedPythonFunctionReturnsTrue(self):
+        def hai2u(cx, this, args):
+            return True
+        self.assertEqual(self._evalJsWrappedPyFunc(hai2u, 'hai2u()'),
+                         True)
+
+    def testJsWrappedPythonFunctionReturnsFalse(self):
+        def hai2u(cx, this, args):
+            return False
+        self.assertEqual(self._evalJsWrappedPyFunc(hai2u, 'hai2u()'),
+                         False)
+
+    def testJsWrappedPythonFunctionReturnsSmallInt(self):
+        def hai2u(cx, this, args):
+            return 5
+        self.assertEqual(self._evalJsWrappedPyFunc(hai2u, 'hai2u()'),
+                         5)
+
+    def testJsWrappedPythonFunctionReturnsFloat(self):
+        def hai2u(cx, this, args):
+            return 5.1
+        self.assertEqual(self._evalJsWrappedPyFunc(hai2u, 'hai2u()'),
+                         5.1)
+
+    def testJsWrappedPythonFunctionReturnsNegativeInt(self):
+        def hai2u(cx, this, args):
+            return -5
+        self.assertEqual(self._evalJsWrappedPyFunc(hai2u, 'hai2u()'),
+                         -5)
+
+    def testJsWrappedPythonFunctionReturnsBigInt(self):
+        def hai2u(cx, this, args):
+            return 2147483647
+        self.assertEqual(self._evalJsWrappedPyFunc(hai2u, 'hai2u()'),
+                         2147483647)
+
+    def testDefinePropertyWorksWithUnicodePropertyNames(self):
+        cx = pymonkey.Runtime().new_context()
+        obj = cx.new_object()
+        cx.init_standard_classes(obj)
+        foo = cx.new_object()
+        cx.define_property(obj, u"foo\u2026", foo)
+        self.assertEqual(
+            cx.get_property(obj, u"foo\u2026"),
+            foo
+            )
+
+    def testDefinePropertyWorksWithObject(self):
+        cx = pymonkey.Runtime().new_context()
+        obj = cx.new_object()
+        cx.init_standard_classes(obj)
+        foo = cx.new_object()
+        cx.define_property(obj, "foo", foo)
+        self.assertEqual(
+            cx.evaluate_script(obj, 'foo', '<string>', 1),
+            foo
+            )
+
+    def testDefinePropertyWorksWithString(self):
+        cx = pymonkey.Runtime().new_context()
+        obj = cx.new_object()
+        cx.init_standard_classes(obj)
+        foo = cx.new_object()
+        cx.define_property(obj, "foo", u"hello")
+        self.assertEqual(
+            cx.evaluate_script(obj, 'foo', '<string>', 1),
+            u"hello"
+            )
+
+    def testObjectIsIdentityPreserving(self):
+        cx = pymonkey.Runtime().new_context()
+        obj = cx.new_object()
+        cx.init_standard_classes(obj)
+        cx.evaluate_script(obj, 'var foo = {bar: 1}', '<string>', 1)
+        self.assertTrue(isinstance(cx.get_property(obj, u"foo"),
+                                   pymonkey.Object))
+        self.assertTrue(cx.get_property(obj, u"foo") is
+                        cx.get_property(obj, "foo"))
+
+    def testObjectGetattrThrowsException(self):
+        cx = pymonkey.Runtime().new_context()
+        obj = cx.new_object()
+        cx.init_standard_classes(obj)
+        result = cx.evaluate_script(obj, '({get foo() { throw "blah"; }})',
+                                    '<string>', 1)
+        self.assertRaises(pymonkey.error,
+                          cx.get_property,
+                          result,
+                          u"foo")
+        self.assertEqual(self.last_exception.args[0], u"blah")
+
+    def testInfiniteRecursionRaisesError(self):
+        cx = pymonkey.Runtime().new_context()
+        obj = cx.new_object()
+        cx.init_standard_classes(obj)
+        self.assertRaises(
+            pymonkey.error,
+            cx.evaluate_script,
+            obj, '(function foo() { foo(); })();', '<string>', 1
+            )
+        self.assertEqual(
+            self._tostring(cx, self.last_exception.args[0]),
+            "InternalError: too much recursion"
+            )
+
+    def testObjectGetattrWorks(self):
+        cx = pymonkey.Runtime().new_context()
+        obj = cx.new_object()
+        cx.init_standard_classes(obj)
+        cx.evaluate_script(obj, 'var boop = 5', '<string>', 1)
+        cx.evaluate_script(obj, 'this["blarg\u2026"] = 5', '<string>', 1)
+        self.assertEqual(cx.get_property(obj, u"beans"),
+                         pymonkey.undefined)
+        self.assertEqual(cx.get_property(obj, u"blarg\u2026"), 5)
+        self.assertEqual(cx.get_property(obj, u"boop"), 5)
+
+    def testContextIsInstance(self):
+        cx = pymonkey.Runtime().new_context()
+        self.assertTrue(isinstance(cx, pymonkey.Context))
+
+    def testContextTypeCannotBeInstantiated(self):
+        self.assertRaises(TypeError, pymonkey.Context)
+
+    def testObjectIsInstance(self):
+        obj = pymonkey.Runtime().new_context().new_object()
+        self.assertTrue(isinstance(obj, pymonkey.Object))
+        self.assertFalse(isinstance(obj, pymonkey.Function))
+
+    def testObjectTypeCannotBeInstantiated(self):
+        self.assertRaises(TypeError, pymonkey.Object)
+
+    def testFunctionIsInstance(self):
+        def boop():
+            pass
+        obj = pymonkey.Runtime().new_context().new_function(boop, "boop")
+        self.assertTrue(isinstance(obj, pymonkey.Object))
+        self.assertTrue(isinstance(obj, pymonkey.Function))
+
+    def testFunctionTypeCannotBeInstantiated(self):
+        self.assertRaises(TypeError, pymonkey.Function)
+
+    def testObjectGetRuntimeWorks(self):
+        rt = pymonkey.Runtime()
+        obj = rt.new_context().new_object()
+        self.assertEqual(obj.get_runtime(), rt)
+
+    def testContextGetRuntimeWorks(self):
+        rt = pymonkey.Runtime()
+        cx = rt.new_context()
+        self.assertEqual(cx.get_runtime(), rt)
+
+    def testUndefinedCannotBeInstantiated(self):
+        self.assertRaises(TypeError, pymonkey.undefined)
+
+    def testEvaluateThrowsException(self):
+        cx = pymonkey.Runtime().new_context()
+        obj = cx.new_object()
+        self.assertRaises(pymonkey.error,
+                          cx.evaluate_script,
+                          obj, 'hai2u()', '<string>', 1)
+        self.assertEqual(self._tostring(cx,
+                                        self.last_exception.args[0]),
+                         'ReferenceError: hai2u is not defined')
+
+    def testEvaluateReturnsUndefined(self):
+        retval = self._evaljs("")
+        self.assertTrue(retval is pymonkey.undefined)
+
+    def testEvaludateReturnsUnicodeWithEmbeddedNULs(self):
+        retval = self._evaljs("'\x00hi'")
+        self.assertEqual(retval, u'\x00hi')
+
+    def testEvaluateReturnsSMPUnicode(self):
+        # This is 'LINEAR B SYLLABLE B008 A', in the supplementary
+        # multilingual plane (SMP).
+        retval = self._evaljs("'\uD800\uDC00'")
+        self.assertEqual(retval, u'\U00010000')
+        self.assertEqual(retval.encode('utf-16'),
+                         '\xff\xfe\x00\xd8\x00\xdc')
+
+    def testEvaluateReturnsBMPUnicode(self):
+        retval = self._evaljs("'o hai\u2026'")
+        self.assertTrue(type(retval) == unicode)
+        self.assertEqual(retval, u'o hai\u2026')
+
+    def testEvaluateReturnsObject(self):
+        cx = pymonkey.Runtime().new_context()
+        obj = cx.new_object()
+        cx.init_standard_classes(obj)
+        obj = cx.evaluate_script(obj, '({boop: 1})', '<string>', 1)
+        self.assertTrue(isinstance(obj, pymonkey.Object))
+        self.assertEqual(cx.get_property(obj, u"boop"), 1)
+
+    def testEvaluateReturnsFunction(self):
+        cx = pymonkey.Runtime().new_context()
+        obj = cx.new_object()
+        cx.init_standard_classes(obj)
+        obj = cx.evaluate_script(obj, '(function boop() { return 1; })',
+                                 '<string>', 1)
+        self.assertTrue(isinstance(obj, pymonkey.Function))
+
+    def testJsExceptionStateIsClearedAfterExceptionIsCaught(self):
+        cx = pymonkey.Runtime().new_context()
+        obj = cx.new_object()
+        self.assertRaises(pymonkey.error,
+                          cx.evaluate_script,
+                          obj, 'blah()', '<string>', 1)
+        self.assertEqual(cx.evaluate_script(obj, '5+3', '<string>', 1),
+                         8)
+
+    def testCallFunctionRaisesErrorOnBadFuncArgs(self):
+        cx = pymonkey.Runtime().new_context()
+        obj = cx.new_object()
+        obj = cx.evaluate_script(
+            obj,
+            '(function boop(a, b) { return a+b+this.c; })',
+            '<string>', 1
+            )
+        self.assertRaises(
+            NotImplementedError,
+            cx.call_function,
+            obj, obj, (1, self)
+            )
+
+    def _tostring(self, cx, obj):
+        return cx.call_function(obj,
+                                cx.get_property(obj, u"toString"),
+                                ())
+
+    def testCallFunctionRaisesErrorFromJS(self):
+        cx = pymonkey.Runtime().new_context()
+        obj = cx.new_object()
+        obj = cx.evaluate_script(
+            obj,
+            '(function boop(a, b) { blarg(); })',
+            '<string>', 1
+            )
+        self.assertRaises(pymonkey.error,
+                          cx.call_function,
+                          obj, obj, (1,))
+        self.assertEqual(self._tostring(cx,
+                                        self.last_exception.args[0]),
+                         'ReferenceError: blarg is not defined')
+
+    def testInitStandardClassesRaisesExcOnRuntimeMismatch(self):
+        cx2 = pymonkey.Runtime().new_context()
+        cx = pymonkey.Runtime().new_context()
+        obj = cx.new_object()
+        self.assertRaises(ValueError,
+                          cx2.init_standard_classes,
+                          obj)
+        self.assertEqual(self.last_exception.args[0],
+                         'JS runtime mismatch')
+
+    def testCallFunctionWorks(self):
+        cx = pymonkey.Runtime().new_context()
+        obj = cx.new_object()
+        thisArg = cx.new_object()
+        cx.define_property(thisArg, "c", 3)
+        cx.init_standard_classes(obj)
+        obj = cx.evaluate_script(
+            obj,
+            '(function boop(a, b) { return a+b+this.c; })',
+            '<string>', 1
+            )
+        self.assertEqual(cx.call_function(thisArg, obj, (1,2)), 6)
+
+    def testEvaluateReturnsTrue(self):
+        self.assertTrue(self._evaljs('true') is True)
+
+    def testEvaluateReturnsFalse(self):
+        self.assertTrue(self._evaljs('false') is False)
+
+    def testEvaluateReturnsNone(self):
+        self.assertTrue(self._evaljs('null') is None)
+
+    def testEvaluateReturnsIntegers(self):
+        self.assertEqual(self._evaljs('1+3'), 4)
+
+    def testEvaluateReturnsNegativeIntegers(self):
+        self.assertEqual(self._evaljs('-5'), -5)
+
+    def testEvaluateReturnsBigIntegers(self):
+        self.assertEqual(self._evaljs('2147483647*2'),
+                         2147483647*2)
+
+    def testEvaluateReturnsFloats(self):
+        self.assertEqual(self._evaljs('1.1+3'), 4.1)
+
+if __name__ == '__main__':
+    unittest.main()
--- a/undefined.cpp	Mon Aug 17 03:52:51 2009 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,82 +0,0 @@
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is Pymonkey.
- *
- * The Initial Developer of the Original Code is Mozilla.
- * Portions created by the Initial Developer are Copyright (C) 2007
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *   Atul Varma <atul@mozilla.com>
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-#include "undefined.h"
-
-static Py_ssize_t PYM_undefinedLength(PyObject *o) {
-  return 0;
-};
-
-static PyMappingMethods PYM_undefinedAsMapping = {
-  PYM_undefinedLength,         /*mp_length*/
-  0,                           /*mp_subscript*/
-  0                            /*mp_ass_subscript*/
-};
-
-static PyObject *PYM_undefinedRepr(PyObject *o) {
-  return PyString_FromString("pymonkey.undefined");
-}
-
-// TODO: We should make this behave as much like JavaScript's
-// "undefined" value as possible; e.g., its string value should
-// be "undefined", the singleton should be falsy, etc.
-PyTypeObject PYM_undefinedType = {
-  PyObject_HEAD_INIT(NULL)
-  0,                           /*ob_size*/
-  "pymonkey.undefined",        /*tp_name*/
-  sizeof(PYM_undefinedObject), /*tp_basicsize*/
-  0,                           /*tp_itemsize*/
-  0,                           /*tp_dealloc*/
-  0,                           /*tp_print*/
-  0,                           /*tp_getattr*/
-  0,                           /*tp_setattr*/
-  0,                           /*tp_compare*/
-  PYM_undefinedRepr,           /*tp_repr*/
-  0,                           /*tp_as_number*/
-  0,                           /*tp_as_sequence*/
-  &PYM_undefinedAsMapping,     /*tp_as_mapping*/
-  0,                           /*tp_hash */
-  0,                           /*tp_call*/
-  PYM_undefinedRepr,           /*tp_str*/
-  0,                           /*tp_getattro*/
-  0,                           /*tp_setattro*/
-  0,                           /*tp_as_buffer*/
-  Py_TPFLAGS_DEFAULT,          /*tp_flags*/
-  /* tp_doc */
-  "Pythonic equivalent of JavaScript's 'undefined' value",
-};
-
-PYM_undefinedObject *PYM_undefined;
--- a/undefined.h	Mon Aug 17 03:52:51 2009 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,53 +0,0 @@
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is Pymonkey.
- *
- * The Initial Developer of the Original Code is Mozilla.
- * Portions created by the Initial Developer are Copyright (C) 2007
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *   Atul Varma <atul@mozilla.com>
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-#ifndef PYM_UNDEFINED_H
-#define PYM_UNDEFINED_H
-
-#include <Python.h>
-
-#define Py_RETURN_UNDEFINED  { Py_INCREF(PYM_undefined);        \
-                               return (PyObject *) PYM_undefined; }
-
-typedef struct {
-  PyObject_HEAD
-} PYM_undefinedObject;
-
-extern PyTypeObject PYM_undefinedType;
-
-extern PYM_undefinedObject *PYM_undefined;
-
-#endif
--- a/utils.cpp	Mon Aug 17 03:52:51 2009 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,257 +0,0 @@
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is Pymonkey.
- *
- * The Initial Developer of the Original Code is Mozilla.
- * Portions created by the Initial Developer are Copyright (C) 2007
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *   Atul Varma <atul@mozilla.com>
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-#include "utils.h"
-#include "undefined.h"
-#include "object.h"
-
-PyObject *PYM_error;
-
-static int
-PYM_doubleToJsval(PYM_JSContextObject *context,
-                  double number,
-                  jsval *rval)
-{
-  jsdouble *numberAsJsdouble = JS_NewDouble(context->cx, number);
-  if (numberAsJsdouble == NULL) {
-    PyErr_SetString(PYM_error, "JS_NewDouble() failed");
-    return -1;
-  }
-  *rval = DOUBLE_TO_JSVAL(numberAsJsdouble);
-  return 0;
-}
-
-int
-PYM_pyObjectToJsval(PYM_JSContextObject *context,
-                    PyObject *object,
-                    jsval *rval)
-{
-  if (PyString_Check(object) || PyUnicode_Check(object)) {
-    PyObject *unicode;
-    if (PyString_Check(object)) {
-      unicode = PyUnicode_FromObject(object);
-      if (unicode == NULL)
-        return -1;
-    } else {
-      unicode = object;
-      Py_INCREF(unicode);
-    }
-
-    PyObject *string = PyUnicode_AsUTF16String(unicode);
-    Py_DECREF(unicode);
-    if (string == NULL)
-      return -1;
-
-    char *buffer = PyString_AS_STRING(string);
-    Py_ssize_t size = PyString_GET_SIZE(string);
-
-    // Note that we're manipulating buffer and size here to get rid of
-    // the BOM.
-    JSString *jsString = JS_NewUCStringCopyN(context->cx,
-                                             (const jschar *) (buffer + 2),
-                                             (size / 2) - 1);
-    Py_DECREF(string);
-    if (jsString == NULL) {
-      PyErr_SetString(PYM_error, "JS_NewUCStringCopyN() failed");
-      return -1;
-    }
-
-    *rval = STRING_TO_JSVAL(jsString);
-    return 0;
-  }
-
-  if (PyInt_Check(object)) {
-    long number = PyInt_AS_LONG(object);
-    if (INT_FITS_IN_JSVAL(number)) {
-      *rval = INT_TO_JSVAL(number);
-      return 0;
-    } else
-      return PYM_doubleToJsval(context, number, rval);
-  }
-
-  if (PyFloat_Check(object))
-    return PYM_doubleToJsval(context, PyFloat_AS_DOUBLE(object), rval);
-
-  if (PyObject_TypeCheck(object, &PYM_JSObjectType)) {
-    PYM_JSObject *jsObject = (PYM_JSObject *) object;
-    JSRuntime *rt = JS_GetRuntime(context->cx);
-    if (rt != jsObject->runtime->rt) {
-      PyErr_SetString(PyExc_ValueError,
-                      "JS object and JS context are from different "
-                      "JS runtimes");
-      return -1;
-    }
-    *rval = OBJECT_TO_JSVAL(jsObject->obj);
-    return 0;
-  }
-
-  if (object == Py_True) {
-    *rval = JSVAL_TRUE;
-    return 0;
-  }
-
-  if (object == Py_False) {
-    *rval = JSVAL_FALSE;
-    return 0;
-  }
-
-  if (object == Py_None) {
-    *rval = JSVAL_NULL;
-    return 0;
-  }
-
-  // TODO: Support more types.
-  PyErr_SetString(PyExc_NotImplementedError,
-                  "Data type conversion not implemented.");
-  return -1;
-}
-
-PyObject *
-PYM_jsvalToPyObject(PYM_JSContextObject *context,
-                    jsval value) {
-  if (JSVAL_IS_INT(value))
-    return PyInt_FromLong(JSVAL_TO_INT(value));
-
-  if (JSVAL_IS_DOUBLE(value)) {
-    jsdouble *doubleRef = JSVAL_TO_DOUBLE(value);
-    return PyFloat_FromDouble(*doubleRef);
-  }
-
-  if (value == JSVAL_FALSE)
-    Py_RETURN_FALSE;
-
-  if (value == JSVAL_TRUE)
-    Py_RETURN_TRUE;
-
-  if (JSVAL_IS_NULL(value))
-    Py_RETURN_NONE;
-
-  if (JSVAL_IS_VOID(value))
-    Py_RETURN_UNDEFINED;
-
-  if (JSVAL_IS_STRING(value)) {
-    // Strings in JS are funky: think of them as 16-bit versions of
-    // Python 2.x's 'str' type.  Whether or not they're valid UTF-16
-    // is entirely up to the client code.
-
-    // TODO: Instead of ignoring errors, consider actually treating
-    // the string as a raw character buffer.
-    JSString *str = JSVAL_TO_STRING(value);
-    const char *chars = (const char *) JS_GetStringChars(str);
-    size_t length = JS_GetStringLength(str);
-
-    // We're multiplying length by two since Python wants the number
-    // of bytes, not the number of 16-bit characters.
-    return PyUnicode_DecodeUTF16(chars, length * 2, "ignore", NULL);
-  }
-
-  if (JSVAL_IS_OBJECT(value))
-    return (PyObject *) PYM_newJSObject(context, JSVAL_TO_OBJECT(value),
-                                        NULL);
-
-  // TODO: Support more types.
-  PyErr_SetString(PyExc_NotImplementedError,
-                  "Data type conversion not implemented.");
-  return NULL;
-}
-
-void
-PYM_pythonExceptionToJs(PYM_JSContextObject *context)
-{
-  PyObject *type;
-  PyObject *value;
-  PyObject *traceback;
-
-  PyErr_Fetch(&type, &value, &traceback);
-
-  if (type == PYM_error && value &&
-      PyObject_HasAttrString(value, "message")) {
-    jsval val;
-    PyObject *message = PyObject_GetAttrString(value, "message");
-    if (message && PYM_pyObjectToJsval(context, message, &val) == 0) {
-      JS_SetPendingException(context->cx, val);
-    } else
-      JS_ReportError(context->cx,
-                     "Python exception occurred, but exception "
-                     "couldn't be converted");
-    Py_XDECREF(message);
-  } else {
-    if (value) {
-      JSObject *exception = PYM_JS_newObject(context->cx, value);
-      if (exception)
-        JS_SetPendingException(context->cx, OBJECT_TO_JSVAL(exception));
-      else
-        JS_ReportOutOfMemory(context->cx);
-    } else
-      JS_ReportError(context->cx, "Python exception occurred");
-  }
-
-  Py_XDECREF(type);
-  Py_XDECREF(value);
-  Py_XDECREF(traceback);
-}
-
-void
-PYM_jsExceptionToPython(PYM_JSContextObject *context)
-{
-  if (!JS_IsExceptionPending(context->cx) &&
-      PyErr_Occurred())
-    return;
-
-  jsval val;
-  if (JS_GetPendingException(context->cx, &val)) {
-    PyObject *obj = PYM_jsvalToPyObject(context, val);
-    if (obj) {
-      PyErr_SetObject(PYM_error, obj);
-      Py_DECREF(obj);
-    } else {
-      PyErr_Clear();
-
-      JSString *str = NULL;
-
-      Py_BEGIN_ALLOW_THREADS;
-      str = JS_ValueToString(context->cx, val);
-      Py_END_ALLOW_THREADS;
-
-      if (str != NULL) {
-        const char *chars = JS_GetStringBytes(str);
-        PyErr_SetString(PYM_error, chars);
-      } else
-        PyErr_SetString(PYM_error, "JS exception occurred");
-    }
-  } else
-    PyErr_SetString(PYM_error, "JS_GetPendingException() failed");
-}
--- a/utils.h	Mon Aug 17 03:52:51 2009 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,81 +0,0 @@
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is Pymonkey.
- *
- * The Initial Developer of the Original Code is Mozilla.
- * Portions created by the Initial Developer are Copyright (C) 2007
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *   Atul Varma <atul@mozilla.com>
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-#ifndef PYM_UTILS_H
-#define PYM_UTILS_H
-
-#include "context.h"
-
-#include <jsapi.h>
-#include <jsdhash.h>
-#include <Python.h>
-
-class PYM_PyAutoEnsureGIL {
-public:
-  PYM_PyAutoEnsureGIL() {
-    state = PyGILState_Ensure();
-  }
-
-  ~PYM_PyAutoEnsureGIL() {
-    PyGILState_Release(state);
-  }
-
-protected:
-  PyGILState_STATE state;
-};
-
-typedef struct {
-  JSDHashEntryStub base;
-  void *value;
-} PYM_HashEntry;
-
-extern PyObject *PYM_error;
-
-extern int
-PYM_pyObjectToJsval(PYM_JSContextObject *context,
-                    PyObject *object,
-                    jsval *rval);
-
-extern PyObject *
-PYM_jsvalToPyObject(PYM_JSContextObject *context, jsval value);
-
-extern void
-PYM_pythonExceptionToJs(PYM_JSContextObject *context);
-
-void
-PYM_jsExceptionToPython(PYM_JSContextObject *context);
-
-#endif