Bug 130653

Summary: Remove code in HTMLObjectElement attribute parsing that forces style resolution and layout
Product: WebKit Reporter: Darin Adler <darin>
Component: Page LoadingAssignee: Darin Adler <darin>
Status: RESOLVED FIXED    
Severity: Normal CC: ap, beidson, buildbot, cdumez, commit-queue, darin, dbates, dewei_zhu, dino, eric.carlson, esprehn+autocc, gyuyoung.kim, japhet, jlewis3, kangil.han, kling, koivisto, rniwa, sam, slewis, webkit-bug-importer
Priority: P2 Keywords: InRadar
Version: 528+ (Nightly build)   
Hardware: All   
OS: All   
See Also: https://bugs.webkit.org/show_bug.cgi?id=126169
https://bugs.webkit.org/show_bug.cgi?id=174988
https://bugs.webkit.org/show_bug.cgi?id=175107
https://bugs.webkit.org/show_bug.cgi?id=175270
https://bugs.webkit.org/show_bug.cgi?id=175329
https://bugs.webkit.org/show_bug.cgi?id=175143
https://bugs.webkit.org/show_bug.cgi?id=176174
Attachments:
Description Flags
Patch
none
Patch
none
Patch
none
Patch
none
Archive of layout-test-results from ews102 for mac-yosemite
none
Archive of layout-test-results from ews113 for mac-yosemite
none
Archive of layout-test-results from ews106 for mac-yosemite-wk2
none
Archive of layout-test-results from ews126 for ios-simulator-wk2
none
Patch
none
Archive of layout-test-results from ews100 for mac-elcapitan
none
Archive of layout-test-results from ews121 for ios-simulator-wk2
none
Archive of layout-test-results from ews112 for mac-elcapitan
none
Archive of layout-test-results from ews106 for mac-elcapitan-wk2
none
Patch
none
Archive of layout-test-results from ews121 for ios-simulator-wk2
none
Archive of layout-test-results from ews115 for mac-elcapitan
none
Archive of layout-test-results from ews101 for mac-elcapitan
none
Archive of layout-test-results from ews104 for mac-elcapitan-wk2
none
Patch
none
Archive of layout-test-results from ews117 for mac-elcapitan
none
Archive of layout-test-results from ews125 for ios-simulator-wk2
none
Patch
none
Archive of layout-test-results from ews105 for mac-elcapitan-wk2
none
Archive of layout-test-results from ews121 for ios-simulator-wk2
none
Patch
buildbot: commit-queue-
Archive of layout-test-results from ews107 for mac-elcapitan-wk2
none
Patch
none
Patch
koivisto: review+, buildbot: commit-queue-
Archive of layout-test-results from ews101 for mac-elcapitan none

Description Darin Adler 2014-03-23 12:19:16 PDT Comment hidden (obsolete)
Comment 1 Darin Adler 2014-03-23 12:43:27 PDT Comment hidden (obsolete)
Comment 2 WebKit Commit Bot 2014-03-23 12:45:48 PDT Comment hidden (obsolete)
Comment 3 Darin Adler 2014-03-23 12:46:37 PDT Comment hidden (obsolete)
Comment 4 Darin Adler 2014-03-23 12:57:11 PDT Comment hidden (obsolete)
Comment 5 Darin Adler 2014-03-23 13:37:35 PDT Comment hidden (obsolete)
Comment 6 Antti Koivisto 2014-03-23 13:39:16 PDT Comment hidden (obsolete)
Comment 7 WebKit Commit Bot 2014-03-23 13:40:01 PDT Comment hidden (obsolete)
Comment 8 Alexey Proskuryakov 2014-03-30 01:39:18 PDT Comment hidden (obsolete)
Comment 9 Darin Adler 2014-03-31 09:44:39 PDT Comment hidden (obsolete)
Comment 10 Stephanie Lewis 2014-04-02 16:59:20 PDT
Rolled out in http://trac.webkit.org/changeset/166680 due to issues with the PLT <rdar://problem/16481284> PLT stops loading on news.google.com
Comment 11 Darin Adler 2014-04-03 09:21:06 PDT Comment hidden (obsolete)
Comment 12 Darin Adler 2014-04-06 13:28:21 PDT Comment hidden (obsolete)
Comment 13 Darin Adler 2014-04-06 14:12:05 PDT Comment hidden (obsolete)
Comment 14 WebKit Commit Bot 2014-04-06 14:14:09 PDT Comment hidden (obsolete)
Comment 15 Alexey Proskuryakov 2015-01-04 12:07:04 PST Comment hidden (obsolete)
Comment 16 Darin Adler 2016-12-11 08:34:31 PST Comment hidden (obsolete)
Comment 17 Darin Adler 2016-12-11 08:36:42 PST Comment hidden (obsolete)
Comment 18 Antti Koivisto 2016-12-11 09:14:43 PST Comment hidden (obsolete)
Comment 19 Build Bot 2016-12-11 09:15:48 PST Comment hidden (obsolete)
Comment 20 Build Bot 2016-12-11 09:15:53 PST Comment hidden (obsolete)
Comment 21 Build Bot 2016-12-11 09:17:49 PST Comment hidden (obsolete)
Comment 22 Build Bot 2016-12-11 09:17:53 PST Comment hidden (obsolete)
Comment 23 Build Bot 2016-12-11 09:45:38 PST Comment hidden (obsolete)
Comment 24 Build Bot 2016-12-11 09:45:43 PST Comment hidden (obsolete)
Comment 25 Build Bot 2016-12-11 09:56:45 PST Comment hidden (obsolete)
Comment 26 Build Bot 2016-12-11 09:56:49 PST Comment hidden (obsolete)
Comment 27 Darin Adler 2016-12-11 10:10:01 PST Comment hidden (obsolete)
Comment 28 Andreas Kling 2017-01-29 03:07:13 PST
If you fix this bug and get rid of its companion updateStyleIfNeeded() in Document::finishedParsing(), you could get a ~3x speedup on PerformanceTests/Parser/html-parser.html

