зеркало из https://github.com/mozilla/gecko-dev.git
Bug 592943 - (3/3) switch nsXULPrototypeCache to use startupCache instead of fastload, Patch by Benedict Hsieh, r=jst
This commit is contained in:
Родитель
1ad90d8d03
Коммит
6a83fe0ff7
|
@ -245,45 +245,11 @@ nsChromeProtocolHandler::NewChannel(nsIURI* aURI,
|
||||||
result->SetOwner(owner);
|
result->SetOwner(owner);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef MOZ_XUL
|
// XXX Removed dependency-tracking code from here, because we're not
|
||||||
// Track FastLoad file dependencies.
|
// tracking them anyways (with fastload we checked only in DEBUG
|
||||||
//
|
// and with startupcache not at all), but this is where we would start
|
||||||
// This is harder than it ought to be! While an nsResChannel "is-a"
|
// if we need to re-add.
|
||||||
// nsIFileChannel, an nsJARChannel is not. Once you unravel the jar:
|
// See bug 531886, bug 533038.
|
||||||
// URI, you may have a resource: URL -- but without a channel for it,
|
|
||||||
// you can't get the URI that it yields through substitution!
|
|
||||||
//
|
|
||||||
// XXXbe fix nsResChannel.cpp to move the substitution code into a new
|
|
||||||
// nsResURL class?
|
|
||||||
nsCOMPtr<nsIFastLoadService> fastLoadServ(do_GetFastLoadService());
|
|
||||||
if (fastLoadServ) {
|
|
||||||
nsCOMPtr<nsIObjectOutputStream> objectOutput;
|
|
||||||
fastLoadServ->GetOutputStream(getter_AddRefs(objectOutput));
|
|
||||||
if (objectOutput) {
|
|
||||||
nsCOMPtr<nsIFile> file;
|
|
||||||
|
|
||||||
nsCOMPtr<nsIURI> uri;
|
|
||||||
result->GetURI(getter_AddRefs(uri));
|
|
||||||
uri = NS_GetInnermostURI(uri);
|
|
||||||
|
|
||||||
// Here we have a URL of the form resource:/chrome/A.jar
|
|
||||||
// or file:/some/path/to/A.jar.
|
|
||||||
nsCOMPtr<nsIFileURL> fileURL(do_QueryInterface(uri));
|
|
||||||
if (fileURL)
|
|
||||||
fileURL->GetFile(getter_AddRefs(file));
|
|
||||||
|
|
||||||
if (file) {
|
|
||||||
rv = fastLoadServ->AddDependency(file);
|
|
||||||
if (NS_FAILED(rv)) {
|
|
||||||
nsCOMPtr<nsIXULPrototypeCache> cache
|
|
||||||
(do_GetService(kXULPrototypeCacheCID));
|
|
||||||
if (cache)
|
|
||||||
cache->AbortFastLoads();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
*aResult = result;
|
*aResult = result;
|
||||||
NS_ADDREF(*aResult);
|
NS_ADDREF(*aResult);
|
||||||
|
|
|
@ -84,7 +84,6 @@
|
||||||
#include "nsIEventListenerManager.h"
|
#include "nsIEventListenerManager.h"
|
||||||
#include "nsEventStateManager.h"
|
#include "nsEventStateManager.h"
|
||||||
#include "nsFocusManager.h"
|
#include "nsFocusManager.h"
|
||||||
#include "nsIFastLoadService.h"
|
|
||||||
#include "nsHTMLStyleSheet.h"
|
#include "nsHTMLStyleSheet.h"
|
||||||
#include "nsINameSpaceManager.h"
|
#include "nsINameSpaceManager.h"
|
||||||
#include "nsIObjectInputStream.h"
|
#include "nsIObjectInputStream.h"
|
||||||
|
@ -2688,9 +2687,9 @@ nsXULPrototypeElement::Serialize(nsIObjectOutputStream* aStream,
|
||||||
|
|
||||||
if (script->mScriptObject.mObject) {
|
if (script->mScriptObject.mObject) {
|
||||||
// This may return NS_OK without muxing script->mSrcURI's
|
// This may return NS_OK without muxing script->mSrcURI's
|
||||||
// data into the FastLoad file, in the case where that
|
// data into the cache file, in the case where that
|
||||||
// muxed document is already there (written by a prior
|
// muxed document is already there (written by a prior
|
||||||
// session, or by an earlier FastLoad episode during this
|
// session, or by an earlier cache episode during this
|
||||||
// session).
|
// session).
|
||||||
rv |= script->SerializeOutOfLine(aStream, aGlobal);
|
rv |= script->SerializeOutOfLine(aStream, aGlobal);
|
||||||
}
|
}
|
||||||
|
@ -2820,8 +2819,8 @@ nsXULPrototypeElement::Deserialize(nsIObjectInputStream* aStream,
|
||||||
|
|
||||||
// Oh dear. Something failed during the deserialization.
|
// Oh dear. Something failed during the deserialization.
|
||||||
// We don't know what. But likely consequences of failed
|
// We don't know what. But likely consequences of failed
|
||||||
// deserializations included calls to |AbortFastLoads| which
|
// deserializations included calls to |AbortCaching| which
|
||||||
// shuts down the FastLoadService and closes our streams.
|
// shuts down the cache and closes our streams.
|
||||||
// If that happens, next time through this loop, we die a messy
|
// If that happens, next time through this loop, we die a messy
|
||||||
// death. So, let's just fail now, and propagate that failure
|
// death. So, let's just fail now, and propagate that failure
|
||||||
// upward so that the ChromeProtocolHandler knows it can't use
|
// upward so that the ChromeProtocolHandler knows it can't use
|
||||||
|
@ -2961,24 +2960,23 @@ nsresult
|
||||||
nsXULPrototypeScript::SerializeOutOfLine(nsIObjectOutputStream* aStream,
|
nsXULPrototypeScript::SerializeOutOfLine(nsIObjectOutputStream* aStream,
|
||||||
nsIScriptGlobalObject* aGlobal)
|
nsIScriptGlobalObject* aGlobal)
|
||||||
{
|
{
|
||||||
|
nsresult rv = NS_ERROR_NOT_IMPLEMENTED;
|
||||||
|
|
||||||
|
PRBool isChrome = PR_FALSE;
|
||||||
|
if (NS_FAILED(mSrcURI->SchemeIs("chrome", &isChrome)) || !isChrome)
|
||||||
|
// Don't cache scripts that don't come from chrome uris.
|
||||||
|
return rv;
|
||||||
|
|
||||||
nsXULPrototypeCache* cache = nsXULPrototypeCache::GetInstance();
|
nsXULPrototypeCache* cache = nsXULPrototypeCache::GetInstance();
|
||||||
if (!cache)
|
if (!cache)
|
||||||
return NS_ERROR_OUT_OF_MEMORY;
|
return NS_ERROR_OUT_OF_MEMORY;
|
||||||
|
|
||||||
NS_ASSERTION(cache->IsEnabled(),
|
NS_ASSERTION(cache->IsEnabled(),
|
||||||
"writing to the FastLoad file, but the XUL cache is off?");
|
"writing to the cache file, but the XUL cache is off?");
|
||||||
|
PRBool exists;
|
||||||
nsIFastLoadService* fastLoadService = cache->GetFastLoadService();
|
cache->HasData(mSrcURI, &exists);
|
||||||
if (!fastLoadService)
|
|
||||||
return NS_ERROR_NOT_AVAILABLE;
|
|
||||||
|
|
||||||
nsCAutoString urispec;
|
|
||||||
nsresult rv = mSrcURI->GetAsciiSpec(urispec);
|
|
||||||
if (NS_FAILED(rv))
|
|
||||||
return rv;
|
|
||||||
|
|
||||||
PRBool exists = PR_FALSE;
|
|
||||||
fastLoadService->HasMuxedDocument(urispec.get(), &exists);
|
|
||||||
/* return will be NS_OK from GetAsciiSpec.
|
/* return will be NS_OK from GetAsciiSpec.
|
||||||
* that makes no sense.
|
* that makes no sense.
|
||||||
* nor does returning NS_OK from HasMuxedDocument.
|
* nor does returning NS_OK from HasMuxedDocument.
|
||||||
|
@ -2987,34 +2985,15 @@ nsXULPrototypeScript::SerializeOutOfLine(nsIObjectOutputStream* aStream,
|
||||||
if (exists)
|
if (exists)
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
|
||||||
// Allow callers to pass null for aStream, meaning
|
nsCOMPtr<nsIObjectOutputStream> oos;
|
||||||
// "use the FastLoad service's default output stream."
|
rv = cache->GetOutputStream(mSrcURI, getter_AddRefs(oos));
|
||||||
// See nsXULDocument.cpp for one use of this.
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
nsCOMPtr<nsIObjectOutputStream> objectOutput = aStream;
|
|
||||||
if (! objectOutput) {
|
rv |= Serialize(oos, aGlobal, nsnull);
|
||||||
fastLoadService->GetOutputStream(getter_AddRefs(objectOutput));
|
rv |= cache->FinishOutputStream(mSrcURI);
|
||||||
if (! objectOutput)
|
|
||||||
return NS_ERROR_NOT_AVAILABLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
rv = fastLoadService->
|
|
||||||
StartMuxedDocument(mSrcURI, urispec.get(),
|
|
||||||
nsIFastLoadService::NS_FASTLOAD_WRITE);
|
|
||||||
NS_ASSERTION(rv != NS_ERROR_NOT_AVAILABLE, "reading FastLoad?!");
|
|
||||||
|
|
||||||
nsCOMPtr<nsIURI> oldURI;
|
|
||||||
rv |= fastLoadService->SelectMuxedDocument(mSrcURI, getter_AddRefs(oldURI));
|
|
||||||
rv |= Serialize(objectOutput, aGlobal, nsnull);
|
|
||||||
rv |= fastLoadService->EndMuxedDocument(mSrcURI);
|
|
||||||
|
|
||||||
if (oldURI) {
|
|
||||||
nsCOMPtr<nsIURI> tempURI;
|
|
||||||
rv |= fastLoadService->
|
|
||||||
SelectMuxedDocument(oldURI, getter_AddRefs(tempURI));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (NS_FAILED(rv))
|
if (NS_FAILED(rv))
|
||||||
cache->AbortFastLoads();
|
cache->AbortCaching();
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3055,33 +3034,24 @@ nsresult
|
||||||
nsXULPrototypeScript::DeserializeOutOfLine(nsIObjectInputStream* aInput,
|
nsXULPrototypeScript::DeserializeOutOfLine(nsIObjectInputStream* aInput,
|
||||||
nsIScriptGlobalObject* aGlobal)
|
nsIScriptGlobalObject* aGlobal)
|
||||||
{
|
{
|
||||||
// Keep track of FastLoad failure via rv, so we can
|
// Keep track of failure via rv, so we can
|
||||||
// AbortFastLoads if things look bad.
|
// AbortCaching if things look bad.
|
||||||
nsresult rv = NS_OK;
|
nsresult rv = NS_OK;
|
||||||
|
|
||||||
nsXULPrototypeCache* cache = nsXULPrototypeCache::GetInstance();
|
nsXULPrototypeCache* cache = nsXULPrototypeCache::GetInstance();
|
||||||
nsIFastLoadService* fastLoadService = cache->GetFastLoadService();
|
|
||||||
|
|
||||||
// Allow callers to pass null for aInput, meaning
|
|
||||||
// "use the FastLoad service's default input stream."
|
|
||||||
// See nsXULContentSink.cpp for one use of this.
|
|
||||||
nsCOMPtr<nsIObjectInputStream> objectInput = aInput;
|
nsCOMPtr<nsIObjectInputStream> objectInput = aInput;
|
||||||
if (! objectInput && fastLoadService)
|
if (cache) {
|
||||||
fastLoadService->GetInputStream(getter_AddRefs(objectInput));
|
|
||||||
|
|
||||||
if (objectInput) {
|
|
||||||
PRBool useXULCache = PR_TRUE;
|
PRBool useXULCache = PR_TRUE;
|
||||||
if (mSrcURI) {
|
if (mSrcURI) {
|
||||||
// NB: we must check the XUL script cache early, to avoid
|
// NB: we must check the XUL script cache early, to avoid
|
||||||
// multiple deserialization attempts for a given script, which
|
// multiple deserialization attempts for a given script.
|
||||||
// would exhaust the multiplexed stream containing the singly
|
// Note that nsXULDocument::LoadScript
|
||||||
// serialized script. Note that nsXULDocument::LoadScript
|
|
||||||
// checks the XUL script cache too, in order to handle the
|
// checks the XUL script cache too, in order to handle the
|
||||||
// serialization case.
|
// serialization case.
|
||||||
//
|
//
|
||||||
// We need do this only for <script src='strres.js'> and the
|
// We need do this only for <script src='strres.js'> and the
|
||||||
// like, i.e., out-of-line scripts that are included by several
|
// like, i.e., out-of-line scripts that are included by several
|
||||||
// different XUL documents multiplexed in the FastLoad file.
|
// different XUL documents stored in the cache file.
|
||||||
useXULCache = cache->IsEnabled();
|
useXULCache = cache->IsEnabled();
|
||||||
|
|
||||||
if (useXULCache) {
|
if (useXULCache) {
|
||||||
|
@ -3105,47 +3075,21 @@ nsXULPrototypeScript::DeserializeOutOfLine(nsIObjectInputStream* aInput,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (! mScriptObject.mObject) {
|
if (! mScriptObject.mObject) {
|
||||||
nsCOMPtr<nsIURI> oldURI;
|
|
||||||
|
|
||||||
if (mSrcURI) {
|
if (mSrcURI) {
|
||||||
nsCAutoString spec;
|
rv = cache->GetInputStream(mSrcURI, getter_AddRefs(objectInput));
|
||||||
mSrcURI->GetAsciiSpec(spec);
|
}
|
||||||
rv = fastLoadService->StartMuxedDocument(mSrcURI, spec.get(),
|
// If !mSrcURI, we have an inline script. We shouldn't have
|
||||||
nsIFastLoadService::NS_FASTLOAD_READ);
|
// to do anything else in that case, I think.
|
||||||
if (NS_SUCCEEDED(rv))
|
|
||||||
rv = fastLoadService->SelectMuxedDocument(mSrcURI, getter_AddRefs(oldURI));
|
|
||||||
} else {
|
|
||||||
// An inline script: check FastLoad multiplexing direction
|
|
||||||
// and skip Deserialize if we're not reading from a
|
|
||||||
// muxed stream to get inline objects that are contained in
|
|
||||||
// the current document.
|
|
||||||
PRInt32 direction;
|
|
||||||
fastLoadService->GetDirection(&direction);
|
|
||||||
if (direction != nsIFastLoadService::NS_FASTLOAD_READ)
|
|
||||||
rv = NS_ERROR_NOT_AVAILABLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// We do reflect errors into rv, but our caller may want to
|
// We do reflect errors into rv, but our caller may want to
|
||||||
// ignore our return value, because mScriptObject will be null
|
// ignore our return value, because mScriptObject will be null
|
||||||
// after any error, and that suffices to cause the script to
|
// after any error, and that suffices to cause the script to
|
||||||
// be reloaded (from the src= URI, if any) and recompiled.
|
// be reloaded (from the src= URI, if any) and recompiled.
|
||||||
// We're better off slow-loading than bailing out due to a
|
// We're better off slow-loading than bailing out due to a
|
||||||
// FastLoad error.
|
// error.
|
||||||
if (NS_SUCCEEDED(rv))
|
if (NS_SUCCEEDED(rv))
|
||||||
rv = Deserialize(objectInput, aGlobal, nsnull, nsnull);
|
rv = Deserialize(objectInput, aGlobal, nsnull, nsnull);
|
||||||
|
|
||||||
if (NS_SUCCEEDED(rv) && mSrcURI) {
|
|
||||||
rv = fastLoadService->EndMuxedDocument(mSrcURI);
|
|
||||||
|
|
||||||
if (NS_SUCCEEDED(rv) && oldURI) {
|
|
||||||
nsCOMPtr<nsIURI> tempURI;
|
|
||||||
rv = fastLoadService->SelectMuxedDocument(oldURI, getter_AddRefs(tempURI));
|
|
||||||
|
|
||||||
NS_ASSERTION(NS_SUCCEEDED(rv) && (!tempURI || tempURI == mSrcURI),
|
|
||||||
"not currently deserializing into the script we thought we were!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (NS_SUCCEEDED(rv)) {
|
if (NS_SUCCEEDED(rv)) {
|
||||||
if (useXULCache && mSrcURI) {
|
if (useXULCache && mSrcURI) {
|
||||||
PRBool isChrome = PR_FALSE;
|
PRBool isChrome = PR_FALSE;
|
||||||
|
@ -3156,17 +3100,17 @@ nsXULPrototypeScript::DeserializeOutOfLine(nsIObjectInputStream* aInput,
|
||||||
mScriptObject.mObject);
|
mScriptObject.mObject);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
cache->FinishInputStream(mSrcURI);
|
||||||
} else {
|
} else {
|
||||||
// If mSrcURI is not in the FastLoad multiplex,
|
// If mSrcURI is not in the cache,
|
||||||
// rv will be NS_ERROR_NOT_AVAILABLE and we'll try to
|
// rv will be NS_ERROR_NOT_AVAILABLE and we'll try to
|
||||||
// update the FastLoad file to hold a serialization of
|
// update the cache file to hold a serialization of
|
||||||
// this script, once it has finished loading.
|
// this script, once it has finished loading.
|
||||||
if (rv != NS_ERROR_NOT_AVAILABLE)
|
if (rv != NS_ERROR_NOT_AVAILABLE)
|
||||||
cache->AbortFastLoads();
|
cache->AbortCaching();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -65,9 +65,9 @@ public:
|
||||||
virtual PRBool IsCached(nsIURI* aURI) = 0;
|
virtual PRBool IsCached(nsIURI* aURI) = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stop the FastLoad process abruptly, removing the FastLoad file.
|
* Stop the caching process abruptly, removing the cache file.
|
||||||
*/
|
*/
|
||||||
virtual void AbortFastLoads() = 0;
|
virtual void AbortCaching() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
NS_DEFINE_STATIC_IID_ACCESSOR(nsIXULPrototypeCache, NS_IXULPROTOTYPECACHE_IID)
|
NS_DEFINE_STATIC_IID_ACCESSOR(nsIXULPrototypeCache, NS_IXULPROTOTYPECACHE_IID)
|
||||||
|
|
|
@ -289,12 +289,11 @@ nsXULDocument::~nsXULDocument()
|
||||||
NS_IF_RELEASE(kNC_attribute);
|
NS_IF_RELEASE(kNC_attribute);
|
||||||
NS_IF_RELEASE(kNC_value);
|
NS_IF_RELEASE(kNC_value);
|
||||||
|
|
||||||
// Remove the current document here from the FastLoad table in
|
// Remove the current document here from the table in
|
||||||
// case the document did not make it past StartLayout in
|
// case the document did not make it past StartLayout in
|
||||||
// ResumeWalk. The FastLoad table must be clear of entries so
|
// ResumeWalk.
|
||||||
// that the FastLoad file footer can be properly written.
|
|
||||||
if (mDocumentURI)
|
if (mDocumentURI)
|
||||||
nsXULPrototypeCache::GetInstance()->RemoveFromFastLoadSet(mDocumentURI);
|
nsXULPrototypeCache::GetInstance()->RemoveFromCacheSet(mDocumentURI);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -451,7 +450,7 @@ nsXULDocument::SetContentType(const nsAString& aContentType)
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is called when the master document begins loading, whether it's
|
// This is called when the master document begins loading, whether it's
|
||||||
// fastloaded or not.
|
// being cached or not.
|
||||||
nsresult
|
nsresult
|
||||||
nsXULDocument::StartDocumentLoad(const char* aCommand, nsIChannel* aChannel,
|
nsXULDocument::StartDocumentLoad(const char* aCommand, nsIChannel* aChannel,
|
||||||
nsILoadGroup* aLoadGroup,
|
nsILoadGroup* aLoadGroup,
|
||||||
|
@ -494,9 +493,9 @@ nsXULDocument::StartDocumentLoad(const char* aCommand, nsIChannel* aChannel,
|
||||||
// to trigger the fail-safe parse-from-disk solution. Example failure cases
|
// to trigger the fail-safe parse-from-disk solution. Example failure cases
|
||||||
// (for reference) include:
|
// (for reference) include:
|
||||||
//
|
//
|
||||||
// NS_ERROR_NOT_AVAILABLE: the URI cannot be found in the FastLoad cache,
|
// NS_ERROR_NOT_AVAILABLE: the URI cannot be found in the startup cache,
|
||||||
// parse from disk
|
// parse from disk
|
||||||
// other: the FastLoad cache file, XUL.mfl, could not be found, probably
|
// other: the startup cache file could not be found, probably
|
||||||
// due to being accessed before a profile has been selected (e.g.
|
// due to being accessed before a profile has been selected (e.g.
|
||||||
// loading chrome for the profile manager itself). This must be
|
// loading chrome for the profile manager itself). This must be
|
||||||
// parsed from disk.
|
// parsed from disk.
|
||||||
|
|
|
@ -57,6 +57,8 @@
|
||||||
#include "nsIObjectInputStream.h"
|
#include "nsIObjectInputStream.h"
|
||||||
#include "nsIObjectOutputStream.h"
|
#include "nsIObjectOutputStream.h"
|
||||||
#include "nsIObserverService.h"
|
#include "nsIObserverService.h"
|
||||||
|
#include "nsIStringStream.h"
|
||||||
|
#include "nsIStorageStream.h"
|
||||||
|
|
||||||
#include "nsNetUtil.h"
|
#include "nsNetUtil.h"
|
||||||
#include "nsAppDirectoryServiceDefs.h"
|
#include "nsAppDirectoryServiceDefs.h"
|
||||||
|
@ -64,13 +66,17 @@
|
||||||
#include "jsxdrapi.h"
|
#include "jsxdrapi.h"
|
||||||
|
|
||||||
#include "mozilla/Preferences.h"
|
#include "mozilla/Preferences.h"
|
||||||
|
#include "mozilla/scache/StartupCache.h"
|
||||||
|
#include "mozilla/scache/StartupCacheUtils.h"
|
||||||
|
|
||||||
using namespace mozilla;
|
using namespace mozilla;
|
||||||
|
using namespace mozilla::scache;
|
||||||
|
|
||||||
static NS_DEFINE_CID(kXULPrototypeCacheCID, NS_XULPROTOTYPECACHE_CID);
|
static NS_DEFINE_CID(kXULPrototypeCacheCID, NS_XULPROTOTYPECACHE_CID);
|
||||||
|
|
||||||
static PRBool gDisableXULCache = PR_FALSE; // enabled by default
|
static PRBool gDisableXULCache = PR_FALSE; // enabled by default
|
||||||
static const char kDisableXULCachePref[] = "nglayout.debug.disable_xul_cache";
|
static const char kDisableXULCachePref[] = "nglayout.debug.disable_xul_cache";
|
||||||
|
static const char kXULCacheInfoKey[] = "nsXULPrototypeCache.startupCache";
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
@ -90,9 +96,7 @@ DisableXULCacheChangedCallback(const char* aPref, void* aClosure)
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
|
|
||||||
|
StartupCache* nsXULPrototypeCache::gStartupCache = nsnull;
|
||||||
nsIFastLoadService* nsXULPrototypeCache::gFastLoadService = nsnull;
|
|
||||||
nsIFile* nsXULPrototypeCache::gFastLoadFile = nsnull;
|
|
||||||
nsXULPrototypeCache* nsXULPrototypeCache::sInstance = nsnull;
|
nsXULPrototypeCache* nsXULPrototypeCache::sInstance = nsnull;
|
||||||
|
|
||||||
|
|
||||||
|
@ -104,9 +108,6 @@ nsXULPrototypeCache::nsXULPrototypeCache()
|
||||||
nsXULPrototypeCache::~nsXULPrototypeCache()
|
nsXULPrototypeCache::~nsXULPrototypeCache()
|
||||||
{
|
{
|
||||||
FlushScripts();
|
FlushScripts();
|
||||||
|
|
||||||
NS_IF_RELEASE(gFastLoadService); // don't need ReleaseService nowadays!
|
|
||||||
NS_IF_RELEASE(gFastLoadFile);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -129,8 +130,13 @@ NS_NewXULPrototypeCache(nsISupports* aOuter, REFNSIID aIID, void** aResult)
|
||||||
if (!(result->mPrototypeTable.Init() &&
|
if (!(result->mPrototypeTable.Init() &&
|
||||||
result->mStyleSheetTable.Init() &&
|
result->mStyleSheetTable.Init() &&
|
||||||
result->mScriptTable.Init() &&
|
result->mScriptTable.Init() &&
|
||||||
result->mXBLDocTable.Init() &&
|
result->mXBLDocTable.Init())) {
|
||||||
result->mFastLoadURITable.Init())) {
|
return NS_ERROR_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(result->mCacheURITable.Init() &&
|
||||||
|
result->mInputStreamTable.Init() &&
|
||||||
|
result->mOutputStreamTable.Init())) {
|
||||||
return NS_ERROR_OUT_OF_MEMORY;
|
return NS_ERROR_OUT_OF_MEMORY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -169,10 +175,10 @@ nsXULPrototypeCache::GetInstance()
|
||||||
return sInstance;
|
return sInstance;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* static */ nsIFastLoadService*
|
/* static */ StartupCache*
|
||||||
nsXULPrototypeCache::GetFastLoadService()
|
nsXULPrototypeCache::GetStartupCache()
|
||||||
{
|
{
|
||||||
return gFastLoadService;
|
return gStartupCache;
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
|
@ -189,7 +195,7 @@ nsXULPrototypeCache::Observe(nsISupports* aSubject,
|
||||||
Flush();
|
Flush();
|
||||||
}
|
}
|
||||||
else if (!strcmp(aTopic, "startupcache-invalidate")) {
|
else if (!strcmp(aTopic, "startupcache-invalidate")) {
|
||||||
AbortFastLoads();
|
AbortCaching();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
NS_WARNING("Unexpected observer topic.");
|
NS_WARNING("Unexpected observer topic.");
|
||||||
|
@ -201,42 +207,34 @@ nsXULPrototypeDocument*
|
||||||
nsXULPrototypeCache::GetPrototype(nsIURI* aURI)
|
nsXULPrototypeCache::GetPrototype(nsIURI* aURI)
|
||||||
{
|
{
|
||||||
nsXULPrototypeDocument* protoDoc = mPrototypeTable.GetWeak(aURI);
|
nsXULPrototypeDocument* protoDoc = mPrototypeTable.GetWeak(aURI);
|
||||||
|
if (protoDoc)
|
||||||
|
return protoDoc;
|
||||||
|
|
||||||
if (!protoDoc) {
|
nsresult rv = BeginCaching(aURI);
|
||||||
// No prototype in XUL memory cache. Spin up FastLoad Service and
|
if (NS_FAILED(rv))
|
||||||
// look in FastLoad file.
|
return nsnull;
|
||||||
nsresult rv = StartFastLoad(aURI);
|
|
||||||
if (NS_SUCCEEDED(rv)) {
|
|
||||||
nsCOMPtr<nsIObjectInputStream> objectInput;
|
|
||||||
gFastLoadService->GetInputStream(getter_AddRefs(objectInput));
|
|
||||||
|
|
||||||
rv = StartFastLoadingURI(aURI, nsIFastLoadService::NS_FASTLOAD_READ);
|
// No prototype in XUL memory cache. Spin up the cache Service.
|
||||||
if (NS_SUCCEEDED(rv)) {
|
nsCOMPtr<nsIObjectInputStream> ois;
|
||||||
nsCOMPtr<nsIURI> oldURI;
|
rv = GetInputStream(aURI, getter_AddRefs(ois));
|
||||||
gFastLoadService->SelectMuxedDocument(aURI, getter_AddRefs(oldURI));
|
if (NS_FAILED(rv))
|
||||||
|
return nsnull;
|
||||||
// Create a new prototype document.
|
|
||||||
nsRefPtr<nsXULPrototypeDocument> newProto;
|
nsRefPtr<nsXULPrototypeDocument> newProto;
|
||||||
rv = NS_NewXULPrototypeDocument(getter_AddRefs(newProto));
|
rv = NS_NewXULPrototypeDocument(getter_AddRefs(newProto));
|
||||||
if (NS_FAILED(rv)) return nsnull;
|
if (NS_FAILED(rv))
|
||||||
|
return nsnull;
|
||||||
rv = newProto->Read(objectInput);
|
|
||||||
if (NS_SUCCEEDED(rv)) {
|
rv = newProto->Read(ois);
|
||||||
rv = PutPrototype(newProto);
|
if (NS_SUCCEEDED(rv)) {
|
||||||
if (NS_FAILED(rv))
|
rv = PutPrototype(newProto);
|
||||||
newProto = nsnull;
|
} else {
|
||||||
|
newProto = nsnull;
|
||||||
gFastLoadService->EndMuxedDocument(aURI);
|
|
||||||
} else {
|
|
||||||
newProto = nsnull;
|
|
||||||
}
|
|
||||||
|
|
||||||
RemoveFromFastLoadSet(aURI);
|
|
||||||
protoDoc = newProto;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return protoDoc;
|
|
||||||
|
mInputStreamTable.Remove(aURI);
|
||||||
|
RemoveFromCacheSet(aURI);
|
||||||
|
return newProto;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
|
@ -405,11 +403,10 @@ nsXULPrototypeCache::IsEnabled()
|
||||||
return !gDisableXULCache;
|
return !gDisableXULCache;
|
||||||
}
|
}
|
||||||
|
|
||||||
static PRBool gDisableXULFastLoad = PR_FALSE; // enabled by default
|
static PRBool gDisableXULDiskCache = PR_FALSE; // enabled by default
|
||||||
static PRBool gChecksumXULFastLoadFile = PR_TRUE; // XXXbe too paranoid
|
|
||||||
|
|
||||||
void
|
void
|
||||||
nsXULPrototypeCache::AbortFastLoads()
|
nsXULPrototypeCache::AbortCaching()
|
||||||
{
|
{
|
||||||
#ifdef DEBUG_brendan
|
#ifdef DEBUG_brendan
|
||||||
NS_BREAK();
|
NS_BREAK();
|
||||||
|
@ -419,282 +416,187 @@ nsXULPrototypeCache::AbortFastLoads()
|
||||||
// script, somehow.
|
// script, somehow.
|
||||||
Flush();
|
Flush();
|
||||||
|
|
||||||
// Clear the FastLoad set
|
// Clear the cache set
|
||||||
mFastLoadURITable.Clear();
|
mCacheURITable.Clear();
|
||||||
|
|
||||||
nsCOMPtr<nsIFastLoadService> fastLoadService = gFastLoadService;
|
|
||||||
nsCOMPtr<nsIFile> file = gFastLoadFile;
|
|
||||||
|
|
||||||
nsresult rv;
|
|
||||||
|
|
||||||
if (! fastLoadService) {
|
|
||||||
fastLoadService = do_GetFastLoadService();
|
|
||||||
if (! fastLoadService)
|
|
||||||
return;
|
|
||||||
|
|
||||||
rv = fastLoadService->NewFastLoadFile(XUL_FASTLOAD_FILE_BASENAME,
|
|
||||||
getter_AddRefs(file));
|
|
||||||
if (NS_FAILED(rv))
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fetch the current input (if FastLoad file existed) or output (if we're
|
|
||||||
// creating the FastLoad file during this app startup) stream.
|
|
||||||
nsCOMPtr<nsIObjectInputStream> objectInput;
|
|
||||||
nsCOMPtr<nsIObjectOutputStream> objectOutput;
|
|
||||||
fastLoadService->GetInputStream(getter_AddRefs(objectInput));
|
|
||||||
fastLoadService->GetOutputStream(getter_AddRefs(objectOutput));
|
|
||||||
|
|
||||||
if (objectOutput) {
|
|
||||||
fastLoadService->SetOutputStream(nsnull);
|
|
||||||
|
|
||||||
if (NS_SUCCEEDED(objectOutput->Close()) && gChecksumXULFastLoadFile)
|
|
||||||
fastLoadService->CacheChecksum(file,
|
|
||||||
objectOutput);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (objectInput) {
|
|
||||||
// If this is the last of one or more XUL master documents loaded
|
|
||||||
// together at app startup, close the FastLoad service's singleton
|
|
||||||
// input stream now.
|
|
||||||
fastLoadService->SetInputStream(nsnull);
|
|
||||||
objectInput->Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now rename or remove the file.
|
|
||||||
if (file) {
|
|
||||||
#ifdef DEBUG
|
|
||||||
// Remove any existing Aborted.mfasl files generated in previous runs.
|
|
||||||
nsCOMPtr<nsIFile> existingAbortedFile;
|
|
||||||
file->Clone(getter_AddRefs(existingAbortedFile));
|
|
||||||
if (existingAbortedFile) {
|
|
||||||
existingAbortedFile->SetLeafName(NS_LITERAL_STRING("Aborted.mfasl"));
|
|
||||||
PRBool fileExists = PR_FALSE;
|
|
||||||
existingAbortedFile->Exists(&fileExists);
|
|
||||||
if (fileExists)
|
|
||||||
existingAbortedFile->Remove(PR_FALSE);
|
|
||||||
}
|
|
||||||
file->MoveToNative(nsnull, NS_LITERAL_CSTRING("Aborted.mfasl"));
|
|
||||||
#else
|
|
||||||
rv = file->Remove(PR_FALSE);
|
|
||||||
if (NS_FAILED(rv))
|
|
||||||
NS_WARNING("Failed to remove fastload file, fastload data may be outdated");
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the list is empty now, the FastLoad process is done.
|
|
||||||
NS_IF_RELEASE(gFastLoadService);
|
|
||||||
NS_IF_RELEASE(gFastLoadFile);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static const char kDisableXULDiskCachePref[] = "nglayout.debug.disable_xul_fastload";
|
||||||
|
|
||||||
void
|
void
|
||||||
nsXULPrototypeCache::RemoveFromFastLoadSet(nsIURI* aURI)
|
nsXULPrototypeCache::RemoveFromCacheSet(nsIURI* aURI)
|
||||||
{
|
{
|
||||||
mFastLoadURITable.Remove(aURI);
|
mCacheURITable.Remove(aURI);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char kDisableXULFastLoadPref[] = "nglayout.debug.disable_xul_fastload";
|
|
||||||
static const char kChecksumXULFastLoadFilePref[] = "nglayout.debug.checksum_xul_fastload_file";
|
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
nsXULPrototypeCache::WritePrototype(nsXULPrototypeDocument* aPrototypeDocument)
|
nsXULPrototypeCache::WritePrototype(nsXULPrototypeDocument* aPrototypeDocument)
|
||||||
{
|
{
|
||||||
nsresult rv = NS_OK, rv2 = NS_OK;
|
nsresult rv = NS_OK, rv2 = NS_OK;
|
||||||
|
|
||||||
// We're here before the FastLoad service has been initialized, probably because
|
// We're here before the startupcache service has been initialized, probably because
|
||||||
// of the profile manager. Bail quietly, don't worry, we'll be back later.
|
// of the profile manager. Bail quietly, don't worry, we'll be back later.
|
||||||
if (! gFastLoadService)
|
if (!gStartupCache)
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
|
|
||||||
// Fetch the current input (if FastLoad file existed) or output (if we're
|
|
||||||
// creating the FastLoad file during this app startup) stream.
|
|
||||||
nsCOMPtr<nsIObjectInputStream> objectInput;
|
|
||||||
nsCOMPtr<nsIObjectOutputStream> objectOutput;
|
|
||||||
gFastLoadService->GetInputStream(getter_AddRefs(objectInput));
|
|
||||||
gFastLoadService->GetOutputStream(getter_AddRefs(objectOutput));
|
|
||||||
|
|
||||||
nsCOMPtr<nsIURI> protoURI = aPrototypeDocument->GetURI();
|
nsCOMPtr<nsIURI> protoURI = aPrototypeDocument->GetURI();
|
||||||
|
|
||||||
// Remove this document from the FastLoad table. We use the table's
|
// Remove this document from the cache table. We use the table's
|
||||||
// emptiness instead of a counter to decide when the FastLoad process
|
// emptiness instead of a counter to decide when the caching process
|
||||||
// has completed. When complete, we can write footer details to the
|
// has completed.
|
||||||
// FastLoad file.
|
RemoveFromCacheSet(protoURI);
|
||||||
RemoveFromFastLoadSet(protoURI);
|
|
||||||
|
|
||||||
PRInt32 count = mFastLoadURITable.Count();
|
PRInt32 count = mCacheURITable.Count();
|
||||||
|
nsCOMPtr<nsIObjectOutputStream> oos;
|
||||||
if (objectOutput) {
|
rv = GetOutputStream(protoURI, getter_AddRefs(oos));
|
||||||
rv = StartFastLoadingURI(protoURI, nsIFastLoadService::NS_FASTLOAD_WRITE);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
if (NS_SUCCEEDED(rv)) {
|
|
||||||
// Re-select the URL of the current prototype, as out-of-line script loads
|
|
||||||
// may have changed
|
|
||||||
nsCOMPtr<nsIURI> oldURI;
|
|
||||||
gFastLoadService->SelectMuxedDocument(protoURI, getter_AddRefs(oldURI));
|
|
||||||
|
|
||||||
aPrototypeDocument->Write(objectOutput);
|
|
||||||
|
|
||||||
gFastLoadService->EndMuxedDocument(protoURI);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If this is the last of one or more XUL master documents loaded
|
|
||||||
// together at app startup, close the FastLoad service's singleton
|
|
||||||
// output stream now.
|
|
||||||
//
|
|
||||||
// NB: we must close input after output, in case the output stream
|
|
||||||
// implementation needs to read from the input stream, to compute a
|
|
||||||
// FastLoad file checksum. In that case, the implementation used
|
|
||||||
// nsIFastLoadFileIO to get the corresponding input stream for this
|
|
||||||
// output stream.
|
|
||||||
if (count == 0) {
|
|
||||||
gFastLoadService->SetOutputStream(nsnull);
|
|
||||||
rv = objectOutput->Close();
|
|
||||||
|
|
||||||
if (NS_SUCCEEDED(rv) && gChecksumXULFastLoadFile) {
|
|
||||||
rv = gFastLoadService->CacheChecksum(gFastLoadFile,
|
|
||||||
objectOutput);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (objectInput) {
|
|
||||||
// If this is the last of one or more XUL master documents loaded
|
|
||||||
// together at app startup, close the FastLoad service's singleton
|
|
||||||
// input stream now.
|
|
||||||
if (count == 0) {
|
|
||||||
gFastLoadService->SetInputStream(nsnull);
|
|
||||||
rv2 = objectInput->Close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the list is empty now, the FastLoad process is done.
|
|
||||||
if (count == 0) {
|
|
||||||
NS_RELEASE(gFastLoadService);
|
|
||||||
NS_RELEASE(gFastLoadFile);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
rv = aPrototypeDocument->Write(oos);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
FinishOutputStream(protoURI);
|
||||||
return NS_FAILED(rv) ? rv : rv2;
|
return NS_FAILED(rv) ? rv : rv2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
nsXULPrototypeCache::GetInputStream(nsIURI* uri, nsIObjectInputStream** stream)
|
||||||
|
{
|
||||||
|
nsCAutoString spec;
|
||||||
|
uri->GetPath(spec);
|
||||||
|
|
||||||
|
nsAutoArrayPtr<char> buf;
|
||||||
|
PRUint32 len;
|
||||||
|
nsCOMPtr<nsIObjectInputStream> ois;
|
||||||
|
if (!gStartupCache)
|
||||||
|
return NS_ERROR_NOT_AVAILABLE;
|
||||||
|
|
||||||
|
nsresult rv = gStartupCache->GetBuffer(spec.get(), getter_Transfers(buf),
|
||||||
|
&len);
|
||||||
|
if (NS_FAILED(rv))
|
||||||
|
return NS_ERROR_NOT_AVAILABLE;
|
||||||
|
|
||||||
|
rv = NS_NewObjectInputStreamFromBuffer(buf, len, getter_AddRefs(ois));
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
buf.forget();
|
||||||
|
|
||||||
|
mInputStreamTable.Put(uri, ois);
|
||||||
|
|
||||||
|
NS_ADDREF(*stream = ois);
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
nsXULPrototypeCache::StartFastLoadingURI(nsIURI* aURI, PRInt32 aDirectionFlags)
|
nsXULPrototypeCache::FinishInputStream(nsIURI* uri) {
|
||||||
|
mInputStreamTable.Remove(uri);
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsresult
|
||||||
|
nsXULPrototypeCache::GetOutputStream(nsIURI* uri, nsIObjectOutputStream** stream)
|
||||||
{
|
{
|
||||||
nsresult rv;
|
nsresult rv;
|
||||||
|
nsCOMPtr<nsIObjectOutputStream> objectOutput;
|
||||||
|
nsCOMPtr<nsIStorageStream> storageStream;
|
||||||
|
PRBool found = mOutputStreamTable.Get(uri, getter_AddRefs(storageStream));
|
||||||
|
if (found) {
|
||||||
|
objectOutput = do_CreateInstance("mozilla.org/binaryoutputstream;1");
|
||||||
|
if (!objectOutput) return NS_ERROR_OUT_OF_MEMORY;
|
||||||
|
nsCOMPtr<nsIOutputStream> outputStream
|
||||||
|
= do_QueryInterface(storageStream);
|
||||||
|
objectOutput->SetOutputStream(outputStream);
|
||||||
|
} else {
|
||||||
|
rv = NS_NewObjectOutputWrappedStorageStream(getter_AddRefs(objectOutput),
|
||||||
|
getter_AddRefs(storageStream),
|
||||||
|
false);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
mOutputStreamTable.Put(uri, storageStream);
|
||||||
|
}
|
||||||
|
NS_ADDREF(*stream = objectOutput);
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
nsCAutoString urlspec;
|
nsresult
|
||||||
rv = aURI->GetAsciiSpec(urlspec);
|
nsXULPrototypeCache::FinishOutputStream(nsIURI* uri)
|
||||||
if (NS_FAILED(rv)) return rv;
|
{
|
||||||
|
nsresult rv;
|
||||||
|
if (!gStartupCache)
|
||||||
|
return NS_ERROR_NOT_AVAILABLE;
|
||||||
|
|
||||||
|
nsCOMPtr<nsIStorageStream> storageStream;
|
||||||
|
PRBool found = mOutputStreamTable.Get(uri, getter_AddRefs(storageStream));
|
||||||
|
if (!found)
|
||||||
|
return NS_ERROR_UNEXPECTED;
|
||||||
|
nsCOMPtr<nsIOutputStream> outputStream
|
||||||
|
= do_QueryInterface(storageStream);
|
||||||
|
outputStream->Close();
|
||||||
|
|
||||||
|
nsAutoArrayPtr<char> buf;
|
||||||
|
PRUint32 len;
|
||||||
|
rv = NS_NewBufferFromStorageStream(storageStream, getter_Transfers(buf),
|
||||||
|
&len);
|
||||||
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
// If StartMuxedDocument returns NS_ERROR_NOT_AVAILABLE, then
|
nsCAutoString spec;
|
||||||
// we must be reading the file, and urlspec was not associated
|
uri->GetPath(spec);
|
||||||
// with any multiplexed stream in it. The FastLoad service
|
rv = gStartupCache->PutBuffer(spec.get(), buf, len);
|
||||||
// will therefore arrange to update the file, writing new data
|
if (NS_SUCCEEDED(rv))
|
||||||
// at the end while old (available) data continues to be read
|
mOutputStreamTable.Remove(uri);
|
||||||
// from the pre-existing part of the file.
|
|
||||||
return gFastLoadService->StartMuxedDocument(aURI, urlspec.get(), aDirectionFlags);
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We have data if we're in the middle of writing it or we already
|
||||||
|
// have it in the cache.
|
||||||
|
nsresult
|
||||||
|
nsXULPrototypeCache::HasData(nsIURI* uri, PRBool* exists)
|
||||||
|
{
|
||||||
|
if (mOutputStreamTable.Get(uri, nsnull)) {
|
||||||
|
*exists = PR_TRUE;
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
nsCAutoString spec;
|
||||||
|
uri->GetPath(spec);
|
||||||
|
nsAutoArrayPtr<char> buf;
|
||||||
|
PRUint32 len;
|
||||||
|
nsresult rv;
|
||||||
|
if (gStartupCache)
|
||||||
|
rv = gStartupCache->GetBuffer(spec.get(), getter_Transfers(buf),
|
||||||
|
&len);
|
||||||
|
else {
|
||||||
|
// We don't have everything we need to call BeginCaching and set up
|
||||||
|
// gStartupCache right now, but we just need to check the cache for
|
||||||
|
// this URI.
|
||||||
|
StartupCache* sc = StartupCache::GetSingleton();
|
||||||
|
if (!sc) {
|
||||||
|
*exists = PR_FALSE;
|
||||||
|
return NS_OK;
|
||||||
|
}
|
||||||
|
rv = sc->GetBuffer(spec.get(), getter_Transfers(buf), &len);
|
||||||
|
}
|
||||||
|
*exists = NS_SUCCEEDED(rv);
|
||||||
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
FastLoadPrefChangedCallback(const char* aPref, void* aClosure)
|
CachePrefChangedCallback(const char* aPref, void* aClosure)
|
||||||
{
|
{
|
||||||
PRBool wasEnabled = !gDisableXULFastLoad;
|
PRBool wasEnabled = !gDisableXULDiskCache;
|
||||||
gDisableXULFastLoad =
|
gDisableXULDiskCache =
|
||||||
Preferences::GetBool(kDisableXULFastLoadPref, gDisableXULFastLoad);
|
Preferences::GetBool(kDisableXULCachePref,
|
||||||
|
gDisableXULDiskCache);
|
||||||
|
|
||||||
if (wasEnabled && gDisableXULFastLoad) {
|
if (wasEnabled && gDisableXULDiskCache) {
|
||||||
static NS_DEFINE_CID(kXULPrototypeCacheCID, NS_XULPROTOTYPECACHE_CID);
|
static NS_DEFINE_CID(kXULPrototypeCacheCID, NS_XULPROTOTYPECACHE_CID);
|
||||||
nsCOMPtr<nsIXULPrototypeCache> cache =
|
nsCOMPtr<nsIXULPrototypeCache> cache =
|
||||||
do_GetService(kXULPrototypeCacheCID);
|
do_GetService(kXULPrototypeCacheCID);
|
||||||
|
|
||||||
if (cache)
|
if (cache)
|
||||||
cache->AbortFastLoads();
|
cache->AbortCaching();
|
||||||
}
|
}
|
||||||
|
|
||||||
gChecksumXULFastLoadFile =
|
|
||||||
Preferences::GetBool(kChecksumXULFastLoadFilePref,
|
|
||||||
gChecksumXULFastLoadFile);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class nsXULFastLoadFileIO : public nsIFastLoadFileIO
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
nsXULFastLoadFileIO(nsIFile* aFile)
|
|
||||||
: mFile(aFile), mTruncateOutputFile(true) {
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ~nsXULFastLoadFileIO() {
|
|
||||||
}
|
|
||||||
|
|
||||||
NS_DECL_ISUPPORTS
|
|
||||||
NS_DECL_NSIFASTLOADFILEIO
|
|
||||||
|
|
||||||
nsCOMPtr<nsIFile> mFile;
|
|
||||||
nsCOMPtr<nsIInputStream> mInputStream;
|
|
||||||
nsCOMPtr<nsIOutputStream> mOutputStream;
|
|
||||||
bool mTruncateOutputFile;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
NS_IMPL_THREADSAFE_ISUPPORTS1(nsXULFastLoadFileIO, nsIFastLoadFileIO)
|
|
||||||
|
|
||||||
|
|
||||||
NS_IMETHODIMP
|
|
||||||
nsXULFastLoadFileIO::GetInputStream(nsIInputStream** aResult)
|
|
||||||
{
|
|
||||||
if (! mInputStream) {
|
|
||||||
nsresult rv;
|
|
||||||
nsCOMPtr<nsIInputStream> fileInput;
|
|
||||||
rv = NS_NewLocalFileInputStream(getter_AddRefs(fileInput), mFile);
|
|
||||||
if (NS_FAILED(rv)) return rv;
|
|
||||||
|
|
||||||
rv = NS_NewBufferedInputStream(getter_AddRefs(mInputStream),
|
|
||||||
fileInput,
|
|
||||||
XUL_DESERIALIZATION_BUFFER_SIZE);
|
|
||||||
if (NS_FAILED(rv)) return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
NS_ADDREF(*aResult = mInputStream);
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
NS_IMETHODIMP
|
|
||||||
nsXULFastLoadFileIO::GetOutputStream(nsIOutputStream** aResult)
|
|
||||||
{
|
|
||||||
if (! mOutputStream) {
|
|
||||||
PRInt32 ioFlags = PR_WRONLY;
|
|
||||||
if (mTruncateOutputFile)
|
|
||||||
ioFlags |= PR_CREATE_FILE | PR_TRUNCATE;
|
|
||||||
|
|
||||||
nsresult rv;
|
|
||||||
nsCOMPtr<nsIOutputStream> fileOutput;
|
|
||||||
rv = NS_NewLocalFileOutputStream(getter_AddRefs(fileOutput), mFile,
|
|
||||||
ioFlags, 0644);
|
|
||||||
if (NS_FAILED(rv)) return rv;
|
|
||||||
|
|
||||||
rv = NS_NewBufferedOutputStream(getter_AddRefs(mOutputStream),
|
|
||||||
fileOutput,
|
|
||||||
XUL_SERIALIZATION_BUFFER_SIZE);
|
|
||||||
if (NS_FAILED(rv)) return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
NS_ADDREF(*aResult = mOutputStream);
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
NS_IMETHODIMP
|
|
||||||
nsXULFastLoadFileIO::DisableTruncate()
|
|
||||||
{
|
|
||||||
mTruncateOutputFile = false;
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsresult
|
nsresult
|
||||||
nsXULPrototypeCache::StartFastLoad(nsIURI* aURI)
|
nsXULPrototypeCache::BeginCaching(nsIURI* aURI)
|
||||||
{
|
{
|
||||||
nsresult rv;
|
nsresult rv;
|
||||||
|
|
||||||
|
@ -703,47 +605,37 @@ nsXULPrototypeCache::StartFastLoad(nsIURI* aURI)
|
||||||
if (!StringEndsWith(path, NS_LITERAL_CSTRING(".xul")))
|
if (!StringEndsWith(path, NS_LITERAL_CSTRING(".xul")))
|
||||||
return NS_ERROR_NOT_AVAILABLE;
|
return NS_ERROR_NOT_AVAILABLE;
|
||||||
|
|
||||||
// Test gFastLoadFile to decide whether this is the first nsXULDocument
|
// Test gStartupCache to decide whether this is the first nsXULDocument
|
||||||
// participating in FastLoad. If gFastLoadFile is non-null, this document
|
// participating in the serialization. If gStartupCache is non-null, this document
|
||||||
// must not be first, but it can join the FastLoad process. Examples of
|
// must not be first, but it can join the process. Examples of
|
||||||
// multiple master documents participating include hiddenWindow.xul and
|
// multiple master documents participating include hiddenWindow.xul and
|
||||||
// navigator.xul on the Mac, and multiple-app-component (e.g., mailnews
|
// navigator.xul on the Mac, and multiple-app-component (e.g., mailnews
|
||||||
// and browser) startup due to command-line arguments.
|
// and browser) startup due to command-line arguments.
|
||||||
//
|
//
|
||||||
// XXXbe we should attempt to update the FastLoad file after startup!
|
if (gStartupCache) {
|
||||||
//
|
mCacheURITable.Put(aURI, 1);
|
||||||
// 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;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use a local to refer to the service till we're sure we succeeded, then
|
// 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
|
// commit to gStartupCache.
|
||||||
// delete the FastLoad file on abort.
|
StartupCache* startupCache = StartupCache::GetSingleton();
|
||||||
nsCOMPtr<nsIFastLoadService> fastLoadService(do_GetFastLoadService());
|
if (!startupCache)
|
||||||
if (! fastLoadService)
|
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
|
|
||||||
gDisableXULFastLoad =
|
gDisableXULDiskCache =
|
||||||
Preferences::GetBool(kDisableXULFastLoadPref, gDisableXULFastLoad);
|
Preferences::GetBool(kDisableXULCachePref, gDisableXULDiskCache);
|
||||||
gChecksumXULFastLoadFile =
|
|
||||||
Preferences::GetBool(kChecksumXULFastLoadFilePref,
|
nsContentUtils::RegisterPrefCallback(kDisableXULCachePref,
|
||||||
gChecksumXULFastLoadFile);
|
CachePrefChangedCallback,
|
||||||
nsContentUtils::RegisterPrefCallback(kDisableXULFastLoadPref,
|
|
||||||
FastLoadPrefChangedCallback,
|
|
||||||
nsnull);
|
|
||||||
nsContentUtils::RegisterPrefCallback(kChecksumXULFastLoadFilePref,
|
|
||||||
FastLoadPrefChangedCallback,
|
|
||||||
nsnull);
|
nsnull);
|
||||||
|
|
||||||
if (gDisableXULFastLoad)
|
if (gDisableXULDiskCache)
|
||||||
return NS_ERROR_NOT_AVAILABLE;
|
return NS_ERROR_NOT_AVAILABLE;
|
||||||
|
|
||||||
// Get the chrome directory to validate against the one stored in the
|
// 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.
|
// cache file, or to store there if we're generating a new file.
|
||||||
nsCOMPtr<nsIFile> chromeDir;
|
nsCOMPtr<nsIFile> chromeDir;
|
||||||
rv = NS_GetSpecialDirectory(NS_APP_CHROME_DIR, getter_AddRefs(chromeDir));
|
rv = NS_GetSpecialDirectory(NS_APP_CHROME_DIR, getter_AddRefs(chromeDir));
|
||||||
if (NS_FAILED(rv))
|
if (NS_FAILED(rv))
|
||||||
|
@ -753,134 +645,85 @@ nsXULPrototypeCache::StartFastLoad(nsIURI* aURI)
|
||||||
if (NS_FAILED(rv))
|
if (NS_FAILED(rv))
|
||||||
return 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 =
|
|
||||||
mozilla::services::GetXULChromeRegistryService();
|
|
||||||
if (!chromeReg)
|
|
||||||
return NS_ERROR_FAILURE;
|
|
||||||
|
|
||||||
// XXXbe we assume the first package's locale is the same as the locale of
|
// XXXbe we assume the first package's locale is the same as the locale of
|
||||||
// all subsequent packages of FastLoaded chrome URIs....
|
// all subsequent packages of cached chrome URIs....
|
||||||
nsCAutoString package;
|
nsCAutoString package;
|
||||||
rv = aURI->GetHost(package);
|
rv = aURI->GetHost(package);
|
||||||
if (NS_FAILED(rv))
|
if (NS_FAILED(rv))
|
||||||
return rv;
|
return rv;
|
||||||
|
nsCOMPtr<nsIXULChromeRegistry> chromeReg
|
||||||
|
= do_GetService(NS_CHROMEREGISTRY_CONTRACTID, &rv);
|
||||||
nsCAutoString locale;
|
nsCAutoString locale;
|
||||||
rv = chromeReg->GetSelectedLocale(package, locale);
|
rv = chromeReg->GetSelectedLocale(package, locale);
|
||||||
if (NS_FAILED(rv))
|
if (NS_FAILED(rv))
|
||||||
return rv;
|
return rv;
|
||||||
|
|
||||||
// Try to read an existent FastLoad file.
|
nsCAutoString fileChromePath, fileLocale;
|
||||||
PRBool exists = PR_FALSE;
|
|
||||||
if (NS_SUCCEEDED(file->Exists(&exists)) && exists) {
|
nsAutoArrayPtr<char> buf;
|
||||||
nsCOMPtr<nsIObjectInputStream> objectInput;
|
PRUint32 len, amtRead;
|
||||||
rv = fastLoadService->NewInputStream(file, getter_AddRefs(objectInput));
|
nsCOMPtr<nsIObjectInputStream> objectInput;
|
||||||
|
|
||||||
|
rv = startupCache->GetBuffer(kXULCacheInfoKey, getter_Transfers(buf),
|
||||||
|
&len);
|
||||||
|
if (NS_SUCCEEDED(rv))
|
||||||
|
rv = NS_NewObjectInputStreamFromBuffer(buf, len, getter_AddRefs(objectInput));
|
||||||
|
|
||||||
|
if (NS_SUCCEEDED(rv)) {
|
||||||
|
buf.forget();
|
||||||
|
rv = objectInput->ReadCString(fileLocale);
|
||||||
|
rv |= objectInput->ReadCString(fileChromePath);
|
||||||
|
if (NS_FAILED(rv) ||
|
||||||
|
(!fileChromePath.Equals(chromePath) ||
|
||||||
|
!fileLocale.Equals(locale))) {
|
||||||
|
// Our cache won't be valid in this case, we'll need to rewrite.
|
||||||
|
// XXX This blows away work that other consumers (like
|
||||||
|
// mozJSComponentLoader) have done, need more fine-grained control.
|
||||||
|
startupCache->InvalidateCache();
|
||||||
|
rv = NS_ERROR_UNEXPECTED;
|
||||||
|
}
|
||||||
|
} else if (rv != NS_ERROR_NOT_AVAILABLE)
|
||||||
|
// NS_ERROR_NOT_AVAILABLE is normal, usually if there's no cachefile.
|
||||||
|
return rv;
|
||||||
|
|
||||||
|
if (NS_FAILED(rv)) {
|
||||||
|
// Either the cache entry was invalid or it didn't exist, so write it now.
|
||||||
|
nsCOMPtr<nsIObjectOutputStream> objectOutput;
|
||||||
|
nsCOMPtr<nsIInputStream> inputStream;
|
||||||
|
nsCOMPtr<nsIStorageStream> storageStream;
|
||||||
|
rv = NS_NewObjectOutputWrappedStorageStream(getter_AddRefs(objectOutput),
|
||||||
|
getter_AddRefs(storageStream),
|
||||||
|
false);
|
||||||
if (NS_SUCCEEDED(rv)) {
|
if (NS_SUCCEEDED(rv)) {
|
||||||
if (NS_SUCCEEDED(rv)) {
|
rv = objectOutput->WriteStringZ(locale.get());
|
||||||
// Get the XUL fastload file version number, which should be
|
rv |= objectOutput->WriteStringZ(chromePath.get());
|
||||||
// decremented whenever the XUL-specific file format changes
|
rv |= objectOutput->Close();
|
||||||
// (see public/nsIXULPrototypeCache.h for the #define).
|
rv |= storageStream->NewInputStream(0, getter_AddRefs(inputStream));
|
||||||
PRUint32 xulFastLoadVersion, jsByteCodeVersion;
|
}
|
||||||
rv = objectInput->Read32(&xulFastLoadVersion);
|
if (NS_SUCCEEDED(rv))
|
||||||
rv |= objectInput->Read32(&jsByteCodeVersion);
|
rv = inputStream->Available(&len);
|
||||||
if (NS_SUCCEEDED(rv)) {
|
|
||||||
if (xulFastLoadVersion != XUL_FASTLOAD_FILE_VERSION ||
|
if (NS_SUCCEEDED(rv)) {
|
||||||
jsByteCodeVersion != JSXDR_BYTECODE_VERSION) {
|
buf = new char[len];
|
||||||
#ifdef DEBUG
|
rv = inputStream->Read(buf, len, &amtRead);
|
||||||
printf((xulFastLoadVersion != XUL_FASTLOAD_FILE_VERSION)
|
if (NS_SUCCEEDED(rv) && len == amtRead)
|
||||||
? "bad FastLoad file version\n"
|
rv = startupCache->PutBuffer(kXULCacheInfoKey, buf, len);
|
||||||
: "bad JS bytecode version\n");
|
else {
|
||||||
#endif
|
rv = NS_ERROR_UNEXPECTED;
|
||||||
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)) {
|
// Failed again, just bail.
|
||||||
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 (NS_FAILED(rv)) {
|
||||||
if (objectOutput)
|
startupCache->InvalidateCache();
|
||||||
objectOutput->Close();
|
|
||||||
else
|
|
||||||
output->Close();
|
|
||||||
xio->mOutputStream = nsnull;
|
|
||||||
|
|
||||||
file->Remove(PR_FALSE);
|
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
fastLoadService->SetOutputStream(objectOutput);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Success! Insert this URI into the mFastLoadURITable
|
// Success! Insert this URI into the mCacheURITable
|
||||||
// and commit locals to globals.
|
// and commit locals to globals.
|
||||||
mFastLoadURITable.Put(aURI, 1);
|
mCacheURITable.Put(aURI, 1);
|
||||||
|
|
||||||
NS_ADDREF(gFastLoadService = fastLoadService);
|
gStartupCache = startupCache;
|
||||||
NS_ADDREF(gFastLoadFile = file);
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -52,8 +52,12 @@
|
||||||
#include "nsRefPtrHashtable.h"
|
#include "nsRefPtrHashtable.h"
|
||||||
#include "nsURIHashKey.h"
|
#include "nsURIHashKey.h"
|
||||||
#include "nsXULPrototypeDocument.h"
|
#include "nsXULPrototypeDocument.h"
|
||||||
|
#include "nsIInputStream.h"
|
||||||
|
#include "nsIStorageStream.h"
|
||||||
|
#include "mozilla/scache/StartupCache.h"
|
||||||
|
|
||||||
|
using namespace mozilla::scache;
|
||||||
|
|
||||||
class nsIFastLoadService;
|
|
||||||
class nsCSSStyleSheet;
|
class nsCSSStyleSheet;
|
||||||
|
|
||||||
struct CacheScriptEntry
|
struct CacheScriptEntry
|
||||||
|
@ -68,7 +72,7 @@ struct CacheScriptEntry
|
||||||
*
|
*
|
||||||
* The cache has two levels:
|
* The cache has two levels:
|
||||||
* 1. In-memory hashtables
|
* 1. In-memory hashtables
|
||||||
* 2. The on-disk fastload file.
|
* 2. The on-disk cache file.
|
||||||
*/
|
*/
|
||||||
class nsXULPrototypeCache : public nsIXULPrototypeCache,
|
class nsXULPrototypeCache : public nsIXULPrototypeCache,
|
||||||
nsIObserver
|
nsIObserver
|
||||||
|
@ -82,7 +86,7 @@ public:
|
||||||
virtual PRBool IsCached(nsIURI* aURI) {
|
virtual PRBool IsCached(nsIURI* aURI) {
|
||||||
return GetPrototype(aURI) != nsnull;
|
return GetPrototype(aURI) != nsnull;
|
||||||
}
|
}
|
||||||
virtual void AbortFastLoads();
|
virtual void AbortCaching();
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -96,16 +100,6 @@ public:
|
||||||
*/
|
*/
|
||||||
void Flush();
|
void Flush();
|
||||||
|
|
||||||
/**
|
|
||||||
* Remove a XUL document from the set of loading documents.
|
|
||||||
*/
|
|
||||||
void RemoveFromFastLoadSet(nsIURI* aDocumentURI);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Write the XUL prototype document to fastload file. The proto must be
|
|
||||||
* fully loaded.
|
|
||||||
*/
|
|
||||||
nsresult WritePrototype(nsXULPrototypeDocument* aPrototypeDocument);
|
|
||||||
|
|
||||||
// The following methods are used to put and retrive various items into and
|
// The following methods are used to put and retrive various items into and
|
||||||
// from the cache.
|
// from the cache.
|
||||||
|
@ -135,9 +129,30 @@ public:
|
||||||
*/
|
*/
|
||||||
nsresult PutStyleSheet(nsCSSStyleSheet* aStyleSheet);
|
nsresult PutStyleSheet(nsCSSStyleSheet* aStyleSheet);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a XUL document from the set of loading documents.
|
||||||
|
*/
|
||||||
|
void RemoveFromCacheSet(nsIURI* aDocumentURI);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write the XUL prototype document to a cache file. The proto must be
|
||||||
|
* fully loaded.
|
||||||
|
*/
|
||||||
|
nsresult WritePrototype(nsXULPrototypeDocument* aPrototypeDocument);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This interface allows partial reads and writes from the buffers in the
|
||||||
|
* startupCache.
|
||||||
|
*/
|
||||||
|
nsresult GetInputStream(nsIURI* aURI, nsIObjectInputStream** objectInput);
|
||||||
|
nsresult FinishInputStream(nsIURI* aURI);
|
||||||
|
nsresult GetOutputStream(nsIURI* aURI, nsIObjectOutputStream** objectOutput);
|
||||||
|
nsresult FinishOutputStream(nsIURI* aURI);
|
||||||
|
nsresult HasData(nsIURI* aURI, PRBool* exists);
|
||||||
|
|
||||||
|
static StartupCache* GetStartupCache();
|
||||||
|
|
||||||
static nsXULPrototypeCache* GetInstance();
|
static nsXULPrototypeCache* GetInstance();
|
||||||
static nsIFastLoadService* GetFastLoadService();
|
|
||||||
|
|
||||||
static void ReleaseGlobals()
|
static void ReleaseGlobals()
|
||||||
{
|
{
|
||||||
|
@ -162,16 +177,16 @@ protected:
|
||||||
nsRefPtrHashtable<nsURIHashKey,nsXBLDocumentInfo> mXBLDocTable;
|
nsRefPtrHashtable<nsURIHashKey,nsXBLDocumentInfo> mXBLDocTable;
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
// FastLoad
|
// StartupCache
|
||||||
// this is really a hash set, with a dummy data parameter
|
// this is really a hash set, with a dummy data parameter
|
||||||
nsDataHashtable<nsURIHashKey,PRUint32> mFastLoadURITable;
|
nsDataHashtable<nsURIHashKey,PRUint32> mCacheURITable;
|
||||||
|
|
||||||
static nsIFastLoadService* gFastLoadService;
|
static StartupCache* gStartupCache;
|
||||||
static nsIFile* gFastLoadFile;
|
nsInterfaceHashtable<nsURIHashKey, nsIStorageStream> mOutputStreamTable;
|
||||||
|
nsInterfaceHashtable<nsURIHashKey, nsIObjectInputStream> mInputStreamTable;
|
||||||
// Bootstrap FastLoad Service
|
|
||||||
nsresult StartFastLoad(nsIURI* aDocumentURI);
|
// Bootstrap caching service
|
||||||
nsresult StartFastLoadingURI(nsIURI* aURI, PRInt32 aDirectionFlags);
|
nsresult BeginCaching(nsIURI* aDocumentURI);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // nsXULPrototypeCache_h__
|
#endif // nsXULPrototypeCache_h__
|
||||||
|
|
|
@ -418,6 +418,13 @@ nsXULPrototypeDocument::Write(nsIObjectOutputStream* aStream)
|
||||||
rv |= aStream->WriteObject(mNodeInfoManager->DocumentPrincipal(),
|
rv |= aStream->WriteObject(mNodeInfoManager->DocumentPrincipal(),
|
||||||
PR_TRUE);
|
PR_TRUE);
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
// XXX Worrisome if we're caching things without system principal.
|
||||||
|
if (nsContentUtils::IsSystemPrincipal(mNodeInfoManager->DocumentPrincipal())) {
|
||||||
|
NS_WARNING("Serializing document without system principal");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// nsINodeInfo table
|
// nsINodeInfo table
|
||||||
nsCOMArray<nsINodeInfo> nodeInfos;
|
nsCOMArray<nsINodeInfo> nodeInfos;
|
||||||
if (mRoot)
|
if (mRoot)
|
||||||
|
|
|
@ -969,7 +969,8 @@ mozJSComponentLoader::WriteScript(StartupCache* cache, JSObject *scriptObj,
|
||||||
nsCOMPtr<nsIObjectOutputStream> oos;
|
nsCOMPtr<nsIObjectOutputStream> oos;
|
||||||
nsCOMPtr<nsIStorageStream> storageStream;
|
nsCOMPtr<nsIStorageStream> storageStream;
|
||||||
rv = NS_NewObjectOutputWrappedStorageStream(getter_AddRefs(oos),
|
rv = NS_NewObjectOutputWrappedStorageStream(getter_AddRefs(oos),
|
||||||
getter_AddRefs(storageStream));
|
getter_AddRefs(storageStream),
|
||||||
|
true);
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
NS_ENSURE_SUCCESS(rv, rv);
|
||||||
|
|
||||||
rv = WriteScriptToStream(cx, scriptObj, oos);
|
rv = WriteScriptToStream(cx, scriptObj, oos);
|
||||||
|
|
|
@ -27,7 +27,8 @@ NS_NewObjectInputStreamFromBuffer(char* buffer, PRUint32 len,
|
||||||
|
|
||||||
NS_EXPORT nsresult
|
NS_EXPORT nsresult
|
||||||
NS_NewObjectOutputWrappedStorageStream(nsIObjectOutputStream **wrapperStream,
|
NS_NewObjectOutputWrappedStorageStream(nsIObjectOutputStream **wrapperStream,
|
||||||
nsIStorageStream** stream)
|
nsIStorageStream** stream,
|
||||||
|
PRBool wantDebugStream)
|
||||||
{
|
{
|
||||||
nsCOMPtr<nsIStorageStream> storageStream;
|
nsCOMPtr<nsIStorageStream> storageStream;
|
||||||
|
|
||||||
|
@ -42,13 +43,17 @@ NS_NewObjectOutputWrappedStorageStream(nsIObjectOutputStream **wrapperStream,
|
||||||
objectOutput->SetOutputStream(outputStream);
|
objectOutput->SetOutputStream(outputStream);
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
// Wrap in debug stream to detect unsupported writes of
|
if (wantDebugStream) {
|
||||||
// multiply-referenced non-singleton objects
|
// Wrap in debug stream to detect unsupported writes of
|
||||||
StartupCache* sc = StartupCache::GetSingleton();
|
// multiply-referenced non-singleton objects
|
||||||
NS_ENSURE_TRUE(sc, NS_ERROR_UNEXPECTED);
|
StartupCache* sc = StartupCache::GetSingleton();
|
||||||
nsCOMPtr<nsIObjectOutputStream> debugStream;
|
NS_ENSURE_TRUE(sc, NS_ERROR_UNEXPECTED);
|
||||||
sc->GetDebugObjectOutputStream(objectOutput, getter_AddRefs(debugStream));
|
nsCOMPtr<nsIObjectOutputStream> debugStream;
|
||||||
debugStream.forget(wrapperStream);
|
sc->GetDebugObjectOutputStream(objectOutput, getter_AddRefs(debugStream));
|
||||||
|
debugStream.forget(wrapperStream);
|
||||||
|
} else {
|
||||||
|
objectOutput.forget(wrapperStream);
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
objectOutput.forget(wrapperStream);
|
objectOutput.forget(wrapperStream);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -50,10 +50,15 @@ NS_NewObjectInputStreamFromBuffer(char* buffer, PRUint32 len,
|
||||||
nsIObjectInputStream** stream);
|
nsIObjectInputStream** stream);
|
||||||
|
|
||||||
// We can't retrieve the wrapped stream from the objectOutputStream later,
|
// We can't retrieve the wrapped stream from the objectOutputStream later,
|
||||||
// so we return it here.
|
// so we return it here. We give callers in debug builds the option
|
||||||
|
// to wrap the outputstream in a debug stream, which will detect if
|
||||||
|
// non-singleton objects are written out multiple times during a serialization.
|
||||||
|
// This could cause them to be deserialized incorrectly (as multiple copies
|
||||||
|
// instead of references).
|
||||||
NS_EXPORT nsresult
|
NS_EXPORT nsresult
|
||||||
NS_NewObjectOutputWrappedStorageStream(nsIObjectOutputStream **wrapperStream,
|
NS_NewObjectOutputWrappedStorageStream(nsIObjectOutputStream **wrapperStream,
|
||||||
nsIStorageStream** stream);
|
nsIStorageStream** stream,
|
||||||
|
PRBool wantDebugStream);
|
||||||
|
|
||||||
NS_EXPORT nsresult
|
NS_EXPORT nsresult
|
||||||
NS_NewBufferFromStorageStream(nsIStorageStream *storageStream,
|
NS_NewBufferFromStorageStream(nsIStorageStream *storageStream,
|
||||||
|
|
|
@ -1,124 +0,0 @@
|
||||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
|
|
||||||
/* ***** BEGIN LICENSE BLOCK *****
|
|
||||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
||||||
*
|
|
||||||
* The contents of this file are subject to the Mozilla Public License Version
|
|
||||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
|
||||||
* the License. You may obtain a copy of the License at
|
|
||||||
* http://www.mozilla.org/MPL/
|
|
||||||
*
|
|
||||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
||||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
||||||
* for the specific language governing rights and limitations under the
|
|
||||||
* License.
|
|
||||||
*
|
|
||||||
* The Original Code is Startup Cache.
|
|
||||||
*
|
|
||||||
* The Initial Developer of the Original Code is
|
|
||||||
* The Mozilla Foundation <http://www.mozilla.org/>.
|
|
||||||
* Portions created by the Initial Developer are Copyright (C) 2009
|
|
||||||
* the Initial Developer. All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Contributor(s):
|
|
||||||
* Benedict Hsieh <bhsieh@mozilla.com>
|
|
||||||
*
|
|
||||||
* Alternatively, the contents of this file may be used under the terms of
|
|
||||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
|
||||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
||||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
|
||||||
* of those above. If you wish to allow use of your version of this file only
|
|
||||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
|
||||||
* use your version of this file under the terms of the MPL, indicate your
|
|
||||||
* decision by deleting the provisions above and replace them with the notice
|
|
||||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
||||||
* the provisions above, a recipient may use your version of this file under
|
|
||||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
|
||||||
*
|
|
||||||
* ***** END LICENSE BLOCK ***** */
|
|
||||||
|
|
||||||
#include "nsStartupCacheUtils.h"
|
|
||||||
|
|
||||||
#include "nsCOMPtr.h"
|
|
||||||
#include "nsComponentManagerUtils.h"
|
|
||||||
#include "nsIInputStream.h"
|
|
||||||
#include "nsIStorageStream.h"
|
|
||||||
#include "nsIStringStream.h"
|
|
||||||
#include "nsIObjectInputStream.h"
|
|
||||||
#include "nsIObjectOutputStream.h"
|
|
||||||
|
|
||||||
nsresult
|
|
||||||
NS_NewObjectInputStreamFromBuffer(char* buffer, int len,
|
|
||||||
nsIObjectInputStream** stream)
|
|
||||||
{
|
|
||||||
nsCOMPtr<nsIStringInputStream> stringStream
|
|
||||||
= do_CreateInstance("@mozilla.org/io/string-input-stream;1");
|
|
||||||
if (!stringStream)
|
|
||||||
return NS_ERROR_OUT_OF_MEMORY;
|
|
||||||
nsCOMPtr<nsIObjectInputStream> objectInput
|
|
||||||
= do_CreateInstance("@mozilla.org/binaryinputstream;1");
|
|
||||||
if (!objectInput)
|
|
||||||
return NS_ERROR_OUT_OF_MEMORY;
|
|
||||||
|
|
||||||
stringStream->AdoptData(buffer, len);
|
|
||||||
objectInput->SetInputStream(stringStream);
|
|
||||||
|
|
||||||
NS_ADDREF(*stream = objectInput);
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is questionable API name and design, but we can't
|
|
||||||
// retrieve the wrapped stream from the objectOutputStream later...
|
|
||||||
nsresult
|
|
||||||
NS_NewObjectOutputWrappedStorageStream(nsIObjectOutputStream **wrapperStream,
|
|
||||||
nsIStorageStream** stream)
|
|
||||||
{
|
|
||||||
nsCOMPtr<nsIStorageStream> storageStream;
|
|
||||||
nsresult rv = NS_NewStorageStream(256, (PRUint32)-1,
|
|
||||||
getter_AddRefs(storageStream));
|
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
|
||||||
|
|
||||||
nsCOMPtr<nsIObjectOutputStream> objectOutput
|
|
||||||
= do_CreateInstance("@mozilla.org/binaryoutputstream;1");
|
|
||||||
if (!objectOutput)
|
|
||||||
return NS_ERROR_OUT_OF_MEMORY;
|
|
||||||
|
|
||||||
nsCOMPtr<nsIOutputStream> outputStream
|
|
||||||
= do_QueryInterface(storageStream);
|
|
||||||
|
|
||||||
objectOutput->SetOutputStream(outputStream);
|
|
||||||
NS_ADDREF(*wrapperStream = objectOutput);
|
|
||||||
NS_ADDREF(*stream = storageStream);
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
nsresult
|
|
||||||
NS_NewBufferFromStorageStream(nsIStorageStream *storageStream,
|
|
||||||
char** buffer, int* len)
|
|
||||||
{
|
|
||||||
nsresult rv;
|
|
||||||
nsCOMPtr<nsIInputStream> inputStream;
|
|
||||||
rv = storageStream->NewInputStream(0, getter_AddRefs(inputStream));
|
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
|
||||||
|
|
||||||
PRUint32 avail, read;
|
|
||||||
rv = inputStream->Available(&avail);
|
|
||||||
NS_ENSURE_SUCCESS(rv, rv);
|
|
||||||
|
|
||||||
char* temp = new char[avail];
|
|
||||||
if (!temp)
|
|
||||||
return NS_ERROR_OUT_OF_MEMORY;
|
|
||||||
|
|
||||||
rv = inputStream->Read(temp, avail, &read);
|
|
||||||
if (NS_SUCCEEDED(rv) && avail != read)
|
|
||||||
rv = NS_ERROR_UNEXPECTED;
|
|
||||||
|
|
||||||
if (NS_FAILED(rv)) {
|
|
||||||
delete temp;
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
*len = avail;
|
|
||||||
*buffer = temp;
|
|
||||||
return NS_OK;
|
|
||||||
}
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче