Bug 891986 - Keep the source ArrayBuffer to a decodeAudioData call alive until the...
[gecko.git] / dom / base / nsJSUtils.cpp
blob6a93b3963bf8893a64f9d86b766e5895dc1d13fc
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=2 sw=2 et tw=78: */
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 /**
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.
14 #include "nsJSUtils.h"
15 #include "jsapi.h"
16 #include "jsdbgapi.h"
17 #include "prprf.h"
18 #include "nsIScriptContext.h"
19 #include "nsIScriptGlobalObject.h"
20 #include "nsIServiceManager.h"
21 #include "nsIXPConnect.h"
22 #include "nsCOMPtr.h"
23 #include "nsIScriptSecurityManager.h"
24 #include "nsPIDOMWindow.h"
26 #include "nsDOMJSUtils.h" // for GetScriptContextFromJSContext
28 #include "nsContentUtils.h"
29 #include "nsJSPrincipals.h"
31 #include "mozilla/dom/BindingUtils.h"
33 JSBool
34 nsJSUtils::GetCallingLocation(JSContext* aContext, const char* *aFilename,
35 uint32_t* aLineno)
37 JSScript* script = nullptr;
38 unsigned lineno = 0;
40 if (!JS_DescribeScriptedCaller(aContext, &script, &lineno)) {
41 return JS_FALSE;
44 *aFilename = ::JS_GetScriptFilename(aContext, script);
45 *aLineno = lineno;
47 return JS_TRUE;
50 nsIScriptGlobalObject *
51 nsJSUtils::GetStaticScriptGlobal(JSObject* aObj)
53 JSClass* clazz;
54 JSObject* glob = aObj; // starting point for search
56 if (!glob)
57 return nullptr;
59 glob = js::GetGlobalForObjectCrossCompartment(glob);
60 NS_ABORT_IF_FALSE(glob, "Infallible returns null");
62 clazz = JS_GetClass(glob);
64 // Whenever we end up with globals that are JSCLASS_IS_DOMJSCLASS
65 // and have an nsISupports DOM object, we will need to modify this
66 // check here.
67 MOZ_ASSERT(!(clazz->flags & JSCLASS_IS_DOMJSCLASS));
68 nsISupports* supports;
69 if (!(clazz->flags & JSCLASS_HAS_PRIVATE) ||
70 !(clazz->flags & JSCLASS_PRIVATE_IS_NSISUPPORTS) ||
71 !(supports = (nsISupports*)::JS_GetPrivate(glob))) {
72 return nullptr;
75 // We might either have a window directly (e.g. if the global is a
76 // sandbox whose script object principal pointer is a window), or an
77 // XPCWrappedNative for a window. We could also have other
78 // sandbox-related script object principals, but we can't do much
79 // about those short of trying to walk the proto chain of |glob|
80 // looking for a window or something.
81 nsCOMPtr<nsIScriptGlobalObject> sgo(do_QueryInterface(supports));
82 if (!sgo) {
83 nsCOMPtr<nsIXPConnectWrappedNative> wrapper(do_QueryInterface(supports));
84 if (!wrapper) {
85 return nullptr;
87 sgo = do_QueryWrappedNative(wrapper);
90 // We're returning a pointer to something that's about to be
91 // released, but that's ok here.
92 return sgo;
95 nsIScriptContext *
96 nsJSUtils::GetStaticScriptContext(JSObject* aObj)
98 nsIScriptGlobalObject *nativeGlobal = GetStaticScriptGlobal(aObj);
99 if (!nativeGlobal)
100 return nullptr;
102 return nativeGlobal->GetScriptContext();
105 nsIScriptGlobalObject *
106 nsJSUtils::GetDynamicScriptGlobal(JSContext* aContext)
108 nsIScriptContext *scriptCX = GetDynamicScriptContext(aContext);
109 if (!scriptCX)
110 return nullptr;
111 return scriptCX->GetGlobalObject();
114 nsIScriptContext *
115 nsJSUtils::GetDynamicScriptContext(JSContext *aContext)
117 return GetScriptContextFromJSContext(aContext);
120 uint64_t
121 nsJSUtils::GetCurrentlyRunningCodeInnerWindowID(JSContext *aContext)
123 if (!aContext)
124 return 0;
126 uint64_t innerWindowID = 0;
128 JSObject *jsGlobal = JS_GetGlobalForScopeChain(aContext);
129 if (jsGlobal) {
130 nsIScriptGlobalObject *scriptGlobal = GetStaticScriptGlobal(jsGlobal);
131 if (scriptGlobal) {
132 nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(scriptGlobal);
133 if (win)
134 innerWindowID = win->WindowID();
138 return innerWindowID;
141 void
142 nsJSUtils::ReportPendingException(JSContext *aContext)
144 if (JS_IsExceptionPending(aContext)) {
145 bool saved = JS_SaveFrameChain(aContext);
146 JS_ReportPendingException(aContext);
147 if (saved) {
148 JS_RestoreFrameChain(aContext);
153 nsresult
154 nsJSUtils::CompileFunction(JSContext* aCx,
155 JS::HandleObject aTarget,
156 JS::CompileOptions& aOptions,
157 const nsACString& aName,
158 uint32_t aArgCount,
159 const char** aArgArray,
160 const nsAString& aBody,
161 JSObject** aFunctionObject)
163 MOZ_ASSERT(js::GetEnterCompartmentDepth(aCx) > 0);
164 MOZ_ASSERT_IF(aTarget, js::IsObjectInContextCompartment(aTarget, aCx));
165 MOZ_ASSERT_IF(aOptions.versionSet, aOptions.version != JSVERSION_UNKNOWN);
166 mozilla::DebugOnly<nsIScriptContext*> ctx = GetScriptContextFromJSContext(aCx);
167 MOZ_ASSERT_IF(ctx, ctx->IsContextInitialized());
169 // Since aTarget and aCx are same-compartment, there should be no distinction
170 // between the object principal and the cx principal.
171 // However, aTarget may be null in the wacky aShared case. So use the cx.
172 JSPrincipals* p = JS_GetCompartmentPrincipals(js::GetContextCompartment(aCx));
173 aOptions.setPrincipals(p);
175 // Do the junk Gecko is supposed to do before calling into JSAPI.
176 xpc_UnmarkGrayObject(aTarget);
178 // Compile.
179 JSFunction* fun = JS::CompileFunction(aCx, aTarget, aOptions,
180 PromiseFlatCString(aName).get(),
181 aArgCount, aArgArray,
182 PromiseFlatString(aBody).get(),
183 aBody.Length());
184 if (!fun) {
185 ReportPendingException(aCx);
186 return NS_ERROR_FAILURE;
189 *aFunctionObject = JS_GetFunctionObject(fun);
190 return NS_OK;