Make a cycle collected version of nsHashPropertyBag and use it from JS

RESOLVED FIXED in mozilla35

Status

()

RESOLVED FIXED
5 years ago
4 years ago

People

(Reporter: mccr8, Assigned: mccr8)

Tracking

(Blocks: 1 bug, {memory-leak})

unspecified
mozilla35
memory-leak
Points:
---
Dependency tree / graph

Firefox Tracking Flags

(Not tracked)

Details

(Whiteboard: [MemShrink])

Attachments

(2 attachments, 1 obsolete attachment)

This is part of an invisible cycle that seems to make us take an extra CC at shutdown whenever I mess with CC (bug 927601 and ICC).  This extra CC problem specifically only shows up in the RSS feed unit tests in toolkit/components/feeds.  This is the same idea as nsArray vs nsArrayCC.  Networking stuff uses nsHashPropertyBag, so I think I have to leave that alone.
Yay! I remember looking at the cycle collector over a year ago and noticing that we should be CCing this class. I never fixed it though.
Created attachment 822796 [details] [diff] [review]
implement CCed subclass, WIP

This is kind of the minimum viable patch.  It works well enough to not immediately blow up.  It implements a new subclass that is cycle collected.

I'm not a big fan of the way this (and nsArrayCC) shadows the refcounting stuff.  It also has the deficiency that if you use XPCOM to get a bag off the main thread, you'll end up with something that will not work.

I think a better approach may be more like bug 931283.
1. Create a base class that leaves ISupports methods abstract, but implements everything else.
2. Create a nsHashPropertyBagMT class that is same as the current nsHashPropertyBag class, with threadsafe refcounting, and switch over existing uses of the class that aren't on the main thread to use it.
3. Create a main-thread-only nsHashPropertyBag like I've defined in this patch. Maybe name it BagCC or maybe not.

Then use the thready factory constructor method I created in bug 931283 to select an implementation depending on which thread you are on.

One weird thing about the bag class is that a number of the methods create nsVariants, which is a single threaded class.  I guess they are only ever called from a single thread?  Maybe I can split the interface out a bit so those methods don't exist for the threadsafe property bag variant.
Assignee: nobody → continuation
No longer blocks: 850065
Duplicate of this bug: 1063312
For some reason hash property bag causes a leak in the child process when used from JS.
Keywords: mlk
Whiteboard: [MemShrink]
Created attachment 8485135 [details] [diff] [review]
part 1 - Factor out a base class for nsHashPropertyBag that does not implement refcounting.

Also remove the unused NS_NewHashPropertyBag.
Attachment #822796 - Attachment is obsolete: true
Created attachment 8485136 [details] [diff] [review]
part 2 - Implement a cycle collected version of nsHashPropertyBag and use it from JS.
Blocks: 1051230
No longer depends on: 1051230
Comment on attachment 8485135 [details] [diff] [review]
part 1 - Factor out a base class for nsHashPropertyBag that does not implement refcounting.

Try run looks green.  well, except for the failures which I'm pretty sure are from other stuff in the queue.

Anyways, the idea here is that we factor out an abstract base class that does not implement refcounting, then subclass it twice, once for threadsafe stuff for Necko and whoever else, then a second one for JS that is CCed.
Attachment #8485135 - Flags: review?(nfroyd)
Comment on attachment 8485136 [details] [diff] [review]
part 2 - Implement a cycle collected version of nsHashPropertyBag and use it from JS.

try: https://tbpl.mozilla.org/?tree=Try&rev=0f0399454863

I could try to be clever and factor out the QI, too, though QI macro code scares me so I just did a copy-paste-modify thing.
Attachment #8485136 - Flags: review?(nfroyd)
Comment on attachment 8485135 [details] [diff] [review]
part 1 - Factor out a base class for nsHashPropertyBag that does not implement refcounting.

Review of attachment 8485135 [details] [diff] [review]:
-----------------------------------------------------------------

r=me with the changes below.

