Changeset 205218 in webkit


Ignore:
Timestamp:
Aug 30, 2016 7:37:12 PM (8 years ago)
Author:
Yusuke Suzuki
Message:

Make PendingScript as ref-counted
https://bugs.webkit.org/show_bug.cgi?id=161350

Reviewed by Ryosuke Niwa.

Currently, while PendingScript is copyable, PendingScript is also CachedResourceClient.
So when copying this, the client registration is done in PendingScript's operator= etc.
However, this copying functionality is not effectively used.
In this patch, we change this PendingScript to ref-counted class and make it noncopyable.
This change makes things simple (dropping this copying functionality), and drops unnecessary
addClient / removeClient calls. And we also simplify PendingScript class. Since we can offer
all the members at the construction time, we do not need any setters like setCachedScript,
setElement etc. This prevents us from accidentally generating the half-baked pending script.

Furthermore, by changing PendingScript noncopyable & ref-counted, we easily make it
observable. In this patch, we add PendingScriptClient to receive the notification from
PendingScript. Previously, we directly used CachedScript in PendingScript to receive the
notification. When introducing ScriptModuleGraph and making this PendingScript the container
of the both CachedScript and ScriptModuleGraph, hiding the raw CachedScript operations is
useful.

No behavior changes.

  • WebCore.xcodeproj/project.pbxproj:
  • dom/PendingScript.cpp:

(WebCore::PendingScript::create): These factory functions take all the information needed
to construct the PendingScript. So the setters of PendingScript are dropped. This is better
since we now do not expose any half-baked pending script accidentally.
(WebCore::PendingScript::PendingScript):
(WebCore::PendingScript::~PendingScript):
(WebCore::PendingScript::notifyClientFinished):
(WebCore::PendingScript::notifyFinished):
(WebCore::PendingScript::isLoaded): When introducing ScriptModuleGraph, this will query to
either CachedScript or ScriptModuleGraph. PendingScript will become the container for the
both types.
(WebCore::PendingScript::setClient):
(WebCore::PendingScript::clearClient): PendingScript is now observable by PendingScriptClient.
This avoids touching CachedScript in PendingScript directly. That is good when we introduce
ScriptModuleGraph and make PendingScript the container of the both CachedScript and ScriptModuleGraph.
(WebCore::PendingScript::releaseElementAndClear): Deleted. Previously, PendingScript is not ref-counted.
So when we would like to say "this pending script is empty", we used the pending script with
m_element = nullptr. This releaseElementAndClear cleared this m_element and made the pending
script empty. Now, we use RefPtr<PendingScript> and empty one is just represented by the nullptr.
This function is no longer necessary. Dropped.
(WebCore::PendingScript::setCachedScript): Deleted. The fields are set in the constructor.
So this setter is no longer necessary. Dropped.

  • dom/PendingScript.h:
  • dom/PendingScriptClient.h: Copied from Source/WebCore/html/parser/HTMLScriptRunnerHost.h.

(WebCore::PendingScriptClient::~PendingScriptClient):

  • dom/ScriptRunner.cpp:

(WebCore::ScriptRunner::queueScriptForExecution):
(WebCore::ScriptRunner::notifyScriptReady):
(WebCore::ScriptRunner::timerFired): We use std::exchange to retrieve the RefPtr<PendingScript>
and make the original vector element nullptr. Without this, all the PendingScript is held until
the iteration finishes. We keep the original semantics here that the pending script can be
released per iteration.

  • dom/ScriptRunner.h:
  • html/parser/HTMLDocumentParser.cpp:

(WebCore::HTMLDocumentParser::watchForLoad):
(WebCore::HTMLDocumentParser::stopWatchingForLoad): Use PendingScript instead of touching
CachedScript directly.
(WebCore::HTMLDocumentParser::notifyFinished):

  • html/parser/HTMLDocumentParser.h:
  • html/parser/HTMLScriptRunner.cpp:

(WebCore::HTMLScriptRunner::~HTMLScriptRunner):
(WebCore::HTMLScriptRunner::sourceFromPendingScript):
(WebCore::HTMLScriptRunner::isPendingScriptReady):
(WebCore::HTMLScriptRunner::executeParsingBlockingScript):
(WebCore::HTMLScriptRunner::executePendingScriptAndDispatchEvent): As the previous comment describes,
we used releaseElementAndClear to make the current pending script empty. Instead of doing so, we now
explicitly clear executeParsingBlockingScript (by assigning nullptr to m_parserBlockingScript).
(WebCore::HTMLScriptRunner::watchForLoad):
(WebCore::HTMLScriptRunner::stopWatchingForLoad): Previously, we used CachedScript::addClient directly
in the m_host.watchForLoad. This means that we did not have a quick way to query whether the pending
script is watched. In the old implementation, we have the m_watchingForLoad : bool flag in PendingScript
to hold the watching status for the given pending script. This pendingScript.setWatchingForLoad(true)
just made this flag true. But now, we do not use CachedScript::addClient directly. Instead, we have
the PendingScriptClient and PendingScript::{setClient,clearClient}. We can know whether this pending
script is watched by checking m_client != nullptr. This makes m_watchingForLoad unnecessary.
So this patch drops m_watchingForLoad and pendingScript.setWatchingForLoad(true) call.
(WebCore::HTMLScriptRunner::hasParserBlockingScript):
(WebCore::HTMLScriptRunner::executeParsingBlockingScripts): We clear the m_parserBlockingScript here
instead of the middle of the executePendingScriptAndDispatchEvent.
(WebCore::HTMLScriptRunner::executeScriptsWaitingForLoad):
(WebCore::HTMLScriptRunner::executeScriptsWaitingForParsing):
(WebCore::requestPendingScript):
(WebCore::HTMLScriptRunner::requestParsingBlockingScript): Setting m_parsingBlockingScript is now done
in this caller side.
(WebCore::HTMLScriptRunner::requestDeferredScript):
(WebCore::HTMLScriptRunner::runScript):
(WebCore::HTMLScriptRunner::requestPendingScript): Instead of configuring the passed PendingScript&,
we return the pending script and the caller sets it to m_parserBlockingScript or holds it. And we now
change this function to static location one and drop the member function. Previously, we always make
PendingScript& valid by always calling setElement(...). I think this is the bug since we accidentally
exposed the half-baked pending script. But this bug is not shown since !cachedScript path is dead code!
This requestPendingScript is called from two places, requestDeferredScript and requestParsingBlockingScript.
And these functions are called if the script has willBeParserExecuted flag. In the case of the script
tag having "src" attribute, this flag is only set if cachedScript is correctly instantiated. So when
these functions are called, we can ensure that cachedScript is correctly instantiated for the given script.
In the case of the script tag not having "src" attribute, these functions are won't be called. This is
because if such a script tag has willBeParserExecuted flag, it also has m_readyToBeParserExecuted
and it does not have m_willExecuteWhenDocumentFinishedParsing flag, and in that case the both
functions are never called. So we drop that path and insert the assertion to ensure the above conditions.

  • html/parser/HTMLScriptRunner.h:
  • html/parser/HTMLScriptRunnerHost.h:
