Bug 1864587 - [angle] Vendor mozilla/angle/firefox-123. r=gfx-reviewers,aosmond
[gecko.git] / js / loader / LoadedScript.cpp
blob7ddd04168ebf20f8c0ba141e5b33e40f4f005e5d
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/. */
7 #include "LoadedScript.h"
9 #include "mozilla/HoldDropJSObjects.h"
10 #include "mozilla/UniquePtr.h" // mozilla::UniquePtr
12 #include "mozilla/dom/ScriptLoadContext.h" // ScriptLoadContext
13 #include "jsfriendapi.h"
14 #include "js/Modules.h" // JS::{Get,Set}ModulePrivate
15 #include "LoadContextBase.h" // LoadContextBase
17 namespace JS::loader {
19 //////////////////////////////////////////////////////////////
20 // LoadedScript
21 //////////////////////////////////////////////////////////////
23 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(LoadedScript)
24 NS_INTERFACE_MAP_ENTRY(nsISupports)
25 NS_INTERFACE_MAP_END
27 NS_IMPL_CYCLE_COLLECTION_CLASS(LoadedScript)
29 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(LoadedScript)
30 NS_IMPL_CYCLE_COLLECTION_UNLINK(mFetchOptions)
31 NS_IMPL_CYCLE_COLLECTION_UNLINK(mBaseURL)
32 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
34 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(LoadedScript)
35 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFetchOptions)
36 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
38 NS_IMPL_CYCLE_COLLECTING_ADDREF(LoadedScript)
39 NS_IMPL_CYCLE_COLLECTING_RELEASE(LoadedScript)
41 LoadedScript::LoadedScript(ScriptKind aKind,
42 mozilla::dom::ReferrerPolicy aReferrerPolicy,
43 ScriptFetchOptions* aFetchOptions, nsIURI* aURI)
44 : mKind(aKind),
45 mReferrerPolicy(aReferrerPolicy),
46 mFetchOptions(aFetchOptions),
47 mURI(aURI),
48 mDataType(DataType::eUnknown),
49 mReceivedScriptTextLength(0),
50 mBytecodeOffset(0) {
51 MOZ_ASSERT(mFetchOptions);
52 MOZ_ASSERT(mURI);
55 LoadedScript::~LoadedScript() { mozilla::DropJSObjects(this); }
57 void LoadedScript::AssociateWithScript(JSScript* aScript) {
58 // Verify that the rewritten URL is available when manipulating LoadedScript.
59 MOZ_ASSERT(mBaseURL);
61 // Set a JSScript's private value to point to this object. The JS engine will
62 // increment our reference count by calling HostAddRefTopLevelScript(). This
63 // is decremented by HostReleaseTopLevelScript() below when the JSScript dies.
65 MOZ_ASSERT(JS::GetScriptPrivate(aScript).isUndefined());
66 JS::SetScriptPrivate(aScript, JS::PrivateValue(this));
69 nsresult LoadedScript::GetScriptSource(JSContext* aCx,
70 MaybeSourceText* aMaybeSource,
71 LoadContextBase* aMaybeLoadContext) {
72 // If there's no script text, we try to get it from the element
73 bool isWindowContext =
74 aMaybeLoadContext && aMaybeLoadContext->IsWindowContext();
75 if (isWindowContext && aMaybeLoadContext->AsWindowContext()->mIsInline) {
76 nsAutoString inlineData;
77 auto* scriptLoadContext = aMaybeLoadContext->AsWindowContext();
78 scriptLoadContext->GetScriptElement()->GetScriptText(inlineData);
80 size_t nbytes = inlineData.Length() * sizeof(char16_t);
81 JS::UniqueTwoByteChars chars(
82 static_cast<char16_t*>(JS_malloc(aCx, nbytes)));
83 if (!chars) {
84 return NS_ERROR_OUT_OF_MEMORY;
87 memcpy(chars.get(), inlineData.get(), nbytes);
89 SourceText<char16_t> srcBuf;
90 if (!srcBuf.init(aCx, std::move(chars), inlineData.Length())) {
91 return NS_ERROR_OUT_OF_MEMORY;
94 aMaybeSource->construct<SourceText<char16_t>>(std::move(srcBuf));
95 return NS_OK;
98 size_t length = ScriptTextLength();
99 if (IsUTF16Text()) {
100 JS::UniqueTwoByteChars chars;
101 chars.reset(ScriptText<char16_t>().extractOrCopyRawBuffer());
102 if (!chars) {
103 JS_ReportOutOfMemory(aCx);
104 return NS_ERROR_OUT_OF_MEMORY;
107 SourceText<char16_t> srcBuf;
108 if (!srcBuf.init(aCx, std::move(chars), length)) {
109 return NS_ERROR_OUT_OF_MEMORY;
112 aMaybeSource->construct<SourceText<char16_t>>(std::move(srcBuf));
113 return NS_OK;
116 MOZ_ASSERT(IsUTF8Text());
117 mozilla::UniquePtr<Utf8Unit[], JS::FreePolicy> chars;
118 chars.reset(ScriptText<Utf8Unit>().extractOrCopyRawBuffer());
119 if (!chars) {
120 JS_ReportOutOfMemory(aCx);
121 return NS_ERROR_OUT_OF_MEMORY;
124 SourceText<Utf8Unit> srcBuf;
125 if (!srcBuf.init(aCx, std::move(chars), length)) {
126 return NS_ERROR_OUT_OF_MEMORY;
129 aMaybeSource->construct<SourceText<Utf8Unit>>(std::move(srcBuf));
130 return NS_OK;
133 inline void CheckModuleScriptPrivate(LoadedScript* script,
134 const JS::Value& aPrivate) {
135 #ifdef DEBUG
136 if (script->IsModuleScript()) {
137 JSObject* module = script->AsModuleScript()->mModuleRecord.unbarrieredGet();
138 MOZ_ASSERT_IF(module, JS::GetModulePrivate(module) == aPrivate);
140 #endif
143 void HostAddRefTopLevelScript(const JS::Value& aPrivate) {
144 // Increment the reference count of a LoadedScript object that is now pointed
145 // to by a JSScript. The reference count is decremented by
146 // HostReleaseTopLevelScript() below.
148 auto script = static_cast<LoadedScript*>(aPrivate.toPrivate());
149 CheckModuleScriptPrivate(script, aPrivate);
150 script->AddRef();
153 void HostReleaseTopLevelScript(const JS::Value& aPrivate) {
154 // Decrement the reference count of a LoadedScript object that was pointed to
155 // by a JSScript. The reference count was originally incremented by
156 // HostAddRefTopLevelScript() above.
158 auto script = static_cast<LoadedScript*>(aPrivate.toPrivate());
159 CheckModuleScriptPrivate(script, aPrivate);
160 script->Release();
163 //////////////////////////////////////////////////////////////
164 // EventScript
165 //////////////////////////////////////////////////////////////
167 EventScript::EventScript(mozilla::dom::ReferrerPolicy aReferrerPolicy,
168 ScriptFetchOptions* aFetchOptions, nsIURI* aURI)
169 : LoadedScript(ScriptKind::eEvent, aReferrerPolicy, aFetchOptions, aURI) {
170 // EventScripts are not using ScriptLoadRequest, and mBaseURL and mURI are
171 // the same thing.
172 SetBaseURL(aURI);
175 //////////////////////////////////////////////////////////////
176 // ClassicScript
177 //////////////////////////////////////////////////////////////
179 ClassicScript::ClassicScript(mozilla::dom::ReferrerPolicy aReferrerPolicy,
180 ScriptFetchOptions* aFetchOptions, nsIURI* aURI)
181 : LoadedScript(ScriptKind::eClassic, aReferrerPolicy, aFetchOptions, aURI) {
184 //////////////////////////////////////////////////////////////
185 // ModuleScript
186 //////////////////////////////////////////////////////////////
188 NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED_0(ModuleScript, LoadedScript)
190 NS_IMPL_CYCLE_COLLECTION_CLASS(ModuleScript)
192 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(ModuleScript, LoadedScript)
193 tmp->UnlinkModuleRecord();
194 tmp->mParseError.setUndefined();
195 tmp->mErrorToRethrow.setUndefined();
196 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
198 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(ModuleScript, LoadedScript)
199 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
201 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(ModuleScript, LoadedScript)
202 NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mModuleRecord)
203 NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mParseError)
204 NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mErrorToRethrow)
205 NS_IMPL_CYCLE_COLLECTION_TRACE_END
207 ModuleScript::ModuleScript(mozilla::dom::ReferrerPolicy aReferrerPolicy,
208 ScriptFetchOptions* aFetchOptions, nsIURI* aURI)
209 : LoadedScript(ScriptKind::eModule, aReferrerPolicy, aFetchOptions, aURI),
210 mDebuggerDataInitialized(false) {
211 MOZ_ASSERT(!ModuleRecord());
212 MOZ_ASSERT(!HasParseError());
213 MOZ_ASSERT(!HasErrorToRethrow());
216 void ModuleScript::Shutdown() {
217 if (mModuleRecord) {
218 JS::ClearModuleEnvironment(mModuleRecord);
221 UnlinkModuleRecord();
224 void ModuleScript::UnlinkModuleRecord() {
225 // Remove the module record's pointer to this object if present and decrement
226 // our reference count. The reference is added by SetModuleRecord() below.
228 // This takes care not to trigger gray unmarking because this takes a lot of
229 // time when we're tearing down the entire page. This is safe because we are
230 // only writing undefined into the module private, so it won't create any
231 // black-gray edges.
232 if (mModuleRecord) {
233 JSObject* module = mModuleRecord.unbarrieredGet();
234 MOZ_ASSERT(JS::GetModulePrivate(module).toPrivate() == this);
235 JS::ClearModulePrivate(module);
236 mModuleRecord = nullptr;
240 ModuleScript::~ModuleScript() {
241 // The object may be destroyed without being unlinked first.
242 UnlinkModuleRecord();
245 void ModuleScript::SetModuleRecord(JS::Handle<JSObject*> aModuleRecord) {
246 MOZ_ASSERT(!mModuleRecord);
247 MOZ_ASSERT_IF(IsModuleScript(), !AsModuleScript()->HasParseError());
248 MOZ_ASSERT_IF(IsModuleScript(), !AsModuleScript()->HasErrorToRethrow());
250 mModuleRecord = aModuleRecord;
252 // Make module's host defined field point to this object. The JS engine will
253 // increment our reference count by calling HostAddRefTopLevelScript(). This
254 // is decremented when the field is cleared in UnlinkModuleRecord() above or
255 // when the module record dies.
256 MOZ_ASSERT(JS::GetModulePrivate(mModuleRecord).isUndefined());
257 JS::SetModulePrivate(mModuleRecord, JS::PrivateValue(this));
259 mozilla::HoldJSObjects(this);
262 void ModuleScript::SetParseError(const JS::Value& aError) {
263 MOZ_ASSERT(!aError.isUndefined());
264 MOZ_ASSERT(!HasParseError());
265 MOZ_ASSERT(!HasErrorToRethrow());
267 UnlinkModuleRecord();
268 mParseError = aError;
269 mozilla::HoldJSObjects(this);
272 void ModuleScript::SetErrorToRethrow(const JS::Value& aError) {
273 MOZ_ASSERT(!aError.isUndefined());
275 // This is only called after SetModuleRecord() or SetParseError() so we don't
276 // need to call HoldJSObjects() here.
277 MOZ_ASSERT(ModuleRecord() || HasParseError());
279 mErrorToRethrow = aError;
282 void ModuleScript::SetDebuggerDataInitialized() {
283 MOZ_ASSERT(ModuleRecord());
284 MOZ_ASSERT(!mDebuggerDataInitialized);
286 mDebuggerDataInitialized = true;
289 } // namespace JS::loader