Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Clearing objects from a Context

6 views
Skip to first unread message

amohr

unread,
Jan 2, 2006, 8:08:46 PM1/2/06
to
I realize this is not the right way to go about things, but because of
our current architecture we need to ensure that when we're destroying a
JSContext, all the objects originally created from that context are
GC'd before I call JS_DestroyContext.

So the first point may be that objects may have references in many
contexts, luckily we prevent this from happening.

What I've tried:

I first create a new Context though JS_NewContext.

I then call JS_NewObject on that context with a JSClass I alloc'd, with
NULL proto and parent.

I then call JS_InitStandardClasses on that context with the object
created above.

I then call JS_SetGlobalObject with the object created above.

After which, all objects created for a context use the above object as
the parent to JS_NewObject.

The issue I'm finding is that even if I remove all roots, and call
JS_ClearScope on the above object before a call to GC, various objects
from that context won't get GC'd until after the context is destroyed.
Is there a way to terminate all references from a context? Or perhaps
I'd doing something wrong? I'd glading add relevant info to the JS API
wiki.

Thanks,

- Alex

Brendan Eich

unread,
Jan 2, 2006, 9:19:29 PM1/2/06
to
amohr wrote:

> I then call JS_InitStandardClasses on that context with the object
> created above.
>
> I then call JS_SetGlobalObject with the object created above.

FYI, there's no need for this (it doesn't hurt), because
JS_InitStandardClasses sets the context's globalObject member to the
|obj| parameter you pass in, iff cx->globalObject is null.

> After which, all objects created for a context use the above object as
> the parent to JS_NewObject.
>
> The issue I'm finding is that even if I remove all roots, and call
> JS_ClearScope on the above object before a call to GC, various objects
> from that context won't get GC'd until after the context is destroyed.
> Is there a way to terminate all references from a context? Or perhaps
> I'd doing something wrong?

You should JS_ClearNewbornRoots(cx) as well.

You might use GC_MARK_DEBUG (define it before building the engine) to
dump the GC's heap before and after you destroy the context, but in both
cases after you think you've cleared everything that might entrain an
object associated by your embedding's customs with the context to be
destroyed. Sort and diff the heaps to see what you missed, that was not
missed by the GC done from JS_DestroyContext.

> I'd glading add relevant info to the JS API wiki.

Thanks -- a tutorial on using GC_MARK_DEBUG might be the best result.

/be

amohr

unread,
Jan 3, 2006, 3:02:03 AM1/3/06
to
thanks for the tips and understanding my broken english :)

So thanks to that tool I see I was down from 2200 non strings to 67
with the added JS_ClearNewbornRoots call. What I see are all the
built-in objects dependant on the global object I created.

i.e. :
061f6810 object 06202ED8 Root via global object(Root @ 0x061f6810).

061f6858 object 061F6860 Object via global object(Root @
0x061f6810).__proto__(Object @ 0x061f6858).

061f6860 object 06324CE0 Function via global object(Root @
0x061f6810).__proto__(Object @ 0x061f6858).constructor(Function @
0x061f6860).

06327090 private 06327090 via global object(Root @
0x061f6810).__proto__(Object @ 0x061f6858).constructor(Function @
0x061f6860).slots().

06324ce0 private 06324CE0 via global object(Root @
0x061f6810).__proto__(Object @ 0x061f6858).constructor(Function @
0x061f6860).private().

061f6818 object 06324CC0 Function via global object(Root @
0x061f6810).__proto__(Object @ 0x061f6858).constructor(Function @
0x061f6860).__proto__(Function @ 0x061f6818).

it seems I'm missing one crucial step to get the "global object"
(cx->globalObject, Root above) to release itself. If I'm reading this
right, everything left seems to be dependant on itself.

any ideas?

Thanks so much,

- Alex

Alex Mohr

unread,
Jan 3, 2006, 1:42:23 PM1/3/06
to
FYI, I just found out when calling JS_GC, JS_ClearNewbornRoots is done
in:

