changeset 70:b0360c0ed546

Factored the JS FunctionHolder class into the JS PymonkeyObject class, so that any PymonkeyObject can contain a private Python object if it needs to.
author Atul Varma <varmaa@toolness.com>
date Mon, 27 Jul 2009 04:47:33 -0700
parents c2972e58fbb6
children 9b3f4e53e365
files context.c function.c object.c object.h
diffstat 4 files changed, 80 insertions(+), 59 deletions(-) [+]
line wrap: on
line diff
--- a/context.c	Sun Jul 26 16:44:12 2009 -0700
+++ b/context.c	Mon Jul 27 04:47:33 2009 -0700
@@ -113,9 +113,9 @@
 static PyObject *
 PYM_newObject(PYM_JSContextObject *self, PyObject *args)
 {
-  JSObject *obj = JS_NewObject(self->cx, &PYM_JS_ObjectClass, NULL, NULL);
+  JSObject *obj = PYM_JS_newObject(self->cx, NULL);
   if (obj == NULL) {
-    PyErr_SetString(PYM_error, "JS_NewObject() failed");
+    PyErr_SetString(PYM_error, "PYM_JS_newObject() failed");
     return NULL;
   }
 
--- a/function.c	Sun Jul 26 16:44:12 2009 -0700
+++ b/function.c	Mon Jul 27 04:47:33 2009 -0700
@@ -37,56 +37,6 @@
 #include "function.h"
 #include "utils.h"
 
-static JSBool
-PYM_getHeldFunction(JSContext *cx, JSObject *obj, PyObject **callable)
-{
-  jsval jsCallable;
-  if (!JS_GetReservedSlot(cx, obj, 0, &jsCallable)) {
-    JS_ReportError(cx, "JS_GetReservedSlot() failed.");
-    return JS_FALSE;
-  }
-  *callable = (PyObject *) JSVAL_TO_PRIVATE(jsCallable);
-  return JS_TRUE;
-}
-
-static void
-PYM_finalizeFunctionHolder(JSContext *cx, JSObject *obj)
-{
-  PYM_PyAutoEnsureGIL gil;
-  PyObject *callable;
-  if (PYM_getHeldFunction(cx, obj, &callable))
-    Py_DECREF(callable);
-}
-
-// This "Python function holder" JSClass just exists so that it can hold
-// a reference to a Python function for as long as the Python function is
-// callable from JS-land. As soon as it's garbage collected by the JS
-// interpreter, it releases its reference on the Python function.
-static JSClass PYM_JS_FunctionHolderClass = {
-  "PymonkeyFunctionHolder", JSCLASS_HAS_RESERVED_SLOTS(1),
-  JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
-  JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub,
-  PYM_finalizeFunctionHolder,
-  JSCLASS_NO_OPTIONAL_MEMBERS
-};
-
-static JSObject *
-PYM_newFunctionHolder(JSContext *cx, PyObject *callable)
-{
-  JSObject *obj = JS_NewObject(cx, &PYM_JS_FunctionHolderClass, NULL, NULL);
-  if (obj) {
-    if (JS_SetReservedSlot(cx, obj, 0, PRIVATE_TO_JSVAL(callable)))
-      Py_INCREF(callable);
-    else {
-      obj = NULL;
-      PyErr_SetString(PYM_error, "JS_SetReservedSlot() failed");
-    }
-  } else {
-    PyErr_SetString(PYM_error, "JS_NewObject() failed");
-  }
-  return obj;
-}
-
 static void
 PYM_JSFunctionDealloc(PYM_JSFunction *self)
 {
@@ -103,13 +53,12 @@
   PYM_PyAutoEnsureGIL gil;
   jsval callee = JS_ARGV_CALLEE(argv);
   jsval functionHolder;
-  if (!JS_GetReservedSlot(cx, JSVAL_TO_OBJECT(callee), 0, &functionHolder)) {
-    JS_ReportError(cx, "JS_GetReservedSlot() failed.");
+  if (!JS_GetReservedSlot(cx, JSVAL_TO_OBJECT(callee), 0, &functionHolder))
     return JS_FALSE;
-  }
 
   PyObject *callable;
-  if (!PYM_getHeldFunction(cx, JSVAL_TO_OBJECT(functionHolder), &callable))
+  if (!PYM_JS_getPrivatePyObject(cx, JSVAL_TO_OBJECT(functionHolder),
+                                 &callable))
     return JS_FALSE;
 
   PYM_JSContextObject *context = (PYM_JSContextObject *)
@@ -252,9 +201,10 @@
     // been decremented by PYM_newJSObject().
     return NULL;
 
-  JSObject *functionHolder = PYM_newFunctionHolder(context->cx, callable);
+  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;
   }
 
--- a/object.c	Sun Jul 26 16:44:12 2009 -0700
+++ b/object.c	Mon Jul 27 04:47:33 2009 -0700
@@ -39,10 +39,72 @@
 #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_SetReservedSlot(cx, obj, 0, PRIVATE_TO_JSVAL(pyObject)))
+      return NULL;
+    Py_XINCREF(pyObject);
+  }
+  return obj;
+}
+
+JSBool
+PYM_JS_setPrivatePyObject(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 *old;
+  if (!PYM_JS_getPrivatePyObject(cx, obj, &old))
+    return JS_FALSE;
+  if (!JS_SetReservedSlot(cx, obj, 0, PRIVATE_TO_JSVAL(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;
+  }
+
+  jsval val;
+  if (!JS_GetReservedSlot(cx, obj, 0, &val))
+    return JS_FALSE;
+  *pyObject = (PyObject *) JSVAL_TO_PRIVATE(val);
+  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,
+  "PymonkeyObject", JSCLASS_GLOBAL_FLAGS | JSCLASS_HAS_RESERVED_SLOTS(1),
   JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
-  JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub,
+  JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, PYM_JS_finalizeObject,
   JSCLASS_NO_OPTIONAL_MEMBERS
 };
 
--- a/object.h	Sun Jul 26 16:44:12 2009 -0700
+++ b/object.h	Mon Jul 27 04:47:33 2009 -0700
@@ -42,6 +42,15 @@
 #include <jsapi.h>
 #include <Python/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 {