Back out bug 520309 part 2. a=#developers for checkin on CLOSED TREE.
authorDan Witte <dwitte@mozilla.com>
Tue, 24 Aug 2010 07:59:27 -0700
changeset 51357 9eb10510dd98
parent 51356 9599efaaa3d8
child 51358 46f402c75824
push id15284
push userdwitte@mozilla.com
push date2010-08-24 15:01 +0000
Treeherderresults
bugs520309
milestone2.0b5pre
Back out bug 520309 part 2. a=#developers for checkin on CLOSED TREE.
js/src/xpconnect/loader/mozJSComponentLoader.cpp
js/src/xpconnect/loader/mozJSComponentLoader.h
--- a/js/src/xpconnect/loader/mozJSComponentLoader.cpp
+++ b/js/src/xpconnect/loader/mozJSComponentLoader.cpp
@@ -70,32 +70,26 @@
 #include "nsIScriptSecurityManager.h"
 #include "nsIURI.h"
 #include "nsIFileURL.h"
 #include "nsIJARURI.h"
 #include "nsNetUtil.h"
 #endif
 #include "jsxdrapi.h"
 #include "jsprf.h"
+#include "nsIFastLoadFileControl.h"
 // For reporting errors with the console service
 #include "nsIScriptError.h"
 #include "nsIConsoleService.h"
-#include "nsIStorageStream.h"
-#include "nsIStringStream.h"
 #include "prmem.h"
 #include "plbase64.h"
 #if defined(XP_WIN)
 #include "nsILocalFileWin.h"
 #endif
 
-#ifdef MOZ_ENABLE_LIBXUL
-#include "mozilla/scache/StartupCache.h"
-#include "mozilla/scache/StartupCacheUtils.h"
-#endif
-
 #if defined(MOZ_SHARK) || defined(MOZ_CALLGRIND) || defined(MOZ_VTUNE) || defined(MOZ_TRACEVIS)
 #include "jsdbgapi.h"
 #endif
 
 #include "mozilla/FunctionTimer.h"
 
 static const char kJSRuntimeServiceContractID[] = "@mozilla.org/js/xpc/RuntimeService;1";
 static const char kXPConnectServiceContractID[] = "@mozilla.org/js/xpc/XPConnect;1";
@@ -108,16 +102,19 @@ static const char kObserverServiceContra
 
 /**
  * Buffer sizes for serialization and deserialization of scripts.
  * FIXME: bug #411579 (tune this macro!) Last updated: Jan 2008
  */
 #define XPC_SERIALIZATION_BUFFER_SIZE   (64 * 1024)
 #define XPC_DESERIALIZATION_BUFFER_SIZE (12 * 8192)
 
+// Inactivity delay before closing our fastload file stream.
+static const int kFastLoadWriteDelay = 10000;   // 10 seconds
+
 #ifdef PR_LOGGING
 // NSPR_LOG_MODULES=JSComponentLoader:5
 static PRLogModuleInfo *gJSCLLog;
 #endif
 
 #define LOG(args) PR_LOG(gJSCLLog, PR_LOG_DEBUG, args)
 
 // Components.utils.import error messages
@@ -386,16 +383,69 @@ ReportOnCaller(JSCLContextHelper &helper
     JSContext *cx = helper.Pop();
     if (!cx) {
         return NS_ERROR_FAILURE;
     }
 
     return OutputError(cx, format, ap);
 }
 
