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
nsXULPrototypeCache::StartFastLoad(nsIURI* aURI)
{
    nsresult rv;

    nsCAutoString path;
    aURI->GetPath(path);
    if (!StringEndsWith(path, NS_LITERAL_CSTRING(".xul")))
        return NS_ERROR_NOT_AVAILABLE;

    // Test gFastLoadFile to decide whether this is the first nsXULDocument
    // participating in FastLoad.  If gFastLoadFile is non-null, this document
    // must not be first, but it can join the FastLoad process.  Examples of
    // multiple master documents participating include hiddenWindow.xul and
    // navigator.xul on the Mac, and multiple-app-component (e.g., mailnews
    // and browser) startup due to command-line arguments.
    //
    // XXXbe we should attempt to update the FastLoad file after startup!
    //
    // XXXbe we do not yet use nsFastLoadPtrs, but once we do, we must keep
    // the FastLoad input stream open for the life of the app.
    if (gFastLoadService && gFastLoadFile) {
        mFastLoadURITable.Put(aURI, 1);

        return NS_OK;
    }

    // Use a local to refer to the service till we're sure we succeeded, then
    // commit to gFastLoadService.  Same for gFastLoadFile, which is used to
    // delete the FastLoad file on abort.
    nsCOMPtr<nsIFastLoadService> fastLoadService(do_GetFastLoadService());
    if (! fastLoadService)
        return NS_ERROR_FAILURE;

    gDisableXULFastLoad =
        nsContentUtils::GetBoolPref(kDisableXULFastLoadPref,
                                    gDisableXULFastLoad);
    gChecksumXULFastLoadFile =
        nsContentUtils::GetBoolPref(kChecksumXULFastLoadFilePref,
                                    gChecksumXULFastLoadFile);
    nsContentUtils::RegisterPrefCallback(kDisableXULFastLoadPref,
                                         FastLoadPrefChangedCallback,
                                         nsnull);
    nsContentUtils::RegisterPrefCallback(kChecksumXULFastLoadFilePref,
                                         FastLoadPrefChangedCallback,
                                         nsnull);

    if (gDisableXULFastLoad)
        return NS_ERROR_NOT_AVAILABLE;

    // Get the chrome directory to validate against the one stored in the
    // FastLoad file, or to store there if we're generating a new file.
    nsCOMPtr<nsIFile> chromeDir;
    rv = NS_GetSpecialDirectory(NS_APP_CHROME_DIR, getter_AddRefs(chromeDir));
    if (NS_FAILED(rv))
        return rv;
    nsCAutoString chromePath;
    rv = chromeDir->GetNativePath(chromePath);
    if (NS_FAILED(rv))
        return rv;

    nsCOMPtr<nsIFile> file;
    rv = fastLoadService->NewFastLoadFile(XUL_FASTLOAD_FILE_BASENAME,
                                          getter_AddRefs(file));
    if (NS_FAILED(rv))
        return rv;

    // Give the FastLoad service an object by which it can get or create a
    // file output stream given an input stream on the same file.
    nsXULFastLoadFileIO* xio = new nsXULFastLoadFileIO(file);
    nsCOMPtr<nsIFastLoadFileIO> io = static_cast<nsIFastLoadFileIO*>(xio);
    if (! io)
        return NS_ERROR_OUT_OF_MEMORY;
    fastLoadService->SetFileIO(io);

    nsCOMPtr<nsIXULChromeRegistry> chromeReg(do_GetService(NS_CHROMEREGISTRY_CONTRACTID, &rv));
    if (NS_FAILED(rv))
        return rv;

    // XXXbe we assume the first package's locale is the same as the locale of
    // all subsequent packages of FastLoaded chrome URIs....
    nsCAutoString package;
    rv = aURI->GetHost(package);
    if (NS_FAILED(rv))
        return rv;

    nsCAutoString locale;
    rv = chromeReg->GetSelectedLocale(package, locale);
    if (NS_FAILED(rv))
        return rv;

    // Try to read an existent FastLoad file.
    PRBool exists = PR_FALSE;
    if (NS_SUCCEEDED(file->Exists(&exists)) && exists) {
        nsCOMPtr<nsIObjectInputStream> objectInput;
        rv = fastLoadService->NewInputStream(file, getter_AddRefs(objectInput));

        if (NS_SUCCEEDED(rv)) {
            if (NS_SUCCEEDED(rv)) {
                // Get the XUL fastload file version number, which should be
                // decremented whenever the XUL-specific file format changes
                // (see public/nsIXULPrototypeCache.h for the #define).
                PRUint32 xulFastLoadVersion, jsByteCodeVersion;
                rv = objectInput->Read32(&xulFastLoadVersion);
                rv |= objectInput->Read32(&jsByteCodeVersion);
                if (NS_SUCCEEDED(rv)) {
                    if (xulFastLoadVersion != XUL_FASTLOAD_FILE_VERSION ||
                        jsByteCodeVersion != JSXDR_BYTECODE_VERSION) {
#ifdef DEBUG
                        printf((xulFastLoadVersion != XUL_FASTLOAD_FILE_VERSION)
                               ? "bad FastLoad file version\n"
                               : "bad JS bytecode version\n");
#endif
                        rv = NS_ERROR_UNEXPECTED;
                    } else {
                        nsCAutoString fileChromePath, fileLocale;

                        rv = objectInput->ReadCString(fileChromePath);
                        rv |= objectInput->ReadCString(fileLocale);
                        if (NS_SUCCEEDED(rv) &&
                            (!fileChromePath.Equals(chromePath) ||
                             !fileLocale.Equals(locale))) {
                            rv = NS_ERROR_UNEXPECTED;
                        }
                    }
                }
            }
        }

        if (NS_SUCCEEDED(rv)) {
            fastLoadService->SetInputStream(objectInput);
        } else {
            // NB: we must close before attempting to remove, for non-Unix OSes
            // that can't do open-unlink.
            if (objectInput)
                objectInput->Close();
            xio->mInputStream = nsnull;

#ifdef DEBUG
            file->MoveToNative(nsnull, NS_LITERAL_CSTRING("Invalid.mfasl"));
#else
            file->Remove(PR_FALSE);
#endif
            exists = PR_FALSE;
        }
    }

    // FastLoad file not found, or invalid: write a new one.
    if (! exists) {
        nsCOMPtr<nsIOutputStream> output;
        rv = io->GetOutputStream(getter_AddRefs(output));
        if (NS_FAILED(rv))
            return rv;

        nsCOMPtr<nsIObjectOutputStream> objectOutput;
        rv = fastLoadService->NewOutputStream(output,
                                              getter_AddRefs(objectOutput));
        if (NS_SUCCEEDED(rv)) {
            rv = objectOutput->Write32(XUL_FASTLOAD_FILE_VERSION);
            rv |= objectOutput->Write32(JSXDR_BYTECODE_VERSION);
            rv |= objectOutput->WriteStringZ(chromePath.get());
            rv |= objectOutput->WriteStringZ(locale.get());
        }

        // Remove here even though some errors above will lead to a FastLoad
        // file invalidation.  Other errors (failure to note the dependency on
        // installed-chrome.txt, e.g.) will not cause invalidation, and we may
        // as well tidy up now.
        if (NS_FAILED(rv)) {
            if (objectOutput)
                objectOutput->Close();
            else
                output->Close();
            xio->mOutputStream = nsnull;

            file->Remove(PR_FALSE);
            return NS_ERROR_FAILURE;
        }

        fastLoadService->SetOutputStream(objectOutput);
    }

    // Success!  Insert this URI into the mFastLoadURITable
    // and commit locals to globals.
    mFastLoadURITable.Put(aURI, 1);

    NS_ADDREF(gFastLoadService = fastLoadService);
    NS_ADDREF(gFastLoadFile = file);
    return NS_OK;
}
nsresult
mozJSComponentLoader::ReallyInit()
{
    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) ||
        NS_FAILED(rv = mRuntimeService->GetRuntime(&mRuntime)))
        return rv;

    // Create our compilation context.
    mContext = JS_NewContext(mRuntime, 256);
    if (!mContext)
        return NS_ERROR_OUT_OF_MEMORY;

    uint32 options = JS_GetOptions(mContext);
    JS_SetOptions(mContext, options | JSOPTION_XML);

    // Always use the latest js version
    JS_SetVersion(mContext, JSVERSION_LATEST);

    // Limit C stack consumption to a reasonable 512K
    int stackDummy;
    const jsuword kStackSize = 0x80000;
    jsuword stackLimit, currentStackAddr = (jsuword)&stackDummy;

