Bug 1356810: Use noScriptRval option by default for loadSubScript. r?billm draft
authorKris Maglione <maglione.k@gmail.com>
Sat, 15 Apr 2017 09:32:34 -0700
changeset 563231 bac5e5a8074f7727586c46d428a5f851422beb8c
parent 563230 05f0e6fea003df5c3d81fd2254486394ef327cf7
child 563236 8eb426870da26be5b86c16a133a11694c17c2843
push id54240
push usermaglione.k@gmail.com
push dateSat, 15 Apr 2017 16:32:56 +0000
reviewersbillm
bugs1356810
milestone55.0a1
Bug 1356810: Use noScriptRval option by default for loadSubScript. r?billm MozReview-Commit-ID: 50QVvrG4lzV
js/xpconnect/idl/mozIJSSubScriptLoader.idl
js/xpconnect/loader/mozJSSubScriptLoader.cpp
js/xpconnect/loader/mozJSSubScriptLoader.h
--- a/js/xpconnect/idl/mozIJSSubScriptLoader.idl
+++ b/js/xpconnect/idl/mozIJSSubScriptLoader.idl
@@ -37,16 +37,21 @@ interface mozIJSSubScriptLoader : nsISup
      *            resource:, or chrome: url, and MUST be local.
      * @param optionsObject an object with parameters. Valid parameters are:
      *                      - charset: specifying the character encoding of the file (default: ASCII)
      *                      - target:  an object to evaluate onto (default: global object of the caller)
      *                      - ignoreCache: if set to true, will bypass the cache for reading the file.
      *                      - async: if set to true, the script will be loaded
      *                        asynchronously, and a Promise is returned which
      *                        resolves to its result when execution is complete.
+     *                      - wantReturnValue: If true, the script will return
+     *                        the value of the last statement that it evaluated.
+     *                        This option disables most optimizations in the
+     *                        top-level scope, and should be avoided if at all
+     *                        possible.
      * @retval rv the value returned by the sub-script
      */
     [implicit_jscontext]
     jsval loadSubScriptWithOptions(in AString url, in jsval options);
 
     /*
      * Compiles a JS script off the main thread and calls back the
      * observer once it's done.
--- a/js/xpconnect/loader/mozJSSubScriptLoader.cpp
+++ b/js/xpconnect/loader/mozJSSubScriptLoader.cpp
@@ -45,29 +45,32 @@ class MOZ_STACK_CLASS LoadSubScriptOptio
 public:
     explicit LoadSubScriptOptions(JSContext* cx = xpc_GetSafeJSContext(),
                                   JSObject* options = nullptr)
         : OptionsBase(cx, options)
         , target(cx)
         , charset(NullString())
         , ignoreCache(false)
         , async(false)
+        , wantReturnValue(false)
     { }
 
     virtual bool Parse() {
       return ParseObject("target", &target) &&
              ParseString("charset", charset) &&
              ParseBoolean("ignoreCache", &ignoreCache) &&
-             ParseBoolean("async", &async);
+             ParseBoolean("async", &async) &&
+             ParseBoolean("wantReturnValue", &wantReturnValue);
     }
 
     RootedObject target;
     nsString charset;
     bool ignoreCache;
     bool async;
+    bool wantReturnValue;
 };
 
 
 /* load() error msgs, XXX localize? */
 #define LOAD_ERROR_NOSERVICE "Error creating IO Service."
 #define LOAD_ERROR_NOURI "Error creating URI (invalid URL scheme?)"
 #define LOAD_ERROR_NOSCHEME "Failed to get URI scheme.  This is bad."
 #define LOAD_ERROR_URI_NOT_LOCAL "Trying to load a non-local URI."
