Bug 101989 - JSC: JSEventListener's m_jsFunction should be a weak ref
Summary: JSC: JSEventListener's m_jsFunction should be a weak ref
Status: RESOLVED FIXED
Alias: None
Product: WebKit
Classification: Unclassified
Component: WebCore JavaScript (show other bugs)
Version: 528+ (Nightly build)
Hardware: Unspecified Unspecified
: P2 Normal
Assignee: Mark Lam
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2012-11-12 14:19 PST by Mark Lam
Modified: 2012-11-14 17:03 PST (History)
4 users (show)

See Also:


Attachments
1st draft. (8.99 KB, patch)
2012-11-12 17:49 PST, Mark Lam
webkit-ews: commit-queue-
Details | Formatted Diff | Diff
2nd draft: added missing file from last patch. (10.76 KB, patch)
2012-11-12 18:03 PST, Mark Lam
webkit-ews: commit-queue-
Details | Formatted Diff | Diff
3rd time's the charm. (11.29 KB, patch)
2012-11-12 19:57 PST, Mark Lam
ggaren: review-
Details | Formatted Diff | Diff
Fix. (9.98 KB, patch)
2012-11-13 20:51 PST, Mark Lam
ggaren: review+
Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Mark Lam 2012-11-12 14:19:41 PST
The GC can collect the JSFunction object without JSEventListener's knowledge.  Hence, JSEventListener's m_jsFunction ref should be a weak ref to reflect this.
Comment 1 Mark Lam 2012-11-12 17:49:36 PST
Created attachment 173774 [details]
1st draft.
Comment 2 Early Warning System Bot 2012-11-12 17:56:24 PST
Comment on attachment 173774 [details]
1st draft.

Attachment 173774 [details] did not pass qt-ews (qt):
Output: http://queues.webkit.org/results/14810697
Comment 3 Mark Lam 2012-11-12 18:03:07 PST
Created attachment 173777 [details]
2nd draft: added missing file from last patch.
Comment 4 Early Warning System Bot 2012-11-12 18:11:16 PST
Comment on attachment 173777 [details]
2nd draft: added missing file from last patch.

Attachment 173777 [details] did not pass qt-ews (qt):
Output: http://queues.webkit.org/results/14810702
Comment 5 Early Warning System Bot 2012-11-12 18:11:58 PST
Comment on attachment 173777 [details]
2nd draft: added missing file from last patch.

Attachment 173777 [details] did not pass qt-wk2-ews (qt):
Output: http://queues.webkit.org/results/14809661
Comment 6 Mark Lam 2012-11-12 18:31:02 PST
Comment on attachment 173777 [details]
2nd draft: added missing file from last patch.

Something is fishy.  Why is it not building?  Will investigate.
Comment 7 Mark Lam 2012-11-12 19:57:56 PST
Created attachment 173801 [details]
3rd time's the charm.
Comment 8 Geoffrey Garen 2012-11-12 20:27:17 PST
Comment on attachment 173801 [details]
3rd time's the charm.

View in context: https://bugs.webkit.org/attachment.cgi?id=173801&action=review

You mentioned that you saw problems on websites with an earlier version of this patch. Does this patch fix those problems?

> Source/JavaScriptCore/heap/SlotVisitor.h:61
> +    void appendUnbarrieredWeakRef(Weak<T>*);

We don't usually use the abbreviation "Ref" outside of CoreFoundation classes. How about just calling this "appendUnbarrieredWeak" or "appendUnbarriered"?

> Source/JavaScriptCore/heap/SlotVisitorInlines.h:73
> +    if (weakRef && *weakRef)

I don't think weakRef can ever be NULL here.

Instead of the *weakRef test, I think you either need a call to .get() or a call to operator!(). It's an error to use operator*() after a weak pointer has been collected.

> Source/JavaScriptCore/heap/Weak.h:160
> +template<typename T> inline JSValue Weak<T>::referee()
> +{
> +    return m_impl ? m_impl->jsValue() : JSValue();
> +}

Why do we need this function, when we already have operator*() and .get()?

> Source/WebCore/bindings/js/JSEventListener.cpp:69
> +    // JSEventListener may outlive its m_jsFunction. In this case, we will
> +    // m_jsFunction to be 0.

"we will": seems like you meant something else here.

There's a lot of commentary about m_jsFunction here, but this function doesn't use that data member. Does any of this explain why the base class implementation of initializeJSFunction() should return 0?
Comment 9 Mark Lam 2012-11-12 20:46:00 PST
(In reply to comment #8)
> (From update of attachment 173801 [details])
> View in context: https://bugs.webkit.org/attachment.cgi?id=173801&action=review
> 
> You mentioned that you saw problems on websites with an earlier version of this patch. Does this patch fix those problems?

Unfortunately not.  Just presenting it to let you have a look in case I made some major mistake.

> > Source/JavaScriptCore/heap/SlotVisitor.h:61
> > +    void appendUnbarrieredWeakRef(Weak<T>*);
> 
> We don't usually use the abbreviation "Ref" outside of CoreFoundation classes. How about just calling this "appendUnbarrieredWeak" or "appendUnbarriered"?

OK, will change to "appendUnbarrieredWeak" to be consistent (plus it's easier to grep for when we don't use overloaded names).  There are already 2 other pre-existing "appendUnbarrieredX" functions.

> > Source/JavaScriptCore/heap/SlotVisitorInlines.h:73
> > +    if (weakRef && *weakRef)
> 
> I don't think weakRef can ever be NULL here.
> 
> Instead of the *weakRef test, I think you either need a call to .get() or a call to operator!(). It's an error to use operator*() after a weak pointer has been collected.

Thanks.  Will fix and change to .get().

> > Source/JavaScriptCore/heap/Weak.h:160
> > +template<typename T> inline JSValue Weak<T>::referee()
> > +{
> > +    return m_impl ? m_impl->jsValue() : JSValue();
> > +}
> 
> Why do we need this function, when we already have operator*() and .get()?

It's a remnant from when I was still trying to understand this code.  I should be able to change it to use .get() and remove this.

> > Source/WebCore/bindings/js/JSEventListener.cpp:69
> > +    // JSEventListener may outlive its m_jsFunction. In this case, we will
> > +    // m_jsFunction to be 0.
> 
> "we will": seems like you meant something else here.
> 
> There's a lot of commentary about m_jsFunction here, but this function doesn't use that data member. Does any of this explain why the base class implementation of initializeJSFunction() should return 0?

There used to be an assertion here that was invalidated by the change to use weak refs.  This comment was meant to explain the circumstances behind why the assertion should not be there, but appears to be incomplete (my thought was probably interrupted in mid edit).  After making the change to check if m_wrapper is 0 at the top of JSEventListener::jsFunction(), the change is no longer necessary and can be reverted.

Thanks.
Comment 10 Mark Lam 2012-11-13 20:51:22 PST
Created attachment 174061 [details]
Fix.

All the issues that Geoff pointed out has been addressed.  The website rendering issue turned out to be because the Weak implementation did not have an operation==() implementation.  As a result, when we changed m_jsFunction to be a Weak ref, JSEventListener::operator==() (which was comparing m_jsFunctions) was getting the wrong result.  This is now fixed by providing an implementation of operator==(const Weak<T>&, const Weak<T>&).
Comment 11 Geoffrey Garen 2012-11-14 13:07:22 PST
Comment on attachment 174061 [details]
Fix.

r=me
Comment 12 Mark Lam 2012-11-14 17:03:59 PST
Fix landed in r134697: <http://trac.webkit.org/changeset/134697>.