Location:
trunk/Source/WebCore
Files:
11 edited
1 copied

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r205214 r205218  
     12016-08-30  Yusuke Suzuki  <utatane.tea@gmail.com>
     2
     3        Make PendingScript as ref-counted
     4        https://bugs.webkit.org/show_bug.cgi?id=161350
     5
     6        Reviewed by Ryosuke Niwa.
     7
     8        Currently, while PendingScript is copyable, PendingScript is also CachedResourceClient.
     9        So when copying this, the client registration is done in PendingScript's operator= etc.
     10        However, this copying functionality is not effectively used.
     11        In this patch, we change this PendingScript to ref-counted class and make it noncopyable.
     12        This change makes things simple (dropping this copying functionality), and drops unnecessary
     13        addClient / removeClient calls. And we also simplify PendingScript class. Since we can offer
     14        all the members at the construction time, we do not need any setters like setCachedScript,
     15        setElement etc. This prevents us from accidentally generating the half-baked pending script.
     16
     17        Furthermore, by changing PendingScript noncopyable & ref-counted, we easily make it
     18        observable. In this patch, we add PendingScriptClient to receive the notification from
     19        PendingScript. Previously, we directly used CachedScript in PendingScript to receive the
     20        notification. When introducing ScriptModuleGraph and making this PendingScript the container
     21        of the both CachedScript and ScriptModuleGraph, hiding the raw CachedScript operations is
     22        useful.
     23
     24        No behavior changes.
     25
     26        * WebCore.xcodeproj/project.pbxproj:
     27        * dom/PendingScript.cpp:
     28        (WebCore::PendingScript::create): These factory functions take all the information needed
     29        to construct the PendingScript. So the setters of PendingScript are dropped. This is better
     30        since we now do not expose any half-baked pending script accidentally.
     31        (WebCore::PendingScript::PendingScript):
     32        (WebCore::PendingScript::~PendingScript):
     33        (WebCore::PendingScript::notifyClientFinished):
     34        (WebCore::PendingScript::notifyFinished):
     35        (WebCore::PendingScript::isLoaded): When introducing ScriptModuleGraph, this will query to
     36        either CachedScript or ScriptModuleGraph. PendingScript will become the container for the
     37        both types.
     38        (WebCore::PendingScript::setClient):
     39        (WebCore::PendingScript::clearClient): PendingScript is now observable by PendingScriptClient.
     40        This avoids touching CachedScript in PendingScript directly. That is good when we introduce
     41        ScriptModuleGraph and make PendingScript the container of the both CachedScript and ScriptModuleGraph.
     42        (WebCore::PendingScript::releaseElementAndClear): Deleted. Previously, PendingScript is not ref-counted.
     43        So when we would like to say "this pending script is empty", we used the pending script with
     44        `m_element = nullptr`. This releaseElementAndClear cleared this m_element and made the pending
     45        script empty. Now, we use RefPtr<PendingScript> and empty one is just represented by the nullptr.
     46        This function is no longer necessary. Dropped.
     47        (WebCore::PendingScript::setCachedScript): Deleted. The fields are set in the constructor.
     48        So this setter is no longer necessary. Dropped.
     49        * dom/PendingScript.h:
     50        * dom/PendingScriptClient.h: Copied from Source/WebCore/html/parser/HTMLScriptRunnerHost.h.
     51        (WebCore::PendingScriptClient::~PendingScriptClient):
     52        * dom/ScriptRunner.cpp:
     53        (WebCore::ScriptRunner::queueScriptForExecution):
     54        (WebCore::ScriptRunner::notifyScriptReady):
     55        (WebCore::ScriptRunner::timerFired): We use `std::exchange` to retrieve the RefPtr<PendingScript>
     56        and make the original vector element nullptr. Without this, all the PendingScript is held until
     57        the iteration finishes. We keep the original semantics here that the pending script can be
     58        released per iteration.
     59        * dom/ScriptRunner.h:
     60        * html/parser/HTMLDocumentParser.cpp:
     61        (WebCore::HTMLDocumentParser::watchForLoad):
     62        (WebCore::HTMLDocumentParser::stopWatchingForLoad): Use PendingScript instead of touching
     63        CachedScript directly.
     64        (WebCore::HTMLDocumentParser::notifyFinished):
     65        * html/parser/HTMLDocumentParser.h:
     66        * html/parser/HTMLScriptRunner.cpp:
     67        (WebCore::HTMLScriptRunner::~HTMLScriptRunner):
     68        (WebCore::HTMLScriptRunner::sourceFromPendingScript):
     69        (WebCore::HTMLScriptRunner::isPendingScriptReady):
     70        (WebCore::HTMLScriptRunner::executeParsingBlockingScript):
     71        (WebCore::HTMLScriptRunner::executePendingScriptAndDispatchEvent): As the previous comment describes,
     72        we used releaseElementAndClear to make the current pending script empty. Instead of doing so, we now
     73        explicitly clear executeParsingBlockingScript (by assigning nullptr to m_parserBlockingScript).
     74        (WebCore::HTMLScriptRunner::watchForLoad):
     75        (WebCore::HTMLScriptRunner::stopWatchingForLoad): Previously, we used CachedScript::addClient directly
     76        in the m_host.watchForLoad. This means that we did not have a quick way to query whether the pending
     77        script is watched. In the old implementation, we have the `m_watchingForLoad : bool` flag in PendingScript
     78        to hold the watching status for the given pending script. This `pendingScript.setWatchingForLoad(true)`
     79        just made this flag `true`. But now, we do not use CachedScript::addClient directly. Instead, we have
     80        the PendingScriptClient and PendingScript::{setClient,clearClient}. We can know whether this pending
     81        script is watched by checking `m_client != nullptr`. This makes `m_watchingForLoad` unnecessary.
     82        So this patch drops `m_watchingForLoad` and `pendingScript.setWatchingForLoad(true)` call.
     83        (WebCore::HTMLScriptRunner::hasParserBlockingScript):
     84        (WebCore::HTMLScriptRunner::executeParsingBlockingScripts): We clear the m_parserBlockingScript here
     85        instead of the middle of the executePendingScriptAndDispatchEvent.
     86        (WebCore::HTMLScriptRunner::executeScriptsWaitingForLoad):
     87        (WebCore::HTMLScriptRunner::executeScriptsWaitingForParsing):
     88        (WebCore::requestPendingScript):
     89        (WebCore::HTMLScriptRunner::requestParsingBlockingScript): Setting m_parsingBlockingScript is now done
     90        in this caller side.
     91        (WebCore::HTMLScriptRunner::requestDeferredScript):
     92        (WebCore::HTMLScriptRunner::runScript):
     93        (WebCore::HTMLScriptRunner::requestPendingScript): Instead of configuring the passed PendingScript&,
     94        we return the pending script and the caller sets it to m_parserBlockingScript or holds it. And we now
     95        change this function to static location one and drop the member function. Previously, we always make
     96        PendingScript& valid by always calling `setElement(...)`. I think this is the bug since we accidentally
     97        exposed the half-baked pending script. But this bug is not shown since `!cachedScript` path is dead code!
     98        This requestPendingScript is called from two places, requestDeferredScript and requestParsingBlockingScript.
     99        And these functions are called if the script has `willBeParserExecuted` flag. In the case of the script
     100        tag having "src" attribute, this flag is only set if `cachedScript` is correctly instantiated. So when
     101        these functions are called, we can ensure that `cachedScript` is correctly instantiated for the given script.
     102        In the case of the script tag not having "src" attribute, these functions are won't be called. This is
     103        because if such a script tag has `willBeParserExecuted` flag, it also has `m_readyToBeParserExecuted`
     104        and it does not have `m_willExecuteWhenDocumentFinishedParsing` flag, and in that case the both
     105        functions are never called. So we drop that path and insert the assertion to ensure the above conditions.
     106        * html/parser/HTMLScriptRunner.h:
     107        * html/parser/HTMLScriptRunnerHost.h:
     108
    11092016-08-30  Ricky Mondello  <rmondello@apple.com>
    2110
  • trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj

    r205212 r205218  
    60926092                E38838981BAD145F00D62EE3 /* JSModuleLoader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = E38838941BAD145F00D62EE3 /* JSModuleLoader.cpp */; };
    60936093                E38838991BAD145F00D62EE3 /* JSModuleLoader.h in Headers */ = {isa = PBXBuildFile; fileRef = E38838951BAD145F00D62EE3 /* JSModuleLoader.h */; };
     6094                E3FA38641D71812D00AA5950 /* PendingScriptClient.h in Headers */ = {isa = PBXBuildFile; fileRef = E3FA38611D716E7600AA5950 /* PendingScriptClient.h */; };
    60946095                E401C27517CE53EC00C41A35 /* ElementIteratorAssertions.h in Headers */ = {isa = PBXBuildFile; fileRef = E401C27417CE53EC00C41A35 /* ElementIteratorAssertions.h */; settings = {ATTRIBUTES = (Private, ); }; };
    60956096                E401E0A41C3C0B8300F34D10 /* StyleChange.h in Headers */ = {isa = PBXBuildFile; fileRef = E401E0A31C3C0B8300F34D10 /* StyleChange.h */; settings = {ATTRIBUTES = (Private, ); }; };
     
    1365813659                E38838941BAD145F00D62EE3 /* JSModuleLoader.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSModuleLoader.cpp; sourceTree = "<group>"; };
    1365913660                E38838951BAD145F00D62EE3 /* JSModuleLoader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSModuleLoader.h; sourceTree = "<group>"; };
     13661                E3FA38611D716E7600AA5950 /* PendingScriptClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PendingScriptClient.h; sourceTree = "<group>"; };
    1366013662                E401C27417CE53EC00C41A35 /* ElementIteratorAssertions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ElementIteratorAssertions.h; sourceTree = "<group>"; };
    1366113663                E401E0A31C3C0B8300F34D10 /* StyleChange.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StyleChange.h; sourceTree = "<group>"; };
     
    2308123083                                8A7CC96F12076F8A001D4588 /* PendingScript.cpp */,
    2308223084                                8A7CC96A12076D73001D4588 /* PendingScript.h */,
     23085                                E3FA38611D716E7600AA5950 /* PendingScriptClient.h */,
    2308323086                                41BF700D0FE86F61005E8DEC /* PlatformMessagePortChannel.cpp */,
    2308423087                                41BF700E0FE86F61005E8DEC /* PlatformMessagePortChannel.h */,
     
    2705727060                                BC772C470C4EB2C60083285F /* XMLHttpRequest.h in Headers */,
    2705827061                                83D35AEC1C7187FA00F70D5A /* XMLHttpRequestEventTarget.h in Headers */,
     27062                                E3FA38641D71812D00AA5950 /* PendingScriptClient.h in Headers */,
    2705927063                                F9F0ED7A0DB50CA200D16DB9 /* XMLHttpRequestProgressEvent.h in Headers */,
    2706027064                                A136A00D1134DBD200CC8D50 /* XMLHttpRequestProgressEventThrottle.h in Headers */,
  • trunk/Source/WebCore/dom/PendingScript.cpp

    r195243 r205218  
    2929#include "CachedScript.h"
    3030#include "Element.h"
     31#include "PendingScriptClient.h"
    3132
    3233namespace WebCore {
     34
     35Ref<PendingScript> PendingScript::create(Element& element, CachedScript& cachedScript)
     36{
     37    Ref<PendingScript> pendingScript = adoptRef(*new PendingScript(element, cachedScript));
     38    cachedScript.addClient(&pendingScript.get());
     39    return pendingScript;
     40}
     41
     42Ref<PendingScript> PendingScript::create(Element& element, TextPosition scriptStartPosition)
     43{
     44    return adoptRef(*new PendingScript(element, scriptStartPosition));
     45}
     46
     47PendingScript::PendingScript(Element& element, TextPosition startingPosition)
     48    : m_element(element)
     49    , m_startingPosition(startingPosition)
     50{
     51}
     52
     53PendingScript::PendingScript(Element& element, CachedScript& cachedScript)
     54    : m_element(element)
     55    , m_cachedScript(&cachedScript)
     56{
     57}
    3358
    3459PendingScript::~PendingScript()
     
    3863}
    3964
    40 RefPtr<Element> PendingScript::releaseElementAndClear()
    41 {
    42     setCachedScript(nullptr);
    43     m_watchingForLoad = false;
    44     m_startingPosition = TextPosition::belowRangePosition();
    45     return WTFMove(m_element);
    46 }
    47 
    48 void PendingScript::setCachedScript(CachedScript* cachedScript)
    49 {
    50     if (m_cachedScript == cachedScript)
    51         return;
    52     if (m_cachedScript)
    53         m_cachedScript->removeClient(this);
    54     m_cachedScript = cachedScript;
    55     if (m_cachedScript)
    56         m_cachedScript->addClient(this);
    57 }
    58 
    5965CachedScript* PendingScript::cachedScript() const
    6066{
     
    6268}
    6369
     70void PendingScript::notifyClientFinished()
     71{
     72    Ref<PendingScript> protectedThis(*this);
     73    if (m_client)
     74        m_client->notifyFinished(*this);
     75}
     76
    6477void PendingScript::notifyFinished(CachedResource*)
    6578{
     79    notifyClientFinished();
     80}
     81
     82bool PendingScript::isLoaded() const
     83{
     84    return m_cachedScript && m_cachedScript->isLoaded();
     85}
     86
     87void PendingScript::setClient(PendingScriptClient* client)
     88{
     89    ASSERT(!m_client);
     90    m_client = client;
     91    if (isLoaded())
     92        notifyClientFinished();
     93}
     94
     95void PendingScript::clearClient()
     96{
     97    ASSERT(m_client);
     98    m_client = nullptr;
    6699}
    67100
  • trunk/Source/WebCore/dom/PendingScript.h

    r197563 r205218  
    2424 */
    2525
    26 #ifndef PendingScript_h
    27 #define PendingScript_h
     26#pragma once
    2827
    2928#include "CachedResourceClient.h"
    3029#include "CachedResourceHandle.h"
     30#include <wtf/Ref.h>
     31#include <wtf/RefCounted.h>
    3132#include <wtf/text/TextPosition.h>
    32 #include <wtf/RefPtr.h>
    3333
    3434namespace WebCore {
     
    3636class CachedScript;
    3737class Element;
     38class PendingScriptClient;
    3839
    3940// A container for an external script which may be loaded and executed.
     
    4243// from purging its data buffer. This class holds a dummy client open for its
    4344// lifetime in order to guarantee that the data buffer will not be purged.
    44 class PendingScript final : public CachedResourceClient {
     45class PendingScript final : public RefCounted<PendingScript>, public CachedResourceClient {
    4546public:
    46     PendingScript()
    47         : m_watchingForLoad(false)
    48         , m_startingPosition(TextPosition::belowRangePosition())
    49     {
    50     }
    51 
    52     PendingScript(Element* element, CachedScript* cachedScript)
    53         : m_watchingForLoad(false)
    54         , m_element(element)
    55     {
    56         setCachedScript(cachedScript);
    57     }
    58 
    59     PendingScript(const PendingScript& other)
    60         : CachedResourceClient(other)
    61         , m_watchingForLoad(other.m_watchingForLoad)
    62         , m_element(other.m_element)
    63         , m_startingPosition(other.m_startingPosition)
    64     {
    65         setCachedScript(other.cachedScript());
    66     }
     47    static Ref<PendingScript> create(Element&, CachedScript&);
     48    static Ref<PendingScript> create(Element&, TextPosition scriptStartPosition);
    6749
    6850    virtual ~PendingScript();
    69 
    70     PendingScript& operator=(const PendingScript& other)
    71     {
    72         if (this == &other)
    73             return *this;
    74 
    75         m_watchingForLoad = other.m_watchingForLoad;
    76         m_element = other.m_element;
    77         m_startingPosition = other.m_startingPosition;
    78         setCachedScript(other.cachedScript());
    79 
    80         return *this;
    81     }
    8251
    8352    TextPosition startingPosition() const { return m_startingPosition; }
    8453    void setStartingPosition(const TextPosition& position) { m_startingPosition = position; }
    8554
    86     bool watchingForLoad() const { return m_watchingForLoad; }
    87     void setWatchingForLoad(bool b) { m_watchingForLoad = b; }
     55    bool watchingForLoad() const { return needsLoading() && m_client; }
    8856
    89     Element* element() const { return m_element.get(); }
    90     void setElement(Element* element) { m_element = element; }
    91     RefPtr<Element> releaseElementAndClear();
     57    Element& element() { return m_element.get(); }
     58    const Element& element() const { return m_element.get(); }
    9259
    9360    CachedScript* cachedScript() const;
    94     void setCachedScript(CachedScript*);
     61    bool needsLoading() const { return cachedScript(); }
     62
     63    bool isLoaded() const;
    9564
    9665    void notifyFinished(CachedResource*) override;
    9766
     67    void setClient(PendingScriptClient*);
     68    void clearClient();
     69
    9870private:
    99     bool m_watchingForLoad;
    100     RefPtr<Element> m_element;
     71    PendingScript(Element&, CachedScript&);
     72    PendingScript(Element&, TextPosition startingPosition);
     73
     74    void notifyClientFinished();
     75
     76    Ref<Element> m_element;
    10177    TextPosition m_startingPosition; // Only used for inline script tags.
    102     CachedResourceHandle<CachedScript> m_cachedScript;
     78    CachedResourceHandle<CachedScript> m_cachedScript;
     79    PendingScriptClient* m_client { nullptr };
    10380};
    10481
    10582}
    106 
    107 #endif
  • trunk/Source/WebCore/dom/PendingScriptClient.h

    r205217 r205218  
    11/*
    2  * Copyright (C) 2010 Google, Inc. All Rights Reserved.
     2 * Copyright (C) 2016 Apple, Inc. All Rights Reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    2121 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    2222 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
     23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    2424 */
    2525
    26 #ifndef HTMLScriptRunnerHost_h
    27 #define HTMLScriptRunnerHost_h
    28 
    29 #include <wtf/Forward.h>
     26#pragma once
    3027
    3128namespace WebCore {
    3229
    33 class CachedResource;
    34 class Element;
    35 class HTMLInputStream;
    36 class ScriptSourceCode;
     30class PendingScript;
    3731
    38 class HTMLScriptRunnerHost {
     32class PendingScriptClient {
    3933public:
    40     virtual ~HTMLScriptRunnerHost() { }
     34    virtual ~PendingScriptClient() { }
    4135
    42     // Implementors should call cachedResource->addClient() here or soon after.
    43     virtual void watchForLoad(CachedResource*) = 0;
    44     // Implementors must call cachedResource->removeClient() immediately.
    45     virtual void stopWatchingForLoad(CachedResource*) = 0;
    46 
    47     virtual HTMLInputStream& inputStream() = 0;
    48 
    49     virtual bool hasPreloadScanner() const = 0;
    50     virtual void appendCurrentInputStreamToPreloadScannerAndScan() = 0;
    51    
     36    virtual void notifyFinished(PendingScript&) = 0;
    5237};
    5338
    5439}
    55 
    56 #endif
  • trunk/Source/WebCore/dom/ScriptRunner.cpp

    r193286 r205218  
    6262    switch (executionType) {
    6363    case ASYNC_EXECUTION:
    64         m_pendingAsyncScripts.add(scriptElement, PendingScript(&element, cachedScript.get()));
     64        m_pendingAsyncScripts.add(scriptElement, PendingScript::create(element, *cachedScript));
    6565        break;
    6666
    6767    case IN_ORDER_EXECUTION:
    68         m_scriptsToExecuteInOrder.append(PendingScript(&element, cachedScript.get()));
     68        m_scriptsToExecuteInOrder.append(PendingScript::create(element, *cachedScript));
    6969        break;
    7070    }
     
    8787    case ASYNC_EXECUTION:
    8888        ASSERT(m_pendingAsyncScripts.contains(scriptElement));
    89         m_scriptsToExecuteSoon.append(m_pendingAsyncScripts.take(scriptElement));
     89        m_scriptsToExecuteSoon.append(m_pendingAsyncScripts.take(scriptElement)->ptr());
    9090        break;
    9191
     
    101101    Ref<Document> protect(m_document);
    102102
    103     Vector<PendingScript> scripts;
     103    Vector<RefPtr<PendingScript>> scripts;
    104104    scripts.swap(m_scriptsToExecuteSoon);
    105105
    106106    size_t numInOrderScriptsToExecute = 0;
    107     for (; numInOrderScriptsToExecute < m_scriptsToExecuteInOrder.size() && m_scriptsToExecuteInOrder[numInOrderScriptsToExecute].cachedScript()->isLoaded(); ++numInOrderScriptsToExecute)
    108         scripts.append(m_scriptsToExecuteInOrder[numInOrderScriptsToExecute]);
     107    for (; numInOrderScriptsToExecute < m_scriptsToExecuteInOrder.size() && m_scriptsToExecuteInOrder[numInOrderScriptsToExecute]->isLoaded(); ++numInOrderScriptsToExecute)
     108        scripts.append(m_scriptsToExecuteInOrder[numInOrderScriptsToExecute].ptr());
    109109    if (numInOrderScriptsToExecute)
    110110        m_scriptsToExecuteInOrder.remove(0, numInOrderScriptsToExecute);
    111111
    112     for (auto& script : scripts) {
    113         CachedScript* cachedScript = script.cachedScript();
    114         RefPtr<Element> element = script.releaseElementAndClear();
    115         ASSERT(element);
     112    for (auto& currentScript : scripts) {
     113        auto script = WTFMove(currentScript);
     114        ASSERT(script);
    116115        // Paper over https://bugs.webkit.org/show_bug.cgi?id=144050
    117         if (!element)
     116        if (!script)
    118117            continue;
    119         toScriptElementIfPossible(element.get())->execute(cachedScript);
     118        auto* scriptElement = toScriptElementIfPossible(&script->element());
     119        ASSERT(scriptElement);
     120        scriptElement->execute(script->cachedScript());
    120121        m_document.decrementLoadEventDelayCount();
    121122    }
  • trunk/Source/WebCore/dom/ScriptRunner.h

    r195243 r205218  
    5757
    5858    Document& m_document;
    59     Vector<PendingScript> m_scriptsToExecuteInOrder;
    60     Vector<PendingScript> m_scriptsToExecuteSoon; // http://www.whatwg.org/specs/web-apps/current-work/#set-of-scripts-that-will-execute-as-soon-as-possible
    61     HashMap<ScriptElement*, PendingScript> m_pendingAsyncScripts;
     59    Vector<Ref<PendingScript>> m_scriptsToExecuteInOrder;
     60    Vector<RefPtr<PendingScript>> m_scriptsToExecuteSoon; // http://www.whatwg.org/specs/web-apps/current-work/#set-of-scripts-that-will-execute-as-soon-as-possible
     61    HashMap<ScriptElement*, Ref<PendingScript>> m_pendingAsyncScripts;
    6262    Timer m_timer;
    6363};
  • trunk/Source/WebCore/html/parser/HTMLDocumentParser.cpp

    r202559 r205218  
    2828#include "HTMLDocumentParser.h"
    2929
     30#include "CachedScript.h"
    3031#include "DocumentFragment.h"
    3132#include "Frame.h"
     
    501502}
    502503
    503 void HTMLDocumentParser::watchForLoad(CachedResource* cachedScript)
    504 {
    505     ASSERT(!cachedScript->isLoaded());
    506     // addClient would call notifyFinished if the load were complete.
     504void HTMLDocumentParser::watchForLoad(PendingScript& pendingScript)
     505{
     506    ASSERT(!pendingScript.isLoaded());
     507    // setClient would call notifyFinished if the load were complete.
    507508    // Callers do not expect to be re-entered from this call, so they should
    508     // not an already-loaded CachedResource.
    509     cachedScript->addClient(this);
    510 }
    511 
    512 void HTMLDocumentParser::stopWatchingForLoad(CachedResource* cachedScript)
    513 {
    514     cachedScript->removeClient(this);
     509    // not an already-loaded PendingScript.
     510    pendingScript.setClient(this);
     511}
     512
     513void HTMLDocumentParser::stopWatchingForLoad(PendingScript& pendingScript)
     514{
     515    pendingScript.clearClient();
    515516}
    516517
     
    522523}
    523524
    524 void HTMLDocumentParser::notifyFinished(CachedResource* cachedResource)
     525void HTMLDocumentParser::notifyFinished(PendingScript& pendingScript)
    525526{
    526527    // pumpTokenizer can cause this parser to be detached from the Document,
     
    535536    }
    536537
    537     m_scriptRunner->executeScriptsWaitingForLoad(cachedResource);
     538    m_scriptRunner->executeScriptsWaitingForLoad(pendingScript);
    538539    if (!isWaitingForScripts())
    539540        resumeParsingAfterScriptExecution();
  • trunk/Source/WebCore/html/parser/HTMLDocumentParser.h

    r197566 r205218  
    2828#define HTMLDocumentParser_h
    2929
    30 #include "CachedResourceClient.h"
    3130#include "HTMLInputStream.h"
    3231#include "HTMLScriptRunnerHost.h"
    3332#include "HTMLSourceTracker.h"
    3433#include "HTMLTokenizer.h"
     34#include "PendingScriptClient.h"
    3535#include "ScriptableDocumentParser.h"
    3636#include "XSSAuditor.h"
     
    4848class PumpSession;
    4949
    50 class HTMLDocumentParser : public ScriptableDocumentParser, private HTMLScriptRunnerHost, private CachedResourceClient {
     50class HTMLDocumentParser : public ScriptableDocumentParser, private HTMLScriptRunnerHost, private PendingScriptClient {
    5151    WTF_MAKE_FAST_ALLOCATED;
    5252public:
     
    9191
    9292    // HTMLScriptRunnerHost
    93     void watchForLoad(CachedResource*) final;
    94     void stopWatchingForLoad(CachedResource*) final;
     93    void watchForLoad(PendingScript&) final;
     94    void stopWatchingForLoad(PendingScript&) final;
    9595    HTMLInputStream& inputStream() final;
    9696    bool hasPreloadScanner() const final;
    9797    void appendCurrentInputStreamToPreloadScannerAndScan() final;
    9898
    99     // CachedResourceClient
    100     void notifyFinished(CachedResource*) final;
     99    // PendingScriptClient
     100    void notifyFinished(PendingScript&) final;
    101101
    102102    Document* contextForParsingSession();
  • trunk/Source/WebCore/html/parser/HTMLScriptRunner.cpp

    r202105 r205218  
    5959{
    6060    // FIXME: Should we be passed a "done loading/parsing" callback sooner than destruction?
    61     if (m_parserBlockingScript.cachedScript() && m_parserBlockingScript.watchingForLoad())
    62         stopWatchingForLoad(m_parserBlockingScript);
     61    if (m_parserBlockingScript) {
     62        if (m_parserBlockingScript->watchingForLoad())
     63            stopWatchingForLoad(*m_parserBlockingScript);
     64    }
    6365
    6466    while (!m_scriptsToExecuteAfterParsing.isEmpty()) {
    65         PendingScript pendingScript = m_scriptsToExecuteAfterParsing.takeFirst();
    66         if (pendingScript.cachedScript() && pendingScript.watchingForLoad())
     67        auto pendingScript = m_scriptsToExecuteAfterParsing.takeFirst();
     68        if (pendingScript->watchingForLoad())
    6769            stopWatchingForLoad(pendingScript);
    6870    }
     
    9698    }
    9799    errorOccurred = false;
    98     return ScriptSourceCode(script.element()->textContent(), documentURLForScriptExecution(m_document), script.startingPosition());
     100    return ScriptSourceCode(script.element().textContent(), documentURLForScriptExecution(m_document), script.startingPosition());
    99101}
    100102
     
    106108    if (m_hasScriptsWaitingForStylesheets)
    107109        return false;
    108     if (script.cachedScript() && !script.cachedScript()->isLoaded())
     110    if (script.needsLoading() && !script.isLoaded())
    109111        return false;
    110112    return true;
     
    116118    ASSERT(!isExecutingScript());
    117119    ASSERT(m_document->haveStylesheetsLoaded());
    118     ASSERT(isPendingScriptReady(m_parserBlockingScript));
     120    ASSERT(isPendingScriptReady(*m_parserBlockingScript));
    119121
    120122    InsertionPointRecord insertionPointRecord(m_host.inputStream());
    121     executePendingScriptAndDispatchEvent(m_parserBlockingScript);
    122 }
    123 
    124 void HTMLScriptRunner::executePendingScriptAndDispatchEvent(PendingScript& pendingScript)
     123    executePendingScriptAndDispatchEvent(WTFMove(m_parserBlockingScript));
     124}
     125
     126void HTMLScriptRunner::executePendingScriptAndDispatchEvent(RefPtr<PendingScript> pendingScript)
    125127{
    126128    bool errorOccurred = false;
    127     ScriptSourceCode sourceCode = sourceFromPendingScript(pendingScript, errorOccurred);
     129    ScriptSourceCode sourceCode = sourceFromPendingScript(*pendingScript, errorOccurred);
    128130
    129131    // Stop watching loads before executeScript to prevent recursion if the script reloads itself.
    130     if (pendingScript.cachedScript() && pendingScript.watchingForLoad())
    131         stopWatchingForLoad(pendingScript);
     132    if (pendingScript->watchingForLoad())
     133        stopWatchingForLoad(*pendingScript);
    132134
    133135    if (!isExecutingScript())
    134136        MicrotaskQueue::mainThreadQueue().performMicrotaskCheckpoint();
    135137
    136     // Clear the pending script before possible rentrancy from executeScript()
    137     RefPtr<Element> element = pendingScript.releaseElementAndClear();
    138     if (ScriptElement* scriptElement = toScriptElementIfPossible(element.get())) {
     138    if (auto* scriptElement = toScriptElementIfPossible(&pendingScript->element())) {
    139139        NestingLevelIncrementer nestingLevelIncrementer(m_scriptNestingLevel);
    140140        IgnoreDestructiveWriteCountIncrementer ignoreDestructiveWriteCountIncrementer(m_document);
     
    144144            ASSERT(isExecutingScript());
    145145            scriptElement->executeScript(sourceCode);
    146             element->dispatchEvent(createScriptLoadEvent());
     146            pendingScript->element().dispatchEvent(createScriptLoadEvent());
    147147        }
    148148    }
     
    153153{
    154154    ASSERT(!pendingScript.watchingForLoad());
    155     m_host.watchForLoad(pendingScript.cachedScript());
    156     pendingScript.setWatchingForLoad(true);
     155    m_host.watchForLoad(pendingScript);
    157156}
    158157
     
    160159{
    161160    ASSERT(pendingScript.watchingForLoad());
    162     m_host.stopWatchingForLoad(pendingScript.cachedScript());
    163     pendingScript.setWatchingForLoad(false);
     161    m_host.stopWatchingForLoad(pendingScript);
    164162}
    165163
     
    188186bool HTMLScriptRunner::hasParserBlockingScript() const
    189187{
    190     return !!m_parserBlockingScript.element();
     188    return !!m_parserBlockingScript;
    191189}
    192190
    193191void HTMLScriptRunner::executeParsingBlockingScripts()
    194192{
    195     while (hasParserBlockingScript() && isPendingScriptReady(m_parserBlockingScript))
     193    while (hasParserBlockingScript() && isPendingScriptReady(*m_parserBlockingScript))
    196194        executeParsingBlockingScript();
    197195}
    198196
    199 void HTMLScriptRunner::executeScriptsWaitingForLoad(CachedResource* cachedScript)
     197void HTMLScriptRunner::executeScriptsWaitingForLoad(PendingScript& pendingScript)
    200198{
    201199    ASSERT(!isExecutingScript());
    202200    ASSERT(hasParserBlockingScript());
    203     ASSERT_UNUSED(cachedScript, m_parserBlockingScript.cachedScript() == cachedScript);
    204     ASSERT(m_parserBlockingScript.cachedScript()->isLoaded());
     201    ASSERT_UNUSED(pendingScript, m_parserBlockingScript.get() == &pendingScript);
     202    ASSERT(m_parserBlockingScript->isLoaded());
    205203    executeParsingBlockingScripts();
    206204}
     
    222220        ASSERT(!isExecutingScript());
    223221        ASSERT(!hasParserBlockingScript());
    224         ASSERT(m_scriptsToExecuteAfterParsing.first().cachedScript());
    225         if (!m_scriptsToExecuteAfterParsing.first().cachedScript()->isLoaded()) {
     222        ASSERT(m_scriptsToExecuteAfterParsing.first()->needsLoading());
     223        if (!m_scriptsToExecuteAfterParsing.first()->isLoaded()) {
    226224            watchForLoad(m_scriptsToExecuteAfterParsing.first());
    227225            return false;
    228226        }
    229         PendingScript first = m_scriptsToExecuteAfterParsing.takeFirst();
    230         executePendingScriptAndDispatchEvent(first);
     227        executePendingScriptAndDispatchEvent(m_scriptsToExecuteAfterParsing.takeFirst());
    231228        // FIXME: What is this m_document check for?
    232229        if (!m_document)
     
    236233}
    237234
     235static Ref<PendingScript> requestPendingScript(Element* script)
     236{
     237    auto& scriptElement = *toScriptElementIfPossible(script);
     238    ASSERT(scriptElement.willBeParserExecuted());
     239    ASSERT(scriptElement.cachedScript());
     240    return PendingScript::create(*script, *scriptElement.cachedScript());
     241}
     242
    238243void HTMLScriptRunner::requestParsingBlockingScript(Element* element)
    239244{
    240     if (!requestPendingScript(m_parserBlockingScript, element))
    241         return;
    242 
    243     ASSERT(m_parserBlockingScript.cachedScript());
     245    ASSERT(!m_parserBlockingScript);
     246    m_parserBlockingScript = requestPendingScript(element);
     247    ASSERT(m_parserBlockingScript->needsLoading());
    244248
    245249    // We only care about a load callback if cachedScript is not already
    246250    // in the cache. Callers will attempt to run the m_parserBlockingScript
    247251    // if possible before returning control to the parser.
    248     if (!m_parserBlockingScript.cachedScript()->isLoaded())
    249         watchForLoad(m_parserBlockingScript);
     252    if (!m_parserBlockingScript->isLoaded())
     253        watchForLoad(*m_parserBlockingScript);
    250254}
    251255
    252256void HTMLScriptRunner::requestDeferredScript(Element* element)
    253257{
    254     PendingScript pendingScript;
    255     if (!requestPendingScript(pendingScript, element))
    256         return;
    257 
    258     ASSERT(pendingScript.cachedScript());
    259     m_scriptsToExecuteAfterParsing.append(pendingScript);
    260 }
    261 
    262 bool HTMLScriptRunner::requestPendingScript(PendingScript& pendingScript, Element* script) const
    263 {
    264     ASSERT(!pendingScript.element());
    265     pendingScript.setElement(script);
    266     // This should correctly return 0 for empty or invalid srcValues.
    267     CachedScript* cachedScript = toScriptElementIfPossible(script)->cachedScript().get();
    268     if (!cachedScript) {
    269         notImplemented(); // Dispatch error event.
    270         return false;
    271     }
    272     pendingScript.setCachedScript(cachedScript);
    273     return true;
     258    auto pendingScript = requestPendingScript(element);
     259    ASSERT(pendingScript->needsLoading());
     260    m_scriptsToExecuteAfterParsing.append(WTFMove(pendingScript));
    274261}
    275262
     
    309296            requestDeferredScript(script);
    310297        else if (scriptElement->readyToBeParserExecuted()) {
    311             if (m_scriptNestingLevel == 1) {
    312                 m_parserBlockingScript.setElement(script);
    313                 m_parserBlockingScript.setStartingPosition(scriptStartPosition);
    314             } else {
    315                 ScriptSourceCode sourceCode(script->textContent(), documentURLForScriptExecution(m_document), scriptStartPosition);
    316                 scriptElement->executeScript(sourceCode);
    317             }
     298            if (m_scriptNestingLevel == 1)
     299                m_parserBlockingScript = PendingScript::create(*script, scriptStartPosition);
     300            else
     301                scriptElement->executeScript(ScriptSourceCode(script->textContent(), documentURLForScriptExecution(m_document), scriptStartPosition));
    318302        } else
    319303            requestParsingBlockingScript(script);
  • trunk/Source/WebCore/html/parser/HTMLScriptRunner.h

    r162275 r205218  
    5252    void execute(PassRefPtr<Element> scriptToProcess, const TextPosition& scriptStartPosition);
    5353
    54     void executeScriptsWaitingForLoad(CachedResource*);
     54    void executeScriptsWaitingForLoad(PendingScript&);
    5555    bool hasScriptsWaitingForStylesheets() const { return m_hasScriptsWaitingForStylesheets; }
    5656    void executeScriptsWaitingForStylesheets();
     
    6464
    6565    void executeParsingBlockingScript();
    66     void executePendingScriptAndDispatchEvent(PendingScript&);
     66    void executePendingScriptAndDispatchEvent(RefPtr<PendingScript>);
    6767    void executeParsingBlockingScripts();
    6868
    6969    void requestParsingBlockingScript(Element*);
    7070    void requestDeferredScript(Element*);
    71     bool requestPendingScript(PendingScript&, Element*) const;
    7271
    7372    void runScript(Element*, const TextPosition& scriptStartPosition);
     
    8180    Document* m_document;
    8281    HTMLScriptRunnerHost& m_host;
    83     PendingScript m_parserBlockingScript;
    84     Deque<PendingScript> m_scriptsToExecuteAfterParsing; // http://www.whatwg.org/specs/web-apps/current-work/#list-of-scripts-that-will-execute-when-the-document-has-finished-parsing
     82    RefPtr<PendingScript> m_parserBlockingScript;
     83    Deque<Ref<PendingScript>> m_scriptsToExecuteAfterParsing; // http://www.whatwg.org/specs/web-apps/current-work/#list-of-scripts-that-will-execute-when-the-document-has-finished-parsing
    8584    unsigned m_scriptNestingLevel;
    8685
  • trunk/Source/WebCore/html/parser/HTMLScriptRunnerHost.h

    r95901 r205218  
    3131namespace WebCore {
    3232
    33 class CachedResource;
    3433class Element;
    3534class HTMLInputStream;
     35class PendingScript;
    3636class ScriptSourceCode;
    3737
     
    4141
    4242    // Implementors should call cachedResource->addClient() here or soon after.
    43     virtual void watchForLoad(CachedResource*) = 0;
     43    virtual void watchForLoad(PendingScript&) = 0;
    4444    // Implementors must call cachedResource->removeClient() immediately.
    45     virtual void stopWatchingForLoad(CachedResource*) = 0;
     45    virtual void stopWatchingForLoad(PendingScript&) = 0;
    4646
    4747    virtual HTMLInputStream& inputStream() = 0;
Note: See TracChangeset for help on using the changeset viewer.