Bug 209754 - Overrides of ActiveDOMObject::hasPendingActivity() should not need to query the base class's hasPendingActivity()
Summary: Overrides of ActiveDOMObject::hasPendingActivity() should not need to query t...
Status: RESOLVED FIXED
Alias: None
Product: WebKit
Classification: Unclassified
Component: Bindings (show other bugs)
Version: WebKit Nightly Build
Hardware: Unspecified Unspecified
: P2 Normal
Assignee: Chris Dumez
URL:
Keywords: InRadar
Depends on:
Blocks:
 
Reported: 2020-03-30 11:04 PDT by Chris Dumez
Modified: 2020-04-02 09:07 PDT (History)
27 users (show)

See Also:


Attachments
Patch (9.67 KB, patch)
2020-03-30 11:07 PDT, Chris Dumez
no flags Details | Formatted Diff | Diff
Patch (55.62 KB, patch)
2020-03-30 15:15 PDT, Chris Dumez
no flags Details | Formatted Diff | Diff
Patch (57.16 KB, patch)
2020-03-30 16:14 PDT, Chris Dumez
no flags Details | Formatted Diff | Diff
Patch (57.16 KB, patch)
2020-03-30 16:37 PDT, Chris Dumez
no flags Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
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) { }