JS_GC->js_ForceGC ... so it seems the call to JS_ClearNewbornRoots is
unneeded. Perhaps js_ForceGC should actually call JS_ClearNewbornRoots
to make this clearer though.

Alex Mohr

unread,
Jan 3, 2006, 1:58:30 PM1/3/06
to
ok, I'm dumb, all what I needed to do was call JS_SetGlobalObject(jsc,
NULL);

I'll put a note about this in that method and create a guide about
GC_MARK_DEBUG.

Thanks again!

- Alex

Brendan Eich

unread,
Jan 3, 2006, 2:28:24 PM1/3/06
to Alex Mohr


No, the layering is such that other calls to js_ForceGC wouldn't benefit
from that move, or wouldn't want it. It's not totally clear to me how
this might matter, but API consumers may have come to depend on it in
the last 8 or 9 years (!), and I don't want to fiddle with it.

But note that only the cx on which you call JS_GC has its newborns
cleared, and it wasn't clear from what you wrote that that was the cx
that might be entraining stuff.

In other words, if you only called JS_DestroyContext(cx) and found some
object that you wanted to be "only for use on that cx" still alive (saw
your followup about clearing the global object, cool), then called
JS_GC(someothercx), you might also suffer from stuff being entrained by
the newborn roots.

That was my point, but it sounds like it's not an issue anyway. And if
you were calling JS_GC(cx) before JS_DestroyContext(cx), then as you
note, cx's newborns will be cleared in time. But you shouldn't have to
call JS_GC(cx) before JS_DestroyContext(cx) -- let the destroy do the
last GC.

/be

Alex Mohr

unread,
Jan 4, 2006, 12:14:21 AM1/4/06
to
Thanks, I now have all the objects releasing correctly after creating
and destroying contexts individually, but I'm left with the following
problem:

A runtime has two contexts initialized as I described in the first
post. The second context is created and initialized before the first
is destroyed. What I'm noticing is that the second context's global
object is getting rooted to the first context's global object through
the following:

061f7db8 object 06202F18 Root via global object(Root @
0x061f6bc8).AnyName(Function @ 0x061f77c0).prototype(AnyName @
0x061f77d0).constructor(Function @ 0x061f8508).__proto__(Function @
0x061f7dc0).__proto__(Object @ 0x061f7df0).__parent__(Root @
0x061f7db8).

here 0x061f7db8 is the globalObject to the second context and
0x061f6bc8 is the first context's global object.

This doesn't happen if I don't call JS_InitStandardClasses on the first
context. So it seems that when I call JS_InitStandardClasses on a
context in a runtime which has an existing context with standard
classes, the new context's root object somehow gets rooted to the other
context's root object. This doesn't sound like the desired behavior.

Any ideas?

Thanks,

- Alex

Mike Shaver

unread,
Jan 4, 2006, 1:37:23 AM1/4/06
to
On 3 Jan 2006 21:14:21 -0800, Alex Mohr <theh...@gmail.com> wrote:
> A runtime has two contexts initialized as I described in the first
> post. The second context is created and initialized before the first
> is destroyed. What I'm noticing is that the second context's global
> object is getting rooted to the first context's global object through
> the following:
>
> 061f7db8 object 06202F18 Root via global object(Root @
> 0x061f6bc8).AnyName(Function @ 0x061f77c0).prototype(AnyName @
> 0x061f77d0).constructor(Function @ 0x061f8508).__proto__(Function @
> 0x061f7dc0).__proto__(Object @ 0x061f7df0).__parent__(Root @
> 0x061f7db8).
>
> here 0x061f7db8 is the globalObject to the second context and
> 0x061f6bc8 is the first context's global object.

This sounds like a bug, and possibly a bad one even for Firefox's use,
if we entrain the first global beyond its natural lifespan.

