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 /**
8 * This is not a generated file. It contains common utility functions
9 * invoked from the JavaScript code generated from IDL interfaces.
10 * The goal of the utility functions is to cut down on the size of
11 * the generated code itself.
12 */
13
14 #include "nsJSUtils.h"
15
16 #include <utility>
17 #include "MainThreadUtils.h"
18 #include "js/ComparisonOperators.h"
19 #include "js/CompilationAndEvaluation.h"
20 #include "js/CompileOptions.h"
21 #include "js/Date.h"
22 #include "js/GCVector.h"
23 #include "js/HeapAPI.h"
24 #include "js/Modules.h"
25 #include "js/RootingAPI.h"
26 #include "js/SourceText.h"
27 #include "js/TypeDecls.h"
28 #include "jsfriendapi.h"
29 #include "mozilla/CycleCollectedJSContext.h"
30 #include "mozilla/dom/BindingUtils.h"
31 #include "mozilla/dom/Element.h"
32 #include "mozilla/dom/ScriptSettings.h"
33 #include "mozilla/fallible.h"
34 #include "mozilla/ProfilerLabels.h"
35 #include "nsContentUtils.h"
36 #include "nsDebug.h"
37 #include "nsGlobalWindowInner.h"
38 #include "nsINode.h"
39 #include "nsString.h"
40 #include "nsTPromiseFlatString.h"
41 #include "nscore.h"
42
43 #if !defined(DEBUG) && !defined(MOZ_ENABLE_JS_DUMP)
44 # include "mozilla/StaticPrefs_browser.h"
45 #endif
46
47 using namespace mozilla;
48 using namespace mozilla::dom;
49
GetCallingLocation(JSContext * aContext,nsACString & aFilename,uint32_t * aLineno,uint32_t * aColumn)50 bool nsJSUtils::GetCallingLocation(JSContext* aContext, nsACString& aFilename,
51 uint32_t* aLineno, uint32_t* aColumn) {
52 JS::AutoFilename filename;
53 if (!JS::DescribeScriptedCaller(aContext, &filename, aLineno, aColumn)) {
54 return false;
55 }
56
57 return aFilename.Assign(filename.get(), fallible);
58 }
59
GetCallingLocation(JSContext * aContext,nsAString & aFilename,uint32_t * aLineno,uint32_t * aColumn)60 bool nsJSUtils::GetCallingLocation(JSContext* aContext, nsAString& aFilename,
61 uint32_t* aLineno, uint32_t* aColumn) {
62 JS::AutoFilename filename;
63 if (!JS::DescribeScriptedCaller(aContext, &filename, aLineno, aColumn)) {
64 return false;
65 }
66
67 return aFilename.Assign(NS_ConvertUTF8toUTF16(filename.get()), fallible);
68 }
69
GetCurrentlyRunningCodeInnerWindowID(JSContext * aContext)70 uint64_t nsJSUtils::GetCurrentlyRunningCodeInnerWindowID(JSContext* aContext) {
71 if (!aContext) return 0;
72
73 nsGlobalWindowInner* win = xpc::CurrentWindowOrNull(aContext);
74 return win ? win->WindowID() : 0;
75 }
76
UpdateFunctionDebugMetadata(AutoJSAPI & jsapi,JS::Handle<JSObject * > aFun,JS::CompileOptions & aOptions,JS::Handle<JSString * > aElementAttributeName,JS::Handle<JS::Value> aPrivateValue)77 nsresult nsJSUtils::UpdateFunctionDebugMetadata(
78 AutoJSAPI& jsapi, JS::Handle<JSObject*> aFun, JS::CompileOptions& aOptions,
79 JS::Handle<JSString*> aElementAttributeName,
80 JS::Handle<JS::Value> aPrivateValue) {
81 JSContext* cx = jsapi.cx();
82
83 JS::Rooted<JSFunction*> fun(cx, JS_GetObjectFunction(aFun));
84 if (!fun) {
85 return NS_ERROR_FAILURE;
86 }
87
88 JS::RootedScript script(cx, JS_GetFunctionScript(cx, fun));
89 if (!script) {
90 return NS_OK;
91 }
92
93 if (!JS::UpdateDebugMetadata(cx, script, aOptions, aPrivateValue,
94 aElementAttributeName, nullptr, nullptr)) {
95 return NS_ERROR_FAILURE;
96 }
97 return NS_OK;
98 }
99
CompileFunction(AutoJSAPI & jsapi,JS::HandleVector<JSObject * > aScopeChain,JS::CompileOptions & aOptions,const nsACString & aName,uint32_t aArgCount,const char ** aArgArray,const nsAString & aBody,JSObject ** aFunctionObject)100 nsresult nsJSUtils::CompileFunction(AutoJSAPI& jsapi,
101 JS::HandleVector<JSObject*> aScopeChain,
102 JS::CompileOptions& aOptions,
103 const nsACString& aName, uint32_t aArgCount,
104 const char** aArgArray,
105 const nsAString& aBody,
106 JSObject** aFunctionObject) {
107 JSContext* cx = jsapi.cx();
108 MOZ_ASSERT(js::GetContextRealm(cx));
109 MOZ_ASSERT_IF(aScopeChain.length() != 0,
110 js::IsObjectInContextCompartment(aScopeChain[0], cx));
111
112 // Do the junk Gecko is supposed to do before calling into JSAPI.
113 for (size_t i = 0; i < aScopeChain.length(); ++i) {
114 JS::ExposeObjectToActiveJS(aScopeChain[i]);
115 }
116
117 // Compile.
118 const nsPromiseFlatString& flatBody = PromiseFlatString(aBody);
119
120 JS::SourceText<char16_t> source;
121 if (!source.init(cx, flatBody.get(), flatBody.Length(),
122 JS::SourceOwnership::Borrowed)) {
123 return NS_ERROR_FAILURE;
124 }
125
126 JS::Rooted<JSFunction*> fun(
127 cx, JS::CompileFunction(cx, aScopeChain, aOptions,
128 PromiseFlatCString(aName).get(), aArgCount,
129 aArgArray, source));
130 if (!fun) {
131 return NS_ERROR_FAILURE;
132 }
133
134 *aFunctionObject = JS_GetFunctionObject(fun);
135 return NS_OK;
136 }
137
138 template <typename Unit>
CompileJSModule(JSContext * aCx,JS::SourceText<Unit> & aSrcBuf,JS::Handle<JSObject * > aEvaluationGlobal,JS::CompileOptions & aCompileOptions,JS::MutableHandle<JSObject * > aModule)139 static nsresult CompileJSModule(JSContext* aCx, JS::SourceText<Unit>& aSrcBuf,
140 JS::Handle<JSObject*> aEvaluationGlobal,
141 JS::CompileOptions& aCompileOptions,
142 JS::MutableHandle<JSObject*> aModule) {
143 AUTO_PROFILER_LABEL("nsJSUtils::CompileModule", JS);
144 MOZ_ASSERT(aCx == nsContentUtils::GetCurrentJSContext());
145 MOZ_ASSERT(aSrcBuf.get());
146 MOZ_ASSERT(JS_IsGlobalObject(aEvaluationGlobal));
147 MOZ_ASSERT(JS::CurrentGlobalOrNull(aCx) == aEvaluationGlobal);
148 MOZ_ASSERT(NS_IsMainThread());
149 MOZ_ASSERT(CycleCollectedJSContext::Get() &&
150 CycleCollectedJSContext::Get()->MicroTaskLevel());
151
152 NS_ENSURE_TRUE(xpc::Scriptability::Get(aEvaluationGlobal).Allowed(), NS_OK);
153
154 JSObject* module = JS::CompileModule(aCx, aCompileOptions, aSrcBuf);
155 if (!module) {
156 return NS_ERROR_FAILURE;
157 }
158
159 aModule.set(module);
160 return NS_OK;
161 }
162
CompileModule(JSContext * aCx,JS::SourceText<char16_t> & aSrcBuf,JS::Handle<JSObject * > aEvaluationGlobal,JS::CompileOptions & aCompileOptions,JS::MutableHandle<JSObject * > aModule)163 nsresult nsJSUtils::CompileModule(JSContext* aCx,
164 JS::SourceText<char16_t>& aSrcBuf,
165 JS::Handle<JSObject*> aEvaluationGlobal,
166 JS::CompileOptions& aCompileOptions,
167 JS::MutableHandle<JSObject*> aModule) {
168 return CompileJSModule(aCx, aSrcBuf, aEvaluationGlobal, aCompileOptions,
169 aModule);
170 }
171
CompileModule(JSContext * aCx,JS::SourceText<Utf8Unit> & aSrcBuf,JS::Handle<JSObject * > aEvaluationGlobal,JS::CompileOptions & aCompileOptions,JS::MutableHandle<JSObject * > aModule)172 nsresult nsJSUtils::CompileModule(JSContext* aCx,
173 JS::SourceText<Utf8Unit>& aSrcBuf,
174 JS::Handle<JSObject*> aEvaluationGlobal,
175 JS::CompileOptions& aCompileOptions,
176 JS::MutableHandle<JSObject*> aModule) {
177 return CompileJSModule(aCx, aSrcBuf, aEvaluationGlobal, aCompileOptions,
178 aModule);
179 }
180
ModuleInstantiate(JSContext * aCx,JS::Handle<JSObject * > aModule)181 nsresult nsJSUtils::ModuleInstantiate(JSContext* aCx,
182 JS::Handle<JSObject*> aModule) {
183 AUTO_PROFILER_LABEL("nsJSUtils::ModuleInstantiate", JS);
184
185 MOZ_ASSERT(aCx == nsContentUtils::GetCurrentJSContext());
186 MOZ_ASSERT(NS_IsMainThread());
187 MOZ_ASSERT(CycleCollectedJSContext::Get() &&
188 CycleCollectedJSContext::Get()->MicroTaskLevel());
189
190 NS_ENSURE_TRUE(xpc::Scriptability::Get(aModule).Allowed(), NS_OK);
191
192 if (!JS::ModuleInstantiate(aCx, aModule)) {
193 return NS_ERROR_FAILURE;
194 }
195
196 return NS_OK;
197 }
198
ModuleEvaluate(JSContext * aCx,JS::Handle<JSObject * > aModule,JS::MutableHandle<JS::Value> aResult)199 nsresult nsJSUtils::ModuleEvaluate(JSContext* aCx,
200 JS::Handle<JSObject*> aModule,
201 JS::MutableHandle<JS::Value> aResult) {
202 AUTO_PROFILER_LABEL("nsJSUtils::ModuleEvaluate", JS);
203
204 MOZ_ASSERT(aCx == nsContentUtils::GetCurrentJSContext());
205 MOZ_ASSERT(NS_IsMainThread());
206 MOZ_ASSERT(CycleCollectedJSContext::Get() &&
207 CycleCollectedJSContext::Get()->MicroTaskLevel());
208
209 NS_ENSURE_TRUE(xpc::Scriptability::Get(aModule).Allowed(), NS_OK);
210
211 if (!JS::ModuleEvaluate(aCx, aModule, aResult)) {
212 return NS_ERROR_FAILURE;
213 }
214
215 return NS_OK;
216 }
217
AddScopeChainItem(JSContext * aCx,nsINode * aNode,JS::MutableHandleVector<JSObject * > aScopeChain)218 static bool AddScopeChainItem(JSContext* aCx, nsINode* aNode,
219 JS::MutableHandleVector<JSObject*> aScopeChain) {
220 JS::RootedValue val(aCx);
221 if (!GetOrCreateDOMReflector(aCx, aNode, &val)) {
222 return false;
223 }
224
225 if (!aScopeChain.append(&val.toObject())) {
226 return false;
227 }
228
229 return true;
230 }
231
232 /* static */
GetScopeChainForElement(JSContext * aCx,Element * aElement,JS::MutableHandleVector<JSObject * > aScopeChain)233 bool nsJSUtils::GetScopeChainForElement(
234 JSContext* aCx, Element* aElement,
235 JS::MutableHandleVector<JSObject*> aScopeChain) {
236 for (nsINode* cur = aElement; cur; cur = cur->GetScopeChainParent()) {
237 if (!AddScopeChainItem(aCx, cur, aScopeChain)) {
238 return false;
239 }
240 }
241
242 return true;
243 }
244
245 /* static */
ResetTimeZone()246 void nsJSUtils::ResetTimeZone() { JS::ResetTimeZone(); }
247
248 /* static */
DumpEnabled()249 bool nsJSUtils::DumpEnabled() {
250 #if defined(DEBUG) || defined(MOZ_ENABLE_JS_DUMP)
251 return true;
252 #else
253 return StaticPrefs::browser_dom_window_dump_enabled();
254 #endif
255 }
256
257 //
258 // nsDOMJSUtils.h
259 //
260
261 template <typename T>
init(const JS::Value & v)262 bool nsTAutoJSString<T>::init(const JS::Value& v) {
263 // Note: it's okay to use danger::GetJSContext here instead of AutoJSAPI,
264 // because the init() call below is careful not to run script (for instance,
265 // it only calls JS::ToString for non-object values).
266 JSContext* cx = danger::GetJSContext();
267 if (!init(cx, v)) {
268 JS_ClearPendingException(cx);
269 return false;
270 }
271 return true;
272 }
273
274 template bool nsTAutoJSString<char16_t>::init(const JS::Value&);
275 template bool nsTAutoJSString<char>::init(const JS::Value&);
276