Then we'd really be cooking :)
Comment 29 Darin Adler 2017-07-24 09:06:53 PDT
Committed r219824: <http://trac.webkit.org/changeset/219824>
Comment 30 Andreas Kling 2017-07-24 13:52:19 PDT
Looks like the test failures are caused by DRT/WTR prematurely dumping the render tree.

It's a long chain of calls, but the dumping is essentially driven by FrameLoaderClient::dispatchDidFinishLoad(), invoked by FrameLoader::checkLoadCompleteForThisFrame().

This gets called basically every time any resource finished loading or has an error, and has no protection against the delay-load-event counter on Document. FrameLoader decides that everything it cares about is finished, and so sounds the alarm.

Simply adding this to the top of FrameLoader::checkLoadCompletedForThisFrame() should fix the failing tests:

    if (m_frame.document()->isDelayingLoadEvent())
        return;

But.. if we look at the start of FrameLoader::checkCompleted(), this is but one of many checks that we might care about in checkLoadCompleteForThisFrame(), too.
Comment 31 Darin Adler 2017-07-24 16:02:42 PDT
Wow, thanks! I will look into that.
Comment 32 Darin Adler 2017-07-25 19:10:06 PDT Comment hidden (obsolete)
Comment 33 Build Bot 2017-07-25 20:50:23 PDT Comment hidden (obsolete)
Comment 34 Build Bot 2017-07-25 20:50:24 PDT Comment hidden (obsolete)
Comment 35 Build Bot 2017-07-25 21:04:33 PDT Comment hidden (obsolete)
Comment 36 Build Bot 2017-07-25 21:04:38 PDT Comment hidden (obsolete)
Comment 37 Build Bot 2017-07-25 21:05:41 PDT Comment hidden (obsolete)
Comment 38 Build Bot 2017-07-25 21:05:42 PDT Comment hidden (obsolete)
Comment 39 Build Bot 2017-07-25 21:09:13 PDT Comment hidden (obsolete)
Comment 40 Build Bot 2017-07-25 21:09:15 PDT Comment hidden (obsolete)
Comment 41 Darin Adler 2017-07-26 08:51:29 PDT
For those of you following along (I’m looking at you Mr. Kling), now that I added the additional check in FrameLoader::checkLoadCompletedForThisFrame, we now have a few different categories of failing tests:

Regressions: Unexpected timeouts
  media/track/track-in-band-duplicate-tracks-when-source-changes.html [ Timeout ]
  webgl/1.0.2/conformance/context/context-attributes-alpha-depth-stencil-antialias.html [ Timeout ]
  webgl/1.0.2/conformance/extensions/oes-texture-float-with-image-data.html [ Timeout ]
  webgl/1.0.2/conformance/textures/copy-tex-image-and-sub-image-2d.html [ Timeout ]
  webgl/1.0.2/conformance/textures/tex-image-and-sub-image-2d-with-image-data-rgb565.html [ Timeout ]
  webgl/1.0.2/conformance/textures/tex-image-and-sub-image-2d-with-image-data-rgba4444.html [ Timeout ]
  webgl/1.0.2/conformance/textures/tex-image-and-sub-image-2d-with-image-data-rgba5551.html [ Timeout ]
  webgl/1.0.2/conformance/textures/tex-image-and-sub-image-2d-with-image-data.html [ Timeout ]
  webgl/1.0.3/conformance/extensions/oes-texture-float-linear.html [ Timeout ]
  webgl/1.0.3/conformance/extensions/oes-texture-half-float-with-image-data.html [ Timeout ]

