ScriptLoadContext.cpp (7791B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "ScriptLoadContext.h" 8 9 #include "GeckoProfiler.h" 10 #include "ModuleLoadRequest.h" 11 #include "js/SourceText.h" 12 #include "js/loader/LoadContextBase.h" 13 #include "js/loader/ModuleLoadRequest.h" 14 #include "mozilla/HoldDropJSObjects.h" 15 #include "mozilla/StaticPrefs_dom.h" 16 #include "mozilla/Utf8.h" // mozilla::Utf8Unit 17 #include "mozilla/dom/Document.h" 18 #include "nsContentUtils.h" 19 #include "nsICacheInfoChannel.h" 20 #include "nsIClassOfService.h" 21 #include "nsISupportsPriority.h" 22 23 namespace mozilla::dom { 24 25 ////////////////////////////////////////////////////////////// 26 // ScriptLoadContext 27 ////////////////////////////////////////////////////////////// 28 29 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ScriptLoadContext) 30 NS_INTERFACE_MAP_END_INHERITING(JS::loader::LoadContextBase) 31 32 NS_IMPL_CYCLE_COLLECTION_CLASS(ScriptLoadContext) 33 34 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(ScriptLoadContext, 35 JS::loader::LoadContextBase) 36 MOZ_ASSERT(!tmp->mCompileOrDecodeTask); 37 tmp->MaybeUnblockOnload(); 38 NS_IMPL_CYCLE_COLLECTION_UNLINK(mScriptElement); 39 NS_IMPL_CYCLE_COLLECTION_UNLINK_END 40 41 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(ScriptLoadContext, 42 JS::loader::LoadContextBase) 43 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLoadBlockedDocument) 44 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mScriptElement); 45 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END 46 47 NS_IMPL_ADDREF_INHERITED(ScriptLoadContext, JS::loader::LoadContextBase) 48 NS_IMPL_RELEASE_INHERITED(ScriptLoadContext, JS::loader::LoadContextBase) 49 50 ScriptLoadContext::ScriptLoadContext( 51 nsIScriptElement* aScriptElement /* = nullptr */, 52 const nsAString& aSourceText /* = VoidString() */) 53 : JS::loader::LoadContextBase(JS::loader::ContextKind::Window), 54 mScriptMode(ScriptMode::eBlocking), 55 mScriptFromHead(false), 56 mIsInline(true), 57 mInDeferList(false), 58 mInAsyncList(false), 59 mIsNonAsyncScriptInserted(false), 60 mIsXSLT(false), 61 mInCompilingList(false), 62 mClassificationFlags({0, 0}), 63 mWasCompiledOMT(false), 64 mLineNo(1), 65 mColumnNo(0), 66 mIsPreload(false), 67 mScriptElement(aScriptElement), 68 mSourceText(aSourceText), 69 mUnreportedPreloadError(NS_OK) {} 70 71 ScriptLoadContext::~ScriptLoadContext() { 72 MOZ_ASSERT(NS_IsMainThread()); 73 74 // Off-thread parsing must have completed or cancelled by this point. 75 MOZ_DIAGNOSTIC_ASSERT(!mCompileOrDecodeTask); 76 77 mRequest = nullptr; 78 79 MaybeUnblockOnload(); 80 } 81 82 void ScriptLoadContext::BlockOnload(Document* aDocument) { 83 MOZ_ASSERT(!mLoadBlockedDocument); 84 aDocument->BlockOnload(); 85 mLoadBlockedDocument = aDocument; 86 } 87 88 void ScriptLoadContext::MaybeUnblockOnload() { 89 if (mLoadBlockedDocument) { 90 mLoadBlockedDocument->UnblockOnload(false); 91 mLoadBlockedDocument = nullptr; 92 } 93 } 94 95 void ScriptLoadContext::MaybeCancelOffThreadScript() { 96 MOZ_ASSERT(NS_IsMainThread()); 97 98 if (!mCompileOrDecodeTask) { 99 return; 100 } 101 102 // Cancel the task if it hasn't been started yet or wait for it to finish. 103 mCompileOrDecodeTask->Cancel(); 104 mCompileOrDecodeTask = nullptr; 105 106 MaybeUnblockOnload(); 107 } 108 109 void ScriptLoadContext::SetScriptMode(bool aDeferAttr, bool aAsyncAttr, 110 bool aLinkPreload) { 111 if (aLinkPreload) { 112 mScriptMode = ScriptMode::eLinkPreload; 113 } else if (aAsyncAttr) { 114 mScriptMode = ScriptMode::eAsync; 115 } else if (aDeferAttr || mRequest->IsModuleRequest()) { 116 mScriptMode = ScriptMode::eDeferred; 117 } else { 118 mScriptMode = ScriptMode::eBlocking; 119 } 120 } 121 122 // static 123 void ScriptLoadContext::PrioritizeAsPreload(nsIChannel* aChannel) { 124 if (nsCOMPtr<nsIClassOfService> cos = do_QueryInterface(aChannel)) { 125 cos->AddClassFlags(nsIClassOfService::Unblocked); 126 } 127 if (nsCOMPtr<nsISupportsPriority> sp = do_QueryInterface(aChannel)) { 128 sp->AdjustPriority(nsISupportsPriority::PRIORITY_HIGHEST); 129 } 130 } 131 132 bool ScriptLoadContext::IsPreload() const { 133 if (mRequest->IsModuleRequest() && 134 mRequest->AsModuleRequest()->IsStaticImport()) { 135 JS::loader::ModuleLoadRequest* root = 136 mRequest->AsModuleRequest()->GetRootModule(); 137 return root->GetScriptLoadContext()->IsPreload(); 138 } 139 140 MOZ_ASSERT_IF(mIsPreload, !HasScriptElement()); 141 return mIsPreload; 142 } 143 144 bool ScriptLoadContext::CompileStarted() const { 145 return mRequest->IsCompiling() || (mRequest->IsFinished() && mWasCompiledOMT); 146 } 147 148 bool ScriptLoadContext::HasScriptElement() const { return !!mScriptElement; } 149 150 void ScriptLoadContext::GetInlineScriptText(nsAString& aText) const { 151 MOZ_ASSERT(mIsInline); 152 if (mSourceText.IsVoid()) { 153 // Lazily retrieve the text of inline script, see bug 1376651. 154 mScriptElement->GetScriptText(aText); 155 } else { 156 aText.Append(mSourceText); 157 } 158 } 159 160 void ScriptLoadContext::GetHintCharset(nsAString& aCharset) const { 161 MOZ_ASSERT(mScriptElement); 162 mScriptElement->GetScriptCharset(aCharset); 163 } 164 165 uint32_t ScriptLoadContext::GetScriptLineNumber() const { 166 if (mScriptElement) { 167 return mScriptElement->GetScriptLineNumber(); 168 } 169 return 0; 170 } 171 172 JS::ColumnNumberOneOrigin ScriptLoadContext::GetScriptColumnNumber() const { 173 if (mScriptElement) { 174 return mScriptElement->GetScriptColumnNumber(); 175 } 176 return JS::ColumnNumberOneOrigin(); 177 } 178 179 void ScriptLoadContext::BeginEvaluatingTopLevel() const { 180 MOZ_ASSERT(mScriptElement); 181 mScriptElement->BeginEvaluating(); 182 } 183 184 void ScriptLoadContext::EndEvaluatingTopLevel() const { 185 MOZ_ASSERT(mScriptElement); 186 mScriptElement->EndEvaluating(); 187 } 188 189 void ScriptLoadContext::UnblockParser() const { 190 MOZ_ASSERT(mScriptElement); 191 mScriptElement->UnblockParser(); 192 } 193 194 void ScriptLoadContext::ContinueParserAsync() const { 195 MOZ_ASSERT(mScriptElement); 196 mScriptElement->ContinueParserAsync(); 197 } 198 199 Document* ScriptLoadContext::GetScriptOwnerDocument() const { 200 nsCOMPtr<nsIContent> scriptContent(do_QueryInterface(mScriptElement)); 201 MOZ_ASSERT(scriptContent); 202 return scriptContent->OwnerDoc(); 203 } 204 205 void ScriptLoadContext::SetIsLoadRequest(nsIScriptElement* aElement) { 206 MOZ_ASSERT(aElement); 207 MOZ_ASSERT(!HasScriptElement()); 208 MOZ_ASSERT(IsPreload()); 209 mScriptElement = aElement; 210 mIsPreload = false; 211 } 212 213 void ScriptLoadContext::GetProfilerLabel(nsACString& aOutString) { 214 if (!profiler_is_active()) { 215 aOutString.Append("<script> element"); 216 return; 217 } 218 aOutString.Append("<script"); 219 if (IsAsyncScript()) { 220 aOutString.Append(" async"); 221 } else if (IsDeferredScript()) { 222 aOutString.Append(" defer"); 223 } 224 if (mRequest->IsModuleRequest()) { 225 aOutString.Append(" type=\"module\""); 226 } 227 228 nsAutoCString url; 229 if (mRequest->URI()) { 230 mRequest->URI()->GetAsciiSpec(url); 231 } else { 232 url = "<unknown>"; 233 } 234 235 if (mIsInline) { 236 if (GetParserCreated() != NOT_FROM_PARSER) { 237 aOutString.Append("> inline at line "); 238 aOutString.AppendInt(mLineNo); 239 aOutString.Append(" of "); 240 } else { 241 aOutString.Append("> inline (dynamically created) in "); 242 } 243 aOutString.Append(url); 244 } else { 245 aOutString.Append(" src=\""); 246 aOutString.Append(url); 247 aOutString.Append("\">"); 248 } 249 } 250 251 already_AddRefed<JS::Stencil> ScriptLoadContext::StealOffThreadResult( 252 JSContext* aCx, JS::InstantiationStorage* aInstantiationStorage) { 253 RefPtr<CompileOrDecodeTask> compileOrDecodeTask = 254 mCompileOrDecodeTask.forget(); 255 256 return compileOrDecodeTask->StealResult(aCx, aInstantiationStorage); 257 } 258 259 } // namespace mozilla::dom