Subj : Re: JS_ASSERT in js_MarkScriptFilename() To : netscape.public.mozilla.jseng From : "Edward Chan" Date : Fri Feb 20 2004 11:12 pm Hi Brendan, I think I know what the problem is. Now that I get what the gc is doing with the mark and sweep phases, I think I finally get it. So as I said before, we have this concept of multiple sandboxes, each with its own runtime, with a single context, and a single execution thread. Multiple sandboxes can be running at the same time. When I force a gc, JS_GC is called on each sandbox. So what's happening is this. GC happens on the first sandbox. It marks everything for that runtime, then eventually calls js_SweepScriptFilenames(). But the script filename table is a static shared by "all" runtimes. So when it calls js_SweepScriptFilenames(), it will sweep the entry for a script that would be marked when the second sandbox (and second runtime) gets gc'd. So now, when gc is invoked on the runtime for the second sandbox, it tries to mark the script that was just swept by the first gc. So in js_MarkScript(), it tries to call js_MarkScriptFilename(), but script->filename was already deleted by the previous gc. It is not null, but it points to deleted memory, so it passes the null check and tries to call js_MarkScriptFilename(). And then I get the JS_ASSERT in js_MarkScriptFilename(). Does that make sense? That's why I didn't see this behavior in rc5, because this global "script_filename_table" in new in rc6. So when we gc'd one runtime, it did not affect others. Since script_filename_table is global and shared by all runtimes, don't we need to mark everything in each runtime before sweeping script_filename_table? Otherwise, something is going to get prematurely swept, and when it does get marked later, it will be too late. Ed "Brendan Eich" wrote in message news:4036D8DF.4030908@meer.net... > Edward Chan wrote: > > >Sorry for my previous post. Regarding (2) and (3), I now understand what the > >mark and sweep is doing. But I'm still not sure about (1). > > > > > > sfe->mark is overlaid on he->value, which is set to NULL by the actual > argument passed to JS_HashTableRawAdd. The assertion is just checking > that NULL == 0 (== JS_FALSE). > > >And I'm still not sure when the script objects (that js engine is creating) > >are unrooted. > > > > Not every live object must be rooted. Every live object must be > reachable from one or more roots. > > Also, the engine makes script data structures (JSScripts), which are not > objects (JSObjects), and not owned by objects. A JSScript is a manually > allocated data structure. If you use the JS API to make one, it's up to > you to call JS_DestoryScript on it. If you hand off ownership of one > that you create to a script object, then you must not call > JS_DestroyScript -- the script object's finalizer will do that for you > when the object is GC'd. > > > Because unless "all" the script objects are unrooted at the > >end (whatever "end" means, perhaps JS_DestroyScript?), the second one is > >unrooted the ScriptFilenameEntry in the script_filename_table will be > >unmarked and deleted. So when the other scripts try to mark it, it will be > >accessing deleted memory. Am I starting to understand the way gc is > >working, or am I still way off? > > > > > > You're still off. The GC works in two phases. The mark phase does no > "unrooting", so nothing changes then. The sweep phase is collecting > only garbage, so what it destroys should not be reachable from any root, > or from any other live data structure. > > >Sorry for all this confusion. > > > > You don't need to call JS_NewScriptObject, JS_AddRoot, or > JS_RemoveRoot. Again, JS_ExecuteScript protects its script parameter by > rooting it from cx->fp->script (a root-by-definition that the GC scans). > > When you see the script->filename still valid for the last time, is the > GC running? Is this the same GC run that then finds that script's > filename member pointing at freed memory later (during the sweep > phase)? You can test the rt->gcNumber member to see which GC occurrence > is running. > > /be .