js_GetAnyName appears, to my tired eyes, to be creating an object
associated with a context's global (and Object.prototype?), and then
keeping it around for what is possibly much longer than the context's
then-current global would otherwise live. We could sever the parent
link directly in js_GetAnyName, but I'm not sure at this hour if
that's the right thing, and it would leave the Object.prototype link
intact -- if that's a real problem indeed.

I'll look again in the AM, time willing, but a pessimistic bug filing
on the issue would not be unwelcome, IMO.

Mike

Brendan Eich

unread,
Jan 4, 2006, 1:43:15 AM1/4/06
to Alex Mohr
Alex Mohr wrote:
> Thanks, I now have all the objects releasing correctly after creating
> and destroying contexts individually, but I'm left with the following
> problem:
>
> A runtime has two contexts initialized as I described in the first
> post. The second context is created and initialized before the first
> is destroyed. What I'm noticing is that the second context's global
> object is getting rooted to the first context's global object through
> the following:
>
> 061f7db8 object 06202F18 Root

Root must be your global objects' class name.

> via global object(Root @
> 0x061f6bc8

The first context's global object, you wrote further on.

> ).AnyName(Function @ 0x061f77c0)

the AnyName constructor is named by the 'AnyName' property of this first
global object.

> .prototype(AnyName @
> 0x061f77d0)

AnyName.prototype

> .constructor(Function @ 0x061f8508)

which has a 'constructor' property which should be the AnyName
constructor traced from 'AnyName' in the first global object, but it's
not! "Don't cross the streams!"

.__proto__(Function @
> 0x061f7dc0).__proto__(Object @ 0x061f7df0).__parent__(Root @
> 0x061f7db8).

This other AnyName has a proto slot linking to a Function.prototype
whose proto links to Object.prototype whose parent is the second
context's global object.

> here 0x061f7db8 is the globalObject to the second context and
> 0x061f6bc8 is the first context's global object.
>
> This doesn't happen if I don't call JS_InitStandardClasses on the first
> context.

It looks to me as though you call JS_InitStandardClasses on the first
context after you called JS_InitStandardClasses on the second, *and*
from a function scoped by the second context's global (directly or not).

Exactly what code calls JS_InitStandardClasses in all cases in your
embedding?

/be

Brendan Eich

unread,
Jan 4, 2006, 1:53:02 AM1/4/06
to Mike Shaver
Mike Shaver wrote:
> On 3 Jan 2006 21:14:21 -0800, Alex Mohr <theh...@gmail.com> wrote:
>
>>A runtime has two contexts initialized as I described in the first
>>post. The second context is created and initialized before the first
>>is destroyed. What I'm noticing is that the second context's global
>>object is getting rooted to the first context's global object through
>>the following:
>>
>>061f7db8 object 06202F18 Root via global object(Root @
>>0x061f6bc8).AnyName(Function @ 0x061f77c0).prototype(AnyName @
>>0x061f77d0).constructor(Function @ 0x061f8508).__proto__(Function @
>>0x061f7dc0).__proto__(Object @ 0x061f7df0).__parent__(Root @
>>0x061f7db8).
>>
>>here 0x061f7db8 is the globalObject to the second context and
>>0x061f6bc8 is the first context's global object.
>
>
> This sounds like a bug, and possibly a bad one even for Firefox's use,
> if we entrain the first global beyond its natural lifespan.


Look closer -- the problem you cite is not (see my followup) Alex's
problem. His embedding appears to be scoping one global object's
JS_InitStandardClasses using another context's global object.


> js_GetAnyName appears, to my tired eyes, to be creating an object
> associated with a context's global (and Object.prototype?),


Associated with is too strong -- parented by (and prototyped by).


> and then
> keeping it around for what is possibly much longer than the context's
> then-current global would otherwise live.


No longer than anyname is needed. The JSRuntime.anynameObject reference
is a weak one, so as soon as the GC can, it will collect this object and
the finalizer will clear rt->anynameObject. The cycle can repeat on
demand and anynameObject can be shared across contexts that use * in E4X
code. Note that * is an intern'ed object, not accessible to JS as an
object reference.

