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"
11 #include "jsfriendapi.h"
12 #include "js/Modules.h" // JS::{Get,Set}ModulePrivate
14 namespace JS::loader
{
16 //////////////////////////////////////////////////////////////
18 //////////////////////////////////////////////////////////////
20 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(LoadedScript
)
21 NS_INTERFACE_MAP_ENTRY(nsISupports
)
24 NS_IMPL_CYCLE_COLLECTION_CLASS(LoadedScript
)
26 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(LoadedScript
)
27 NS_IMPL_CYCLE_COLLECTION_UNLINK(mFetchOptions
)
28 NS_IMPL_CYCLE_COLLECTION_UNLINK(mBaseURL
)
29 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
31 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(LoadedScript
)
32 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFetchOptions
)
33 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
35 NS_IMPL_CYCLE_COLLECTING_ADDREF(LoadedScript
)
36 NS_IMPL_CYCLE_COLLECTING_RELEASE(LoadedScript
)
38 LoadedScript::LoadedScript(ScriptKind aKind
, ScriptFetchOptions
* aFetchOptions
,
40 : mKind(aKind
), mFetchOptions(aFetchOptions
), mBaseURL(aBaseURL
) {
41 MOZ_ASSERT(mFetchOptions
);
45 LoadedScript::~LoadedScript() { mozilla::DropJSObjects(this); }
47 void LoadedScript::AssociateWithScript(JSScript
* aScript
) {
48 // Set a JSScript's private value to point to this object. The JS engine will
49 // increment our reference count by calling HostAddRefTopLevelScript(). This
50 // is decremented by HostReleaseTopLevelScript() below when the JSScript dies.
52 MOZ_ASSERT(JS::GetScriptPrivate(aScript
).isUndefined());
53 JS::SetScriptPrivate(aScript
, JS::PrivateValue(this));
56 inline void CheckModuleScriptPrivate(LoadedScript
* script
,
57 const JS::Value
& aPrivate
) {
59 if (script
->IsModuleScript()) {
60 JSObject
* module
= script
->AsModuleScript()->mModuleRecord
.unbarrieredGet();
61 MOZ_ASSERT_IF(module
, JS::GetModulePrivate(module
) == aPrivate
);
66 void HostAddRefTopLevelScript(const JS::Value
& aPrivate
) {
67 // Increment the reference count of a LoadedScript object that is now pointed
68 // to by a JSScript. The reference count is decremented by
69 // HostReleaseTopLevelScript() below.
71 auto script
= static_cast<LoadedScript
*>(aPrivate
.toPrivate());
72 CheckModuleScriptPrivate(script
, aPrivate
);
76 void HostReleaseTopLevelScript(const JS::Value
& aPrivate
) {
77 // Decrement the reference count of a LoadedScript object that was pointed to
78 // by a JSScript. The reference count was originally incremented by
79 // HostAddRefTopLevelScript() above.
81 auto script
= static_cast<LoadedScript
*>(aPrivate
.toPrivate());
82 CheckModuleScriptPrivate(script
, aPrivate
);
86 //////////////////////////////////////////////////////////////
88 //////////////////////////////////////////////////////////////
90 EventScript::EventScript(ScriptFetchOptions
* aFetchOptions
, nsIURI
* aBaseURL
)
91 : LoadedScript(ScriptKind::eEvent
, aFetchOptions
, aBaseURL
) {}
93 //////////////////////////////////////////////////////////////
95 //////////////////////////////////////////////////////////////
97 ClassicScript::ClassicScript(ScriptFetchOptions
* aFetchOptions
,
99 : LoadedScript(ScriptKind::eClassic
, aFetchOptions
, aBaseURL
) {}
101 //////////////////////////////////////////////////////////////
103 //////////////////////////////////////////////////////////////
105 NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED_0(ModuleScript
, LoadedScript
)
107 NS_IMPL_CYCLE_COLLECTION_CLASS(ModuleScript
)
109 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(ModuleScript
, LoadedScript
)
110 tmp
->UnlinkModuleRecord();
111 tmp
->mParseError
.setUndefined();
112 tmp
->mErrorToRethrow
.setUndefined();
113 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
115 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(ModuleScript
, LoadedScript
)
116 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
118 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(ModuleScript
, LoadedScript
)
119 NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mModuleRecord
)
120 NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mParseError
)
121 NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mErrorToRethrow
)
122 NS_IMPL_CYCLE_COLLECTION_TRACE_END
124 ModuleScript::ModuleScript(ScriptFetchOptions
* aFetchOptions
, nsIURI
* aBaseURL
)
125 : LoadedScript(ScriptKind::eModule
, aFetchOptions
, aBaseURL
),
126 mDebuggerDataInitialized(false) {
127 MOZ_ASSERT(!ModuleRecord());
128 MOZ_ASSERT(!HasParseError());
129 MOZ_ASSERT(!HasErrorToRethrow());
132 void ModuleScript::Shutdown() {
134 JS::ClearModuleEnvironment(mModuleRecord
);
137 UnlinkModuleRecord();
140 void ModuleScript::UnlinkModuleRecord() {
141 // Remove the module record's pointer to this object if present and decrement
142 // our reference count. The reference is added by SetModuleRecord() below.
144 // This takes care not to trigger gray unmarking because this takes a lot of
145 // time when we're tearing down the entire page. This is safe because we are
146 // only writing undefined into the module private, so it won't create any
149 JSObject
* module
= mModuleRecord
.unbarrieredGet();
150 MOZ_ASSERT(JS::GetModulePrivate(module
).toPrivate() == this);
151 JS::ClearModulePrivate(module
);
152 mModuleRecord
= nullptr;
156 ModuleScript::~ModuleScript() {
157 // The object may be destroyed without being unlinked first.
158 UnlinkModuleRecord();
161 void ModuleScript::SetModuleRecord(JS::Handle
<JSObject
*> aModuleRecord
) {
162 MOZ_ASSERT(!mModuleRecord
);
163 MOZ_ASSERT_IF(IsModuleScript(), !AsModuleScript()->HasParseError());
164 MOZ_ASSERT_IF(IsModuleScript(), !AsModuleScript()->HasErrorToRethrow());
166 mModuleRecord
= aModuleRecord
;
168 // Make module's host defined field point to this object. The JS engine will
169 // increment our reference count by calling HostAddRefTopLevelScript(). This
170 // is decremented when the field is cleared in UnlinkModuleRecord() above or
171 // when the module record dies.
172 MOZ_ASSERT(JS::GetModulePrivate(mModuleRecord
).isUndefined());
173 JS::SetModulePrivate(mModuleRecord
, JS::PrivateValue(this));
175 mozilla::HoldJSObjects(this);
178 void ModuleScript::SetParseError(const JS::Value
& aError
) {
179 MOZ_ASSERT(!aError
.isUndefined());
180 MOZ_ASSERT(!HasParseError());
181 MOZ_ASSERT(!HasErrorToRethrow());
183 UnlinkModuleRecord();
184 mParseError
= aError
;
185 mozilla::HoldJSObjects(this);
188 void ModuleScript::SetErrorToRethrow(const JS::Value
& aError
) {
189 MOZ_ASSERT(!aError
.isUndefined());
191 // This is only called after SetModuleRecord() or SetParseError() so we don't
192 // need to call HoldJSObjects() here.
193 MOZ_ASSERT(ModuleRecord() || HasParseError());
195 mErrorToRethrow
= aError
;
198 void ModuleScript::SetDebuggerDataInitialized() {
199 MOZ_ASSERT(ModuleRecord());
200 MOZ_ASSERT(!mDebuggerDataInitialized
);
202 mDebuggerDataInitialized
= true;
205 } // namespace JS::loader