Subj : Re: updated jsgen (maybe rc1?) To : netscape.public.mozilla.jseng From : Marcello Bastea-Forte Date : Thu Jan 01 2004 08:04 pm > What context-dependent or -related data do you store in your classes? > That seems like a bug, to be fixed ASAP if possible. It ought not be > necessary. I'm not entirely sure if it will work with multiple contexts or not, I really don't know how I'd test it (perhaps some insight here would help). I store a single JSObject * with the classes so you can get the JSObject from a C++ instance, although I'm looking at the Embedder's Guide, and it's saying that multiple contexts can access the same object (so a single JSObject* can be used on multiple contexts?) Right now I'm caching the JSContext for the getJSObject routine (this either returns a previously made JSObject*, or makes a new one with JS_NewObject), but it only uses the cached context if a context isn't passed to getJSObject(). After looking at that code again, I think I'll take the caching out altogether, since it seems pointless and unnecessary now. The problem I see is in the JSInit function that initializes a class into an object for use: ----------------------------------------------------------------------- ///// JavaScript Initialization Method JSObject *JSTest::_JSInitObject = NULL; // static JSObject *JSTest::JSInit(JSContext *cx, JSObject *obj, JSObject *proto) { if (!_JSInitObject) _JSInitObject = JS_InitClass(cx, obj, proto, &JSTest::_jsClass, JSTest::JSConstructor, 0, JSTest::_JSPropertySpec, JSTest::_JSFunctionSpec, JSTest::_JSPropertySpec_static, JSTest::_JSFunctionSpec_static); return _JSInitObject; } ----------------------------------------------------------------------- In my code, proto is NULL by default (I think I'll take out the extra prototype code as well), and if the class inherits from another class, the init function looks slightly different: ----------------------------------------------------------------------- JSObject *JSTestChild::JSInit(JSContext *cx, JSObject *obj, JSObject *proto) { if (!_JSInitObject) _JSInitObject = JS_InitClass(cx, obj, proto ? proto : JSTest::JSInit(cx,obj), &JSTestChild::_jsClass, /* <- I'll take out that proto ? proto : stuff */ JSTestChild::JSConstructor, 0, NULL, JSTestChild::_JSFunctionSpec, NULL, NULL); return _JSInitObject; } ----------------------------------------------------------------------- I don't know if that init object can be used across contexts, but looking at the code I see a bug. You wouldn't be able to initialize the class for use in multiple (global) objects. The problem is with JS_InitClass being called multiple times on the same class. If you call getJSObject on the child class, it will call JS_NewObject with a prototype: ----------------------------------------------------------------------- ///// JavaScript Object Linking JSObject *JSTestChild::getJSObject(JSContext *cx) { if (!cx) cx = _JSinternal.cx; else if (!_JSinternal.cx) _JSinternal.cx = cx; /*** Note the ugly context caching above that I'll take out ***/ if (!cx) return NULL; if (!_JSinternal.o) { _JSinternal.o = JS_NewObject(cx, &JSTestChild::_jsClass, JSTest::_JSInitObject, NULL); if (!JS_SetPrivate(cx, _JSinternal.o, this)) return NULL; } return _JSinternal.o; } ----------------------------------------------------------------------- Here I have to refer to the cached init object (I think), because JSInit requires an object to create it in. Perhaps there's another way to do this? In summary, those are the two problem points. Is it a problem to be calling JS_InitClass for the same thing multiple times on the same object? Should I be doing that instead? (For example, a child class will call the init of its parent class for the prototype.) I would also need some way to do deal with the prototype in the JS_NewObject for child classes. Thanks, Marcello .