Changeset 61940 in webkit
- Timestamp:
- Jun 25, 2010 10:27:37 PM (14 years ago)
- Location:
- trunk/WebCore
- Files:
-
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/WebCore/ChangeLog
r61939 r61940 1 2010-06-25 Tony Gentilcore <tonyg@chromium.org> 2 3 Reviewed by Eric Seidel. 4 5 Make PendingScript hold a CachedResourceClient open for its lifetime 6 https://bugs.webkit.org/show_bug.cgi?id=40968 7 8 This replaces the mechanism introduced in r61374 with a simpler 9 appraoch for preventing unexpected purges: always keep a client open. 10 This approach will allow deferred scripts to add a client after 11 the resource may have already been loaded without having to worry about 12 the buffer being purged in the meantime. 13 14 No new tests because making a CachedResource purse itself is not 15 testable from a LayoutTest. 16 17 * html/HTMLDocumentParser.cpp: 18 (WebCore::HTMLDocumentParser::watchForLoad): 19 (WebCore::HTMLDocumentParser::notifyFinished): 20 * html/HTMLScriptRunner.cpp: 21 (WebCore::HTMLScriptRunner::~HTMLScriptRunner): 22 (WebCore::HTMLScriptRunner::sourceFromPendingScript): 23 (WebCore::HTMLScriptRunner::isPendingScriptReady): 24 (WebCore::HTMLScriptRunner::executePendingScript): 25 (WebCore::HTMLScriptRunner::watchForLoad): 26 (WebCore::HTMLScriptRunner::stopWatchingForLoad): 27 (WebCore::HTMLScriptRunner::executeScriptsWaitingForLoad): 28 (WebCore::HTMLScriptRunner::requestScript): 29 (WebCore::HTMLScriptRunner::PendingScript::~PendingScript): 30 (WebCore::HTMLScriptRunner::PendingScript::releaseElementAndClear): 31 (WebCore::HTMLScriptRunner::PendingScript::setCachedScript): 32 (WebCore::HTMLScriptRunner::PendingScript::cachedScript): 33 * html/HTMLScriptRunner.h: 34 (WebCore::HTMLScriptRunner::PendingScript::PendingScript): 35 (WebCore::HTMLScriptRunner::PendingScript::watchingForLoad): 36 (WebCore::HTMLScriptRunner::PendingScript::setWatchingForLoad): 37 (WebCore::HTMLScriptRunner::PendingScript::notifyFinished): 38 * html/HTMLScriptRunnerHost.h: 39 1 40 2010-06-25 Zhenyao Mo <zmo@google.com> 2 41 -
trunk/WebCore/html/HTMLDocumentParser.cpp
r61904 r61940 341 341 void HTMLDocumentParser::watchForLoad(CachedResource* cachedScript) 342 342 { 343 ASSERT(!cachedScript->isLoaded()); 344 // addClient would call notifyFinished if the load were complete. 345 // Callers do not expect to be re-entered from this call, so they should 346 // not an already-loaded CachedResource. 343 347 cachedScript->addClient(this); 344 348 } … … 359 363 { 360 364 ASSERT(m_scriptRunner); 361 // Ignore calls unless we have a script blocking the parser waiting362 // for its own load. Otherwise this may be a load callback from363 // CachedResource::addClient because the script was already in the cache.364 // HTMLScriptRunner may not be ready to handle running that script yet.365 if (!m_scriptRunner->hasScriptsWaitingForLoad()) {366 ASSERT(m_scriptRunner->inScriptExecution());367 return;368 }369 365 ASSERT(!inScriptExecution()); 370 366 ASSERT(m_treeBuilder->isPaused()); -
trunk/WebCore/html/HTMLScriptRunner.cpp
r61673 r61940 75 75 { 76 76 // FIXME: Should we be passed a "done loading/parsing" callback sooner than destruction? 77 if (m_parsingBlockingScript.cachedScript && m_parsingBlockingScript.watchingForLoad())77 if (m_parsingBlockingScript.cachedScript() && m_parsingBlockingScript.watchingForLoad()) 78 78 stopWatchingForLoad(m_parsingBlockingScript); 79 79 } … … 100 100 ScriptSourceCode HTMLScriptRunner::sourceFromPendingScript(const PendingScript& script, bool& errorOccurred) 101 101 { 102 if (script.cachedScript ) {103 errorOccurred = script.cachedScript ->errorOccurred();104 ASSERT(script.cachedScript ->isLoaded());105 return ScriptSourceCode(script.cachedScript .get());102 if (script.cachedScript()) { 103 errorOccurred = script.cachedScript()->errorOccurred(); 104 ASSERT(script.cachedScript()->isLoaded()); 105 return ScriptSourceCode(script.cachedScript()); 106 106 } 107 107 errorOccurred = false; … … 114 114 if (m_hasScriptsWaitingForStylesheets) 115 115 return false; 116 if (script.cachedScript && !script.cachedScript->isLoaded())116 if (script.cachedScript() && !script.cachedScript()->isLoaded()) 117 117 return false; 118 118 return true; … … 128 128 129 129 // Stop watching loads before executeScript to prevent recursion if the script reloads itself. 130 if (m_parsingBlockingScript.cachedScript && m_parsingBlockingScript.watchingForLoad())130 if (m_parsingBlockingScript.cachedScript() && m_parsingBlockingScript.watchingForLoad()) 131 131 stopWatchingForLoad(m_parsingBlockingScript); 132 132 133 133 // Clear the pending script before possible rentrancy from executeScript() 134 RefPtr<Element> scriptElement = m_parsingBlockingScript.element.release(); 135 m_parsingBlockingScript = PendingScript(); 134 RefPtr<Element> scriptElement = m_parsingBlockingScript.releaseElementAndClear(); 136 135 { 137 136 NestScript nestingLevel(m_scriptNestingLevel, m_host->inputStream()); … … 162 161 } 163 162 164 bool HTMLScriptRunner::hasScriptsWaitingForLoad() const165 {166 // We're only actually waiting for a load. This allows us to ignore load167 // callbacks when CachedResource::addClient calls notifyFinished because168 // of a cache hit (not because of a load we were set up to wait for).169 return m_parsingBlockingScript.watchingForLoadState == PendingScript::WatchingForLoad;170 }171 172 163 void HTMLScriptRunner::watchForLoad(PendingScript& pendingScript) 173 164 { 174 165 ASSERT(!pendingScript.watchingForLoad()); 175 // CachedResource::addClient will call notifyFinished if the load is already 176 // complete. We set watchingForLoadState to RegisteringForWatch so that we 177 // know to ignore any notifyFinished call during addClient. 178 pendingScript.watchingForLoadState = PendingScript::RegisteringForWatch; 179 m_host->watchForLoad(pendingScript.cachedScript.get()); 180 pendingScript.watchingForLoadState = PendingScript::WatchingForLoad; 166 m_host->watchForLoad(pendingScript.cachedScript()); 167 pendingScript.setWatchingForLoad(true); 181 168 } 182 169 … … 184 171 { 185 172 ASSERT(pendingScript.watchingForLoad()); 186 m_host->stopWatchingForLoad(pendingScript.cachedScript .get());187 pendingScript. watchingForLoadState = PendingScript::NotWatchingForLoad;173 m_host->stopWatchingForLoad(pendingScript.cachedScript()); 174 pendingScript.setWatchingForLoad(false); 188 175 } 189 176 … … 225 212 bool HTMLScriptRunner::executeScriptsWaitingForLoad(CachedResource* cachedScript) 226 213 { 227 // Callers should check hasScriptsWaitingForLoad() before calling228 // to prevent parser or script re-entry during due to229 // CachedResource::addClient calling notifyFinished on cache-hits.230 ASSERT(hasScriptsWaitingForLoad());231 214 ASSERT(!m_scriptNestingLevel); 232 215 ASSERT(haveParsingBlockingScript()); 233 ASSERT_UNUSED(cachedScript, m_parsingBlockingScript.cachedScript == cachedScript);234 ASSERT(m_parsingBlockingScript.cachedScript ->isLoaded());216 ASSERT_UNUSED(cachedScript, m_parsingBlockingScript.cachedScript() == cachedScript); 217 ASSERT(m_parsingBlockingScript.cachedScript()->isLoaded()); 235 218 return executeParsingBlockingScripts(); 236 219 } … … 263 246 return; 264 247 } 265 m_parsingBlockingScript.cachedScript = cachedScript; 266 267 // Always call watchForLoad, even if the script is already loaded. 268 // CachedResource may purge its data if it has no clients, which would cause 269 // later script execution to fail. watchForLoad sets m_parsingBlockingScript 270 // to the RegisteringForWatch state so we know to ignore any 271 // executeScriptsWaitingForLoad callbacks during the watchForLoad call. 272 watchForLoad(m_parsingBlockingScript); 273 // Callers will attempt to run the m_parsingBlockingScript if possible 274 // before returning control to the parser. 248 249 m_parsingBlockingScript.setCachedScript(cachedScript); 250 251 // We only care about a load callback if cachedScript is not already 252 // in the cache. Callers will attempt to run the m_parsingBlockingScript 253 // if possible before returning control to the parser. 254 if (!m_parsingBlockingScript.cachedScript()->isLoaded()) 255 watchForLoad(m_parsingBlockingScript); 275 256 } 276 257 … … 298 279 } 299 280 300 } 281 HTMLScriptRunner::PendingScript::~PendingScript() 282 { 283 if (m_cachedScript) 284 m_cachedScript->removeClient(this); 285 } 286 287 PassRefPtr<Element> HTMLScriptRunner::PendingScript::releaseElementAndClear() 288 { 289 setCachedScript(0); 290 startingLineNumber = 0; 291 m_watchingForLoad = false; 292 return element.release(); 293 } 294 295 void HTMLScriptRunner::PendingScript::setCachedScript(CachedScript* cachedScript) 296 { 297 if (m_cachedScript == cachedScript) 298 return; 299 if (m_cachedScript) 300 m_cachedScript->removeClient(this); 301 m_cachedScript = cachedScript; 302 if (m_cachedScript) 303 m_cachedScript->addClient(this); 304 } 305 306 CachedScript* HTMLScriptRunner::PendingScript::cachedScript() const 307 { 308 return m_cachedScript.get(); 309 } 310 311 } -
trunk/WebCore/html/HTMLScriptRunner.h
r61673 r61940 50 50 bool execute(PassRefPtr<Element> scriptToProcess, int scriptStartLine); 51 51 52 bool hasScriptsWaitingForLoad() const;53 52 bool executeScriptsWaitingForLoad(CachedResource*); 54 55 53 bool hasScriptsWaitingForStylesheets() const { return m_hasScriptsWaitingForStylesheets; } 56 54 bool executeScriptsWaitingForStylesheets(); … … 59 57 60 58 private: 61 struct PendingScript { 62 // This state controls whether we need to do anything with this script 63 // when we get a executeScriptsWaitingForLoad callback. 64 // We ignore callbacks during RegisteringForWatch. 65 enum WatchingForLoadState { 66 NotWatchingForLoad, 67 RegisteringForWatch, 68 WatchingForLoad, 69 }; 70 59 // A container for an external script which may be loaded and executed. 60 // 61 // A CachedResourceHandle alone does not prevent the underlying CachedResource 62 // from purging its data buffer. This class holds a dummy client open for its 63 // lifetime in order to guarantee that the data buffer will not be purged. 64 // 65 // FIXME: Finish turning this into a proper class. 66 class PendingScript : public CachedResourceClient, Noncopyable { 67 public: 71 68 PendingScript() 72 : watchingForLoadState(NotWatchingForLoad)73 , startingLineNumber(0)69 : startingLineNumber(0) 70 , m_watchingForLoad(false) 74 71 { 75 72 } 76 73 77 bool watchingForLoad() 74 ~PendingScript(); 75 76 PassRefPtr<Element> releaseElementAndClear(); 77 78 bool watchingForLoad() const { return m_watchingForLoad; } 79 void setWatchingForLoad(bool b) { m_watchingForLoad = b; } 80 81 CachedScript* cachedScript() const; 82 void setCachedScript(CachedScript*); 83 84 virtual void notifyFinished(CachedResource*) 78 85 { 79 return watchingForLoadState != NotWatchingForLoad;80 86 } 81 87 82 88 RefPtr<Element> element; 83 CachedResourceHandle<CachedScript> cachedScript;84 WatchingForLoadState watchingForLoadState;85 89 int startingLineNumber; // Only used for inline script tags. 86 90 // HTML5 has an isReady parameter, however isReady ends up equivalent to 87 91 // m_document->haveStylesheetsLoaded() && cachedScript->isLoaded() 92 93 private: 94 bool m_watchingForLoad; 95 CachedResourceHandle<CachedScript> m_cachedScript; 88 96 }; 89 97 -
trunk/WebCore/html/HTMLScriptRunnerHost.h
r61673 r61940 39 39 virtual ~HTMLScriptRunnerHost() { } 40 40 41 // Implementors must call cachedResource->addClient() immediately.41 // Implementors should call cachedResource->addClient() here or soon after. 42 42 virtual void watchForLoad(CachedResource*) = 0; 43 43 // Implementors must call cachedResource->removeClient() immediately.
Note: See TracChangeset
for help on using the changeset viewer.