Bug 811784: Account for subscripts when figuring out what object to stick properties on. r=mrbkap
☠☠ backed out by aae9b913320f ☠ ☠
authorKyle Huey <khuey@kylehuey.com>
Fri, 16 Nov 2012 08:54:58 -0800
changeset 118150 4bc502c08da4fed2bd93d3a5cb2f315cd3364560
parent 118149 c8b8756142f7059def2dc089163eb781a78fce20
child 118151 d86aa72c7dbf6ff76bea32db9079de93de53cf8d
push idunknown
push userunknown
push dateunknown
reviewersmrbkap
bugs811784
milestone19.0a1
Bug 811784: Account for subscripts when figuring out what object to stick properties on. r=mrbkap
js/xpconnect/loader/mozJSComponentLoader.cpp
js/xpconnect/loader/mozJSComponentLoader.h
js/xpconnect/loader/mozJSSubScriptLoader.cpp
js/xpconnect/loader/mozJSSubScriptLoader.h
--- a/js/xpconnect/loader/mozJSComponentLoader.cpp
+++ b/js/xpconnect/loader/mozJSComponentLoader.cpp
@@ -620,16 +620,22 @@ mozJSComponentLoader::FindTargetObject(J
 
         targetObject = JS_GetGlobalForObject(aCx, targetObject);
     }
 
     *aTargetObject = targetObject;
     return NS_OK;
 }
 
