Subj : Re: Problems with garbage collection and read-only properties. To : Chris Nuernberger From : Brendan Eich Date : Thu Nov 20 2003 11:25 am Chris Nuernberger wrote: >Hey, we have managed to set up a situation where we have made it difficult >to mark a jsobject as a property of another object. > >Using prototypes and the tinyid system, we set up a few properties to be >read only. Then when we actually make an object of the class, we cannot set >its read-only members as properties of the new class on construction of the >class (that makes sense...). But then if you run the garbage collection >routine, because the read-only objects cannot be set into the objects slots, >the marking phase misses them and they get nuked. > > Patient: "It hurts when I do this [hits self on head with hammer]." Doctor: "Don't do that." ;-) I don't understand why you are defining properties (with tinyids, yet) on individual objects, instead of on the object's class prototype. Do you not use JS_InitClass? It's trivial to make per-property getters and setters; you don't have to use the class getProperty and setPropert hooks if you don't want to. Just an aside, in case you were thinking that you couldn't have per-property getters and setters. If you want to use the property value (slots) storage provided by native objects, you can do that several ways. If you don't want to use a slot, use the JSPROP_SHARED attribute on the property (which should really be defined in the class prototype, if you support more than one instance of the class), and store the property value yourself in private data. In the latter case, you'll need to implement JSClass.mark yourself, and call JS_MarkGCThing on any gc-thing (JSObject *, JSString *, or jsdouble * -- or a jsval for which JSVAL_IS_GCTHING reports true). There's enough rope in the JS API to hang yourself, for sure, but there's no way that you are stuck. Please don't hack another JS_SetProperty-like function into the engine if you don't understand how to use the existing API to do what you want. >To reiterate, > >jsobject myObject = (create new js object representation); >//Property defined without initial value (just for the example, and because >at the initial creation of the object we don't know what it's context will >always be, we just know the script shouldn't change it) >JS_DefinePropertyWithTinyId( cx, myObject, "context", blah, > > Note first use of blah, immediately above. >JSPROP_READONLY ); >jsobject myContext = (create new js context); >//Oops, this will not work... >JS_SetProperty( blah, myObject, blah, myContext ); > > Your use of blah here confuses me -- don't you mean cx? Why didn't you create myContext (assuming it's of type JSObject * -- it probably should have a less confusing name than anything spelled c-o-n-t-e-x-t) before calling JS_DefinePropertyWithTinyId, and pass OBJECT_TO_JSVAL(myContext) instead of the first blah? If you switch to defining properties via JS_InitClass, so they take up memory only once per property per class in the class's prototype object, then you don't need the prototype property to have any value. But since you're using tinyids, you do want the class getProperty hook handle ids for which JSVAL_IS_INT(id) reports true, usually by switching on JSVAL_TO_INT(id) with cases for all the well-known tinyids. Each case would then fetch the appropriate private data member, which (again) you are reponsible for marking via your JSClass.mark hook. Then the problem becomes: how to set the private data member so that subsequent getProperty calls can return it via *vp. That's up to you: you define the native data structure, you can provide setters for its members. /be .