^^^ Without actually studying anything here and diagnosing, here is my guess: Given that my last change was to make FrameLoader::checkLoadCompletedForThisFrame decide the load is not completed in some cases, it’s likely that we need to pair that with a change that guarantees FrameLoader::checkLoadCompletedForThisFrame is called once the document is no longer delaying the load event.

Regressions: Unexpected text-only failures
  webarchive/loading/video-in-webarchive.html [ Failure ]

^^^ The issue here seems to different ordering of "load completed" callbacks; to me it seems likely the new behavior is correct and my patch just needs to include new expected results for this test.

Other failures seem likely unrelated to the patch; not sure what to do about those. Need some more "gardening" it seems.
Comment 42 Darin Adler 2017-07-26 09:17:07 PDT
(In reply to Darin Adler from comment #41)
> Given that my last change was to make
> FrameLoader::checkLoadCompletedForThisFrame decide the load is not completed
> in some cases, it’s likely that we need to pair that with a change that
> guarantees FrameLoader::checkLoadCompletedForThisFrame is called once the
> document is no longer delaying the load event.

Document::loadEventDelayTimerFired does call FrameLoader::checkLoadComplete, which calls FrameLoader::checkLoadCompleteForThisFrame on all the frames, not just the one with the document.

Some possible (unlikely) holes in this:

1) If the document's frame get set to some other frame or to null, we might never call FrameLoader::checkLoadComplete.

2) If the frame's page gets set to null at just the wrong time, FrameLoader::checkLoadComplete might decide not to do anything.

Given that my above guess doesn’t seem like it can be exactly right. Need to debug probably rather than just studying the code.

Another possibility is that isDelayingLoadEvent should block when in FrameStateCommittedPage and FrameStateComplete but not FrameStateProvisional. Unlikely to actually be the issue in this case, but it seems in inappropriate for isDelayingLoadEvent to prevent a frame from moving from provisional to committed state.
Comment 43 Andreas Kling 2017-07-26 16:21:44 PDT
>I’m looking at you Mr. Kling

Oh jeez, guess I better hop to it!

>2) If the frame's page gets set to null at just the wrong time, FrameLoader::checkLoadComplete might decide not to do anything.

This is the correct guess! Some frames are now unloaded before they get a chance to fire a load event in their documents, and so the Document::frame() is null when we get to decrementLoadEventDelayCount().

Here's a backtrace for Document::detachFromFrame() when running webgl/1.0.3/conformance/extensions/oes-texture-float-linear.html

WebCore::Document::detachFromFrame() <--
WebCore::Document::prepareForDestruction()
WebCore::Frame::setView(WTF::RefPtr<WebCore::FrameView>&&)
WebCore::FrameLoader::closeAndRemoveChild(WebCore::Frame&)
WebCore::FrameLoader::detachFromParent()
0x10ffab7c6 WebCore::FrameLoader::frameDetached()
WebCore::HTMLFrameOwnerElement::disconnectContentFrame()
WebCore::disconnectSubframes(WebCore::ContainerNode&, WebCore::SubframeDisconnectPolicy)
WebCore::willRemoveChildren(WebCore::ContainerNode&)
WebCore::ContainerNode::removeChildren()
WebCore::replaceChildrenWithFragment(WebCore::ContainerNode&, WTF::Ref<WebCore::DocumentFragment>&&)
WebCore::Element::setInnerHTML(WTF::String const&)
WebCore::setJSElementInnerHTML(JSC::ExecState*, long long, long long)
JSC::callCustomSetter(JSC::ExecState*, JSC::JSValue, bool, JSC::JSObject*, JSC::JSValue, JSC::JSValue)
JSC::JSObject::putInlineSlow(JSC::ExecState*, JSC::PropertyName, JSC::JSValue, JSC::PutPropertySlot&)
llint_slow_path_put_by_id
llint_entry
vmEntryToJavaScript
JSC::JITCode::execute(JSC::VM*, JSC::ProtoCallFrame*)
JSC::Interpreter::executeProgram(JSC::SourceCode const&, JSC::ExecState*, JSC::JSObject*)
JSC::evaluate(JSC::ExecState*, JSC::SourceCode const&, JSC::JSValue, WTF::NakedPtr<JSC::Exception>&)
WebCore::ScriptController::evaluateInWorld(WebCore::ScriptSourceCode const&, WebCore::DOMWrapperWorld&, WebCore::ExceptionDetails*)
WebCore::ScriptElement::executeClassicScript(WebCore::ScriptSourceCode const&)
WebCore::LoadableClassicScript::execute(WebCore::ScriptElement&)
WebCore::ScriptElement::executeScriptAndDispatchEvent(WebCore::LoadableScript&)
WebCore::ScriptRunner::timerFired()
WebCore::ThreadTimers::sharedTimerFiredInternal()
WebCore::timerFired(__CFRunLoopTimer*, void*)

