Changeset 61638 in webkit
- Timestamp:
- Jun 22, 2010 4:46:53 PM (14 years ago)
- Location:
- trunk/WebCore
- Files:
-
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/WebCore/ChangeLog
r61637 r61638 1 2010-06-22 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 approach from preventing unexpected purges; always keep a client open. 10 This will 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 purge itself is not 15 testable from a LayoutTest. 16 17 * html/HTML5DocumentParser.cpp: 18 (WebCore::HTML5DocumentParser::watchForLoad): 19 (WebCore::HTML5DocumentParser::notifyFinished): 20 * html/HTML5ScriptRunner.cpp: 21 (WebCore::HTML5ScriptRunner::~HTML5ScriptRunner): 22 (WebCore::HTML5ScriptRunner::sourceFromPendingScript): 23 (WebCore::HTML5ScriptRunner::isPendingScriptReady): 24 (WebCore::HTML5ScriptRunner::executePendingScript): 25 (WebCore::HTML5ScriptRunner::watchForLoad): 26 (WebCore::HTML5ScriptRunner::stopWatchingForLoad): 27 (WebCore::HTML5ScriptRunner::executeScriptsWaitingForLoad): 28 (WebCore::HTML5ScriptRunner::executeScriptsWaitingForStylesheets): 29 (WebCore::HTML5ScriptRunner::requestScript): 30 * html/HTML5ScriptRunner.h: 31 (WebCore::HTML5ScriptRunner::PendingScript::PendingScript): 32 (WebCore::HTML5ScriptRunner::PendingScript::~PendingScript): 33 (WebCore::HTML5ScriptRunner::PendingScript::setCachedScript): 34 (WebCore::HTML5ScriptRunner::PendingScript::cachedScript): 35 (WebCore::HTML5ScriptRunner::PendingScript::notifyFinished): 36 * html/HTML5ScriptRunnerHost.h: 37 1 38 2010-06-22 Eric Seidel <eric@webkit.org> 2 39 -
trunk/WebCore/html/HTML5DocumentParser.cpp
r61637 r61638 414 414 void HTML5DocumentParser::watchForLoad(CachedResource* cachedScript) 415 415 { 416 ASSERT(!cachedScript->isLoaded()); 417 // addClient would call notifyFinished if the load were complete. 418 // Callers do not expect to be re-entered from this call, so they should 419 // not an already-loaded CachedResource. 416 420 cachedScript->addClient(this); 417 421 } … … 432 436 { 433 437 ASSERT(m_scriptRunner); 434 // Ignore calls unless we have a script blocking the parser waiting435 // for its own load. Otherwise this may be a load callback from436 // CachedResource::addClient because the script was already in the cache.437 // HTML5ScriptRunner may not be ready to handle running that script yet.438 if (!m_scriptRunner->hasScriptsWaitingForLoad()) {439 ASSERT(m_scriptRunner->inScriptExecution());440 return;441 }442 438 ASSERT(!inScriptExecution()); 443 439 ASSERT(m_treeConstructor->isPaused()); -
trunk/WebCore/html/HTML5ScriptRunner.cpp
r61608 r61638 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 HTML5ScriptRunner::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 … … 162 162 } 163 163 164 bool HTML5ScriptRunner::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 164 void HTML5ScriptRunner::watchForLoad(PendingScript& pendingScript) 173 165 { 174 166 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; 167 m_host->watchForLoad(pendingScript.cachedScript()); 168 pendingScript.setWatchingForLoad(true); 181 169 } 182 170 … … 184 172 { 185 173 ASSERT(pendingScript.watchingForLoad()); 186 m_host->stopWatchingForLoad(pendingScript.cachedScript .get());187 pendingScript. watchingForLoadState = PendingScript::NotWatchingForLoad;174 m_host->stopWatchingForLoad(pendingScript.cachedScript()); 175 pendingScript.setWatchingForLoad(false); 188 176 } 189 177 … … 225 213 bool HTML5ScriptRunner::executeScriptsWaitingForLoad(CachedResource* cachedScript) 226 214 { 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 215 ASSERT(!m_scriptNestingLevel); 232 216 ASSERT(haveParsingBlockingScript()); 233 ASSERT_UNUSED(cachedScript, m_parsingBlockingScript.cachedScript == cachedScript);234 ASSERT(m_parsingBlockingScript.cachedScript ->isLoaded());217 ASSERT_UNUSED(cachedScript, m_parsingBlockingScript.cachedScript() == cachedScript); 218 ASSERT(m_parsingBlockingScript.cachedScript()->isLoaded()); 235 219 return executeParsingBlockingScripts(); 236 220 } … … 240 224 // Callers should check hasScriptsWaitingForStylesheets() before calling 241 225 // to prevent parser or script re-entry during </style> parsing. 242 ASSERT( hasScriptsWaitingForStylesheets());226 ASSERT(m_hasScriptsWaitingForStylesheets); 243 227 ASSERT(!m_scriptNestingLevel); 244 228 ASSERT(m_document->haveStylesheetsLoaded()); … … 263 247 return; 264 248 } 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. 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 HTML5ScriptRunner::PendingScript::~PendingScript() 282 { 283 if (m_cachedScript) 284 m_cachedScript->removeClient(this); 285 } 286 287 void HTML5ScriptRunner::PendingScript::setCachedScript(CachedScript* cachedScript) 288 { 289 if (m_cachedScript) 290 m_cachedScript->removeClient(this); 291 m_cachedScript = cachedScript; 292 if (m_cachedScript) 293 m_cachedScript->addClient(this); 294 } 295 296 CachedScript* HTML5ScriptRunner::PendingScript::cachedScript() const 297 { 298 return m_cachedScript.get(); 299 } 300 301 } -
trunk/WebCore/html/HTML5ScriptRunner.h
r61374 r61638 49 49 // Processes the passed in script and any pending scripts if possible. 50 50 bool execute(PassRefPtr<Element> scriptToProcess, int scriptStartLine); 51 52 bool hasScriptsWaitingForLoad() const; 51 // Processes any pending scripts. 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 class PendingScript : public CachedResourceClient { 65 public: 71 66 PendingScript() 72 : watchingForLoadState(NotWatchingForLoad)67 : m_watchingForLoad(false) 73 68 , startingLineNumber(0) 74 69 { 75 70 } 76 71 77 bool watchingForLoad() 72 ~PendingScript(); 73 74 bool watchingForLoad() const { return m_watchingForLoad; } 75 void setWatchingForLoad(bool b) { m_watchingForLoad = b; } 76 77 CachedScript* cachedScript() const; 78 void setCachedScript(CachedScript* cachedScript); 79 80 virtual void notifyFinished(CachedResource*) 78 81 { 79 return watchingForLoadState != NotWatchingForLoad;80 82 } 81 83 82 84 RefPtr<Element> element; 83 CachedResourceHandle<CachedScript> cachedScript;84 WatchingForLoadState watchingForLoadState;85 85 int startingLineNumber; // Only used for inline script tags. 86 86 // HTML5 has an isReady parameter, however isReady ends up equivalent to 87 87 // m_document->haveStylesheetsLoaded() && cachedScript->isLoaded() 88 89 private: 90 bool m_watchingForLoad; // Did we pass the cachedScript to the HTML5ScriptRunnerHost. 91 CachedResourceHandle<CachedScript> m_cachedScript; 88 92 }; 89 93 -
trunk/WebCore/html/HTML5ScriptRunnerHost.h
r61607 r61638 39 39 virtual ~HTML5ScriptRunnerHost() { } 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.