You're right that scripts compiled using the first context's global may
keep that context's global alive as long as the scripts live. That is
not a problem in content windows in general, any more than literals of
other object type keeping the window in which the literal was compiled
alive.

With chrome windows loading long-lived scripts, there could be a worse
entrainment problem. I'll take that bug, but cheer up -- no need to be
pessimistic when filing it!

/be

Alex Mohr

unread,
Jan 4, 2006, 8:01:54 PM1/4/06
to
nope! The same sequence happens for each context in order, with the
first context before the second (second gets messed up): Create
Context -> Create New Object in context without proto or parent ->
InitStandardClasses with new Object. InitStandardClasses is not
called from any scope (no JS on callstack).

I think I just realized what the problem is...for the second context,
in JS_InitClass for the AnyName class, it's setting the
cx2->globalObject.AnyName function property to the rt->anynameObject
(created from cx1). Then, because it thinks it just constructed a new
AnyName object it set's cx1->globalObject.AnyName.constructor to
cx2->globalObject.AnyName...and it set's
cx2->globalObject.AnyName.prototype to cx1->globalObject.AnyName.

I think this means cx1->globalObject.AnyName can't be GC'd until
cx2->globalObject.AnyName...which in turn can't get put up for GC until
cx1->globalObject.AnyName is put for GC....circular dependency my
friends :)

could rt->anynameObject be moved to cx->anynameObject ? seems like
that would solve the problem.

Thanks,

- Alex

Alex Mohr

unread,
Jan 4, 2006, 8:41:58 PM1/4/06
to
FYI, after moving anynameObject and functionNamespaceObject to the
context everything seems to be working!!!! I still can't believe it
.. soo many crashers b4 :)

should I submit a patch and put a note in the JSRuntime struct on why
not to add objects to it?

- Alex

Brendan Eich

unread,
Jan 4, 2006, 9:32:37 PM1/4/06
to Alex Mohr
Alex Mohr wrote:
> nope! The same sequence happens for each context in order, with the
> first context before the second (second gets messed up): Create
> Context -> Create New Object in context without proto or parent ->
> InitStandardClasses with new Object. InitStandardClasses is not
> called from any scope (no JS on callstack).
>
> I think I just realized what the problem is...for the second context,
> in JS_InitClass for the AnyName class, it's setting the
> cx2->globalObject.AnyName function property to the rt->anynameObject
> (created from cx1).

That can't be, the AnyName property's value is a function object, not an
anyname object. Do you mean AnyName.prototype? That'd be a problem!

> Then, because it thinks it just constructed a new
> AnyName object it set's cx1->globalObject.AnyName.constructor to

cx1->globalObject.AnyName.prototype.constructor, right.

> cx2->globalObject.AnyName...and it set's
> cx2->globalObject.AnyName.prototype to cx1->globalObject.AnyName.
>
> I think this means cx1->globalObject.AnyName can't be GC'd until
> cx2->globalObject.AnyName...which in turn can't get put up for GC until
> cx1->globalObject.AnyName is put for GC....circular dependency my
> friends :)

Yeah, it's ugly.

> could rt->anynameObject be moved to cx->anynameObject ? seems like
> that would solve the problem.

The * identifier has to be runtime-wide, or it won't match in E4X
expressions evaluated "across contexts" -- the match uses pointer identity.

Please do file a bug on this.

/be

Alex Mohr

unread,
Jan 5, 2006, 3:01:00 PM1/5/06
to

Brendan Eich

unread,
Jan 5, 2006, 7:58:32 PM1/5/06
to Alex Mohr
Alex Mohr wrote:
> bug filed: https://bugzilla.mozilla.org/show_bug.cgi?id=322499
>


Patch in bug, singletons remain, comment added to jscntxt.h.

/be

Alex Mohr

unread,
Jan 5, 2006, 10:28:37 PM1/5/06
to
u da man! this means I don't need to check in my hack locally =)

0 new messages