Subj : Multithreaded SpiderMonkey/GC/Managing Memory To : netscape.public.mozilla.jseng From : amadtiger@yahoo.com (Amit Garde) Date : Tue Jan 28 2003 06:10 am I would appreciate any help that folks more knowledgeable than I can provide regarding this problem. My questions are at the end of the post (skip ahead if you wish) - before that here's the background: I am trying to debug a multithreaded C++ server application that embeds the SpiderMonkey JS engine. There is heavy use of native functions - JS code calls native functions and these in turn call on other C++ stuff in the server. String arguments are passed quite often between JS, native functions and the rest of the server code. This is where the problem appears to be: string values get garbled leading to all sorts of weirdness. I suspect this is because of incorrect use of the engine embedding being stepped on by garbage collection. The JS engine has been compiled with JS_THREADSAFE. JS API calls are not bracketed with JS_BeginRequest or JS_EndRequest anywhere. (I know this is a bad idea, but I've inherited this code and that's the way it was written). This is supposedly okay because each thread while executing a script, does so in a separate runtime - the application maintains a pool of runtimes; threads that need to execute a script pick up a runtime from the pool, waiting for one to become available if necessary. After getting a runtime a new context and object are created, and the script is compiled and executed (using the newly created context and object). After the script is executed the script and context are destroyed (in that order, using JS_DestroyScript and JS_DestroyContext). Therefore at any one time only one thread can be executing a script in a particular context and runtime; multiple threads might be executing the same script, but it would be a separate compiled instance of that script and the context and runtime would be different as well. Not using JS_BeginRequest and JS_EndRequest is assumed to be safe because the "one runtime and context per script execution per thread" condition ensures that no thread executing a script would be racing with a GC triggered by another thread (because that thread would be in a different runtime and context of its own). Because of this assumption no explicit rooting is being done either (i.e JS_AddRoot and JS_AddNamedRoot are not used anywhere either). I am not very familiar yet with using an embedded SpiderMonkey so while I have read the documentation available and also trawled this newsgroup, there are several things I don't fully understand, so please excuse me if the answers to these questions are obvious; My Questions: 1. Is this assumption - that as long as a thread has exclusive access to a runtime and context and object over the lifetime of that context and object it needn't worry about GC-interference from other threads and therefore can get away with not using JS_BeginRequest/JS_EndRequest and not rooting - correct ? If not what are the things that could go wrong ? 2. A garbage collector is specific to one runtime and its heap. If *cx1 and *cx2 are JSContexts that were created with different runtimes, i.e JSContext *cx1 = JS_NewContext(rt1,STACKSIZE); JSContext *cx2 = JS_NewContext(rt2,STACKSIZE); Then a call to JS_GC(cx1) or JS_MaybeGC(cx1) will not have any effect on rt2 and will not interfere in any way with any call to JS_GC(cx2) or JS_MaybeGC(cx2) or with the execution of scripts executing with the context cx2, even if those calls or the script execution was simultaneous. Correct ? 3. If, in fact rt1 = rt2 in the above, then JS_GC(cx1) or JS_MaybeGC(cx1) could result in disaster for scripts executing with the context cx2, unless care had been taken to root objects and bracket calls with JS_BeginRequest and JS_EndRequest. 4. If in a native function I have code as follows: static JSBool myNativeFunction(JSContext *cx, JSObject *obj, uintN argc, jsval * argv, jsval * rval) ) { MyType mt; // automatically allocated object // of type MyType MyOtherType *pMOT = new MyOtherType(); // dynamically allocated object of // MyOtherType JSObject * newObj = JS_NewObject(cx, &objecttype_class, 0, 0); /* Other stuff */ } Then, destruction of mt happens in the ordinary way, when mt goes out of scope, pMOT will have to be explicitly deleted at some appropriate point and newObj will be garbage collected by the JS engine's GC. Correct ? Is there any situation in which the engine GC could touch memory used by objects created outside the aegis of the JS engine ? Thank you for your time ! Amit .