+NS_IMPL_ISUPPORTS1(nsXPCFastLoadIO, nsIFastLoadFileIO)
+
+NS_IMETHODIMP
+nsXPCFastLoadIO::GetInputStream(nsIInputStream **_retval)
+{
+    if (! mInputStream) {
+        nsCOMPtr<nsIInputStream> fileInput;
+        nsresult rv = NS_NewLocalFileInputStream(getter_AddRefs(fileInput),
+                                                 mFile);
+        NS_ENSURE_SUCCESS(rv, rv);
+
+        rv = NS_NewBufferedInputStream(getter_AddRefs(mInputStream),
+                                       fileInput,
+                                       XPC_DESERIALIZATION_BUFFER_SIZE);
+        NS_ENSURE_SUCCESS(rv, rv);
+        mTruncateOutputFile = false;
+    }
+
+    NS_ADDREF(*_retval = mInputStream);
+    return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPCFastLoadIO::GetOutputStream(nsIOutputStream **_retval)
+{
+    if (! mOutputStream) {
+        PRInt32 ioFlags = PR_WRONLY;
+        if (mTruncateOutputFile) {
+            ioFlags |= PR_CREATE_FILE | PR_TRUNCATE;
+        }
+
+        nsCOMPtr<nsIOutputStream> fileOutput;
+        nsresult rv = NS_NewLocalFileOutputStream(getter_AddRefs(fileOutput),
+                                                  mFile, ioFlags, 0644);
+        NS_ENSURE_SUCCESS(rv, rv);
+
+        rv = NS_NewBufferedOutputStream(getter_AddRefs(mOutputStream),
+                                        fileOutput,
+                                        XPC_SERIALIZATION_BUFFER_SIZE);
+        NS_ENSURE_SUCCESS(rv, rv);
+    }
+
+    NS_ADDREF(*_retval = mOutputStream);
+    return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXPCFastLoadIO::DisableTruncate()
+{
+    mTruncateOutputFile = false;
+    return NS_OK;
+}
+
 static nsresult
 ReadScriptFromStream(JSContext *cx, nsIObjectInputStream *stream,
                      JSScript **script)
 {
     *script = nsnull;
 
     PRUint32 size;
     nsresult rv = stream->Read32(&size);
@@ -511,34 +561,37 @@ mozJSComponentLoader::mozJSComponentLoad
 
 mozJSComponentLoader::~mozJSComponentLoader()
 {
     if (mInitialized) {
         NS_ERROR("'xpcom-shutdown-loaders' was not fired before cleaning up mozJSComponentLoader");
         UnloadModules();
     }
 
+    NS_ASSERTION(!mFastLoadTimer,
+                 "Fastload file should have been closed via xpcom-shutdown");
+
     sSelf = nsnull;
 }
 
 mozJSComponentLoader*
 mozJSComponentLoader::sSelf;
 
 NS_IMPL_ISUPPORTS3(mozJSComponentLoader,
                    mozilla::ModuleLoader,
                    xpcIJSModuleLoader,
                    nsIObserver)
  
 nsresult
 mozJSComponentLoader::ReallyInit()
 {
     NS_TIME_FUNCTION;
+
     nsresult rv;
 
-
     /*
      * Get the JSRuntime from the runtime svc, if possible.
      * We keep a reference around, because it's a Bad Thing if the runtime
      * service gets shut down before we're done.  Bad!
      */
 
     mRuntimeService = do_GetService(kJSRuntimeServiceContractID, &rv);
     if (NS_FAILED(rv) ||
@@ -576,20 +629,33 @@ mozJSComponentLoader::ReallyInit()
 
     if (!mModules.Init(32))
         return NS_ERROR_OUT_OF_MEMORY;
     if (!mImports.Init(32))
         return NS_ERROR_OUT_OF_MEMORY;
     if (!mInProgressImports.Init(32))
         return NS_ERROR_OUT_OF_MEMORY;
 
+    // Set up our fastload file
+    nsCOMPtr<nsIFastLoadService> flSvc = do_GetFastLoadService(&rv);
+    if (NS_SUCCEEDED(rv))
+        rv = flSvc->NewFastLoadFile("XPC", getter_AddRefs(mFastLoadFile));
+    if (NS_FAILED(rv)) {
+        LOG(("Could not get fastload file location\n"));
+    }
+
+    // Listen for xpcom-shutdown so that we can close out our fastload file
+    // at that point (after that we can no longer create an input stream).
     nsCOMPtr<nsIObserverService> obsSvc =
         do_GetService(kObserverServiceContractID, &rv);
     NS_ENSURE_SUCCESS(rv, rv);
 
+    rv = obsSvc->AddObserver(this, NS_XPCOM_SHUTDOWN_OBSERVER_ID, PR_FALSE);
+    NS_ENSURE_SUCCESS(rv, rv);
+
     rv = obsSvc->AddObserver(this, "xpcom-shutdown-loaders", PR_FALSE);
     NS_ENSURE_SUCCESS(rv, rv);
 
 #ifdef DEBUG_shaver_off
     fprintf(stderr, "mJCL: ReallyInit success!\n");
 #endif
     mInitialized = PR_TRUE;
 
@@ -861,76 +927,255 @@ class JSScriptHolder
     JSScriptHolder(JSContext *cx, JSScript *script)
         : mCx(cx), mScript(script) {}
     ~JSScriptHolder() { ::JS_DestroyScript(mCx, mScript); }
  private:
     JSContext *mCx;
     JSScript *mScript;
 };
 
+class FastLoadStateHolder
+{
+ public:
+    explicit FastLoadStateHolder(nsIFastLoadService *service);
+    ~FastLoadStateHolder() { pop(); }
+
+    void pop();
+
+ private:
+    nsCOMPtr<nsIFastLoadService> mService;
+    nsCOMPtr<nsIFastLoadFileIO> mIO;
+    nsCOMPtr<nsIObjectInputStream> mInputStream;
+    nsCOMPtr<nsIObjectOutputStream> mOutputStream;
+};
+
+FastLoadStateHolder::FastLoadStateHolder(nsIFastLoadService *service)
+{
+    if (!service)
+        return;
+
+    mService = service;
+    service->GetFileIO(getter_AddRefs(mIO));
+    service->GetInputStream(getter_AddRefs(mInputStream));
+    service->GetOutputStream(getter_AddRefs(mOutputStream));
+}
+
+void
+FastLoadStateHolder::pop()
+{
+    if (!mService)
+        return;
+
+    mService->SetFileIO(mIO);
+    mService->SetInputStream(mInputStream);
+    mService->SetOutputStream(mOutputStream);
+
+    mService = nsnull;
+}
 
 /* static */
-#ifdef MOZ_ENABLE_LIBXUL
+void
+mozJSComponentLoader::CloseFastLoad(nsITimer *timer, void *closure)
+{
+    static_cast<mozJSComponentLoader*>(closure)->CloseFastLoad();
+}
+
+void
+mozJSComponentLoader::CloseFastLoad()
+{
+    // Close our fastload streams
+    LOG(("Closing fastload file\n"));
+    if (mFastLoadOutput) {
+        nsresult rv = mFastLoadOutput->Close();
+        if (NS_SUCCEEDED(rv)) {
+            nsCOMPtr<nsIFastLoadService> flSvc = do_GetFastLoadService(&rv);
+            if (NS_SUCCEEDED(rv)) {
+                flSvc->CacheChecksum(mFastLoadFile, mFastLoadOutput);
+            }
+        }
+        mFastLoadOutput = nsnull;
+    }
+    if (mFastLoadInput) {
+        mFastLoadInput->Close();
+        mFastLoadInput = nsnull;
+    }
+
+    mFastLoadIO = nsnull;
+    mFastLoadTimer = nsnull;
+}
+
 nsresult
-mozJSComponentLoader::ReadScript(StartupCache* cache, nsIURI *uri,
+mozJSComponentLoader::StartFastLoad(nsIFastLoadService *flSvc)
+{
+    if (!mFastLoadFile || !flSvc) {
+        return NS_ERROR_NOT_AVAILABLE;
+    }
+
+    // Now set our IO object as current, and create our streams.
+    if (!mFastLoadIO) {
+        mFastLoadIO = new nsXPCFastLoadIO(mFastLoadFile);
+        NS_ENSURE_TRUE(mFastLoadIO, NS_ERROR_OUT_OF_MEMORY);
+    }
+
+    nsresult rv = flSvc->SetFileIO(mFastLoadIO);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    if (!mFastLoadInput && !mFastLoadOutput) {
+        // First time accessing the fastload file
+        PRBool exists;
+        mFastLoadFile->Exists(&exists);
+        if (exists) {
+            LOG(("trying to use existing fastload file\n"));
+
+            rv = flSvc->NewInputStream(mFastLoadFile, getter_AddRefs(mFastLoadInput));
+            if (NS_SUCCEEDED(rv)) {
+                LOG(("opened fastload file for reading\n"));
+
+                nsCOMPtr<nsIFastLoadReadControl>
+                    readControl(do_QueryInterface(mFastLoadInput));
+                if (NS_SUCCEEDED(rv)) {
+                    /* Get the JS bytecode version number and validate it. */
+                    PRUint32 version;
+                    rv = mFastLoadInput->Read32(&version);
+                    if (NS_SUCCEEDED(rv) && version != JSXDR_BYTECODE_VERSION) {
+                        LOG(("Bad JS bytecode version\n"));
+                        rv = NS_ERROR_UNEXPECTED;
+                    }
+                }
+            }
+            if (NS_FAILED(rv)) {
+                LOG(("Invalid fastload file detected, removing it\n"));
+                if (mFastLoadInput) {
+                    mFastLoadInput->Close();
+                    mFastLoadInput = nsnull;
+                } 
+                mFastLoadIO->SetInputStream(nsnull);
+                mFastLoadFile->Remove(PR_FALSE);
+                exists = PR_FALSE;
+            }
+        }
+
+        if (!exists) {
+            LOG(("Creating new fastload file\n"));
+
+            nsCOMPtr<nsIOutputStream> output;
+            rv = mFastLoadIO->GetOutputStream(getter_AddRefs(output));
+            NS_ENSURE_SUCCESS(rv, rv);
+
+            rv = flSvc->NewOutputStream(output,
+                                        getter_AddRefs(mFastLoadOutput));
+
+            if (NS_SUCCEEDED(rv))
+                rv = mFastLoadOutput->Write32(JSXDR_BYTECODE_VERSION);
+
+            if (NS_FAILED(rv)) {
+                LOG(("Fatal error, could not create fastload file\n"));
+
+                if (mFastLoadOutput) {
+                    mFastLoadOutput->Close();
+                    mFastLoadOutput = nsnull;
+                } else {
+                    output->Close();
+                }
+                mFastLoadIO->SetOutputStream(nsnull);
+                mFastLoadFile->Remove(PR_FALSE);
+                return rv;
+            }
+        }
+    }
+
+    flSvc->SetInputStream(mFastLoadInput);
+    flSvc->SetOutputStream(mFastLoadOutput);
+
+    // Start our update timer.  This allows us to keep the stream open
+    // when many components are loaded in succession, but close it once
+    // there has been a period of inactivity.
+
+    if (!mFastLoadTimer) {
+        mFastLoadTimer = do_CreateInstance(NS_TIMER_CONTRACTID, &rv);
+        NS_ENSURE_SUCCESS(rv, rv);
+
+        rv = mFastLoadTimer->InitWithFuncCallback(&mozJSComponentLoader::CloseFastLoad,
+                                                  this,
+                                                  kFastLoadWriteDelay,
+                                                  nsITimer::TYPE_ONE_SHOT);
+    } else {
+        // Note, that since CloseFastLoad nulls out mFastLoadTimer,
+        // SetDelay() will only be called on a timer that hasn't fired.
+        rv = mFastLoadTimer->SetDelay(kFastLoadWriteDelay);
+    }
+
+    return rv;
+}
+
+nsresult
+mozJSComponentLoader::ReadScript(nsIFastLoadService *flSvc,
+                                 const char *nativePath, nsIURI *uri,
                                  JSContext *cx, JSScript **script)
 {
-    nsresult rv;
-    
-    nsCAutoString spec;
-    rv = uri->GetSpec(spec);
-    NS_ENSURE_SUCCESS(rv, rv);
-    nsAutoArrayPtr<char> buf;   
-    PRUint32 len;
-    rv = cache->GetBuffer(spec.get(), getter_Transfers(buf), 
-                          &len);
+    NS_ASSERTION(flSvc, "fastload not initialized");
+
+    nsresult rv = flSvc->StartMuxedDocument(uri, nativePath,
+                                            nsIFastLoadService::NS_FASTLOAD_READ);
     if (NS_FAILED(rv)) {
         return rv; // don't warn since NOT_AVAILABLE is an ok error
     }
 
-    LOG(("Found %s in startupcache\n", spec.get()));
-    nsCOMPtr<nsIObjectInputStream> ois;
-    rv = NS_NewObjectInputStreamFromBuffer(buf, len, getter_AddRefs(ois));
+    LOG(("Found %s in fastload file\n", nativePath));
+
+    nsCOMPtr<nsIURI> oldURI;
+    rv = flSvc->SelectMuxedDocument(uri, getter_AddRefs(oldURI));
     NS_ENSURE_SUCCESS(rv, rv);
-    buf.forget();
 
-    return ReadScriptFromStream(cx, ois, script);
+    NS_ASSERTION(mFastLoadInput,
+                 "FASTLOAD_READ should only succeed with an input stream");
+
+    rv = ReadScriptFromStream(cx, mFastLoadInput, script);
+    if (NS_SUCCEEDED(rv)) {
+        rv = flSvc->EndMuxedDocument(uri);
+    }
+
+    return rv;
 }
 
 nsresult
-mozJSComponentLoader::WriteScript(StartupCache* cache, JSScript *script,
-                                  nsIFile *component, nsIURI *uri, JSContext *cx)
+mozJSComponentLoader::WriteScript(nsIFastLoadService *flSvc, JSScript *script,
+                                  nsIFile *component, const char *nativePath,
+                                  nsIURI *uri, JSContext *cx)
 {
+    NS_ASSERTION(flSvc, "fastload not initialized");
     nsresult rv;
 
-    nsCAutoString spec;
-    rv = uri->GetSpec(spec);
+    if (!mFastLoadOutput) {
+        // Trying to read a URI that was not in the fastload file will have
+        // created an output stream for us.  But, if we haven't tried to
+        // load anything that was missing, it will still be null.
+        rv = flSvc->GetOutputStream(getter_AddRefs(mFastLoadOutput));
+        NS_ENSURE_SUCCESS(rv, rv);
+    }
+
+    NS_ASSERTION(mFastLoadOutput, "must have an output stream here");
+
+    LOG(("Writing %s to fastload\n", nativePath));
+    rv = flSvc->AddDependency(component);
     NS_ENSURE_SUCCESS(rv, rv);
 
-    LOG(("Writing %s to startupcache\n", spec.get()));
-    nsCOMPtr<nsIObjectOutputStream> oos;
-    nsCOMPtr<nsIStorageStream> storageStream; 
-    rv = NS_NewObjectOutputWrappedStorageStream(getter_AddRefs(oos),
-                                                getter_AddRefs(storageStream));
+    rv = flSvc->StartMuxedDocument(uri, nativePath,
+                                   nsIFastLoadService::NS_FASTLOAD_WRITE);
     NS_ENSURE_SUCCESS(rv, rv);
 
-    rv = WriteScriptToStream(cx, script, oos);
-    oos->Close();
+    nsCOMPtr<nsIURI> oldURI;
+    rv = flSvc->SelectMuxedDocument(uri, getter_AddRefs(oldURI));
     NS_ENSURE_SUCCESS(rv, rv);
- 
-    nsAutoArrayPtr<char> buf;
-    PRUint32 len;
-    rv = NS_NewBufferFromStorageStream(storageStream, getter_Transfers(buf), 
-                                       &len);
+
+    rv = WriteScriptToStream(cx, script, mFastLoadOutput);
     NS_ENSURE_SUCCESS(rv, rv);
- 
-    rv = cache->PutBuffer(spec.get(), buf, len);
-    return rv;
+
+    return flSvc->EndMuxedDocument(uri);
 }
-#endif //MOZ_ENABLE_LIBXUL
 
 nsresult
 mozJSComponentLoader::GlobalForLocation(nsILocalFile *aComponentFile,
                                         nsIURI *aURI,
                                         JSObject **aGlobal,
                                         char **aLocation,
                                         jsval *exception)
 {
@@ -1013,41 +1258,70 @@ mozJSComponentLoader::GlobalForLocation(
     // See: http://bugzilla.mozilla.org/show_bug.cgi?id=121438
 #ifdef XPCONNECT_STANDALONE
     localFile->GetNativePath(nativePath);
 #else
     rv = aURI->GetSpec(nativePath);
     NS_ENSURE_SUCCESS(rv, rv);
 #endif
 
+    // Before compiling the script, first check to see if we have it in
+    // the fastload file.  Note: as a rule, fastload errors are not fatal
+    // to loading the script, since we can always slow-load.
+    nsCOMPtr<nsIFastLoadService> flSvc = do_GetFastLoadService(&rv);
+
+    // Save the old state and restore it upon return
+    FastLoadStateHolder flState(flSvc);
+    PRBool fastLoading = PR_FALSE;
+
+    if (NS_SUCCEEDED(rv)) {
+        rv = StartFastLoad(flSvc);
+        if (NS_SUCCEEDED(rv)) {
+            fastLoading = PR_TRUE;
+        }
+    }
+
     JSScript *script = nsnull;
 
-#ifdef MOZ_ENABLE_LIBXUL  
-    // Before compiling the script, first check to see if we have it in
-    // the startupcache.  Note: as a rule, startupcache errors are not fatal
-    // to loading the script, since we can always slow-load.
-    
-    PRBool writeToCache = PR_FALSE;
-    StartupCache* cache = StartupCache::GetSingleton();
+    if (fastLoading) {
+        rv = ReadScript(flSvc, nativePath.get(), aURI, cx, &script);
+        if (NS_SUCCEEDED(rv)) {
+            LOG(("Successfully loaded %s from fastload\n", nativePath.get()));
+            fastLoading = PR_FALSE; // no need to write out the script
+        } else if (rv == NS_ERROR_NOT_AVAILABLE) {
+            // This is ok, it just means the script is not yet in the
+            // fastload file.
+            rv = NS_OK;
+        } else {
+            LOG(("Failed to deserialize %s\n", nativePath.get()));
 
-    if (cache) {
-        rv = ReadScript(cache, aURI, cx, &script);
-        if (NS_SUCCEEDED(rv)) {
-            LOG(("Successfully loaded %s from startupcache\n", nativePath.get()));
-        } else {
-            // This is ok, it just means the script is not yet in the
-            // cache. Could mean that the cache was corrupted and got removed,
-            // but either way we're going to write this out.
-            writeToCache = PR_TRUE;
+            // Remove the fastload file, it may be corrupted.
+            LOG(("Invalid fastload file detected, removing it\n"));
+            nsCOMPtr<nsIObjectOutputStream> objectOutput;
+            flSvc->GetOutputStream(getter_AddRefs(objectOutput));
+            if (objectOutput) {
+                flSvc->SetOutputStream(nsnull);
+                objectOutput->Close();
+            }
+            nsCOMPtr<nsIObjectInputStream> objectInput;
+            flSvc->GetInputStream(getter_AddRefs(objectInput));
+            if (objectInput) {
+                flSvc->SetInputStream(nsnull);
+                objectInput->Close();
+            }
+            if (mFastLoadFile) {
+                mFastLoadFile->Remove(PR_FALSE);
+            }
+            fastLoading = PR_FALSE;
         }
     }
-#endif
 
-    if (!script) {
-        // The script wasn't in the cache , so compile it now.
+
+    if (!script || NS_FAILED(rv)) {
+        // The script wasn't in the fastload cache, so compile it now.
         LOG(("Slow loading %s\n", nativePath.get()));
 
         // If |exception| is non-null, then our caller wants us to propagate
         // any exceptions out to our caller. Ensure that the engine doesn't
         // eagerly report the exception.
         uint32 oldopts = 0;
         if (exception) {
             oldopts = JS_GetOptions(cx);
@@ -1196,30 +1470,31 @@ mozJSComponentLoader::GlobalForLocation(
     // anyway...  So maybe flagging as a prefix is fine.
     xpc->FlagSystemFilenamePrefix(nativePath.get(), PR_TRUE);
 
 #ifdef DEBUG_shaver_off
     fprintf(stderr, "mJCL: compiled JS component %s\n",
             nativePath.get());
 #endif
 
-#ifdef MOZ_ENABLE_LIBXUL
-    if (writeToCache) {
-        // We successfully compiled the script, so cache it. 
-        rv = WriteScript(cache, script, aComponentFile, aURI, cx);
+    if (fastLoading) {
+        // We successfully compiled the script, so cache it in fastload.
+        rv = WriteScript(flSvc, script, aComponentFile, nativePath.get(), aURI, cx);
 
         // Don't treat failure to write as fatal, since we might be working
-        // with a read-only cache.
+        // with a read-only fastload file.
         if (NS_SUCCEEDED(rv)) {
-            LOG(("Successfully wrote to cache\n"));
+            LOG(("Successfully wrote to fastload\n"));
         } else {
-            LOG(("Failed to write to cache\n"));
+            LOG(("Failed to write to fastload\n"));
         }
     }
-#endif
+
+    // Restore the old state of the fastload service.
+    flState.pop();
 
     // Assign aGlobal here so that it's available to recursive imports.
     // See bug 384168.
     *aGlobal = global;
 
     jsval retval;
     if (!JS_ExecuteScript(cx, global, script, &retval)) {
 #ifdef DEBUG_shaver_off
@@ -1539,17 +1814,24 @@ mozJSComponentLoader::ImportInto(const n
     
     return NS_OK;
 }
 
 NS_IMETHODIMP
 mozJSComponentLoader::Observe(nsISupports *subject, const char *topic,
                               const PRUnichar *data)
 {
-    if (!strcmp(topic, "xpcom-shutdown-loaders")) {
+    if (!strcmp(topic, NS_XPCOM_SHUTDOWN_OBSERVER_ID)) {
+        if (mFastLoadTimer) {
+            mFastLoadTimer->Cancel();
+        }
+
+        CloseFastLoad();
+    }
+    else if (!strcmp(topic, "xpcom-shutdown-loaders")) {
         UnloadModules();
     }
     else {
         NS_ERROR("Unexpected observer topic.");
     }
 
     return NS_OK;
 }
--- a/js/src/xpconnect/loader/mozJSComponentLoader.h
+++ b/js/src/xpconnect/loader/mozJSComponentLoader.h
@@ -52,22 +52,16 @@
 #include "nsITimer.h"
 #include "nsIObserver.h"
 #include "xpcIJSModuleLoader.h"
 #include "nsClassHashtable.h"
 #include "nsDataHashtable.h"
 #ifndef XPCONNECT_STANDALONE
 #include "nsIPrincipal.h"
 #endif
-#ifdef MOZ_ENABLE_LIBXUL
-#include "mozilla/scache/StartupCache.h"
-
-using namespace mozilla::scache;
-#endif
-
 #include "xpcIJSGetFactory.h"
 
 /* 6bd13476-1dd2-11b2-bbef-f0ccb5fa64b6 (thanks, mozbot) */
 
 #define MOZJSCOMPONENTLOADER_CID \
   {0x6bd13476, 0x1dd2, 0x11b2, \
     { 0xbb, 0xef, 0xf0, 0xcc, 0xb5, 0xfa, 0x64, 0xb6 }}
 #define MOZJSCOMPONENTLOADER_CONTRACTID "@mozilla.org/moz/jsloader;1"
@@ -128,26 +122,33 @@ class mozJSComponentLoader : public mozi
                                           nsIURI* aComponentURI);
 
     nsresult GlobalForLocation(nsILocalFile* aComponentFile,
                                nsIURI *aComponent,
                                JSObject **aGlobal,
                                char **location,
                                jsval *exception);
 
-#ifdef MOZ_ENABLE_LIBXUL
-    nsresult ReadScript(StartupCache *cache, nsIURI *uri, 
-                        JSContext *cx, JSScript **script);
-    nsresult WriteScript(StartupCache *cache, JSScript *script,
-                         nsIFile *component, nsIURI *uri, JSContext *cx);
-#endif
+    nsresult StartFastLoad(nsIFastLoadService *flSvc);
+    nsresult ReadScript(nsIFastLoadService *flSvc, const char *nativePath,
+                        nsIURI *uri, JSContext *cx, JSScript **script);
+    nsresult WriteScript(nsIFastLoadService *flSvc, JSScript *script,
+                         nsIFile *component, const char *nativePath,
+                         nsIURI *uri, JSContext *cx);
+    static void CloseFastLoad(nsITimer *timer, void *closure);
+    void CloseFastLoad();
 
     nsCOMPtr<nsIComponentManager> mCompMgr;
     nsCOMPtr<nsIJSRuntimeService> mRuntimeService;
     nsCOMPtr<nsIThreadJSContextStack> mContextStack;
+    nsCOMPtr<nsIFile> mFastLoadFile;
+    nsRefPtr<nsXPCFastLoadIO> mFastLoadIO;
+    nsCOMPtr<nsIObjectInputStream> mFastLoadInput;
+    nsCOMPtr<nsIObjectOutputStream> mFastLoadOutput;
+    nsCOMPtr<nsITimer> mFastLoadTimer;
 #ifndef XPCONNECT_STANDALONE
     nsCOMPtr<nsIPrincipal> mSystemPrincipal;
 #endif
     JSRuntime *mRuntime;
     JSContext *mContext;
 
     class ModuleEntry : public mozilla::Module
     {