comparison object.cpp @ 96:3570ab12747b

Renamed .c files to .cpp, since we use minor amounts of C++ code in pymonkey.
author Atul Varma <varmaa@toolness.com>
date Sat, 15 Aug 2009 10:24:17 -0700
parents object.c@9e8e56b4de6f
children
comparison
equal deleted inserted replaced
95:0701aee1b0cd 96:3570ab12747b
1 /* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
3 *
4 * The contents of this file are subject to the Mozilla Public License Version
5 * 1.1 (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 * http://www.mozilla.org/MPL/
8 *
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
12 * License.
13 *
14 * The Original Code is Pymonkey.
15 *
16 * The Initial Developer of the Original Code is Mozilla.
17 * Portions created by the Initial Developer are Copyright (C) 2007
18 * the Initial Developer. All Rights Reserved.
19 *
20 * Contributor(s):
21 * Atul Varma <atul@mozilla.com>
22 *
23 * Alternatively, the contents of this file may be used under the terms of
24 * either the GNU General Public License Version 2 or later (the "GPL"), or
25 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26 * in which case the provisions of the GPL or the LGPL are applicable instead
27 * of those above. If you wish to allow use of your version of this file only
28 * under the terms of either the GPL or the LGPL, and not to allow others to
29 * use your version of this file under the terms of the MPL, indicate your
30 * decision by deleting the provisions above and replace them with the notice
31 * and other provisions required by the GPL or the LGPL. If you do not delete
32 * the provisions above, a recipient may use your version of this file under
33 * the terms of any one of the MPL, the GPL or the LGPL.
34 *
35 * ***** END LICENSE BLOCK ***** */
36
37 #include "object.h"
38 #include "function.h"
39 #include "runtime.h"
40 #include "utils.h"
41
42 JSObject *
43 PYM_JS_newObject(JSContext *cx, PyObject *pyObject)
44 {
45 JSObject *obj = JS_NewObject(cx, &PYM_JS_ObjectClass, NULL, NULL);
46 if (obj) {
47 if (!JS_SetPrivate(cx, obj, pyObject))
48 return NULL;
49 Py_XINCREF(pyObject);
50 }
51 return obj;
52 }
53
54 JSBool
55 PYM_JS_setPrivatePyObject(JSContext *cx, JSObject *obj, PyObject *pyObject)
56 {
57 PyObject *old;
58 if (!PYM_JS_getPrivatePyObject(cx, obj, &old))
59 return JS_FALSE;
60 if (!JS_SetPrivate(cx, obj, pyObject))
61 return JS_FALSE;
62 Py_INCREF(pyObject);
63 Py_XDECREF(old);
64 return JS_TRUE;
65 }
66
67 JSBool
68 PYM_JS_getPrivatePyObject(JSContext *cx, JSObject *obj, PyObject **pyObject)
69 {
70 JSClass *klass = JS_GET_CLASS(cx, obj);
71 if (klass != &PYM_JS_ObjectClass) {
72 JS_ReportError(cx, "Object is not an instance of PymonkeyObject");
73 return JS_FALSE;
74 }
75
76 *pyObject = (PyObject *) JS_GetPrivate(cx, obj);
77 return JS_TRUE;
78 }
79
80 static void
81 PYM_JS_finalizeObject(JSContext *cx, JSObject *obj)
82 {
83 PYM_PyAutoEnsureGIL gil;
84 PyObject *pyObject;
85 // TODO: What if this fails?
86 if (PYM_JS_getPrivatePyObject(cx, obj, &pyObject))
87 Py_XDECREF(pyObject);
88 }
89
90 // This one-size-fits-all JSClass is used for any JS objects created
91 // in Python. It can hold a reference to a Python object for as long as
92 // its parent JS object is accessible from JS-land. As soon as it's
93 // garbage collected by the JS interpreter, it releases its reference on
94 // the Python object.
95 JSClass PYM_JS_ObjectClass = {
96 "PymonkeyObject", JSCLASS_GLOBAL_FLAGS | JSCLASS_HAS_PRIVATE,
97 JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
98 JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, PYM_JS_finalizeObject,
99 JSCLASS_NO_OPTIONAL_MEMBERS
100 };
101
102 static void
103 PYM_JSObjectDealloc(PYM_JSObject *self)
104 {
105 if (self->obj) {
106 JS_DHashTableOperate(&self->runtime->objects,
107 (void *) self->obj,
108 JS_DHASH_REMOVE);
109
110 // JS_RemoveRoot() always returns JS_TRUE, so don't
111 // bother checking its return value.
112 JS_RemoveRootRT(self->runtime->rt, &self->obj);
113 self->obj = NULL;
114 }
115
116 if (self->runtime) {
117 Py_DECREF(self->runtime);
118 self->runtime = NULL;
119 }
120
121 self->ob_type->tp_free((PyObject *) self);
122 }
123
124 static PyObject *
125 PYM_getRuntime(PYM_JSObject *self, PyObject *args)
126 {
127 Py_INCREF(self->runtime);
128 return (PyObject *) self->runtime;
129 }
130
131 static PyMethodDef PYM_JSObjectMethods[] = {
132 {"get_runtime", (PyCFunction) PYM_getRuntime, METH_VARARGS,
133 "Get the JavaScript runtime associated with this object."},
134 {NULL, NULL, 0, NULL}
135 };
136
137 PyTypeObject PYM_JSObjectType = {
138 PyObject_HEAD_INIT(NULL)
139 0, /*ob_size*/
140 "pymonkey.Object", /*tp_name*/
141 sizeof(PYM_JSObject), /*tp_basicsize*/
142 0, /*tp_itemsize*/
143 /*tp_dealloc*/
144 (destructor) PYM_JSObjectDealloc,
145 0, /*tp_print*/
146 0, /*tp_getattr*/
147 0, /*tp_setattr*/
148 0, /*tp_compare*/
149 0, /*tp_repr*/
150 0, /*tp_as_number*/
151 0, /*tp_as_sequence*/
152 0, /*tp_as_mapping*/
153 0, /*tp_hash */
154 0, /*tp_call*/
155 0, /*tp_str*/
156 0, /*tp_getattro*/
157 0, /*tp_setattro*/
158 0, /*tp_as_buffer*/
159 /*tp_flags*/
160 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
161 /* tp_doc */
162 "JavaScript Object.",
163 0, /* tp_traverse */
164 0, /* tp_clear */
165 0, /* tp_richcompare */
166 0, /* tp_weaklistoffset */
167 0, /* tp_iter */
168 0, /* tp_iternext */
169 PYM_JSObjectMethods, /* tp_methods */
170 0, /* tp_members */
171 0, /* tp_getset */
172 0, /* tp_base */
173 0, /* tp_dict */
174 0, /* tp_descr_get */
175 0, /* tp_descr_set */
176 0, /* tp_dictoffset */
177 0, /* tp_init */
178 0, /* tp_alloc */
179 0, /* tp_new */
180 };
181
182 PYM_JSObject *PYM_newJSObject(PYM_JSContextObject *context,
183 JSObject *obj,
184 PYM_JSObject *subclass) {
185 PYM_JSRuntimeObject *runtime = context->runtime;
186 PYM_HashEntry *cached = (PYM_HashEntry *) JS_DHashTableOperate(
187 &runtime->objects,
188 (void *) obj,
189 JS_DHASH_LOOKUP
190 );
191
192 if (JS_DHASH_ENTRY_IS_BUSY((JSDHashEntryHdr *) cached)) {
193 Py_INCREF((PyObject *) cached->value);
194 return (PYM_JSObject *) cached->value;
195 }
196
197 PYM_JSObject *object;
198
199 if (subclass)
200 object = subclass;
201 else {
202 if (JS_ObjectIsFunction(context->cx, obj)) {
203 PYM_JSFunction *func = PyObject_New(PYM_JSFunction,
204 &PYM_JSFunctionType);
205 object = (PYM_JSObject *) func;
206 } else
207 object = PyObject_New(PYM_JSObject,
208 &PYM_JSObjectType);
209 }
210
211 if (object == NULL)
212 return NULL;
213
214 object->runtime = NULL;
215 object->obj = NULL;
216
217 cached = (PYM_HashEntry *) JS_DHashTableOperate(&runtime->objects,
218 (void *) obj,
219 JS_DHASH_ADD);
220 if (cached == NULL) {
221 Py_DECREF(object);
222 PyErr_SetString(PYM_error, "JS_DHashTableOperate() failed");
223 return NULL;
224 }
225
226 cached->base.key = (void *) obj;
227 cached->value = object;
228
229 object->runtime = context->runtime;
230 Py_INCREF(object->runtime);
231
232 object->obj = obj;
233
234 JS_AddNamedRootRT(object->runtime->rt, &object->obj,
235 "Pymonkey-Generated Object");
236
237 return object;
238 }