LCOV - code coverage report
Current view: top level - dom/base - nsJSUtils.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 81 219 37.0 %
Date: 2017-07-14 16:53:18 Functions: 10 21 47.6 %
Legend: Lines: hit not hit

          Line data    Source code
       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             : #include "jsapi.h"
      16             : #include "jsfriendapi.h"
      17             : #include "nsIScriptContext.h"
      18             : #include "nsIScriptGlobalObject.h"
      19             : #include "nsIXPConnect.h"
      20             : #include "nsCOMPtr.h"
      21             : #include "nsIScriptSecurityManager.h"
      22             : #include "nsPIDOMWindow.h"
      23             : #include "GeckoProfiler.h"
      24             : #include "nsJSPrincipals.h"
      25             : #include "xpcpublic.h"
      26             : #include "nsContentUtils.h"
      27             : #include "nsGlobalWindow.h"
      28             : 
      29             : #include "mozilla/dom/BindingUtils.h"
      30             : #include "mozilla/dom/Date.h"
      31             : #include "mozilla/dom/Element.h"
      32             : #include "mozilla/dom/ScriptSettings.h"
      33             : 
      34             : using namespace mozilla::dom;
      35             : 
      36             : bool
      37          13 : nsJSUtils::GetCallingLocation(JSContext* aContext, nsACString& aFilename,
      38             :                               uint32_t* aLineno, uint32_t* aColumn)
      39             : {
      40          26 :   JS::AutoFilename filename;
      41          13 :   if (!JS::DescribeScriptedCaller(aContext, &filename, aLineno, aColumn)) {
      42           0 :     return false;
      43             :   }
      44             : 
      45          13 :   aFilename.Assign(filename.get());
      46          13 :   return true;
      47             : }
      48             : 
      49             : bool
      50           0 : nsJSUtils::GetCallingLocation(JSContext* aContext, nsAString& aFilename,
      51             :                               uint32_t* aLineno, uint32_t* aColumn)
      52             : {
      53           0 :   JS::AutoFilename filename;
      54           0 :   if (!JS::DescribeScriptedCaller(aContext, &filename, aLineno, aColumn)) {
      55           0 :     return false;
      56             :   }
      57             : 
      58           0 :   aFilename.Assign(NS_ConvertUTF8toUTF16(filename.get()));
      59           0 :   return true;
      60             : }
      61             : 
      62             : nsIScriptGlobalObject *
      63           1 : nsJSUtils::GetStaticScriptGlobal(JSObject* aObj)
      64             : {
      65           1 :   if (!aObj)
      66           0 :     return nullptr;
      67           1 :   return xpc::WindowGlobalOrNull(aObj);
      68             : }
      69             : 
      70             : nsIScriptContext *
      71           0 : nsJSUtils::GetStaticScriptContext(JSObject* aObj)
      72             : {
      73           0 :   nsIScriptGlobalObject *nativeGlobal = GetStaticScriptGlobal(aObj);
      74           0 :   if (!nativeGlobal)
      75           0 :     return nullptr;
      76             : 
      77           0 :   return nativeGlobal->GetScriptContext();
      78             : }
      79             : 
      80             : uint64_t
      81           0 : nsJSUtils::GetCurrentlyRunningCodeInnerWindowID(JSContext *aContext)
      82             : {
      83           0 :   if (!aContext)
      84           0 :     return 0;
      85             : 
      86           0 :   nsGlobalWindow* win = xpc::CurrentWindowOrNull(aContext);
      87           0 :   return win ? win->WindowID() : 0;
      88             : }
      89             : 
      90             : nsresult
      91          11 : nsJSUtils::CompileFunction(AutoJSAPI& jsapi,
      92             :                            JS::AutoObjectVector& aScopeChain,
      93             :                            JS::CompileOptions& aOptions,
      94             :                            const nsACString& aName,
      95             :                            uint32_t aArgCount,
      96             :                            const char** aArgArray,
      97             :                            const nsAString& aBody,
      98             :                            JSObject** aFunctionObject)
      99             : {
     100          11 :   JSContext* cx = jsapi.cx();
     101          11 :   MOZ_ASSERT(js::GetEnterCompartmentDepth(cx) > 0);
     102          11 :   MOZ_ASSERT_IF(aScopeChain.length() != 0,
     103             :                 js::IsObjectInContextCompartment(aScopeChain[0], cx));
     104          11 :   MOZ_ASSERT_IF(aOptions.versionSet, aOptions.version != JSVERSION_UNKNOWN);
     105             : 
     106             :   // Do the junk Gecko is supposed to do before calling into JSAPI.
     107          38 :   for (size_t i = 0; i < aScopeChain.length(); ++i) {
     108          27 :     JS::ExposeObjectToActiveJS(aScopeChain[i]);
     109             :   }
     110             : 
     111             :   // Compile.
     112          22 :   JS::Rooted<JSFunction*> fun(cx);
     113          55 :   if (!JS::CompileFunction(cx, aScopeChain, aOptions,
     114          22 :                            PromiseFlatCString(aName).get(),
     115             :                            aArgCount, aArgArray,
     116          22 :                            PromiseFlatString(aBody).get(),
     117          11 :                            aBody.Length(), &fun))
     118             :   {
     119           0 :     return NS_ERROR_FAILURE;
     120             :   }
     121             : 
     122          11 :   *aFunctionObject = JS_GetFunctionObject(fun);
     123          11 :   return NS_OK;
     124             : }
     125             : 
     126             : static nsresult
     127           0 : EvaluationExceptionToNSResult(JSContext* aCx)
     128             : {
     129           0 :   if (JS_IsExceptionPending(aCx)) {
     130           0 :     return NS_SUCCESS_DOM_SCRIPT_EVALUATION_THREW;
     131             :   }
     132           0 :   return NS_SUCCESS_DOM_SCRIPT_EVALUATION_THREW_UNCATCHABLE;
     133             : }
     134             : 
     135         117 : nsJSUtils::ExecutionContext::ExecutionContext(JSContext* aCx,
     136         117 :                                               JS::Handle<JSObject*> aGlobal)
     137             :   :
     138             :     mAutoProfilerLabel("nsJSUtils::ExecutionContext", /* dynamicStr */ nullptr,
     139             :                        __LINE__, js::ProfileEntry::Category::JS),
     140             :     mCx(aCx)
     141             :   , mCompartment(aCx, aGlobal)
     142             :   , mRetValue(aCx)
     143             :   , mScopeChain(aCx)
     144             :   , mRv(NS_OK)
     145             :   , mSkip(false)
     146             :   , mCoerceToString(false)
     147             :   , mEncodeBytecode(false)
     148             : #ifdef DEBUG
     149             :   , mWantsReturnValue(false)
     150         117 :   , mExpectScopeChain(false)
     151             : #endif
     152             : {
     153         117 :   MOZ_ASSERT(aCx == nsContentUtils::GetCurrentJSContext());
     154         117 :   MOZ_ASSERT(NS_IsMainThread());
     155         117 :   MOZ_ASSERT(nsContentUtils::IsInMicroTask());
     156         117 :   MOZ_ASSERT(mRetValue.isUndefined());
     157             : 
     158         117 :   MOZ_ASSERT(js::GetGlobalForObjectCrossCompartment(aGlobal) == aGlobal);
     159         117 :   if (MOZ_UNLIKELY(!xpc::Scriptability::Get(aGlobal).Allowed())) {
     160           0 :     mSkip = true;
     161           0 :     mRv = NS_OK;
     162             :   }
     163         117 : }
     164             : 
     165             : void
     166         112 : nsJSUtils::ExecutionContext::SetScopeChain(
     167             :   const JS::AutoObjectVector& aScopeChain)
     168             : {
     169         112 :   if (mSkip) {
     170           0 :     return;
     171             :   }
     172             : 
     173             : #ifdef DEBUG
     174         112 :   mExpectScopeChain = true;
     175             : #endif
     176             :   // Now make sure to wrap the scope chain into the right compartment.
     177         112 :   if (!mScopeChain.reserve(aScopeChain.length())) {
     178           0 :     mSkip = true;
     179           0 :     mRv = NS_ERROR_OUT_OF_MEMORY;
     180           0 :     return;
     181             :   }
     182             : 
     183        1282 :   for (size_t i = 0; i < aScopeChain.length(); ++i) {
     184        1170 :     JS::ExposeObjectToActiveJS(aScopeChain[i]);
     185        1170 :     mScopeChain.infallibleAppend(aScopeChain[i]);
     186        1170 :     if (!JS_WrapObject(mCx, mScopeChain[i])) {
     187           0 :       mSkip = true;
     188           0 :       mRv = NS_ERROR_OUT_OF_MEMORY;
     189           0 :       return;
     190             :     }
     191             :   }
     192             : }
     193             : 
     194             : nsresult
     195           0 : nsJSUtils::ExecutionContext::JoinAndExec(void **aOffThreadToken,
     196             :                                          JS::MutableHandle<JSScript*> aScript)
     197             : {
     198           0 :   if (mSkip) {
     199           0 :     return mRv;
     200             :   }
     201             : 
     202           0 :   MOZ_ASSERT(!mWantsReturnValue);
     203           0 :   MOZ_ASSERT(!mExpectScopeChain);
     204           0 :   aScript.set(JS::FinishOffThreadScript(mCx, *aOffThreadToken));
     205           0 :   *aOffThreadToken = nullptr; // Mark the token as having been finished.
     206           0 :   if (!aScript) {
     207           0 :     mSkip = true;
     208           0 :     mRv = EvaluationExceptionToNSResult(mCx);
     209           0 :     return mRv;
     210             :   }
     211             : 
     212           0 :   if (mEncodeBytecode && !StartIncrementalEncoding(mCx, aScript)) {
     213           0 :     mSkip = true;
     214           0 :     mRv = EvaluationExceptionToNSResult(mCx);
     215           0 :     return mRv;
     216             :   }
     217             : 
     218           0 :   if (!JS_ExecuteScript(mCx, mScopeChain, aScript)) {
     219           0 :     mSkip = true;
     220           0 :     mRv = EvaluationExceptionToNSResult(mCx);
     221           0 :     return mRv;
     222             :   }
     223             : 
     224           0 :   return NS_OK;
     225             : }
     226             : 
     227             : nsresult
     228         117 : nsJSUtils::ExecutionContext::CompileAndExec(JS::CompileOptions& aCompileOptions,
     229             :                                             JS::SourceBufferHolder& aSrcBuf,
     230             :                                             JS::MutableHandle<JSScript*> aScript)
     231             : {
     232         117 :   if (mSkip) {
     233           0 :     return mRv;
     234             :   }
     235             : 
     236         117 :   MOZ_ASSERT_IF(aCompileOptions.versionSet,
     237             :                 aCompileOptions.version != JSVERSION_UNKNOWN);
     238         117 :   MOZ_ASSERT(aSrcBuf.get());
     239         117 :   MOZ_ASSERT(mRetValue.isUndefined());
     240             : #ifdef DEBUG
     241         117 :   mWantsReturnValue = !aCompileOptions.noScriptRval;
     242             : #endif
     243             : 
     244         117 :   bool compiled = true;
     245         117 :   if (mScopeChain.length() == 0) {
     246           5 :     compiled = JS::Compile(mCx, aCompileOptions, aSrcBuf, aScript);
     247             :   } else {
     248         112 :     compiled = JS::CompileForNonSyntacticScope(mCx, aCompileOptions, aSrcBuf, aScript);
     249             :   }
     250             : 
     251         117 :   MOZ_ASSERT_IF(compiled, aScript);
     252         117 :   if (!compiled) {
     253           0 :     mSkip = true;
     254           0 :     mRv = EvaluationExceptionToNSResult(mCx);
     255           0 :     return mRv;
     256             :   }
     257             : 
     258         117 :   if (mEncodeBytecode && !StartIncrementalEncoding(mCx, aScript)) {
     259           0 :     mSkip = true;
     260           0 :     mRv = EvaluationExceptionToNSResult(mCx);
     261           0 :     return mRv;
     262             :   }
     263             : 
     264         117 :   MOZ_ASSERT(!mCoerceToString || mWantsReturnValue);
     265         117 :   if (!JS_ExecuteScript(mCx, mScopeChain, aScript, &mRetValue)) {
     266           0 :     mSkip = true;
     267           0 :     mRv = EvaluationExceptionToNSResult(mCx);
     268           0 :     return mRv;
     269             :   }
     270             : 
     271         117 :   return NS_OK;
     272             : }
     273             : 
     274             : nsresult
     275         112 : nsJSUtils::ExecutionContext::CompileAndExec(JS::CompileOptions& aCompileOptions,
     276             :                                             const nsAString& aScript)
     277             : {
     278         112 :   MOZ_ASSERT(!mEncodeBytecode, "A JSScript is needed for calling FinishIncrementalEncoding");
     279         112 :   if (mSkip) {
     280           0 :     return mRv;
     281             :   }
     282             : 
     283         224 :   const nsPromiseFlatString& flatScript = PromiseFlatString(aScript);
     284         112 :   JS::SourceBufferHolder srcBuf(flatScript.get(), aScript.Length(),
     285         224 :                                 JS::SourceBufferHolder::NoOwnership);
     286         224 :   JS::Rooted<JSScript*> script(mCx);
     287         112 :   return CompileAndExec(aCompileOptions, srcBuf, &script);
     288             : }
     289             : 
     290             : nsresult
     291           0 : nsJSUtils::ExecutionContext::DecodeAndExec(JS::CompileOptions& aCompileOptions,
     292             :                                            mozilla::Vector<uint8_t>& aBytecodeBuf,
     293             :                                            size_t aBytecodeIndex)
     294             : {
     295           0 :   MOZ_ASSERT(!mEncodeBytecode, "A JSScript is needed for calling FinishIncrementalEncoding");
     296           0 :   if (mSkip) {
     297           0 :     return mRv;
     298             :   }
     299             : 
     300           0 :   MOZ_ASSERT(!mWantsReturnValue);
     301           0 :   JS::Rooted<JSScript*> script(mCx);
     302           0 :   JS::TranscodeResult tr = JS::DecodeScript(mCx, aBytecodeBuf, &script, aBytecodeIndex);
     303             :   // These errors are external parameters which should be handled before the
     304             :   // decoding phase, and which are the only reasons why you might want to
     305             :   // fallback on decoding failures.
     306           0 :   MOZ_ASSERT(tr != JS::TranscodeResult_Failure_BadBuildId &&
     307             :              tr != JS::TranscodeResult_Failure_WrongCompileOption);
     308           0 :   if (tr != JS::TranscodeResult_Ok) {
     309           0 :     mSkip = true;
     310           0 :     mRv = NS_ERROR_DOM_JS_DECODING_ERROR;
     311           0 :     return mRv;
     312             :   }
     313             : 
     314           0 :   if (!JS_ExecuteScript(mCx, mScopeChain, script)) {
     315           0 :     mSkip = true;
     316           0 :     mRv = EvaluationExceptionToNSResult(mCx);
     317           0 :     return mRv;
     318             :   }
     319             : 
     320           0 :   return mRv;
     321             : }
     322             : 
     323             : nsresult
     324           0 : nsJSUtils::ExecutionContext::DecodeJoinAndExec(void **aOffThreadToken)
     325             : {
     326           0 :   if (mSkip) {
     327           0 :     return mRv;
     328             :   }
     329             : 
     330           0 :   MOZ_ASSERT(!mWantsReturnValue);
     331           0 :   MOZ_ASSERT(!mExpectScopeChain);
     332           0 :   JS::Rooted<JSScript*> script(mCx);
     333           0 :   script.set(JS::FinishOffThreadScriptDecoder(mCx, *aOffThreadToken));
     334           0 :   *aOffThreadToken = nullptr; // Mark the token as having been finished.
     335           0 :   if (!script || !JS_ExecuteScript(mCx, mScopeChain, script)) {
     336           0 :     mSkip = true;
     337           0 :     mRv = EvaluationExceptionToNSResult(mCx);
     338           0 :     return mRv;
     339             :   }
     340             : 
     341           0 :   return NS_OK;
     342             : }
     343             : 
     344             : nsresult
     345         112 : nsJSUtils::ExecutionContext::ExtractReturnValue(JS::MutableHandle<JS::Value> aRetValue)
     346             : {
     347         112 :   MOZ_ASSERT(aRetValue.isUndefined());
     348         112 :   if (mSkip) {
     349             :     // Repeat earlier result, as NS_SUCCESS_DOM_SCRIPT_EVALUATION_THREW are not
     350             :     // failures cases.
     351             : #ifdef DEBUG
     352           0 :     mWantsReturnValue = false;
     353             : #endif
     354           0 :     return mRv;
     355             :   }
     356             : 
     357         112 :   MOZ_ASSERT(mWantsReturnValue);
     358             : #ifdef DEBUG
     359         112 :   mWantsReturnValue = false;
     360             : #endif
     361         112 :   if (mCoerceToString && !mRetValue.isUndefined()) {
     362           0 :     JSString* str = JS::ToString(mCx, mRetValue);
     363           0 :     if (!str) {
     364             :       // ToString can be a function call, so an exception can be raised while
     365             :       // executing the function.
     366           0 :       mSkip = true;
     367           0 :       return EvaluationExceptionToNSResult(mCx);
     368             :     }
     369           0 :     mRetValue.set(JS::StringValue(str));
     370             :   }
     371             : 
     372         112 :   aRetValue.set(mRetValue);
     373         112 :   return NS_OK;
     374             : }
     375             : 
     376             : nsresult
     377           0 : nsJSUtils::CompileModule(JSContext* aCx,
     378             :                        JS::SourceBufferHolder& aSrcBuf,
     379             :                        JS::Handle<JSObject*> aEvaluationGlobal,
     380             :                        JS::CompileOptions &aCompileOptions,
     381             :                        JS::MutableHandle<JSObject*> aModule)
     382             : {
     383           0 :   AUTO_PROFILER_LABEL("nsJSUtils::CompileModule", JS);
     384             : 
     385           0 :   MOZ_ASSERT_IF(aCompileOptions.versionSet,
     386             :                 aCompileOptions.version != JSVERSION_UNKNOWN);
     387           0 :   MOZ_ASSERT(aCx == nsContentUtils::GetCurrentJSContext());
     388           0 :   MOZ_ASSERT(aSrcBuf.get());
     389           0 :   MOZ_ASSERT(js::GetGlobalForObjectCrossCompartment(aEvaluationGlobal) ==
     390             :              aEvaluationGlobal);
     391           0 :   MOZ_ASSERT(JS::CurrentGlobalOrNull(aCx) == aEvaluationGlobal);
     392           0 :   MOZ_ASSERT(NS_IsMainThread());
     393           0 :   MOZ_ASSERT(nsContentUtils::IsInMicroTask());
     394             : 
     395           0 :   NS_ENSURE_TRUE(xpc::Scriptability::Get(aEvaluationGlobal).Allowed(), NS_OK);
     396             : 
     397           0 :   if (!JS::CompileModule(aCx, aCompileOptions, aSrcBuf, aModule)) {
     398           0 :     return NS_ERROR_FAILURE;
     399             :   }
     400             : 
     401           0 :   return NS_OK;
     402             : }
     403             : 
     404             : nsresult
     405           0 : nsJSUtils::ModuleDeclarationInstantiation(JSContext* aCx, JS::Handle<JSObject*> aModule)
     406             : {
     407           0 :   AUTO_PROFILER_LABEL("nsJSUtils::ModuleDeclarationInstantiation", JS);
     408             : 
     409           0 :   MOZ_ASSERT(aCx == nsContentUtils::GetCurrentJSContext());
     410           0 :   MOZ_ASSERT(NS_IsMainThread());
     411             : 
     412           0 :   NS_ENSURE_TRUE(xpc::Scriptability::Get(aModule).Allowed(), NS_OK);
     413             : 
     414           0 :   if (!JS::ModuleDeclarationInstantiation(aCx, aModule)) {
     415           0 :     return NS_ERROR_FAILURE;
     416             :   }
     417             : 
     418           0 :   return NS_OK;
     419             : }
     420             : 
     421             : nsresult
     422           0 : nsJSUtils::ModuleEvaluation(JSContext* aCx, JS::Handle<JSObject*> aModule)
     423             : {
     424           0 :   AUTO_PROFILER_LABEL("nsJSUtils::ModuleEvaluation", JS);
     425             : 
     426           0 :   MOZ_ASSERT(aCx == nsContentUtils::GetCurrentJSContext());
     427           0 :   MOZ_ASSERT(NS_IsMainThread());
     428           0 :   MOZ_ASSERT(nsContentUtils::IsInMicroTask());
     429             : 
     430           0 :   NS_ENSURE_TRUE(xpc::Scriptability::Get(aModule).Allowed(), NS_OK);
     431             : 
     432           0 :   if (!JS::ModuleEvaluation(aCx, aModule)) {
     433           0 :     return NS_ERROR_FAILURE;
     434             :   }
     435             : 
     436           0 :   return NS_OK;
     437             : }
     438             : 
     439             : /* static */
     440             : bool
     441         173 : nsJSUtils::GetScopeChainForElement(JSContext* aCx,
     442             :                                    mozilla::dom::Element* aElement,
     443             :                                    JS::AutoObjectVector& aScopeChain)
     444             : {
     445        1746 :   for (nsINode* cur = aElement; cur; cur = cur->GetScopeChainParent()) {
     446        3146 :     JS::RootedValue val(aCx);
     447        1573 :     if (!GetOrCreateDOMReflector(aCx, cur, &val)) {
     448           0 :       return false;
     449             :     }
     450             : 
     451        1573 :     if (!aScopeChain.append(&val.toObject())) {
     452           0 :       return false;
     453             :     }
     454             :   }
     455             : 
     456         173 :   return true;
     457             : }
     458             : 
     459             : /* static */
     460             : void
     461           3 : nsJSUtils::ResetTimeZone()
     462             : {
     463           3 :   JS::ResetTimeZone();
     464           3 : }
     465             : 
     466             : //
     467             : // nsDOMJSUtils.h
     468             : //
     469             : 
     470           0 : bool nsAutoJSString::init(const JS::Value &v)
     471             : {
     472             :   // Note: it's okay to use danger::GetJSContext here instead of AutoJSAPI,
     473             :   // because the init() call below is careful not to run script (for instance,
     474             :   // it only calls JS::ToString for non-object values).
     475           0 :   JSContext* cx = danger::GetJSContext();
     476           0 :   if (!init(cx, v)) {
     477           0 :     JS_ClearPendingException(cx);
     478           0 :     return false;
     479             :   }
     480             : 
     481           0 :   return true;
     482             : }
     483             : 

Generated by: LCOV version 1.13