LCOV - code coverage report
Current view: top level - js/xpconnect/loader - ChromeScriptLoader.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 157 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 32 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /* vim: set ts=8 sts=4 et sw=4 tw=99: */
       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             : #include "PrecompiledScript.h"
       8             : 
       9             : #include "nsIURI.h"
      10             : #include "nsIChannel.h"
      11             : #include "nsNetUtil.h"
      12             : #include "nsThreadUtils.h"
      13             : 
      14             : #include "jsapi.h"
      15             : #include "jsfriendapi.h"
      16             : #include "js/Utility.h"
      17             : 
      18             : #include "mozilla/dom/ChromeUtils.h"
      19             : #include "mozilla/dom/Promise.h"
      20             : #include "mozilla/dom/ScriptLoader.h"
      21             : #include "mozilla/HoldDropJSObjects.h"
      22             : #include "mozilla/SystemGroup.h"
      23             : #include "nsCycleCollectionParticipant.h"
      24             : 
      25             : using namespace JS;
      26             : using namespace mozilla;
      27             : using namespace mozilla::dom;
      28             : 
      29             : class AsyncScriptCompiler final : public nsIIncrementalStreamLoaderObserver
      30             :                                 , public Runnable
      31             : {
      32             : public:
      33             :     // Note: References to this class are never held by cycle-collected objects.
      34             :     // If at any point a reference is returned to a caller, please update this
      35             :     // class to implement cycle collection.
      36             :     NS_DECL_ISUPPORTS_INHERITED
      37             :     NS_DECL_NSIINCREMENTALSTREAMLOADEROBSERVER
      38             :     NS_DECL_NSIRUNNABLE
      39             : 
      40           0 :     AsyncScriptCompiler(JSContext* aCx,
      41             :                         nsIGlobalObject* aGlobal,
      42             :                         const nsACString& aURL,
      43             :                         const CompileScriptOptionsDictionary& aOptions,
      44             :                         Promise* aPromise)
      45           0 :       : mozilla::Runnable("AsyncScriptCompiler")
      46             :       , mOptions(aCx)
      47             :       , mURL(aURL)
      48             :       , mGlobalObject(aGlobal)
      49             :       , mPromise(aPromise)
      50           0 :       , mCharset(aOptions.mCharset)
      51             :     {
      52           0 :         mOptions.setVersion(JSVERSION_DEFAULT)
      53           0 :                 .setNoScriptRval(!aOptions.mHasReturnValue)
      54           0 :                 .setCanLazilyParse(aOptions.mLazilyParse)
      55           0 :                 .setFile(aCx, mURL.get());
      56           0 :     }
      57             : 
      58             :     nsresult Start(nsIPrincipal* aPrincipal);
      59             : 
      60             :     inline void
      61           0 :     SetToken(void* aToken)
      62             :     {
      63           0 :         mToken = aToken;
      64           0 :     }
      65             : 
      66             : protected:
      67           0 :     virtual ~AsyncScriptCompiler() {
      68           0 :         if (mPromise->State() == Promise::PromiseState::Pending) {
      69           0 :             mPromise->MaybeReject(NS_ERROR_FAILURE);
      70             :         }
      71           0 :     }
      72             : 
      73             : private:
      74             :     void Reject(JSContext* aCx);
      75             :     void Reject(JSContext* aCx, const char* aMxg);
      76             : 
      77             :     bool StartCompile(JSContext* aCx);
      78             :     void FinishCompile(JSContext* aCx);
      79             :     void Finish(JSContext* aCx, Handle<JSScript*> script);
      80             : 
      81             :     OwningCompileOptions        mOptions;
      82             :     nsCString                   mURL;
      83             :     nsCOMPtr<nsIGlobalObject>   mGlobalObject;
      84             :     RefPtr<Promise>             mPromise;
      85             :     nsString                    mCharset;
      86             :     void*                       mToken;
      87             :     UniqueTwoByteChars          mScriptText;
      88             :     size_t                      mScriptLength;
      89             : };
      90             : 
      91           0 : NS_IMPL_QUERY_INTERFACE_INHERITED(AsyncScriptCompiler, Runnable, nsIIncrementalStreamLoaderObserver)
      92           0 : NS_IMPL_ADDREF_INHERITED(AsyncScriptCompiler, Runnable)
      93           0 : NS_IMPL_RELEASE_INHERITED(AsyncScriptCompiler, Runnable)
      94             : 
      95             : nsresult
      96           0 : AsyncScriptCompiler::Start(nsIPrincipal* aPrincipal)
      97             : {
      98           0 :     nsCOMPtr<nsIURI> uri;
      99           0 :     nsresult rv = NS_NewURI(getter_AddRefs(uri), mURL);
     100           0 :     NS_ENSURE_SUCCESS(rv, rv);
     101             : 
     102           0 :     nsCOMPtr<nsIChannel> channel;
     103           0 :     rv = NS_NewChannel(getter_AddRefs(channel),
     104             :                        uri, aPrincipal,
     105             :                        nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL,
     106           0 :                        nsIContentPolicy::TYPE_OTHER);
     107           0 :     NS_ENSURE_SUCCESS(rv, rv);
     108             : 
     109           0 :     nsCOMPtr<nsIIncrementalStreamLoader> loader;
     110           0 :     rv = NS_NewIncrementalStreamLoader(getter_AddRefs(loader), this);
     111           0 :     NS_ENSURE_SUCCESS(rv, rv);
     112             : 
     113           0 :     return channel->AsyncOpen2(loader);
     114             : }
     115             : 
     116             : static void
     117           0 : OffThreadScriptLoaderCallback(void* aToken, void* aCallbackData)
     118             : {
     119           0 :     RefPtr<AsyncScriptCompiler> scriptCompiler = dont_AddRef(
     120           0 :         static_cast<AsyncScriptCompiler*>(aCallbackData));
     121             : 
     122           0 :     scriptCompiler->SetToken(aToken);
     123             : 
     124           0 :     SystemGroup::Dispatch("ScriptLoader::FinishCompile",
     125             :                           TaskCategory::Other,
     126           0 :                           scriptCompiler.forget());
     127           0 : }
     128             : 
     129             : bool
     130           0 : AsyncScriptCompiler::StartCompile(JSContext* aCx)
     131             : {
     132           0 :     Rooted<JSObject*> global(aCx, mGlobalObject->GetGlobalJSObject());
     133             : 
     134           0 :     if (JS::CanCompileOffThread(aCx, mOptions, mScriptLength)) {
     135           0 :         if (!JS::CompileOffThread(aCx, mOptions, mScriptText.get(), mScriptLength,
     136             :                                   OffThreadScriptLoaderCallback,
     137             :                                   static_cast<void*>(this))) {
     138           0 :             return false;
     139             :         }
     140             : 
     141           0 :         NS_ADDREF(this);
     142           0 :         return true;
     143             :     }
     144             : 
     145           0 :     Rooted<JSScript*> script(aCx);
     146           0 :     if (!JS::Compile(aCx, mOptions, mScriptText.get(), mScriptLength, &script)) {
     147           0 :         return false;
     148             :     }
     149             : 
     150           0 :     Finish(aCx, script);
     151           0 :     return true;
     152             : }
     153             : 
     154             : NS_IMETHODIMP
     155           0 : AsyncScriptCompiler::Run()
     156             : {
     157           0 :     AutoJSAPI jsapi;
     158           0 :     if (jsapi.Init(mGlobalObject)) {
     159           0 :         FinishCompile(jsapi.cx());
     160             :     } else {
     161           0 :         jsapi.Init();
     162           0 :         JS::CancelOffThreadScript(jsapi.cx(), mToken);
     163             : 
     164           0 :         mPromise->MaybeReject(NS_ERROR_FAILURE);
     165             :     }
     166             : 
     167           0 :     return NS_OK;
     168             : }
     169             : 
     170             : void
     171           0 : AsyncScriptCompiler::FinishCompile(JSContext* aCx)
     172             : {
     173           0 :     Rooted<JSScript*> script(aCx, JS::FinishOffThreadScript(aCx, mToken));
     174           0 :     if (script) {
     175           0 :         Finish(aCx, script);
     176             :     } else {
     177           0 :         Reject(aCx);
     178             :     }
     179           0 : }
     180             : 
     181             : 
     182             : void
     183           0 : AsyncScriptCompiler::Finish(JSContext* aCx, Handle<JSScript*> aScript)
     184             : {
     185           0 :     RefPtr<PrecompiledScript> result = new PrecompiledScript(mGlobalObject, aScript, mOptions);
     186             : 
     187           0 :     mPromise->MaybeResolve(result);
     188           0 : }
     189             : 
     190             : void
     191           0 : AsyncScriptCompiler::Reject(JSContext* aCx)
     192             : {
     193           0 :     RootedValue value(aCx, JS::UndefinedValue());
     194           0 :     if (JS_GetPendingException(aCx, &value)) {
     195           0 :         JS_ClearPendingException(aCx);
     196             :     }
     197           0 :     mPromise->MaybeReject(aCx, value);
     198           0 : }
     199             : 
     200             : void
     201           0 : AsyncScriptCompiler::Reject(JSContext* aCx, const char* aMsg)
     202             : {
     203           0 :     nsAutoString msg;
     204           0 :     msg.AppendASCII(aMsg);
     205           0 :     msg.AppendLiteral(": ");
     206           0 :     AppendUTF8toUTF16(mURL, msg);
     207             : 
     208           0 :     RootedValue exn(aCx);
     209           0 :     if (xpc::NonVoidStringToJsval(aCx, msg, &exn)) {
     210           0 :         JS_SetPendingException(aCx, exn);
     211             :     }
     212             : 
     213           0 :     Reject(aCx);
     214           0 : }
     215             : 
     216             : NS_IMETHODIMP
     217           0 : AsyncScriptCompiler::OnIncrementalData(nsIIncrementalStreamLoader* aLoader,
     218             :                                        nsISupports* aContext,
     219             :                                        uint32_t aDataLength,
     220             :                                        const uint8_t* aData,
     221             :                                        uint32_t *aConsumedData)
     222             : {
     223           0 :     return NS_OK;
     224             : }
     225             : 
     226             : NS_IMETHODIMP
     227           0 : AsyncScriptCompiler::OnStreamComplete(nsIIncrementalStreamLoader* aLoader,
     228             :                                       nsISupports* aContext,
     229             :                                       nsresult aStatus,
     230             :                                       uint32_t aLength,
     231             :                                       const uint8_t* aBuf)
     232             : {
     233           0 :     AutoJSAPI jsapi;
     234           0 :     if (!jsapi.Init(mGlobalObject)) {
     235           0 :         mPromise->MaybeReject(NS_ERROR_FAILURE);
     236           0 :         return NS_OK;
     237             :     }
     238             : 
     239           0 :     JSContext* cx = jsapi.cx();
     240             : 
     241           0 :     if (NS_FAILED(aStatus)) {
     242           0 :         Reject(cx, "Unable to load script");
     243           0 :         return NS_OK;
     244             :     }
     245             : 
     246           0 :     nsresult rv = ScriptLoader::ConvertToUTF16(
     247           0 :         nullptr, aBuf, aLength, mCharset, nullptr, mScriptText, mScriptLength);
     248           0 :     if (NS_FAILED(rv)) {
     249           0 :         Reject(cx, "Unable to decode script");
     250           0 :         return NS_OK;
     251             :     }
     252             : 
     253           0 :     if (!StartCompile(cx)) {
     254           0 :         Reject(cx);
     255             :     }
     256             : 
     257           0 :     return NS_OK;
     258             : }
     259             : 
     260             : 
     261             : namespace mozilla {
     262             : namespace dom {
     263             : 
     264             : /* static */ already_AddRefed<Promise>
     265           0 : ChromeUtils::CompileScript(GlobalObject& aGlobal,
     266             :                            const nsAString& aURL,
     267             :                            const CompileScriptOptionsDictionary& aOptions,
     268             :                            ErrorResult& aRv)
     269             : {
     270           0 :     nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
     271           0 :     MOZ_ASSERT(global);
     272             : 
     273           0 :     RefPtr<Promise> promise = Promise::Create(global, aRv);
     274           0 :     if (aRv.Failed()) {
     275           0 :         return nullptr;
     276             :     }
     277             : 
     278           0 :     NS_ConvertUTF16toUTF8 url(aURL);
     279           0 :     RefPtr<AsyncScriptCompiler> compiler = new AsyncScriptCompiler(aGlobal.Context(), global, url, aOptions, promise);
     280             : 
     281           0 :     nsresult rv = compiler->Start(aGlobal.GetSubjectPrincipal());
     282           0 :     if (NS_FAILED(rv)) {
     283           0 :         promise->MaybeReject(rv);
     284             :     }
     285             : 
     286           0 :     return promise.forget();
     287             : }
     288             : 
     289           0 : PrecompiledScript::PrecompiledScript(nsISupports* aParent, Handle<JSScript*> aScript,
     290           0 :                                      JS::ReadOnlyCompileOptions& aOptions)
     291             :     : mParent(aParent)
     292             :     , mScript(aScript)
     293             :     , mURL(aOptions.filename())
     294           0 :     , mHasReturnValue(!aOptions.noScriptRval)
     295             : {
     296           0 :     MOZ_ASSERT(aParent);
     297           0 :     MOZ_ASSERT(aScript);
     298             : 
     299           0 :     mozilla::HoldJSObjects(this);
     300           0 : };
     301             : 
     302           0 : PrecompiledScript::~PrecompiledScript()
     303             : {
     304           0 :     mozilla::DropJSObjects(this);
     305           0 : }
     306             : 
     307             : void
     308           0 : PrecompiledScript::ExecuteInGlobal(JSContext* aCx, HandleObject aGlobal,
     309             :                                    MutableHandleValue aRval,
     310             :                                    ErrorResult& aRv)
     311             : {
     312             :     {
     313           0 :         RootedObject targetObj(aCx, JS_FindCompilationScope(aCx, aGlobal));
     314           0 :         JSAutoCompartment ac(aCx, targetObj);
     315             : 
     316           0 :         Rooted<JSScript*> script(aCx, mScript);
     317           0 :         if (!JS::CloneAndExecuteScript(aCx, script, aRval)) {
     318           0 :             aRv.NoteJSContextException(aCx);
     319           0 :             return;
     320             :         }
     321             :     }
     322             : 
     323           0 :     JS_WrapValue(aCx, aRval);
     324             : }
     325             : 
     326             : void
     327           0 : PrecompiledScript::GetUrl(nsAString& aUrl)
     328             : {
     329           0 :     CopyUTF8toUTF16(mURL, aUrl);
     330           0 : }
     331             : 
     332             : bool
     333           0 : PrecompiledScript::HasReturnValue()
     334             : {
     335           0 :     return mHasReturnValue;
     336             : }
     337             : 
     338             : JSObject*
     339           0 : PrecompiledScript::WrapObject(JSContext* aCx, HandleObject aGivenProto)
     340             : {
     341           0 :     return PrecompiledScriptBinding::Wrap(aCx, this, aGivenProto);
     342             : }
     343             : 
     344             : NS_IMPL_CYCLE_COLLECTION_CLASS(PrecompiledScript)
     345             : 
     346           0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(PrecompiledScript)
     347           0 :     NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
     348           0 :     NS_INTERFACE_MAP_ENTRY(nsISupports)
     349           0 : NS_INTERFACE_MAP_END
     350             : 
     351           0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(PrecompiledScript)
     352           0 :     NS_IMPL_CYCLE_COLLECTION_UNLINK(mParent)
     353           0 :     NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
     354             : 
     355           0 :     tmp->mScript = nullptr;
     356           0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
     357             : 
     358           0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(PrecompiledScript)
     359           0 :     NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParent)
     360           0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
     361             : 
     362           0 : NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(PrecompiledScript)
     363           0 :     NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mScript)
     364           0 :     NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
     365           0 : NS_IMPL_CYCLE_COLLECTION_TRACE_END
     366             : 
     367           0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(PrecompiledScript)
     368           0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(PrecompiledScript)
     369             : 
     370             : } // namespace dom
     371             : } // namespace mozilla

Generated by: LCOV version 1.13