Commit c1b18767 authored by Kris Maglione's avatar Kris Maglione
Browse files

Bug 1359653: Part 9 - Observe "startupcache-invalidate" and flush the cache when received. r=erahm

Flushing the cache at startup is already handled automatically by the
AppStartup code, which removes the entire startupCache directory when
necessary. The add-on manager requires being able to flush the cache at
runtime, though, for the sake of updating bootstrapped add-ons.

MozReview-Commit-ID: LIdiNHrXYXu

--HG--
extra : rebase_source : e5b16490f47e20c78d081ad03dec02c6b2874fc3
extra : absorb_source : 6cd94504c8247f375161b2afdca5c61d59cf8f01
parent 42440e7f
Loading
Loading
Loading
Loading
+57 −0
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@
#define DELAYED_STARTUP_TOPIC "browser-delayed-startup-finished"
#define CLEANUP_TOPIC "xpcom-shutdown"
#define SHUTDOWN_TOPIC "quit-application-granted"
#define CACHE_FLUSH_TOPIC "startupcache-invalidate"

namespace mozilla {
namespace {
@@ -124,6 +125,7 @@ ScriptPreloader::ScriptPreloader()
    obs->AddObserver(this, DELAYED_STARTUP_TOPIC, false);
    obs->AddObserver(this, SHUTDOWN_TOPIC, false);
    obs->AddObserver(this, CLEANUP_TOPIC, false);
    obs->AddObserver(this, CACHE_FLUSH_TOPIC, false);

    AutoSafeJSAPI jsapi;
    JS_AddExtraGCRootsTracer(jsapi.cx(), TraceOp, this);
@@ -161,6 +163,44 @@ ScriptPreloader::Cleanup()
    UnregisterWeakMemoryReporter(this);
}

void
ScriptPreloader::FlushScripts(LinkedList<CachedScript>& scripts)
{
    for (auto next = scripts.getFirst(); next; ) {
        auto script = next;
        next = script->getNext();

        // We can only purge finished scripts here. Async scripts that are
        // still being parsed off-thread have a non-refcounted reference to
        // this script, which needs to stay alive until they finish parsing.
        if (script->mReadyToExecute) {
            script->Cancel();
            script->remove();
            delete script;
        }
    }
}

void
ScriptPreloader::FlushCache()
{
    MonitorAutoLock mal(mMonitor);

    FlushScripts(mSavedScripts);
    FlushScripts(mRestoredScripts);

    // If we've already finished saving the cache at this point, start a new
    // delayed save operation. This will write out an empty cache file in place
    // of any cache file we've already written out this session, which will
    // prevent us from falling back to the current session's cache file on the
    // next startup.
    if (mSaveComplete) {
        mSaveComplete = false;

        Unused << NS_NewNamedThread("SaveScripts",
                                    getter_AddRefs(mSaveThread), this);
    }
}

nsresult
ScriptPreloader::Observe(nsISupports* subject, const char* topic, const char16_t* data)
@@ -179,6 +219,8 @@ ScriptPreloader::Observe(nsISupports* subject, const char* topic, const char16_t
        ForceWriteCacheFile();
    } else if (!strcmp(topic, CLEANUP_TOPIC)) {
        Cleanup();
    } else if (!strcmp(topic, CACHE_FLUSH_TOPIC)) {
        FlushCache();
    }

    return NS_OK;
@@ -609,6 +651,7 @@ ScriptPreloader::OffThreadDecodeCallback(void* token, void* context)
    mal.NotifyAll();
}

inline
ScriptPreloader::CachedScript::CachedScript(InputBuffer& buf)
{
    Code(buf);
@@ -631,6 +674,20 @@ ScriptPreloader::CachedScript::XDREncode(JSContext* cx)
    return false;
}

void
ScriptPreloader::CachedScript::Cancel()
{
    if (mToken) {
        GetSingleton().mMonitor.AssertCurrentThreadOwns();

        AutoSafeJSAPI jsapi;
        JS::CancelOffThreadScriptDecoder(jsapi.cx(), mToken);

        mReadyToExecute = true;
        mToken = nullptr;
    }
}

JSScript*
ScriptPreloader::CachedScript::GetJSScript(JSContext* cx)
{
+5 −0
Original line number Diff line number Diff line
@@ -111,6 +111,8 @@ private:
            cache.mScripts.Remove(mCachePath);
        }

        void Cancel();

        // Encodes this script into XDR data, and stores the result in mXDRData.
        // Returns true on success, false on failure.
        bool XDREncode(JSContext* cx);
@@ -210,6 +212,9 @@ private:
    void ForceWriteCacheFile();
    void Cleanup();

    void FlushCache();
    void FlushScripts(LinkedList<CachedScript>& scripts);

    // Opens the cache file for reading.
    Result<Ok, nsresult> OpenCache();