Bug 209754

Summary: Overrides of ActiveDOMObject::hasPendingActivity() should not need to query the base class's hasPendingActivity()
Product: WebKit Reporter: Chris Dumez <cdumez>
Component: BindingsAssignee: Chris Dumez <cdumez>
Status: RESOLVED FIXED    
Severity: Normal CC: achristensen, alecflett, beidson, calvaris, cdumez, darin, dino, eric.carlson, esprehn+autocc, ews-watchlist, ggaren, glenn, graouts, gyuyoung.kim, hta, jer.noble, jsbell, kangil.han, kondapallykalyan, macpherson, menard, philipj, rniwa, sergio, sihui_liu, tommyw, webkit-bug-importer
Priority: P2 Keywords: InRadar
Version: WebKit Nightly Build   
Hardware: Unspecified   
OS: Unspecified   
See Also: https://bugs.webkit.org/show_bug.cgi?id=209886
Attachments:
Description Flags
Patch
none
Patch
none
Patch
none
Patch none

Description Chris Dumez 2020-03-30 11:04:26 PDT
hasPendingActivity() overrides should make sure to query ActiveDOMObject::hasPendingActivity(). It is important because code may be using makePendingActivity().
Comment 1 Ryosuke Niwa 2020-03-30 11:07:25 PDT
Maybe we can add an assert? Convert all call sites to call something else and make sure ActiveDOMObject::hasPendingActivity() is called in that function?
Comment 2 Chris Dumez 2020-03-30 11:07:30 PDT
Created attachment 394935 [details]
Patch
Comment 3 Darin Adler 2020-03-30 13:30:33 PDT
Comment on attachment 394935 [details]
Patch

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

How did you decide when to use || and when to use a separate if instead? What about when to do base class first and when to do the subclass first?

Could also consider a different design where the code calling hasPendingActivity deals with the rules currently followed by ActiveDOMObject::hasPendingActivity instead of requiring calling through to the base class to make this mistake impossible.

> Source/WebCore/dom/MessagePort.cpp:320
> +    if (ActiveDOMObject::hasPendingActivity())
> +        return true;

A little strange to do this after checking m_closed. Probably fine but I don’t really understand this fully.

> Source/WebCore/html/canvas/WebGLRenderingContextBase.cpp:5558
>  bool WebGLRenderingContextBase::hasPendingActivity() const
>  {
> -    return false;
> +    return ActiveDOMObject::hasPendingActivity();
>  }