#if JS_STACK_GROWTH_DIRECTION < 0
    stackLimit = (currentStackAddr > kStackSize)
                 ? currentStackAddr - kStackSize
                 : 0;
#else
    stackLimit = (currentStackAddr + kStackSize > currentStackAddr)
                 ? currentStackAddr + kStackSize
                 : (jsuword) -1;
#endif
    
    JS_SetThreadStackLimit(mContext, stackLimit);

#ifndef XPCONNECT_STANDALONE
    nsCOMPtr<nsIScriptSecurityManager> secman = 
        do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID);
    if (!secman)
        return NS_ERROR_FAILURE;

    rv = secman->GetSystemPrincipal(getter_AddRefs(mSystemPrincipal));
    if (NS_FAILED(rv) || !mSystemPrincipal)
        return NS_ERROR_FAILURE;
#endif

    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;

    return NS_OK;
}
nsresult
mozJSComponentLoader::GlobalForLocation(nsILocalFile *aComponent,
                                        JSObject **aGlobal,
                                        char **aLocation)
{
    nsresult rv;

    JSPrincipals* jsPrincipals = nsnull;
    JSCLContextHelper cx(mContext);

#ifndef XPCONNECT_STANDALONE
    rv = mSystemPrincipal->GetJSPrincipals(cx, &jsPrincipals);
    NS_ENSURE_SUCCESS(rv, rv);

    JSPrincipalsHolder princHolder(mContext, jsPrincipals);
#endif

    nsCOMPtr<nsIXPCScriptable> backstagePass;
    rv = mRuntimeService->GetBackstagePass(getter_AddRefs(backstagePass));
    NS_ENSURE_SUCCESS(rv, rv);

    JSCLAutoErrorReporterSetter aers(cx, mozJSLoaderErrorReporter);

    nsCOMPtr<nsIXPConnect> xpc =
        do_GetService(kXPConnectServiceContractID, &rv);
    NS_ENSURE_SUCCESS(rv, rv);

    // Make sure InitClassesWithNewWrappedGlobal() installs the
    // backstage pass as the global in our compilation context.
    JS_SetGlobalObject(cx, nsnull);

    nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
    rv = xpc->InitClassesWithNewWrappedGlobal(cx, backstagePass,
                                              NS_GET_IID(nsISupports),
                                              nsIXPConnect::
                                                  FLAG_SYSTEM_GLOBAL_OBJECT,
                                              getter_AddRefs(holder));
    NS_ENSURE_SUCCESS(rv, rv);

    JSObject *global;
    rv = holder->GetJSObject(&global);
    NS_ENSURE_SUCCESS(rv, rv);

    if (!JS_DefineFunctions(cx, global, gGlobalFun)) {
        return NS_ERROR_FAILURE;
    }

    nsCOMPtr<nsIXPConnectJSObjectHolder> locationHolder;
    rv = xpc->WrapNative(cx, global, aComponent,
                         NS_GET_IID(nsILocalFile),
                         getter_AddRefs(locationHolder));
    NS_ENSURE_SUCCESS(rv, rv);

    JSObject *locationObj;
    rv = locationHolder->GetJSObject(&locationObj);
    NS_ENSURE_SUCCESS(rv, rv);

    if (!JS_DefineProperty(cx, global, "__LOCATION__",
                           OBJECT_TO_JSVAL(locationObj), nsnull, nsnull, 0)) {
        return NS_ERROR_FAILURE;
    }

    nsCAutoString nativePath;
    // Quick hack to unbust XPCONNECT_STANDALONE.
    // This leaves the jsdebugger with a non-URL pathname in the 
    // XPCONNECT_STANDALONE case - but at least it builds and runs otherwise.
    // See: http://bugzilla.mozilla.org/show_bug.cgi?id=121438
#ifdef XPCONNECT_STANDALONE
    localFile->GetNativePath(nativePath);
#else
    NS_GetURLSpecFromFile(aComponent, nativePath);
#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;
        }
    }

    nsCOMPtr<nsIURI> uri;
    rv = NS_NewURI(getter_AddRefs(uri), nativePath);
    NS_ENSURE_SUCCESS(rv, rv);

    JSScript *script = nsnull;

    if (fastLoading) {
        rv = ReadScript(flSvc, nativePath.get(), uri, 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()));

            // 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;
        }
    }


    if (!script || NS_FAILED(rv)) {
        // The script wasn't in the fastload cache, so compile it now.
        LOG(("Slow loading %s\n", nativePath.get()));

#ifdef HAVE_PR_MEMMAP
        PRInt64 fileSize;
        rv = aComponent->GetFileSize(&fileSize);
        if (NS_FAILED(rv))
            return rv;

        PRInt64 maxSize;
        LL_UI2L(maxSize, PR_UINT32_MAX);
        if (LL_CMP(fileSize, >, maxSize)) {
            NS_ERROR("file too large");
            return NS_ERROR_FAILURE;
        }

        PRFileDesc *fileHandle;
        rv = aComponent->OpenNSPRFileDesc(PR_RDONLY, 0, &fileHandle);
        NS_ENSURE_SUCCESS(rv, rv);

        // Make sure the file is closed, no matter how we return.
        FileAutoCloser fileCloser(fileHandle);

        PRFileMap *map = PR_CreateFileMap(fileHandle, fileSize,
                                          PR_PROT_READONLY);
        if (!map) {
            NS_ERROR("Failed to create file map");
            return NS_ERROR_FAILURE;
        }

        // Make sure the file map is closed, no matter how we return.
        FileMapAutoCloser mapCloser(map);

        PRUint32 fileSize32;
        LL_L2UI(fileSize32, fileSize);

        char *buf = static_cast<char*>(PR_MemMap(map, 0, fileSize32));
        if (!buf) {
            NS_WARNING("Failed to map file");
            return NS_ERROR_FAILURE;
        }

        script = JS_CompileScriptForPrincipals(cx, global,
                                               jsPrincipals,
                                               buf, fileSize32,
                                               nativePath.get(), 1);
        PR_MemUnmap(buf, fileSize32);

#else  /* HAVE_PR_MEMMAP */

        /**
         * No memmap implementation, so fall back to using
         * JS_CompileFileHandleForPrincipals().
         */

        FILE *fileHandle;
        rv = aComponent->OpenANSIFileDesc("r", &fileHandle);
        NS_ENSURE_SUCCESS(rv, rv);

        script = JS_CompileFileHandleForPrincipals(cx, global,
                                                   nativePath.get(),
                                                   fileHandle, jsPrincipals);

        /* JS will close the filehandle after compilation is complete. */

#endif /* HAVE_PR_MEMMAP */
    }