@@ -125,24 +128,26 @@ bool
 PrepareScript(nsIURI* uri,
               JSContext* cx,
               RootedObject& targetObj,
               const char* uriStr,
               const nsAString& charset,
               const char* buf,
               int64_t len,
               bool reuseGlobal,
+              bool wantReturnValue,
               MutableHandleScript script,
               MutableHandleFunction function)
 {
     JS::CompileOptions options(cx);
     // Use line 0 to make the function body starts from line 1 when
     // |reuseGlobal == true|.
     options.setFileAndLine(uriStr, reuseGlobal ? 0 : 1)
-           .setVersion(JSVERSION_LATEST);
+           .setVersion(JSVERSION_LATEST)
+           .setNoScriptRval(!wantReturnValue);
     if (!charset.IsVoid()) {
         char16_t* scriptBuf = nullptr;
         size_t scriptLength = 0;
 
         nsresult rv =
             nsScriptLoader::ConvertToUTF16(nullptr, reinterpret_cast<const uint8_t*>(buf), len,
                                            charset, nullptr, scriptBuf, scriptLength);
 
@@ -251,40 +256,42 @@ EvalScript(JSContext* cx,
 class AsyncScriptLoader : public nsIIncrementalStreamLoaderObserver
 {
 public:
     NS_DECL_CYCLE_COLLECTING_ISUPPORTS
     NS_DECL_NSIINCREMENTALSTREAMLOADEROBSERVER
 
     NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(AsyncScriptLoader)
 
-    AsyncScriptLoader(nsIChannel* aChannel, bool aReuseGlobal,
+    AsyncScriptLoader(nsIChannel* aChannel, bool aReuseGlobal, bool aWantReturnValue,
                       JSObject* aTargetObj, const nsAString& aCharset,
                       bool aCache, Promise* aPromise)
         : mChannel(aChannel)
         , mTargetObj(aTargetObj)
         , mPromise(aPromise)
         , mCharset(aCharset)
         , mReuseGlobal(aReuseGlobal)
+        , mWantReturnValue(aWantReturnValue)
         , mCache(aCache)
     {
         // Needed for the cycle collector to manage mTargetObj.
         mozilla::HoldJSObjects(this);
     }
 
 private:
     virtual ~AsyncScriptLoader() {
         mozilla::DropJSObjects(this);
     }
 
     RefPtr<nsIChannel>      mChannel;
     Heap<JSObject*>           mTargetObj;
     RefPtr<Promise>         mPromise;
     nsString                  mCharset;
     bool                      mReuseGlobal;
+    bool                      mWantReturnValue;
     bool                      mCache;
 };
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(AsyncScriptLoader)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(AsyncScriptLoader)
   NS_INTERFACE_MAP_ENTRY(nsIIncrementalStreamLoaderObserver)
 NS_INTERFACE_MAP_END
@@ -383,33 +390,34 @@ AsyncScriptLoader::OnStreamComplete(nsII
     nsAutoCString spec;
     nsresult rv = uri->GetSpec(spec);
     NS_ENSURE_SUCCESS(rv, rv);
 
     RootedObject target_obj(cx, mTargetObj);
 
     if (!PrepareScript(uri, cx, target_obj, spec.get(), mCharset,
                        reinterpret_cast<const char*>(aBuf), aLength,
-                       mReuseGlobal, &script, &function))
+                       mReuseGlobal, mWantReturnValue, &script, &function))
     {
         return NS_OK;
     }
 
     JS::Rooted<JS::Value> retval(cx);
     if (EvalScript(cx, target_obj, &retval, uri, mCache, script, function)) {
         autoPromise.ResolvePromise(retval);
     }
 
     return NS_OK;
 }
 
 nsresult
 mozJSSubScriptLoader::ReadScriptAsync(nsIURI* uri, JSObject* targetObjArg,
                                       const nsAString& charset,
                                       nsIIOService* serv, bool reuseGlobal,
+                                      bool wantReturnValue,
                                       bool cache, MutableHandleValue retval)
 {
     RootedObject target_obj(RootingCx(), targetObjArg);
 
     nsCOMPtr<nsIGlobalObject> globalObject = xpc::NativeGlobal(target_obj);
     ErrorResult result;
 
     AutoJSAPI jsapi;
@@ -443,16 +451,17 @@ mozJSSubScriptLoader::ReadScriptAsync(ns
         return rv;
     }
 
     channel->SetContentType(NS_LITERAL_CSTRING("application/javascript"));
 
     RefPtr<AsyncScriptLoader> loadObserver =
         new AsyncScriptLoader(channel,
                               reuseGlobal,
+                              wantReturnValue,
                               target_obj,
                               charset,
                               cache,
                               promise);
 
     nsCOMPtr<nsIIncrementalStreamLoader> loader;
     rv = NS_NewIncrementalStreamLoader(getter_AddRefs(loader), loadObserver);
     NS_ENSURE_SUCCESS(rv, rv);
@@ -460,17 +469,18 @@ mozJSSubScriptLoader::ReadScriptAsync(ns
     nsCOMPtr<nsIStreamListener> listener = loader.get();
     return channel->AsyncOpen2(listener);
 }
 
 bool
 mozJSSubScriptLoader::ReadScript(nsIURI* uri, JSContext* cx, JSObject* targetObjArg,
                                  const nsAString& charset, const char* uriStr,
                                  nsIIOService* serv, nsIPrincipal* principal,
-                                 bool reuseGlobal, JS::MutableHandleScript script,
+                                 bool reuseGlobal, bool wantReturnValue,
+                                 JS::MutableHandleScript script,
                                  JS::MutableHandleFunction function)
 {
     script.set(nullptr);
     function.set(nullptr);
 
     RootedObject target_obj(cx, targetObjArg);
 
     // We create a channel and call SetContentType, to avoid expensive MIME type
@@ -512,17 +522,17 @@ mozJSSubScriptLoader::ReadScript(nsIURI*
     }
 
     nsCString buf;
     rv = NS_ReadInputStreamToString(instream, buf, len);
     NS_ENSURE_SUCCESS(rv, false);
 
     return PrepareScript(uri, cx, target_obj, uriStr, charset,
                          buf.get(), len,
-                         reuseGlobal,
+                         reuseGlobal, wantReturnValue,
                          script, function);
 }
 
 NS_IMETHODIMP
 mozJSSubScriptLoader::LoadSubScript(const nsAString& url,
                                     HandleValue target,
                                     const nsAString& charset,
                                     JSContext* cx,
@@ -679,23 +689,25 @@ mozJSSubScriptLoader::DoLoadSubScriptWit
             // ReadCachedScript may have set a pending exception.
             JS_ClearPendingException(cx);
         }
     }
 
     // If we are doing an async load, trigger it and bail out.
     if (!script && options.async) {
         return ReadScriptAsync(uri, targetObj, options.charset, serv,
-                               reusingGlobal, !!cache, retval);
+                               reusingGlobal, options.wantReturnValue,
+                               !!cache, retval);
     }
 
     if (!script) {
         if (!ReadScript(uri, cx, targetObj, options.charset,
                         static_cast<const char*>(uriStr.get()), serv,
-                        principal, reusingGlobal, &script, &function))
+                        principal, reusingGlobal, options.wantReturnValue,
+                        &script, &function))
         {
             return NS_OK;
         }
     } else {
         cache = nullptr;
     }
 
     Unused << EvalScript(cx, targetObj, retval, uri, !!cache, script, function);
--- a/js/xpconnect/loader/mozJSSubScriptLoader.h
+++ b/js/xpconnect/loader/mozJSSubScriptLoader.h
@@ -31,23 +31,25 @@ public:
     NS_DECL_MOZIJSSUBSCRIPTLOADER
 
 private:
     virtual ~mozJSSubScriptLoader();
 
     bool ReadScript(nsIURI* uri, JSContext* cx, JSObject* target_obj,
                     const nsAString& charset, const char* uriStr,
                     nsIIOService* serv, nsIPrincipal* principal,
-                    bool reuseGlobal, JS::MutableHandleScript script,
+                    bool reuseGlobal, bool wantReturnValue,
+                    JS::MutableHandleScript script,
                     JS::MutableHandleFunction function);
 
     nsresult ReadScriptAsync(nsIURI* uri, JSObject* target_obj,
                              const nsAString& charset,
                              nsIIOService* serv, bool reuseGlobal,
-                             bool cache, JS::MutableHandleValue retval);
+                             bool wantReturnValue, bool cache,
+                             JS::MutableHandleValue retval);
 
     nsresult DoLoadSubScriptWithOptions(const nsAString& url,
                                         LoadSubScriptOptions& options,
                                         JSContext* cx,
                                         JS::MutableHandle<JS::Value> retval);
 
     nsCOMPtr<nsIPrincipal> mSystemPrincipal;
 };