Why does this override exist at all? I think we should remove it instead.
Comment 4 Chris Dumez 2020-03-30 13:37:32 PDT
(In reply to Darin Adler from comment #3)
> Comment on attachment 394935 [details]
> Patch
> 
> View in context:
> https://bugs.webkit.org/attachment.cgi?id=394935&action=review
> 
> How did you decide when to use || and when to use a separate if instead?

Sometimes the return statement already looked so complicated that I felt an early if check & return looked clearer. This was just my own personal judgement.


> What about when to do base class first and when to do the subclass first?

Thinking about this more, I think we should always return true if the base class method returns true. See explanation below.

> 
> Could also consider a different design where the code calling
> hasPendingActivity deals with the rules currently followed by
> ActiveDOMObject::hasPendingActivity instead of requiring calling through to
> the base class to make this mistake impossible.

Hmm. This would indeed be a better design. I will give this a shot and if I come up with something good, will upload it for review instead of this.

> 
> > Source/WebCore/dom/MessagePort.cpp:320
> > +    if (ActiveDOMObject::hasPendingActivity())
> > +        return true;
> 
> A little strange to do this after checking m_closed. Probably fine but I
> don’t really understand this fully.

Hmm. I is probably safer to check this first. You could imagine closing a port, and the action of closing the port scheduling an event to be dispatched asynchronously (using makePendingActivity()).
If this happened, you'd want the wrapper to stay alive long enough to dispatch the event. Will fix.

> 
> > Source/WebCore/html/canvas/WebGLRenderingContextBase.cpp:5558
> >  bool WebGLRenderingContextBase::hasPendingActivity() const
> >  {
> > -    return false;
> > +    return ActiveDOMObject::hasPendingActivity();
> >  }
> 
> Why does this override exist at all? I think we should remove it instead.

Fair point. Will remove.
Comment 5 Ryosuke Niwa 2020-03-30 14:52:12 PDT
Can we also add an assertion?
Comment 6 Chris Dumez 2020-03-30 14:54:12 PDT
(In reply to Ryosuke Niwa from comment #5)
> Can we also add an assertion?

With Darin's proposal, I don't think there will be any need for an assertion. I am working on that patch.
Comment 7 Ryosuke Niwa 2020-03-30 15:05:41 PDT
(In reply to Chris Dumez from comment #6)
> (In reply to Ryosuke Niwa from comment #5)
> > Can we also add an assertion?
> 
> With Darin's proposal, I don't think there will be any need for an
> assertion. I am working on that patch.

Ok.
Comment 8 Chris Dumez 2020-03-30 15:15:06 PDT
Created attachment 394973 [details]
Patch
Comment 9 Ryosuke Niwa 2020-03-30 16:08:05 PDT
Comment on attachment 394973 [details]
Patch

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

> Source/WebCore/ChangeLog:12
> +        To address the issue, ActiveDOMObject::hasPendingActivity() is no longer virtual and
> +        checks both m_pendingActivityCount and a virtual virtualHasPendingActivity() function.

It's confusing that m_pendingActivityCount can be 0 and ActiveDOMObject::hasPendingActivity() can still return true.
How about calling the former m_pendingActivity*Token*Count and this subclass-specific pending activity concept hasInternalPendingActivity.
Then we can rename ActiveDOMObject::makePendingActivity to ActiveDOMObject::makePendingActivityToken as well.
Comment 10 Chris Dumez 2020-03-30 16:11:36 PDT
(In reply to Ryosuke Niwa from comment #9)
> Comment on attachment 394973 [details]
> Patch
> 
> View in context:
> https://bugs.webkit.org/attachment.cgi?id=394973&action=review
> 
> > Source/WebCore/ChangeLog:12
> > +        To address the issue, ActiveDOMObject::hasPendingActivity() is no longer virtual and
> > +        checks both m_pendingActivityCount and a virtual virtualHasPendingActivity() function.
> 
> It's confusing that m_pendingActivityCount can be 0 and
> ActiveDOMObject::hasPendingActivity() can still return true.

I buy that but this has always been the case.

> How about calling the former m_pendingActivity*Token*Count and this
> subclass-specific pending activity concept hasInternalPendingActivity.
> Then we can rename ActiveDOMObject::makePendingActivity to
> ActiveDOMObject::makePendingActivityToken as well.

Not a big fan of the naming suggested but I agree we can likely make things a bit clearer through renaming. I need to give it more thought to see if I can come up with better naming.
Comment 11 Chris Dumez 2020-03-30 16:14:01 PDT
Created attachment 394980 [details]
Patch
Comment 12 Darin Adler 2020-03-30 16:14:19 PDT
Comment on attachment 394973 [details]
Patch

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

A little clunky to have virtual in the name, but I like it!

> Source/WebCore/dom/ActiveDOMObject.h:76
> +    // FIXME: Drop this method.

Nitpick: "function" instead of "method"?

> Source/WebCore/dom/ActiveDOMObject.h:85
> +    // FIXME: Drop this method.

Ditto.
Comment 13 Chris Dumez 2020-03-30 16:16:00 PDT
(In reply to Darin Adler from comment #12)
> Comment on attachment 394973 [details]
> Patch
> 
> View in context:
> https://bugs.webkit.org/attachment.cgi?id=394973&action=review
> 
> A little clunky to have virtual in the name, but I like it!
> 
> > Source/WebCore/dom/ActiveDOMObject.h:76
> > +    // FIXME: Drop this method.
> 
> Nitpick: "function" instead of "method"?
> 
> > Source/WebCore/dom/ActiveDOMObject.h:85
> > +    // FIXME: Drop this method.
> 
> Ditto.

Why isn't is a method? It can operate on data members.
Comment 14 Chris Dumez 2020-03-30 16:16:54 PDT
Comment on attachment 394980 [details]
Patch

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

> Source/WebCore/dom/ActiveDOMObject.h:153
> +    unsigned m_pendingActivityInstancesCount { 0 };

I renamed this to address the confusion that Ryosuke was talking about.
Comment 15 Geoffrey Garen 2020-03-30 16:30:18 PDT
I wonder if ActiveDOMObject::hasPendingActivity should be non-virtual, checking m_pendingActivityCount and then calling out to a virtual hasPendingActivityVirtual() or something like that. That would eliminate this class of bugs.
Comment 16 Geoffrey Garen 2020-03-30 16:30:43 PDT
(In reply to Geoffrey Garen from comment #15)
> I wonder if ActiveDOMObject::hasPendingActivity should be non-virtual,
> checking m_pendingActivityCount and then calling out to a virtual
> hasPendingActivityVirtual() or something like that. That would eliminate
> this class of bugs.

Oh, LOL, that's what you did.
Comment 17 Darin Adler 2020-03-30 16:31:00 PDT
(In reply to Chris Dumez from comment #13)
> Why isn't is a method? It can operate on data members.

C++ has member functions.

Objective-C has methods.

Obviously you can use other terminology besides what is used to document the language. If you want to use "method" as a term of art for non-const member functions in C++ that is OK, I guess.

But I personally like using the actual terms from the language's own specification to avoid ambiguity. I thought this was consensus but maybe not.
Comment 18 Chris Dumez 2020-03-30 16:31:19 PDT
(In reply to Geoffrey Garen from comment #15)
> I wonder if ActiveDOMObject::hasPendingActivity should be non-virtual,
> checking m_pendingActivityCount and then calling out to a virtual
> hasPendingActivityVirtual() or something like that. That would eliminate
> this class of bugs.

Isn't that exactly what my patch does? :) except that I called the method virtualHasPendingActivity() and you called it hasPendingActivityVirtual().
Comment 19 Geoffrey Garen 2020-03-30 16:32:54 PDT
Comment on attachment 394980 [details]
Patch

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

r=me

>> Source/WebCore/dom/ActiveDOMObject.h:153
>> +    unsigned m_pendingActivityInstancesCount { 0 };
> 
> I renamed this to address the confusion that Ryosuke was talking about.

I think we usually say "m_pendingActivityInstanceCount", without the plural.
Comment 20 Chris Dumez 2020-03-30 16:37:16 PDT
Created attachment 394984 [details]
Patch
Comment 21 Chris Dumez 2020-03-30 16:38:06 PDT
(In reply to Geoffrey Garen from comment #19)
> Comment on attachment 394980 [details]
> Patch
> 
> View in context:
> https://bugs.webkit.org/attachment.cgi?id=394980&action=review
> 
> r=me
> 
> >> Source/WebCore/dom/ActiveDOMObject.h:153
> >> +    unsigned m_pendingActivityInstancesCount { 0 };
> > 
> > I renamed this to address the confusion that Ryosuke was talking about.
> 
> I think we usually say "m_pendingActivityInstanceCount", without the plural.

Fixed.
Comment 22 Chris Dumez 2020-03-30 16:39:53 PDT
(In reply to Darin Adler from comment #17)
> (In reply to Chris Dumez from comment #13)
> > Why isn't is a method? It can operate on data members.
> 
> C++ has member functions.

Oh OK. I have have calling these methods all these years :) Fixed.
Comment 23 Ryosuke Niwa 2020-03-30 16:58:33 PDT
Comment on attachment 394984 [details]
Patch

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

> Source/WebCore/ChangeLog:12
> +        checks both m_pendingActivityCount and a virtual virtualHasPendingActivity() function.

Can we call virtualHasPendingActivity hasPendingActivityInternal instead?
That's usually what we call these internal / override-only functions.
Comment 24 EWS 2020-03-30 17:25:31 PDT
Committed r259252: <https://trac.webkit.org/changeset/259252>

All reviewed patches have been landed. Closing bug and clearing flags on attachment 394984 [details].
Comment 25 Radar WebKit Bug Importer 2020-03-30 17:26:17 PDT
<rdar://problem/61081753>
Comment 26 Geoffrey Garen 2020-03-30 20:17:27 PDT
> Can we call virtualHasPendingActivity hasPendingActivityInternal instead?
> That's usually what we call these internal / override-only functions.

I'm not familiar with the use of Internal in this way. Can you give an example?

I see "...Impl" used by RenderFlexibleBox's isFlexibleBoxImpl. 

I see "virtual..." used by InlineBox's logicalHeight.

"Internal" strikes me as surprising because usually "internal" usually means something that others can't poke at. But this function facilitates overrides by subclasses.
Comment 27 Ryosuke Niwa 2020-04-01 15:58:30 PDT
(In reply to Geoffrey Garen from comment #26)
> > Can we call virtualHasPendingActivity hasPendingActivityInternal instead?
> > That's usually what we call these internal / override-only functions.
> 
> I'm not familiar with the use of Internal in this way. Can you give an
> example?
> 
> I see "...Impl" used by RenderFlexibleBox's isFlexibleBoxImpl. 
> 
> I see "virtual..." used by InlineBox's logicalHeight.
> 
> "Internal" strikes me as surprising because usually "internal" usually means
> something that others can't poke at. But this function facilitates overrides
> by subclasses.

I don't think it's strange. It communicates that it's not a function that can be called externally. It's internal to the class and its subclasses, not a part of a public API.

e.g.
Node
    virtual Ref<Node> cloneNodeInternal(Document&, CloningOperation) = 0;

CSSStyleDeclaration
    virtual RefPtr<CSSValue> getPropertyCSSValueInternal(CSSPropertyID) = 0;
    virtual String getPropertyValueInternal(CSSPropertyID) = 0;
    virtual ExceptionOr<bool> setPropertyInternal(CSSPropertyID, const String& value, bool important) = 0;

GraphicsLayer
    virtual void setOpacityInternal(float) { }