I think what happens is that a <script> is inserted somewhere via modifying innerHTML. ScriptRunner sets up a zero-timer and executes the script in the callback.
At the end of ScriptRunner::timerFired(), we call decrementLoadEventDelayCount(), but by then it's too late, the script made the document detach from the frame. :/
Comment 44 Andreas Kling 2017-07-26 16:36:23 PDT
Something is off here though, looking at the webgl test harness code:
LayoutTests/webgl/1.0.3/resources/webkit-webgl-test-harness.js

It appears to me that this test uses testRunner.waitUntilDone() / testRunner.notifyDone() and so shouldn't depend on the whimsy of our load event.

I think maybe it's something else that's broken here.
Comment 45 Darin Adler 2017-07-26 21:07:19 PDT
The problem is caused by the increment/decrementLoadEventDelayCount in ScriptRunner. By the time decrementLoadEventDelayCount is called, the document's frame is already null.
Comment 46 Darin Adler 2017-07-26 21:20:32 PDT
That’s because the script overwrites the frame’s content with a pass/fail result.

I have a fix, but it’s pretty peculiar.
Comment 47 Darin Adler 2017-07-26 21:25:22 PDT Comment hidden (obsolete)
Comment 48 Build Bot 2017-07-26 23:01:35 PDT Comment hidden (obsolete)
Comment 49 Build Bot 2017-07-26 23:01:37 PDT Comment hidden (obsolete)
Comment 50 Build Bot 2017-07-26 23:06:35 PDT Comment hidden (obsolete)
Comment 51 Build Bot 2017-07-26 23:06:37 PDT Comment hidden (obsolete)
Comment 52 Build Bot 2017-07-27 00:35:16 PDT Comment hidden (obsolete)
Comment 53 Build Bot 2017-07-27 00:35:17 PDT Comment hidden (obsolete)
Comment 54 Build Bot 2017-07-27 00:41:34 PDT Comment hidden (obsolete)
Comment 55 Build Bot 2017-07-27 00:41:36 PDT Comment hidden (obsolete)
Comment 56 Darin Adler 2017-07-29 19:11:50 PDT Comment hidden (obsolete)
Comment 57 Darin Adler 2017-07-29 19:19:23 PDT
To fix one of the failing tests, I had to make a change to HTMLMediaElement. I made it after reading the HTML specification text; the fix makes us match the specification. But I do want some media loading experts to look, not so much because I doubt the correctness of the change in the patch, but because the FIXME I am adding points to some other similar changes we might want to make.
Comment 58 Darin Adler 2017-07-29 19:24:00 PDT
Maybe we should add some new tests for this media loading fix.
Comment 59 Build Bot 2017-07-29 20:47:16 PDT Comment hidden (obsolete)
Comment 60 Build Bot 2017-07-29 20:47:18 PDT Comment hidden (obsolete)
Comment 61 Build Bot 2017-07-29 20:53:06 PDT Comment hidden (obsolete)
Comment 62 Build Bot 2017-07-29 20:53:08 PDT Comment hidden (obsolete)
Comment 63 Darin Adler 2017-07-30 05:37:18 PDT Comment hidden (obsolete)
Comment 64 Build Bot 2017-07-30 06:41:34 PDT Comment hidden (obsolete)
Comment 65 Build Bot 2017-07-30 06:41:36 PDT Comment hidden (obsolete)
Comment 66 Build Bot 2017-07-30 07:17:23 PDT Comment hidden (obsolete)
Comment 67 Build Bot 2017-07-30 07:17:25 PDT Comment hidden (obsolete)
Comment 68 Darin Adler 2017-07-30 10:07:49 PDT Comment hidden (obsolete)
Comment 69 Build Bot 2017-07-30 10:50:17 PDT Comment hidden (obsolete)
Comment 70 Build Bot 2017-07-30 10:50:19 PDT Comment hidden (obsolete)
Comment 71 Darin Adler 2017-07-30 12:07:58 PDT Comment hidden (obsolete)
Comment 72 Darin Adler 2017-07-30 13:32:49 PDT
After years of trying and lots of craziness, looks like this is ready for review again.

