nsJSUtils.cpp (6125B)
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 18 #include "MainThreadUtils.h" 19 #include "js/ArrayBuffer.h" 20 #include "js/ComparisonOperators.h" 21 #include "js/CompilationAndEvaluation.h" 22 #include "js/CompileOptions.h" 23 #include "js/Date.h" 24 #include "js/EnvironmentChain.h" 25 #include "js/GCVector.h" 26 #include "js/HeapAPI.h" 27 #include "js/Modules.h" 28 #include "js/RootingAPI.h" 29 #include "js/SourceText.h" 30 #include "js/TypeDecls.h" 31 #include "js/experimental/TypedData.h" 32 #include "jsfriendapi.h" 33 #include "mozilla/CycleCollectedJSContext.h" 34 #include "mozilla/ProfilerLabels.h" 35 #include "mozilla/dom/BindingUtils.h" 36 #include "mozilla/dom/Element.h" 37 #include "mozilla/dom/ScriptSettings.h" 38 #include "nsContentUtils.h" 39 #include "nsDebug.h" 40 #include "nsGlobalWindowInner.h" 41 #include "nsINode.h" 42 #include "nsString.h" 43 #include "nsTPromiseFlatString.h" 44 #include "nscore.h" 45 #include "prenv.h" 46 47 #if !defined(DEBUG) && !defined(MOZ_ENABLE_JS_DUMP) 48 # include "mozilla/StaticPrefs_browser.h" 49 #endif 50 51 using namespace mozilla; 52 using namespace mozilla::dom; 53 54 uint64_t nsJSUtils::GetCurrentlyRunningCodeInnerWindowID(JSContext* aContext) { 55 if (!aContext) return 0; 56 57 nsGlobalWindowInner* win = xpc::CurrentWindowOrNull(aContext); 58 return win ? win->WindowID() : 0; 59 } 60 61 nsresult nsJSUtils::UpdateFunctionDebugMetadata( 62 AutoJSAPI& jsapi, JS::Handle<JSObject*> aFun, JS::CompileOptions& aOptions, 63 JS::Handle<JSString*> aElementAttributeName, 64 JS::Handle<JS::Value> aPrivateValue) { 65 JSContext* cx = jsapi.cx(); 66 67 JS::Rooted<JSFunction*> fun(cx, JS_GetObjectFunction(aFun)); 68 if (!fun) { 69 return NS_ERROR_FAILURE; 70 } 71 72 JS::Rooted<JSScript*> script(cx, JS_GetFunctionScript(cx, fun)); 73 if (!script) { 74 return NS_OK; 75 } 76 77 JS::InstantiateOptions instantiateOptions(aOptions); 78 if (!JS::UpdateDebugMetadata(cx, script, instantiateOptions, aPrivateValue, 79 aElementAttributeName, nullptr, nullptr)) { 80 return NS_ERROR_FAILURE; 81 } 82 return NS_OK; 83 } 84 85 nsresult nsJSUtils::CompileFunction(AutoJSAPI& jsapi, 86 const JS::EnvironmentChain& aEnvChain, 87 JS::CompileOptions& aOptions, 88 const nsACString& aName, uint32_t aArgCount, 89 const char** aArgArray, 90 const nsAString& aBody, 91 JSObject** aFunctionObject) { 92 JSContext* cx = jsapi.cx(); 93 MOZ_ASSERT(js::GetContextRealm(cx)); 94 MOZ_ASSERT_IF(aEnvChain.length() != 0, 95 js::IsObjectInContextCompartment(aEnvChain.chain()[0], cx)); 96 97 // Do the junk Gecko is supposed to do before calling into JSAPI. 98 for (size_t i = 0; i < aEnvChain.length(); ++i) { 99 JS::ExposeObjectToActiveJS(aEnvChain.chain()[i]); 100 } 101 102 // Compile. 103 const nsPromiseFlatString& flatBody = PromiseFlatString(aBody); 104 105 JS::SourceText<char16_t> source; 106 if (!source.init(cx, flatBody.get(), flatBody.Length(), 107 JS::SourceOwnership::Borrowed)) { 108 return NS_ERROR_FAILURE; 109 } 110 111 JS::Rooted<JSFunction*> fun( 112 cx, JS::CompileFunction(cx, aEnvChain, aOptions, 113 PromiseFlatCString(aName).get(), aArgCount, 114 aArgArray, source)); 115 if (!fun) { 116 return NS_ERROR_FAILURE; 117 } 118 119 *aFunctionObject = JS_GetFunctionObject(fun); 120 return NS_OK; 121 } 122 123 /* static */ 124 bool nsJSUtils::IsScriptable(JS::Handle<JSObject*> aEvaluationGlobal) { 125 return xpc::Scriptability::AllowedIfExists(aEvaluationGlobal); 126 } 127 128 static bool AddEnvChainItem(JSContext* aCx, nsINode* aNode, 129 JS::EnvironmentChain& aEnvChain) { 130 JS::Rooted<JS::Value> val(aCx); 131 if (!GetOrCreateDOMReflector(aCx, aNode, &val)) { 132 return false; 133 } 134 135 if (!aEnvChain.append(&val.toObject())) { 136 return false; 137 } 138 139 return true; 140 } 141 142 /* static */ 143 bool nsJSUtils::GetEnvironmentChainForElement(JSContext* aCx, Element* aElement, 144 JS::EnvironmentChain& aEnvChain) { 145 for (nsINode* cur = aElement; cur; cur = cur->GetScopeChainParent()) { 146 if (!AddEnvChainItem(aCx, cur, aEnvChain)) { 147 return false; 148 } 149 } 150 151 return true; 152 } 153 154 /* static */ 155 void nsJSUtils::ResetTimeZone() { JS::ResetTimeZone(); } 156 157 /* static */ 158 bool nsJSUtils::DumpEnabled() { 159 #ifdef FUZZING 160 static bool mozFuzzDebug = !!PR_GetEnv("MOZ_FUZZ_DEBUG"); 161 return mozFuzzDebug; 162 #endif 163 164 #if defined(DEBUG) || defined(MOZ_ENABLE_JS_DUMP) 165 return true; 166 #else 167 return StaticPrefs::browser_dom_window_dump_enabled(); 168 #endif 169 } 170 171 JSObject* nsJSUtils::MoveBufferAsUint8Array( 172 JSContext* aCx, size_t aSize, 173 UniquePtr<uint8_t[], JS::FreePolicy> aBuffer) { 174 JS::Rooted<JSObject*> arrayBuffer( 175 aCx, JS::NewArrayBufferWithContents(aCx, aSize, std::move(aBuffer))); 176 if (!arrayBuffer) { 177 return nullptr; 178 } 179 180 return JS_NewUint8ArrayWithBuffer(aCx, arrayBuffer, 0, 181 static_cast<int64_t>(aSize)); 182 } 183 184 // 185 // nsDOMJSUtils.h 186 // 187 188 template <typename T> 189 bool nsTAutoJSString<T>::init(const JS::Value& v) { 190 // Note: it's okay to use danger::GetJSContext here instead of AutoJSAPI, 191 // because the init() call below is careful not to run script (for instance, 192 // it only calls JS::ToString for non-object values). 193 JSContext* cx = danger::GetJSContext(); 194 if (!init(cx, v)) { 195 JS_ClearPendingException(cx); 196 return false; 197 } 198 return true; 199 } 200 201 template bool nsTAutoJSString<char16_t>::init(const JS::Value&); 202 template bool nsTAutoJSString<char>::init(const JS::Value&);