Closed Bug 190746 Opened 22 years ago Closed 22 years ago

Add a "forget/release" method to nsCOMPtr

Categories

(Core :: XPCOM, enhancement)

enhancement
Not set
normal

Tracking

()

RESOLVED DUPLICATE of bug 78016

People

(Reporter: dbradley, Assigned: dbradley)

References

Details

(Keywords: perf)

Attachments

(1 file)

There are numerous, probably thousands, places where code is forced to do an NS_ADDREF becaused there's no way to have nsCOMPtr give up it's reference. Those creates a needless addref/release pair. In testing, such a function would remove more than 17,000 addref/release pairs from startup and shutdown. And around 13,000 for a page like www.cnn.com.
This patch is large, and probably touches on things that are old, or things that shouldn't be touched, but it's a starting point. Unfortunately I'm sure it will go stale pretty quick. Also, I believe it introduces a crash. I'm not sure if the crash is truly due to the changes here, or just uncovered. There are a few places where I took the liberty of cleaning some things up, so I may go back and take out some of the changes that are more than just adding forget. The other issue is that more than a patch will be needed. People will have to become familiar with the pattern and start using it, else we'll just get more of the old pattern.
Are you saying you want the |nsCOMPtr| to forget to |Release| the thing it's pointing to, so that you can return an |AddRef|ed result? If so, what you are really complaining about is that the normal form of getter returns is inconvenient, right? We are hunting for a solution to this problem in bug #178182 though much of the discussion can be found in http://bugzilla.mozilla.org/show_bug.cgi?id=172030#c18 The _one_ thing |nsCOMPtr| does is manage ownership of a single resource. To my eye, it seems like adding a |forget| member function subverts the single purpose of |nsCOMPtr|. Are you in love with |forget|? Or would you be happy with any solution that solved the `|AddRef| on exit' problem?
On the other hand, this solution may be simpler than any suggested yet in the aforementioned bugs. It certainly bears thinking about. I'll make this bug block the |nsCOMPtr| tracking bug #178174 and I'll link to this bug from the `|AddRef| on return' bug #178182
No, I'm more than open to alternative solutions. In my view, the goal is to remove the unecessary addref/release that occurs with the current pattern. If there are better alternatives that achieve that, then I'd be more than happy with that. Adding "forget" was fairly easy and allowed me to see how big the problem was and if it was even worth considering. dbaron has added forget to nsRefPtr. I think we should try and keep the usage of the two fairly similar if possible. And I don't think that's an argument to force forget into nsCOMPtr, but just noting that nsRefPtr should probably follow what ever is done to nsCOMPtr. I'll take a look a the other bugs to see what the alternatives are.
This is actually bug 178187. Returning from a function is not the only place where this is useful. There is at least one spot where I converted raw pointers over to nsCOMPtr where I had to do an unnecessary addref / release because of ownership transfer *within* a function: http://bonsai.mozilla.org/cvsblame.cgi?file=mozilla/content/events/src/nsEventStateManager.cpp#3823 notifyContent[4] = mDragOverContent; NS_IF_ADDREF(notifyContent[4]); // addref mDragOverContent = aContent; // release, addref With forget() this could turn into: notifyContent[4] = mDragOverContent.forget(); mDragOverContent = aContent; // addref As we hashed out over a long period of time, a function like accept_ownership_of() is probably a best bet.
Hrm, perhaps it's not precisely the same as that other bug, but it should be--if you transfer ownership out of the COMPtr you should not release the pointer, so nulling it out is a very viable option. And I love the fact that this patch fixes so many callers. Mega-kudos.
My main goal was to try and find out how much a perf benefit removing the unnecessary addref/release pair from the pattern. 13k for a page seems substantial, but to get that requires a lot of modifications to code and the associated risk. Also it would be nice something besides forget is the ideal solution that, dbaron's nsRefPtr gets that addition as well before it gets turned on and used. P.S. I've had the flu for the past week, and need something mindless to do in the evenings ;-)
Welll, your patch is just about minimum risk. accept_ownership_of() or something similar would be too. The risk of changing the callers to be more efficient is just something we'll be forced to take.
John, your snippet from |nsEventStateManager| is not a good argument, because |notifyContent| innappropriately manages references to COM objects with raw pointers, and requires hand |Release|ing at the end of the function. If |notifyContent| were an array of |nsCOMPtr|s, then we could have used the |swap| function proposed in bug #78016 I recognize the humor in your comment beginning with "Welll, your patch is just about minimum risk.", but someone just reading through these comments might believe you meant that at face value. Obviously a patch that induces a crash is nowhere near minimal risk. And we'd probably want to split this patch into at least two pieces anyway, one to add the functionality to |nsCOMPtr|, and another to start exploiting it. I like |forget|, but I like |swap| better between to |nsCOMPtr|s. In a way, |forget| is a one-way version of |swap|. I actually think I |swap| might be reasonable between a raw pointer and an |nsCOMPtr| as well. In which case, |swap|ing with a raw pointer variable that initially has the value |0| is equivalent to |forget|. Consider: nsIFoo* result = 0; nsCOMPtr<nsIFoo> foo = ... // ... lot's of work, possibly altering |foo| foo.swap(&result); return result; Along the |swap| road, many additional signatures occur to me, including forms that would be syntactically identical to |forget|... but I don't know that we really need any of them given void nsCOMPtr<T>::swap( nsCOMPtr<T>& ); void nsCOMPtr<T>::swap( T** ); // or perhaps, for consistency void nsCOMPtr<T>::swap( T*& );
Please excuse the bad spelling and typos in the post above... I've got the flu and the medication is making me stupid. Thinking about |swap|, though, has me wondering if this isn't the solution to several of the annoyances about |nsCOMPtr| we've been wanting to fix.
Although, you know T* nsCOMPtr<T>::swap( T* ); has a certain charm to it. The downside is the potential for leaks. In the form given a couple of comments back, the old managed pointer is stuffed into the in/out parameter, and so we have at least some guarantee that the caller has not lost the pointer. In this form, though it's pretty and let's us say, e.g., return foo.swap(0); // very convenient, but not very communicative or result = foo.swap(result); // less convenient, more communicative return result; You can see how easy it would be to drop the result. foo.swap(0); // leak ...it's convenient, yes, but I think much too sloppy.
And since with the sloppy signature just above, foo.swap(0); // is identical in meaning to foo.forget(); you can see that |forget()| is the way to get |nsCOMPtr|s to `leak on command'.
scc is right, swap() would be a better alternative for my case, if only because the raw pointer should be null, and therefore null will be transferred into the COMPtr. So is returning a COMPtr really the only case we're trying to deal with here?
swap sounds much more useful than forget, I like it.
After discussion on irc with dbradley, marking this bug a duplicate of bug #78016 and upping that bug's priority. We need |swap|. *** This bug has been marked as a duplicate of 78016 ***
Status: NEW → RESOLVED
Closed: 22 years ago
Resolution: --- → DUPLICATE
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Creator:
Created:
Updated:
Size: