Bug 1089026 part 4. Change the CompileFunction calls in the component loader and subscript loader to pass in their desired scope chains. r=bholley
authorBoris Zbarsky <bzbarsky@mit.edu>
Thu, 30 Oct 2014 19:40:29 -0400
changeset 213256 5ccd3c29891cdf7b7cd817ca96c20157b78a8b1f
parent 213255 cb53a4bac4c8c778823cec7c0769e6e894e6c0c5
child 213257 715ded1f9639136c6cbee52b65d78b7898b1ad26
push id51182
push userbzbarsky@mozilla.com
push dateThu, 30 Oct 2014 23:40:47 +0000
treeherdermozilla-inbound@715ded1f9639 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbholley
bugs1089026
milestone36.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1089026 part 4. Change the CompileFunction calls in the component loader and subscript loader to pass in their desired scope chains. r=bholley
js/xpconnect/loader/mozJSComponentLoader.cpp
js/xpconnect/loader/mozJSSubScriptLoader.cpp
--- a/js/xpconnect/loader/mozJSComponentLoader.cpp
+++ b/js/xpconnect/loader/mozJSComponentLoader.cpp
@@ -452,17 +452,17 @@ mozJSComponentLoader::FindTargetObject(J
                                        MutableHandleObject aTargetObject)
 {
     aTargetObject.set(nullptr);
 
     RootedObject targetObject(aCx);
     if (mReuseLoaderGlobal) {
         JSFunction *fun = js::GetOutermostEnclosingFunctionOfScriptedCaller(aCx);
         if (fun) {
-            JSObject *funParent = js::GetObjectParent(JS_GetFunctionObject(fun));
+            JSObject *funParent = js::GetObjectEnvironmentObjectForFunction(fun);
             if (JS_GetClass(funParent) == &kFakeBackstagePassJSClass)
                 targetObject = funParent;
         }
     }
 
     // The above could fail, even if mReuseLoaderGlobal, if the scripted
     // caller is not a component/JSM (it could be a DOM scope, for
     // instance).
@@ -778,19 +778,24 @@ mozJSComponentLoader::ObjectForLocation(
             if (!buf) {
                 NS_WARNING("Failed to map file");
                 return NS_ERROR_FAILURE;
             }
 
             if (!mReuseLoaderGlobal) {
                 Compile(cx, obj, options, buf, fileSize32, &script);
             } else {
-                CompileFunction(cx, obj, options,
-                                nullptr, 0, nullptr,
-                                buf, fileSize32, &function);
+                // Note: exceptions will get handled further down;
+                // don't early return for them here.
+                AutoObjectVector scopeChain(cx);
+                if (scopeChain.append(obj)) {
+                    CompileFunction(cx, scopeChain,
+                                    options, nullptr, 0, nullptr,
+                                    buf, fileSize32, &function);
+                }
             }
 
             PR_MemUnmap(buf, fileSize32);
 
 #else  /* HAVE_PR_MEMMAP */
 
             /**
              * No memmap implementation, so fall back to
@@ -824,19 +829,24 @@ mozJSComponentLoader::ObjectForLocation(
                 NS_WARNING("Failed to read file");
                 return NS_ERROR_FAILURE;
             }
 
             if (!mReuseLoaderGlobal) {
                 script = Compile(cx, obj, options, buf,
                                      fileSize32);
             } else {
-                function = CompileFunction(cx, obj, options,
-                                           nullptr, 0, nullptr,
-                                           buf, fileSize32);
+                // Note: exceptions will get handled further down;
+                // don't early return for them here.
+                AutoObjectVector scopeChain(cx);
+                if (scopeChain.append(obj)) {
+                    CompileFunction(cx, scopeChain,
+                                    options, nullptr, 0, nullptr,
+                                    buf, fileSize32, &function);
+                }
             }
 
             free(buf);
 
 #endif /* HAVE_PR_MEMMAP */
         } else {
             rv = aInfo.EnsureScriptChannel();
             NS_ENSURE_SUCCESS(rv, rv);
@@ -864,19 +874,24 @@ mozJSComponentLoader::ObjectForLocation(
             if (bytesRead != len)
                 return NS_BASE_STREAM_OSERROR;
 
             buf[len] = '\0';
 
             if (!mReuseLoaderGlobal) {
                 Compile(cx, obj, options, buf, bytesRead, &script);
             } else {
-                CompileFunction(cx, obj, options,
-                                nullptr, 0, nullptr,
-                                buf, bytesRead, &function);
+                // Note: exceptions will get handled further down;
+                // don't early return for them here.
+                AutoObjectVector scopeChain(cx);
+                if (scopeChain.append(obj)) {
+                    CompileFunction(cx, scopeChain,
+                                    options, nullptr, 0, nullptr,
+                                    buf, bytesRead, &function);
+                }
             }
         }
         // Propagate the exception, if one exists. Also, don't leave the stale
         // exception on this context.
         if (!script && !function && aPropagateExceptions) {
             JS_GetPendingException(cx, aException);
             JS_ClearPendingException(cx);
         }
--- a/js/xpconnect/loader/mozJSSubScriptLoader.cpp
+++ b/js/xpconnect/loader/mozJSSubScriptLoader.cpp
@@ -85,16 +85,32 @@ NS_IMPL_ISUPPORTS(mozJSSubScriptLoader, 
 static nsresult
 ReportError(JSContext *cx, const char *msg)
 {
     RootedValue exn(cx, JS::StringValue(JS_NewStringCopyZ(cx, msg)));
     JS_SetPendingException(cx, exn);
     return NS_OK;
 }
 
+// There probably aren't actually any consumers that rely on having the full
+// scope chain up the parent chain of "obj" (instead of just having obj and then
+// the global), but we do this for now to preserve backwards compat.
+static bool
+BuildScopeChainForObject(JSContext *cx, HandleObject obj,
+                         AutoObjectVector &scopeChain)
+{
+    RootedObject cur(cx, obj);
+    for ( ; cur && !JS_IsGlobalObject(cur); cur = JS_GetParent(cur)) {
+        if (!scopeChain.append(cur)) {
+            return false;
+        }
+    }
+    return true;
+}
+
 nsresult
 mozJSSubScriptLoader::ReadScript(nsIURI *uri, JSContext *cx, JSObject *targetObjArg,
                                  const nsAString &charset, const char *uriStr,
                                  nsIIOService *serv, nsIPrincipal *principal,
                                  bool reuseGlobal, JS::MutableHandleScript script,
                                  JS::MutableHandleFunction function)
 {
     RootedObject target_obj(cx, targetObjArg);
@@ -156,31 +172,38 @@ mozJSSubScriptLoader::ReadScript(nsIURI 
 
         if (NS_FAILED(rv)) {
             return ReportError(cx, LOAD_ERROR_BADCHARSET);
         }
 
         if (!reuseGlobal) {
             JS::Compile(cx, target_obj, options, srcBuf, script);
         } else {
-            JS::CompileFunction(cx, target_obj, options,
-                                nullptr, 0, nullptr,
-                                srcBuf,
-                                function);
+            AutoObjectVector scopeChain(cx);
+            if (!BuildScopeChainForObject(cx, target_obj, scopeChain)) {
+                return NS_ERROR_OUT_OF_MEMORY;
+            }
+            // XXXbz do we really not care if the compile fails???
+            JS::CompileFunction(cx, scopeChain, options, nullptr, 0, nullptr,
+                                srcBuf, function);
         }
     } else {
         // We only use lazy source when no special encoding is specified because
         // the lazy source loader doesn't know the encoding.
         if (!reuseGlobal) {
             options.setSourceIsLazy(true);
             JS::Compile(cx, target_obj, options, buf.get(), len, script);
         } else {
-            JS::CompileFunction(cx, target_obj, options,
-                                nullptr, 0, nullptr, buf.get(),
-                                len, function);
+            AutoObjectVector scopeChain(cx);
+            if (!BuildScopeChainForObject(cx, target_obj, scopeChain)) {
+                return NS_ERROR_OUT_OF_MEMORY;
+            }
+            // XXXbz do we really not care if the compile fails???
+            JS::CompileFunction(cx, scopeChain, options, nullptr, 0, nullptr,
+                                buf.get(), len, function);
         }
     }
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
 mozJSSubScriptLoader::LoadSubScript(const nsAString &url,