Antti reviewed the original applet/embed/frame/iframe/object element loading change, and there is a little more to the patch now because of bugs I had to fix in five or six regression tests, in a small part of the load event logic in document, document loader, and frame loader, in the "when to dump" logic in WebKitTestRunner, and in the load event delay machinery in one small place in the media element.

But patch still didn’t get giant. And this one is likely to pass all the EWS tests.
Comment 73 Darin Adler 2017-07-30 13:33:35 PDT
Created attachment 316750 [details]
Patch
Comment 74 Darin Adler 2017-07-30 13:45:34 PDT
Comment on attachment 316750 [details]
Patch

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

Looks like the change log is missing quite a few of the changes. I’ll likely upload a new patch later with a better change log.

> Source/WebCore/html/HTMLPlugInImageElement.cpp:295
> +        document().incrementLoadEventDelayCount();

Style-wise should probably be newDocument rather than document(), although I don’t see how that can matter given we assert they are the same. My patch predated the addition of the newDocument argument.
Comment 75 Antti Koivisto 2017-07-30 13:51:01 PDT
Comment on attachment 316750 [details]
Patch

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

r=me, nice

> Source/WebCore/dom/Document.cpp:6228
> +    // FIXME: Should the call to FrameLoader::checkLoadComplete be moved inside Document::checkCompleted?
> +    // FIXME: Should this also call DocumentLoader::checkLoadComplete?
> +    // FIXME: Not obvious why checkCompleted needs to go first. The order these are called is
> +    // visible to WebKit clients, but it's more like a race than a well-defined relationship.

This logic should be cleaned up at some point. It feels as if the original intent of the differnt check/loadCompleted/isLoading functions has been lost at some point and they are now being called without rhyme or reason.
Comment 76 Darin Adler 2017-07-30 14:09:22 PDT
(In reply to Antti Koivisto from comment #75)
> This logic should be cleaned up at some point. It feels as if the original
> intent of the differnt check/loadCompleted/isLoading functions has been lost
> at some point and they are now being called without rhyme or reason.

My thought exactly. Basically there is one concept here from KHTMLPart (checkComplete) and one from the Objective-C WebKit framework (checkLoadComplete). We never reconciled the two when we put them together in the same framework.
Comment 77 Darin Adler 2017-07-30 14:12:14 PDT
I have this ready to land now with a better ChangeLog. Will land after I confirm that the EWS succeeds.
Comment 78 Build Bot 2017-07-30 14:41:45 PDT
Comment on attachment 316750 [details]
Patch

Attachment 316750 [details] did not pass mac-ews (mac):
Output: http://webkit-queues.webkit.org/results/4225801

New failing tests:
fast/images/large-size-image-crash.html
Comment 79 Build Bot 2017-07-30 14:41:46 PDT
Created attachment 316751 [details]
Archive of layout-test-results from ews101 for mac-elcapitan

The attached test failures were seen while running run-webkit-tests on the mac-ews.
Bot: ews101  Port: mac-elcapitan  Platform: Mac OS X 10.11.6
Comment 80 Darin Adler 2017-07-30 14:44:04 PDT
Committed r220052: <http://trac.webkit.org/changeset/220052>
Comment 81 Andreas Kling 2017-07-30 23:56:02 PDT
Great work! 32% speedup on PerformanceTests/Parser/HTML5-8266-FullRender.html :)

https://perf.webkit.org/v3/#/charts?since=1500879248694&zoom=(1501396022165.3025-1501482250189.8582)&paneList=((18-311-null-null-(5-2.5-500)))
Comment 82 Sam Weinig 2017-07-31 07:52:08 PDT
Wow!
Comment 83 dewei_zhu 2017-07-31 12:12:03 PDT
Great! 1-3% page load progression is observed.
Comment 84 Alexey Proskuryakov 2017-07-31 13:17:37 PDT
This caused bug 174988. I'm somewhat hesitant to roll back right away, but I may have to, as there quite a few new failures over the weekend, and we need to make bots green soon.
Comment 85 Darin Adler 2017-07-31 13:23:11 PDT
I suggest skipping the test to make the bots green. I absolutely will fix this bug and reenable the test, and I think a rollout is unnecessary.
Comment 86 Matt Lewis 2017-08-02 19:00:21 PDT
This caused bug: https://bugs.webkit.org/show_bug.cgi?id=175107
Comment 87 Alexey Proskuryakov 2017-08-10 13:57:21 PDT
Another regression: bug 175329.
Comment 88 Radar WebKit Bug Importer 2017-08-31 12:07:15 PDT
<rdar://problem/34191442>