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
treeherdermozilla-central@46f402c75824 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs520309
milestone2.0b5pre
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
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();
+
+    NS_ASSERTION(mFastLoadInput,
+                 "FASTLOAD_READ should only succeed with an input stream");
 
-    return ReadScriptFromStream(cx, ois, script);
+    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
     {