diff options
Diffstat (limited to '')
-rw-r--r-- | dom/base/nsJSUtils.cpp | 252 |
1 files changed, 252 insertions, 0 deletions
diff --git a/dom/base/nsJSUtils.cpp b/dom/base/nsJSUtils.cpp new file mode 100644 index 0000000000..46db78b384 --- /dev/null +++ b/dom/base/nsJSUtils.cpp @@ -0,0 +1,252 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/** + * This is not a generated file. It contains common utility functions + * invoked from the JavaScript code generated from IDL interfaces. + * The goal of the utility functions is to cut down on the size of + * the generated code itself. + */ + +#include "nsJSUtils.h" + +#include <utility> +#include "GeckoProfiler.h" +#include "MainThreadUtils.h" +#include "js/ComparisonOperators.h" +#include "js/CompilationAndEvaluation.h" +#include "js/CompileOptions.h" +#include "js/Date.h" +#include "js/GCVector.h" +#include "js/HeapAPI.h" +#include "js/Modules.h" +#include "js/RootingAPI.h" +#include "js/SourceText.h" +#include "js/TypeDecls.h" +#include "jsfriendapi.h" +#include "mozilla/CycleCollectedJSContext.h" +#include "mozilla/dom/BindingUtils.h" +#include "mozilla/dom/Element.h" +#include "mozilla/dom/ScriptSettings.h" +#include "mozilla/fallible.h" +#include "nsContentUtils.h" +#include "nsDebug.h" +#include "nsGlobalWindowInner.h" +#include "nsINode.h" +#include "nsString.h" +#include "nsTPromiseFlatString.h" +#include "nscore.h" + +#if !defined(DEBUG) && !defined(MOZ_ENABLE_JS_DUMP) +# include "mozilla/StaticPrefs_browser.h" +#endif + +using namespace mozilla; +using namespace mozilla::dom; + +bool nsJSUtils::GetCallingLocation(JSContext* aContext, nsACString& aFilename, + uint32_t* aLineno, uint32_t* aColumn) { + JS::AutoFilename filename; + if (!JS::DescribeScriptedCaller(aContext, &filename, aLineno, aColumn)) { + return false; + } + + return aFilename.Assign(filename.get(), fallible); +} + +bool nsJSUtils::GetCallingLocation(JSContext* aContext, nsAString& aFilename, + uint32_t* aLineno, uint32_t* aColumn) { + JS::AutoFilename filename; + if (!JS::DescribeScriptedCaller(aContext, &filename, aLineno, aColumn)) { + return false; + } + + return aFilename.Assign(NS_ConvertUTF8toUTF16(filename.get()), fallible); +} + +uint64_t nsJSUtils::GetCurrentlyRunningCodeInnerWindowID(JSContext* aContext) { + if (!aContext) return 0; + + nsGlobalWindowInner* win = xpc::CurrentWindowOrNull(aContext); + return win ? win->WindowID() : 0; +} + +nsresult nsJSUtils::CompileFunction(AutoJSAPI& jsapi, + JS::HandleVector<JSObject*> aScopeChain, + JS::CompileOptions& aOptions, + const nsACString& aName, uint32_t aArgCount, + const char** aArgArray, + const nsAString& aBody, + JSObject** aFunctionObject) { + JSContext* cx = jsapi.cx(); + MOZ_ASSERT(js::GetContextRealm(cx)); + MOZ_ASSERT_IF(aScopeChain.length() != 0, + js::IsObjectInContextCompartment(aScopeChain[0], cx)); + + // Do the junk Gecko is supposed to do before calling into JSAPI. + for (size_t i = 0; i < aScopeChain.length(); ++i) { + JS::ExposeObjectToActiveJS(aScopeChain[i]); + } + + // Compile. + const nsPromiseFlatString& flatBody = PromiseFlatString(aBody); + + JS::SourceText<char16_t> source; + if (!source.init(cx, flatBody.get(), flatBody.Length(), + JS::SourceOwnership::Borrowed)) { + return NS_ERROR_FAILURE; + } + + JS::Rooted<JSFunction*> fun( + cx, JS::CompileFunction(cx, aScopeChain, aOptions, + PromiseFlatCString(aName).get(), aArgCount, + aArgArray, source)); + if (!fun) { + return NS_ERROR_FAILURE; + } + + *aFunctionObject = JS_GetFunctionObject(fun); + return NS_OK; +} + +template <typename Unit> +static nsresult CompileJSModule(JSContext* aCx, JS::SourceText<Unit>& aSrcBuf, + JS::Handle<JSObject*> aEvaluationGlobal, + JS::CompileOptions& aCompileOptions, + JS::MutableHandle<JSObject*> aModule) { + AUTO_PROFILER_LABEL("nsJSUtils::CompileModule", JS); + MOZ_ASSERT(aCx == nsContentUtils::GetCurrentJSContext()); + MOZ_ASSERT(aSrcBuf.get()); + MOZ_ASSERT(JS_IsGlobalObject(aEvaluationGlobal)); + MOZ_ASSERT(JS::CurrentGlobalOrNull(aCx) == aEvaluationGlobal); + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(CycleCollectedJSContext::Get() && + CycleCollectedJSContext::Get()->MicroTaskLevel()); + + NS_ENSURE_TRUE(xpc::Scriptability::Get(aEvaluationGlobal).Allowed(), NS_OK); + + JSObject* module = JS::CompileModule(aCx, aCompileOptions, aSrcBuf); + if (!module) { + return NS_ERROR_FAILURE; + } + + aModule.set(module); + return NS_OK; +} + +nsresult nsJSUtils::CompileModule(JSContext* aCx, + JS::SourceText<char16_t>& aSrcBuf, + JS::Handle<JSObject*> aEvaluationGlobal, + JS::CompileOptions& aCompileOptions, + JS::MutableHandle<JSObject*> aModule) { + return CompileJSModule(aCx, aSrcBuf, aEvaluationGlobal, aCompileOptions, + aModule); +} + +nsresult nsJSUtils::CompileModule(JSContext* aCx, + JS::SourceText<Utf8Unit>& aSrcBuf, + JS::Handle<JSObject*> aEvaluationGlobal, + JS::CompileOptions& aCompileOptions, + JS::MutableHandle<JSObject*> aModule) { + return CompileJSModule(aCx, aSrcBuf, aEvaluationGlobal, aCompileOptions, + aModule); +} + +nsresult nsJSUtils::ModuleInstantiate(JSContext* aCx, + JS::Handle<JSObject*> aModule) { + AUTO_PROFILER_LABEL("nsJSUtils::ModuleInstantiate", JS); + + MOZ_ASSERT(aCx == nsContentUtils::GetCurrentJSContext()); + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(CycleCollectedJSContext::Get() && + CycleCollectedJSContext::Get()->MicroTaskLevel()); + + NS_ENSURE_TRUE(xpc::Scriptability::Get(aModule).Allowed(), NS_OK); + + if (!JS::ModuleInstantiate(aCx, aModule)) { + return NS_ERROR_FAILURE; + } + + return NS_OK; +} + +nsresult nsJSUtils::ModuleEvaluate(JSContext* aCx, + JS::Handle<JSObject*> aModule, + JS::MutableHandle<JS::Value> aResult) { + AUTO_PROFILER_LABEL("nsJSUtils::ModuleEvaluate", JS); + + MOZ_ASSERT(aCx == nsContentUtils::GetCurrentJSContext()); + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(CycleCollectedJSContext::Get() && + CycleCollectedJSContext::Get()->MicroTaskLevel()); + + NS_ENSURE_TRUE(xpc::Scriptability::Get(aModule).Allowed(), NS_OK); + + if (!JS::ModuleEvaluate(aCx, aModule, aResult)) { + return NS_ERROR_FAILURE; + } + + return NS_OK; +} + +static bool AddScopeChainItem(JSContext* aCx, nsINode* aNode, + JS::MutableHandleVector<JSObject*> aScopeChain) { + JS::RootedValue val(aCx); + if (!GetOrCreateDOMReflector(aCx, aNode, &val)) { + return false; + } + + if (!aScopeChain.append(&val.toObject())) { + return false; + } + + return true; +} + +/* static */ +bool nsJSUtils::GetScopeChainForElement( + JSContext* aCx, Element* aElement, + JS::MutableHandleVector<JSObject*> aScopeChain) { + for (nsINode* cur = aElement; cur; cur = cur->GetScopeChainParent()) { + if (!AddScopeChainItem(aCx, cur, aScopeChain)) { + return false; + } + } + + return true; +} + +/* static */ +void nsJSUtils::ResetTimeZone() { JS::ResetTimeZone(); } + +/* static */ +bool nsJSUtils::DumpEnabled() { +#if defined(DEBUG) || defined(MOZ_ENABLE_JS_DUMP) + return true; +#else + return StaticPrefs::browser_dom_window_dump_enabled(); +#endif +} + +// +// nsDOMJSUtils.h +// + +template <typename T> +bool nsTAutoJSString<T>::init(const JS::Value& v) { + // Note: it's okay to use danger::GetJSContext here instead of AutoJSAPI, + // because the init() call below is careful not to run script (for instance, + // it only calls JS::ToString for non-object values). + JSContext* cx = danger::GetJSContext(); + if (!init(cx, v)) { + JS_ClearPendingException(cx); + return false; + } + return true; +} + +template bool nsTAutoJSString<char16_t>::init(const JS::Value&); +template bool nsTAutoJSString<char>::init(const JS::Value&); |