+void
+mozJSComponentLoader::NoteSubScript(JSScript* aScript, JSObject* aThisObject)
+{
+  mThisObjects.Put(aScript, aThisObject);
+}
+
 // Some stack based classes for cleaning up on early return
 #ifdef HAVE_PR_MEMMAP
 class FileAutoCloser
 {
  public:
     explicit FileAutoCloser(PRFileDesc *file) : mFile(file) {}
     ~FileAutoCloser() { PR_Close(mFile); }
  private:
--- a/js/xpconnect/loader/mozJSComponentLoader.h
+++ b/js/xpconnect/loader/mozJSComponentLoader.h
@@ -49,16 +49,18 @@ class mozJSComponentLoader : public mozi
 
     // ModuleLoader
     const mozilla::Module* LoadModule(mozilla::FileLocation &aFile);
 
     nsresult FindTargetObject(JSContext* aCx, JSObject** aTargetObject);
 
     static mozJSComponentLoader* Get() { return sSelf; }
 
+    void NoteSubScript(JSScript* aScript, JSObject* aThisObject);
+
  protected:
     static mozJSComponentLoader* sSelf;
 
     nsresult ReallyInit();
     void UnloadModules();
 
     JSObject* PrepareObjectForLocation(JSCLContextHelper& aCx,
                                        nsIFile* aComponentFile,
--- a/js/xpconnect/loader/mozJSSubScriptLoader.cpp
+++ b/js/xpconnect/loader/mozJSSubScriptLoader.cpp
@@ -26,16 +26,17 @@
 
 #include "jsapi.h"
 #include "jsdbgapi.h"
 #include "jsfriendapi.h"
 #include "nsJSPrincipals.h"
 
 #include "mozilla/scache/StartupCache.h"
 #include "mozilla/scache/StartupCacheUtils.h"
+#include "mozilla/Preferences.h"
 
 using namespace mozilla::scache;
 
 /* 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."
@@ -52,16 +53,17 @@ using namespace mozilla::scache;
 extern void
 mozJSLoaderErrorReporter(JSContext *cx, const char *message, JSErrorReport *rep);
 
 mozJSSubScriptLoader::mozJSSubScriptLoader() : mSystemPrincipal(nullptr)
 {
     // Force construction of the JS component loader.  We may need it later.
     nsCOMPtr<xpcIJSModuleLoader> componentLoader =
         do_GetService(MOZJSCOMPONENTLOADER_CONTRACTID);
+    mReuseLoaderGlobal = mozilla::Preferences::GetBool("jsloader.reuseGlobal");
 }
 
 mozJSSubScriptLoader::~mozJSSubScriptLoader()
 {
     /* empty */
 }
 
 NS_IMPL_THREADSAFE_ISUPPORTS1(mozJSSubScriptLoader, mozIJSSubScriptLoader)
@@ -72,22 +74,25 @@ ReportError(JSContext *cx, const char *m
     JS_SetPendingException(cx, STRING_TO_JSVAL(JS_NewStringCopyZ(cx, msg)));
     return NS_OK;
 }
 
 nsresult
 mozJSSubScriptLoader::ReadScript(nsIURI *uri, JSContext *cx, JSObject *target_obj,
                                  const nsAString& charset, const char *uriStr,
                                  nsIIOService *serv, nsIPrincipal *principal,
-                                 JSScript **scriptp)
+                                 JSScript **scriptp, JSFunction **functionp)
 {
     nsCOMPtr<nsIChannel>     chan;
     nsCOMPtr<nsIInputStream> instream;
     JSErrorReporter  er;
 
+    *scriptp = nullptr;
+    *functionp = nullptr;
+
     nsresult rv;
     // Instead of calling NS_OpenURI, we create the channel ourselves and call
     // SetContentType, to avoid expensive MIME type lookups (bug 632490).
     rv = NS_NewChannel(getter_AddRefs(chan), uri, serv,
                        nullptr, nullptr, nsIRequest::LOAD_NORMAL);
     if (NS_SUCCEEDED(rv)) {
         chan->SetContentType(NS_LITERAL_CSTRING("application/javascript"));
         rv = chan->Open(getter_AddRefs(instream));
@@ -115,31 +120,47 @@ mozJSSubScriptLoader::ReadScript(nsIURI 
 
     /* set our own error reporter so we can report any bad things as catchable
      * exceptions, including the source/line number */
     er = JS_SetErrorReporter(cx, mozJSLoaderErrorReporter);
 
     JS::CompileOptions options(cx);
     options.setPrincipals(nsJSPrincipals::get(principal))
            .setFileAndLine(uriStr, 1)
-           .setSourcePolicy(JS::CompileOptions::LAZY_SOURCE);
+           .setSourcePolicy(mReuseLoaderGlobal ?
+                            JS::CompileOptions::NO_SOURCE :
+                            JS::CompileOptions::LAZY_SOURCE);
     js::RootedObject target_obj_root(cx, target_obj);
     if (!charset.IsVoid()) {
         nsString script;
         rv = nsScriptLoader::ConvertToUTF16(nullptr, reinterpret_cast<const uint8_t*>(buf.get()), len,
                                             charset, nullptr, script);
 
         if (NS_FAILED(rv)) {
             return ReportError(cx, LOAD_ERROR_BADCHARSET);
         }
 
-        *scriptp = JS::Compile(cx, target_obj_root, options,
-                               reinterpret_cast<const jschar*>(script.get()), script.Length());
+        if (!mReuseLoaderGlobal) {
+            *scriptp = JS::Compile(cx, target_obj_root, options,
+                                   reinterpret_cast<const jschar*>(script.get()),
+                                   script.Length());
+        } else {
+            *functionp = JS::CompileFunction(cx, target_obj_root, options,
+                                             nullptr, 0, nullptr,
+                                             reinterpret_cast<const jschar*>(script.get()),
+                                             script.Length());
+        }
     } else {
-        *scriptp = JS::Compile(cx, target_obj_root, options, buf.get(), len);
+        if (!mReuseLoaderGlobal) {
+            *scriptp = JS::Compile(cx, target_obj_root, options, buf.get(), len);
+        } else {
+            *functionp = JS::CompileFunction(cx, target_obj_root, options,
+                                             nullptr, 0, nullptr, buf.get(),
+                                             len);
+        }
     }
 
     /* repent for our evil deeds */
     JS_SetErrorReporter(cx, er);
 
     return NS_OK;
 }
 
@@ -176,20 +197,19 @@ mozJSSubScriptLoader::LoadSubScript(cons
     }
 
     JSAutoRequest ar(cx);
 
     JSObject* targetObj;
     if (!JS_ValueToObject(cx, target, &targetObj))
         return NS_ERROR_ILLEGAL_VALUE;
 
-
+    mozJSComponentLoader* loader = mozJSComponentLoader::Get();
     if (!targetObj) {
         // If the user didn't provide an object to eval onto, find one.
-        mozJSComponentLoader* loader = mozJSComponentLoader::Get();
         rv = loader->FindTargetObject(cx, &targetObj);
         NS_ENSURE_SUCCESS(rv, rv);
     }
 
     // Remember an object out of the calling compartment so that we
     // can properly wrap the result later.
     nsCOMPtr<nsIPrincipal> principal = mSystemPrincipal;
     JSObject *result_obj = targetObj;
@@ -267,30 +287,42 @@ mozJSSubScriptLoader::LoadSubScript(cons
     }
 
     bool writeScript = false;
     JSVersion version = JS_GetVersion(cx);
     nsAutoCString cachePath;
     cachePath.AppendPrintf("jssubloader/%d", version);
     PathifyURI(uri, cachePath);
 
+    JSFunction* function = nullptr;
     script = nullptr;
     if (cache)
         rv = ReadCachedScript(cache, cachePath, cx, mSystemPrincipal, &script);
     if (!script) {
         rv = ReadScript(uri, cx, targetObj, charset,
                         static_cast<const char*>(uriStr.get()), serv,
-                        principal, &script);
-        writeScript = true;
+                        principal, &script, &function);
+        writeScript = !!script;
     }
 
-    if (NS_FAILED(rv) || !script)
+    if (NS_FAILED(rv) || (!script && !function))
         return rv;
 
-    bool ok = JS_ExecuteScriptVersion(cx, targetObj, script, retval, version);
+    if (function) {
+        script = JS_GetFunctionScript(cx, function);
+    }
+
+    loader->NoteSubScript(script, targetObj);
+
+    bool ok = false;
+    if (function) {
+        ok = JS_CallFunction(cx, targetObj, function, 0, nullptr, retval);
+    } else {
+        ok = JS_ExecuteScriptVersion(cx, targetObj, script, retval, version);
+    }
 
     if (ok) {
         JSAutoCompartment rac(cx, result_obj);
         if (!JS_WrapValue(cx, retval))
             return NS_ERROR_UNEXPECTED;
     }
 
     if (cache && ok && writeScript) {
--- a/js/xpconnect/loader/mozJSSubScriptLoader.h
+++ b/js/xpconnect/loader/mozJSSubScriptLoader.h
@@ -28,12 +28,13 @@ public:
     // all the interface method declarations...
     NS_DECL_ISUPPORTS
     NS_DECL_MOZIJSSUBSCRIPTLOADER
 
 private:
     nsresult ReadScript(nsIURI *uri, JSContext *cx, JSObject *target_obj,
                         const nsAString& charset, const char *uriStr,
                         nsIIOService *serv, nsIPrincipal *principal,
-                        JSScript **scriptp);
+                        JSScript **scriptp, JSFunction **functionp);
 
+    bool mReuseLoaderGlobal;
     nsCOMPtr<nsIPrincipal> mSystemPrincipal;
 };