::: xpcom/ds/nsHashPropertyBag.cpp
@@ -15,5 @@
> -nsresult
> -NS_NewHashPropertyBag(nsIWritablePropertyBag** aResult)
> -{
> -  nsRefPtr<nsHashPropertyBag> hpb = new nsHashPropertyBag();
> -  hpb.forget(aResult);

It's too bad that deleting dead code removes one of the few ways we do these NS_New* constructors correctly. =/

::: xpcom/ds/nsHashPropertyBag.h
@@ +32,2 @@
>  
> +class nsHashPropertyBag : public nsHashPropertyBagBase

Since we're already here, maybe make this MOZ_FINAL?

@@ +40,1 @@
>    virtual ~nsHashPropertyBag() {}

Probably doesn't matter much, since this is nsISupports stuff, but I think you want to have the (protected!) virtual destructor in the base class, for code cleanliness, if nothing else.
Attachment #8485135 - Flags: review?(nfroyd) → review+
(In reply to Nathan Froyd (:froydnj) from comment #9)
> It's too bad that deleting dead code removes one of the few ways we do these
> NS_New* constructors correctly. =/
I dunno, this looks so trivial I wasn't sure how useful it was to have it. :)

> Since we're already here, maybe make this MOZ_FINAL?
A ton of networking code inherits from nsHashPropertyBag.  That's why I have to go through this whole rigamarole in the first place. :)

> Probably doesn't matter much, since this is nsISupports stuff, but I think
> you want to have the (protected!) virtual destructor in the base class, for
> code cleanliness, if nothing else.

Good point, I'll try that.
Comment on attachment 8485136 [details] [diff] [review]
part 2 - Implement a cycle collected version of nsHashPropertyBag and use it from JS.

Review of attachment 8485136 [details] [diff] [review]:
-----------------------------------------------------------------

r=me with changes and answers.

::: xpcom/build/XPCOMModule.inc
@@ +62,5 @@
>  
>      COMPONENT(VARIANT, nsVariantConstructor)
>      COMPONENT(INTERFACEINFOMANAGER_SERVICE, nsXPTIInterfaceInfoManagerGetSingleton)
>  
> +    COMPONENT(HASH_PROPERTY_BAG, nsHashPropertyBagCCConstructor)

Have you audited all the places that create these things through XPCOM to see if the newly created objects get passed to other threads?  Admittedly, they were probably doing dodgy things before, but the dodginess at least had the virtue of working.  This change will loudly break them.

::: xpcom/ds/nsHashPropertyBag.cpp
@@ +279,5 @@
> +
> +NS_IMPL_CYCLE_COLLECTION(nsHashPropertyBagCC, mPropertyHash)
> +
> +NS_IMPL_CYCLE_COLLECTING_ADDREF(nsHashPropertyBagCC)
> +NS_IMPL_CYCLE_COLLECTING_RELEASE(nsHashPropertyBagCC)

No higher-order macro for all this stuff?  Very disappointed. ;)

::: xpcom/ds/nsHashPropertyBag.h
@@ +42,5 @@
>    virtual ~nsHashPropertyBag() {}
>  };
>  
> +/* A cycle collected nsHashPropertyBag for use from JS. */
> +class nsHashPropertyBagCC : public nsHashPropertyBagBase

MOZ_FINAL, please.
Attachment #8485136 - Flags: review?(nfroyd) → review+
> Have you audited all the places that create these things through XPCOM to see if the newly created objects get passed to other threads?

My impression is that the users who care about threadsafety don't use XPCOM, but I'll look.  Would that basically be looking at places where @mozilla.org/hash-property-bag;1 appears in the code base?  eg http://mxr.mozilla.org/mozilla-central/search?string=@mozilla.org/hash-property-bag;1
(In reply to Andrew McCreight [:mccr8] from comment #10)
> > Since we're already here, maybe make this MOZ_FINAL?
> A ton of networking code inherits from nsHashPropertyBag.  That's why I have
> to go through this whole rigamarole in the first place. :)

That sounds...not so good.  Are all the other nsHashPropertyBag users paying for threadsafe AddRef/Release, when it's really Necko's weird use of this as a base class that requires it, for instance?  File a followup bug, please?

> > Probably doesn't matter much, since this is nsISupports stuff, but I think
> > you want to have the (protected!) virtual destructor in the base class, for
> > code cleanliness, if nothing else.
> 
> Good point, I'll try that.

...and since I didn't realize Necko used it as a base class, the virtual destructor can be kept in this class too.

(In reply to Andrew McCreight [:mccr8] from comment #12)
> > Have you audited all the places that create these things through XPCOM to see if the newly created objects get passed to other threads?
> 
> My impression is that the users who care about threadsafety don't use XPCOM,
> but I'll look.  Would that basically be looking at places where
> @mozilla.org/hash-property-bag;1 appears in the code base?  eg
> http://mxr.mozilla.org/mozilla-central/search?string=@mozilla.org/hash-
> property-bag;1

Yeah.  Looking at those, it seems like none of them have off-main-thread usages, so I think we're good here.
I filed bug 1064361 for changing C++ consumers.  To that end, I changed the comment on nsHashPropertyBagCC to "A cycle collected nsHashPropertyBag for main-thread-only use." instead of saying "for use from JS".
The only other change I made was to mark nsHashPropertyBagCC MOZ_FINAL as that seemed to be where the discussion here left things.  Thanks for the review.
Oh, and while I'm bugspamming, this did seem to be the last leak in M4 e10s, with the rest of my sketchy patch queue:
  https://tbpl.mozilla.org/?tree=Try&rev=0f0399454863
https://hg.mozilla.org/mozilla-central/rev/55f41b0d3ab2
https://hg.mozilla.org/mozilla-central/rev/98d7d9f16f17
Status: NEW → RESOLVED
Last Resolved: 4 years ago
Resolution: --- → FIXED
Target Milestone: --- → mozilla35
You need to log in before you can comment on or make changes to this bug.