зеркало из https://github.com/mozilla/gecko-dev.git
Reduce seeks outside the FastLoad file's underlying stream buffer (195010,
r=ben, sr=bryner). - Pass null scope objects into nsIScriptContext::Compile{EventHandler,Script} when precompiling for brutal sharing. The JS engine does not need a non-null object parameter for static scope. That parameter can be non-null only if it helps the compiler "pre-bind" functions to the same scope object that they'll be parented by when executing, but with brutal sharing, functions are precompiled once and executed against many different scope objects. - A problem in XUL FastLoad was that it would serialize master .xul document out-of-line scripts (those included via script src= from non-overlay, "master" .xul docs) far from the place in the FastLoad file where XUL prototype script info was serialized for the <script src=> tag itself. I fixed that so that, unless the out-of-line script was previously serialized (by a different src= reference from another .xul file), the OOL script data immediately follows the proto-script info in the FastLoad file. This required adding a SerializeOutOfLine method to nsXULPrototypeScript, which restores symmetry by matching the existing DeserializeOutOfLine(Script) (note: I dropped the redundant "Script" from the end of the latter method's name. We need SerializeOutOfLine to handle overlay OOL scripts. They are serialized by nsXULDocument::OnStreamComplete, because that code knows the difference between an overlay and a master doc. This removes all trace of FastLoad writing from nsXULPrototypeScript::Compile -- FastLoad stuff didn't belong there, not only because we now want to write master OOL scripts later, when walking the master XUL prototype doc's element tree, but also for modularity reasons. The caller knows about FastLoad, nsXULPrototypeScript::Compile does just what its name implies. There are 132 seeks with the patch, only 49 of which dump the underlying file stream's buffer, vs. 133 seeks without the patch, 87 of which dump the buffer. - Nit-picked some comments to fit in 80 columns, and made other cosmetic fixes. - Implicated the nsXULDocument::mIsWritingFastLoad flag from the useXULCache "is the XUL cache enabled?" flag, so other places that test mIsWritingFastLoad don't have to query whether the cache is enabled. - Added METERING synchronous meter-dumping to /tmp/bufstats, only ifdef DEBUG_brendan, in netwerk/base/src/nsBufferedStreams.cpp. - Added the deferred seek optimization from the first patch in bug 195010 to nsFastLoadFile.cpp. - Fixed nsFastLoadFileReader so it overrides readSegments as well as read. This catches up with the interface extension made to nsIInputStream to add readSegments. The nsFastLoadFileReader extends nsBinaryInputStream, which is a concrete class, and overrides Read in order to snoop on *all* bytes read. It does this in order to demultiplex documents interleaved when the FastLoad file was written. But since the readSegments move into nsIInputStream.idl, certain primitives in nsBinaryStream.cpp, e.g., nsBinaryInputStream::ReadCString, have used ReadSegments, not Read, to consume parts of the underlying stream (to read the C string's chars, in that example), and the FastLoad file implementation has not accounted for those bytes. - Added a new method to nsIFastLoadFileControl and its impls: hasMuxedDocument. This is needed when serializing master XUL doc OOL scripts, because we must not serialize twice, and any OOL script that other XUL docs can include via script src= could already be in the FastLoad mux. /be
This commit is contained in:
Родитель
b4c1c81ff5
Коммит
e81a02eeb2
|
@ -17,7 +17,7 @@
|
|||
* Copyright (C) 1998 Netscape Communications Corporation. All
|
||||
* Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Contributor(s):
|
||||
* Chris Waterson <waterson@netscape.com>
|
||||
* Pierre Phaneuf <pp@ludusdesign.com>
|
||||
* Peter Annema <disttsc@bart.nl>
|
||||
|
@ -565,7 +565,7 @@ nsXULElement::Create(nsINodeInfo *aNodeInfo, nsIContent** aResult)
|
|||
|
||||
NS_ASSERTION(aNodeInfo, "need nodeinfo for non-proto Create");
|
||||
element->mSlots->mNodeInfo = aNodeInfo;
|
||||
|
||||
|
||||
*aResult = NS_REINTERPRET_CAST(nsIStyledContent*, element);
|
||||
NS_ADDREF(*aResult);
|
||||
|
||||
|
@ -583,7 +583,7 @@ nsXULElement::Create(nsINodeInfo *aNodeInfo, nsIContent** aResult)
|
|||
backtrace_symbols_fd(back, sizeof(back) / sizeof(back[0]), 2);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -1177,11 +1177,11 @@ nsXULElement::CloneNode(PRBool aDeep, nsIDOMNode** aReturn)
|
|||
NS_ASSERTION(attr != nsnull, "null ptr");
|
||||
if (! attr)
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
|
||||
|
||||
nsAutoString value;
|
||||
rv = attr->GetValue(value);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
|
||||
rv = result->SetAttr(attr->GetNodeInfo(), value,
|
||||
PR_FALSE);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
@ -1507,7 +1507,7 @@ nsXULElement::GetElementsByTagNameNS(const nsAString& aNamespaceURI,
|
|||
if (!aNamespaceURI.Equals(NS_LITERAL_STRING("*"))) {
|
||||
nsContentUtils::GetNSManagerWeakRef()->GetNameSpaceID(aNamespaceURI,
|
||||
nameSpaceId);
|
||||
|
||||
|
||||
if (nameSpaceId == kNameSpaceID_Unknown) {
|
||||
// Unknown namespace means no matches, we create an empty list...
|
||||
NS_GetContentList(mDocument, nsnull, kNameSpaceID_None, nsnull,
|
||||
|
@ -1786,63 +1786,28 @@ nsXULElement::CompileEventHandler(nsIScriptContext* aContext,
|
|||
void** aHandler)
|
||||
{
|
||||
nsresult rv;
|
||||
JSObject* scopeObject;
|
||||
|
||||
XUL_PROTOTYPE_ATTRIBUTE_METER(gNumCacheSets);
|
||||
|
||||
nsCOMPtr<nsIScriptContext> context;
|
||||
JSObject* scopeObject;
|
||||
PRBool shared;
|
||||
|
||||
if (mPrototype) {
|
||||
// It'll be shared amonst the instances of the prototype
|
||||
shared = PR_TRUE;
|
||||
|
||||
// Use the prototype document's special context
|
||||
nsCOMPtr<nsIXULDocument> xuldoc = do_QueryInterface(mDocument);
|
||||
NS_ASSERTION(xuldoc != nsnull, "mDocument is not an nsIXULDocument");
|
||||
if (! xuldoc)
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
|
||||
nsCOMPtr<nsIXULPrototypeDocument> protodoc;
|
||||
rv = xuldoc->GetMasterPrototype(getter_AddRefs(protodoc));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
NS_ASSERTION(protodoc != nsnull, "xul document has no prototype");
|
||||
if (! protodoc)
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
|
||||
nsCOMPtr<nsIScriptGlobalObjectOwner> globalOwner = do_QueryInterface(protodoc);
|
||||
nsCOMPtr<nsIScriptGlobalObject> global;
|
||||
globalOwner->GetScriptGlobalObject(getter_AddRefs(global));
|
||||
NS_ASSERTION(global != nsnull, "prototype doc does not have a script global");
|
||||
if (! global)
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
|
||||
rv = global->GetContext(getter_AddRefs(context));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
// Use the prototype script's special scope object
|
||||
|
||||
scopeObject = global->GetGlobalJSObject();
|
||||
if (!scopeObject)
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
// It'll be shared among the instances of the prototype.
|
||||
// Use null for the scope object when precompiling shared
|
||||
// prototype scripts.
|
||||
scopeObject = nsnull;
|
||||
}
|
||||
else {
|
||||
// We don't have a prototype; do a one-off compile.
|
||||
shared = PR_FALSE;
|
||||
context = aContext;
|
||||
NS_ASSERTION(aTarget != nsnull, "no prototype and no target?!");
|
||||
scopeObject = NS_REINTERPRET_CAST(JSObject*, aTarget);
|
||||
}
|
||||
|
||||
NS_ASSERTION(context != nsnull, "no script context");
|
||||
if (! context)
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
|
||||
// Compile the event handler
|
||||
rv = context->CompileEventHandler(scopeObject, aName, aBody, shared, aHandler);
|
||||
rv = aContext->CompileEventHandler(scopeObject, aName, aBody, !scopeObject,
|
||||
aHandler);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
if (shared) {
|
||||
if (! scopeObject) {
|
||||
// If it's a shared handler, we need to bind the shared
|
||||
// function object to the real target.
|
||||
rv = aContext->BindCompiledEventHandler(aTarget, aName, *aHandler);
|
||||
|
@ -1859,7 +1824,7 @@ nsXULElement::CompileEventHandler(nsIScriptContext* aContext,
|
|||
attr->mEventHandler = *aHandler;
|
||||
|
||||
if (attr->mEventHandler) {
|
||||
JSContext *cx = (JSContext*) context->GetNativeContext();
|
||||
JSContext *cx = (JSContext*) aContext->GetNativeContext();
|
||||
if (!cx)
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
|
||||
|
@ -1916,7 +1881,7 @@ nsXULElement::AddListenerFor(nsINodeInfo *aNodeInfo,
|
|||
nsIID iid;
|
||||
PRBool isHandler = PR_FALSE;
|
||||
GetEventHandlerIID(attr, &iid, &isHandler);
|
||||
|
||||
|
||||
if (isHandler) {
|
||||
nsAutoString value;
|
||||
GetAttr(nameSpaceID, attr, value);
|
||||
|
@ -2146,7 +2111,7 @@ nsXULElement::InsertChildAt(nsIContent* aKid, PRInt32 aIndex, PRBool aNotify,
|
|||
if (aNotify && mDocument) {
|
||||
mDocument->ContentInserted(NS_STATIC_CAST(nsIStyledContent*, this), aKid, aIndex);
|
||||
}
|
||||
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -2345,7 +2310,7 @@ nsXULElement::RemoveChildAt(PRInt32 aIndex, PRBool aNotify)
|
|||
controlElement->SetCurrentItem(nsnull);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (fireSelectionHandler) {
|
||||
nsCOMPtr<nsIDOMDocumentEvent> doc(do_QueryInterface(mDocument));
|
||||
nsCOMPtr<nsIDOMEvent> event;
|
||||
|
@ -2426,7 +2391,7 @@ void
|
|||
nsXULElement::UnregisterAccessKey(const nsAString& aOldValue)
|
||||
{
|
||||
// If someone changes the accesskey, unregister the old one
|
||||
//
|
||||
//
|
||||
if (mDocument && !aOldValue.IsEmpty()) {
|
||||
nsCOMPtr<nsIPresShell> shell;
|
||||
mDocument->GetShellAt(0, getter_AddRefs(shell));
|
||||
|
@ -2540,7 +2505,7 @@ nsXULElement::SetAttr(nsINodeInfo* aNodeInfo,
|
|||
} else {
|
||||
modification = PR_FALSE;
|
||||
}
|
||||
|
||||
|
||||
rv = nsXULAttribute::Create(NS_STATIC_CAST(nsIStyledContent*, this),
|
||||
aNodeInfo, aValue, &attr);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
@ -2599,7 +2564,7 @@ nsXULElement::SetAttr(nsINodeInfo* aNodeInfo,
|
|||
? PRInt32(nsIDOMMutationEvent::MODIFICATION)
|
||||
: PRInt32(nsIDOMMutationEvent::ADDITION);
|
||||
|
||||
mDocument->AttributeChanged(this, attrns, attrName, modHint,
|
||||
mDocument->AttributeChanged(this, attrns, attrName, modHint,
|
||||
StyleHintFor(NodeInfo()));
|
||||
|
||||
// XXXwaterson do we need to mDocument->EndUpdate() here?
|
||||
|
@ -2871,7 +2836,7 @@ nsXULElement::UnsetAttr(PRInt32 aNameSpaceID,
|
|||
|
||||
if (aNotify) {
|
||||
mDocument->AttributeChanged(this, aNameSpaceID, aName,
|
||||
nsIDOMMutationEvent::REMOVAL,
|
||||
nsIDOMMutationEvent::REMOVAL,
|
||||
StyleHintFor(NodeInfo()));
|
||||
|
||||
// XXXwaterson do we need to mDocument->EndUpdate() here?
|
||||
|
@ -2917,7 +2882,7 @@ nsXULElement::GetAttrNameAt(PRInt32 aIndex,
|
|||
if (aIndex >= 0 && aIndex < mPrototype->mNumAttributes) {
|
||||
PRBool skip;
|
||||
nsXULPrototypeAttribute* attr;
|
||||
do {
|
||||
do {
|
||||
attr = &(mPrototype->mAttributes[aIndex]);
|
||||
skip = haveLocalAttributes && FindLocalAttribute(attr->mNodeInfo);
|
||||
#ifdef DEBUG_ATTRIBUTE_STATS
|
||||
|
@ -3390,7 +3355,7 @@ nsXULElement::HandleDOMEvent(nsIPresContext* aPresContext,
|
|||
aDOMEvent = nsnull;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -3699,7 +3664,7 @@ nsXULElement::GetMappedAttributeImpact(const nsIAtom* aAttribute, PRInt32 aModTy
|
|||
{
|
||||
aHint = NS_STYLE_HINT_CONTENT; // by default, never map attributes to style
|
||||
|
||||
if (aAttribute == nsXULAtoms::value &&
|
||||
if (aAttribute == nsXULAtoms::value &&
|
||||
(aModType == nsIDOMMutationEvent::REMOVAL || aModType == nsIDOMMutationEvent::ADDITION)) {
|
||||
nsCOMPtr<nsIAtom> tag;
|
||||
GetTag(*getter_AddRefs(tag));
|
||||
|
@ -4269,7 +4234,7 @@ nsXULElement::Focus()
|
|||
|
||||
nsCOMPtr<nsIPresShell> shell;
|
||||
mDocument->GetShellAt(0, getter_AddRefs(shell));
|
||||
|
||||
|
||||
// Retrieve the context
|
||||
nsCOMPtr<nsIPresContext> aPresContext;
|
||||
shell->GetPresContext(getter_AddRefs(aPresContext));
|
||||
|
@ -4292,7 +4257,7 @@ nsXULElement::Blur()
|
|||
|
||||
nsCOMPtr<nsIPresShell> shell;
|
||||
mDocument->GetShellAt(0, getter_AddRefs(shell));
|
||||
|
||||
|
||||
// Retrieve the context
|
||||
nsCOMPtr<nsIPresContext> aPresContext;
|
||||
shell->GetPresContext(getter_AddRefs(aPresContext));
|
||||
|
@ -4348,7 +4313,7 @@ nsXULElement::Click()
|
|||
HandleDOMEvent(context, &eventClick, nsnull, NS_EVENT_FLAG_INIT, &status);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// oncommand is fired when an element is clicked...
|
||||
return DoCommand();
|
||||
}
|
||||
|
@ -4366,7 +4331,7 @@ nsXULElement::DoCommand()
|
|||
for (PRInt32 i=0; i<numShells; i++) {
|
||||
doc->GetShellAt(i, getter_AddRefs(shell));
|
||||
shell->GetPresContext(getter_AddRefs(context));
|
||||
|
||||
|
||||
nsEventStatus status = nsEventStatus_eIgnore;
|
||||
nsMouseEvent event;
|
||||
event.eventStructType = NS_EVENT;
|
||||
|
@ -4648,21 +4613,21 @@ nsXULElement::HideWindowChrome(PRBool aShouldHide)
|
|||
{
|
||||
PRInt32 shellCount = mDocument->GetNumberOfShells();
|
||||
if (shellCount > 0) {
|
||||
nsCOMPtr<nsIPresShell> shell;
|
||||
nsCOMPtr<nsIPresShell> shell;
|
||||
mDocument->GetShellAt(0, getter_AddRefs(shell));
|
||||
|
||||
if (shell) {
|
||||
nsIContent* content = NS_STATIC_CAST(nsIContent*, this);
|
||||
nsIFrame* frame = nsnull;
|
||||
shell->GetPrimaryFrameFor(content, &frame);
|
||||
|
||||
|
||||
nsCOMPtr<nsIPresContext> presContext;
|
||||
shell->GetPresContext(getter_AddRefs(presContext));
|
||||
|
||||
|
||||
if (frame && presContext) {
|
||||
nsIView* view = nsnull;
|
||||
frame->GetView(presContext, &view);
|
||||
|
||||
|
||||
if (!view) {
|
||||
frame->GetParentWithView(presContext, &frame);
|
||||
if (frame)
|
||||
|
@ -4675,7 +4640,7 @@ nsXULElement::HideWindowChrome(PRBool aShouldHide)
|
|||
|
||||
widget->HideWindowChrome(aShouldHide);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4736,7 +4701,7 @@ nsXULPrototypeElement::Serialize(nsIObjectOutputStream* aStream,
|
|||
rv |= aStream->Write32(index);
|
||||
|
||||
// Write Attributes
|
||||
rv |= aStream->Write32(mNumAttributes);
|
||||
rv |= aStream->Write32(mNumAttributes);
|
||||
|
||||
nsAutoString attributeValue;
|
||||
PRInt32 i;
|
||||
|
@ -4762,17 +4727,25 @@ nsXULPrototypeElement::Serialize(nsIObjectOutputStream* aStream,
|
|||
rv |= aStream->Write32(child->mType);
|
||||
nsXULPrototypeScript* script = NS_STATIC_CAST(nsXULPrototypeScript*, child);
|
||||
|
||||
if (script) {
|
||||
rv |= aStream->Write8(script->mOutOfLine);
|
||||
if (! script->mOutOfLine)
|
||||
rv |= script->Serialize(aStream, aContext, aNodeInfos);
|
||||
else
|
||||
rv |= aStream->WriteCompoundObject(script->mSrcURI,
|
||||
NS_GET_IID(nsIURI),
|
||||
PR_TRUE);
|
||||
rv |= aStream->Write8(script->mOutOfLine);
|
||||
if (! script->mOutOfLine) {
|
||||
rv |= script->Serialize(aStream, aContext, aNodeInfos);
|
||||
} else {
|
||||
rv |= aStream->WriteCompoundObject(script->mSrcURI,
|
||||
NS_GET_IID(nsIURI),
|
||||
PR_TRUE);
|
||||
|
||||
if (script->mJSObject) {
|
||||
// This may return NS_OK without muxing script->mSrcURI's
|
||||
// data into the FastLoad file, in the case where that
|
||||
// muxed document is already there (written by a prior
|
||||
// session, or by an earlier FastLoad episode during this
|
||||
// session).
|
||||
rv |= script->SerializeOutOfLine(aStream, aContext);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
|
@ -4780,7 +4753,7 @@ nsXULPrototypeElement::Serialize(nsIObjectOutputStream* aStream,
|
|||
|
||||
nsresult
|
||||
nsXULPrototypeElement::Deserialize(nsIObjectInputStream* aStream,
|
||||
nsIScriptContext* aContext,
|
||||
nsIScriptContext* aContext,
|
||||
nsIURI* aDocumentURI,
|
||||
nsISupportsArray* aNodeInfos)
|
||||
{
|
||||
|
@ -4852,7 +4825,7 @@ nsXULPrototypeElement::Deserialize(nsIObjectInputStream* aStream,
|
|||
switch (childType) {
|
||||
case eType_Element:
|
||||
child = new nsXULPrototypeElement();
|
||||
if (! child)
|
||||
if (! child)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
child->mType = childType;
|
||||
|
||||
|
@ -4864,7 +4837,7 @@ nsXULPrototypeElement::Deserialize(nsIObjectInputStream* aStream,
|
|||
if (! child)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
child->mType = childType;
|
||||
|
||||
|
||||
rv |= child->Deserialize(aStream, aContext, aDocumentURI,
|
||||
aNodeInfos);
|
||||
break;
|
||||
|
@ -4884,7 +4857,7 @@ nsXULPrototypeElement::Deserialize(nsIObjectInputStream* aStream,
|
|||
else {
|
||||
rv |= aStream->ReadObject(PR_TRUE, getter_AddRefs(script->mSrcURI));
|
||||
|
||||
rv |= script->DeserializeOutOfLineScript(aStream, aContext);
|
||||
rv |= script->DeserializeOutOfLine(aStream, aContext);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -4892,13 +4865,14 @@ nsXULPrototypeElement::Deserialize(nsIObjectInputStream* aStream,
|
|||
|
||||
mChildren[i] = child;
|
||||
|
||||
// Oh dear. Something failed during the deserialization. We don't know what.
|
||||
// But likely consequences of failed deserializations included calls to
|
||||
// |AbortFastLoads| which shuts down the FastLoadService and closes our
|
||||
// streams. If that happens, next time through this loop, we die a messy
|
||||
// death. So, let's just fail now, and propagate that failure upward so that
|
||||
// the ChromeProtocolHandler knows it can't use a cached chrome channel for
|
||||
// this.
|
||||
// Oh dear. Something failed during the deserialization.
|
||||
// We don't know what. But likely consequences of failed
|
||||
// deserializations included calls to |AbortFastLoads| which
|
||||
// shuts down the FastLoadService and closes our streams.
|
||||
// If that happens, next time through this loop, we die a messy
|
||||
// death. So, let's just fail now, and propagate that failure
|
||||
// upward so that the ChromeProtocolHandler knows it can't use
|
||||
// a cached chrome channel for this.
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
}
|
||||
|
@ -5011,9 +4985,67 @@ nsXULPrototypeScript::Serialize(nsIObjectOutputStream* aStream,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsXULPrototypeScript::SerializeOutOfLine(nsIObjectOutputStream* aStream,
|
||||
nsIScriptContext* aContext)
|
||||
{
|
||||
nsIXULPrototypeCache* cache = GetXULCache();
|
||||
#ifdef NS_DEBUG
|
||||
PRBool useXULCache = PR_TRUE;
|
||||
cache->GetEnabled(&useXULCache);
|
||||
NS_ASSERTION(useXULCache,
|
||||
"writing to the FastLoad file, but the XUL cache is off?");
|
||||
#endif
|
||||
|
||||
nsCOMPtr<nsIFastLoadService> fastLoadService;
|
||||
cache->GetFastLoadService(getter_AddRefs(fastLoadService));
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
if (!fastLoadService)
|
||||
return rv;
|
||||
|
||||
nsCAutoString urispec;
|
||||
rv = mSrcURI->GetAsciiSpec(urispec);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
PRBool exists = PR_FALSE;
|
||||
fastLoadService->HasMuxedDocument(urispec.get(), &exists);
|
||||
if (exists)
|
||||
return rv;
|
||||
|
||||
// Allow callers to pass null for aStream, meaning
|
||||
// "use the FastLoad service's default output stream."
|
||||
// See nsXULDocument.cpp for one use of this.
|
||||
nsCOMPtr<nsIObjectOutputStream> objectOutput = aStream;
|
||||
if (! objectOutput)
|
||||
fastLoadService->GetOutputStream(getter_AddRefs(objectOutput));
|
||||
|
||||
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, aContext, nsnull);
|
||||
rv |= fastLoadService->EndMuxedDocument(mSrcURI);
|
||||
|
||||
if (oldURI) {
|
||||
nsCOMPtr<nsIURI> tempURI;
|
||||
rv |= fastLoadService->
|
||||
SelectMuxedDocument(oldURI, getter_AddRefs(tempURI));
|
||||
}
|
||||
|
||||
if (NS_FAILED(rv))
|
||||
cache->AbortFastLoads();
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
nsresult
|
||||
nsXULPrototypeScript::Deserialize(nsIObjectInputStream* aStream,
|
||||
nsIScriptContext* aContext,
|
||||
nsIScriptContext* aContext,
|
||||
nsIURI* aDocumentURI,
|
||||
nsISupportsArray* aNodeInfos)
|
||||
{
|
||||
|
@ -5022,10 +5054,10 @@ nsXULPrototypeScript::Deserialize(nsIObjectInputStream* aStream,
|
|||
|
||||
// Read basic prototype data
|
||||
aStream->Read16(&mLineNo);
|
||||
|
||||
|
||||
NS_ASSERTION(!mSrcLoading || mSrcLoadWaiters != nsnull || !mJSObject,
|
||||
"prototype script not well-initialized when deserializing?!");
|
||||
|
||||
|
||||
PRUint32 size;
|
||||
rv = aStream->Read32(&size);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
@ -5098,8 +5130,8 @@ nsXULPrototypeScript::Deserialize(nsIObjectInputStream* aStream,
|
|||
|
||||
|
||||
nsresult
|
||||
nsXULPrototypeScript::DeserializeOutOfLineScript(nsIObjectInputStream* aInput,
|
||||
nsIScriptContext* aContext)
|
||||
nsXULPrototypeScript::DeserializeOutOfLine(nsIObjectInputStream* aInput,
|
||||
nsIScriptContext* aContext)
|
||||
{
|
||||
// Keep track of FastLoad failure via rv, so we can
|
||||
// AbortFastLoads if things look bad.
|
||||
|
@ -5173,7 +5205,7 @@ nsXULPrototypeScript::DeserializeOutOfLineScript(nsIObjectInputStream* aInput,
|
|||
nsCOMPtr<nsIURI> tempURI;
|
||||
rv = fastLoadService->SelectMuxedDocument(oldURI, getter_AddRefs(tempURI));
|
||||
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv) && (!tempURI || tempURI == mSrcURI),
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv) && (!tempURI || tempURI == mSrcURI),
|
||||
"not currently deserializing into the script we thought we were!");
|
||||
}
|
||||
}
|
||||
|
@ -5183,7 +5215,6 @@ nsXULPrototypeScript::DeserializeOutOfLineScript(nsIObjectInputStream* aInput,
|
|||
PRBool isChrome = PR_FALSE;
|
||||
mSrcURI->SchemeIs("chrome", &isChrome);
|
||||
if (isChrome) {
|
||||
nsIXULPrototypeCache* cache = GetXULCache();
|
||||
cache->PutScript(mSrcURI, NS_REINTERPRET_CAST(void*, mJSObject));
|
||||
}
|
||||
}
|
||||
|
@ -5218,16 +5249,12 @@ nsXULPrototypeScript::Compile(const PRUnichar* aText,
|
|||
// __parent__ pointer to the first document's global. If that
|
||||
// happened, our script object would reference the first document,
|
||||
// and the first document would indirectly reference the prototype
|
||||
// document because it keeps the prototype cache
|
||||
// alive. Circularity!
|
||||
// document because it keeps the prototype cache alive. Circularity!
|
||||
nsresult rv;
|
||||
|
||||
// Use the prototype document's special context
|
||||
nsCOMPtr<nsIScriptContext> context;
|
||||
|
||||
// Use the prototype script's special scope object
|
||||
JSObject* scopeObject;
|
||||
|
||||
{
|
||||
nsCOMPtr<nsIScriptGlobalObject> global;
|
||||
nsCOMPtr<nsIScriptGlobalObjectOwner> globalOwner
|
||||
|
@ -5243,10 +5270,6 @@ nsXULPrototypeScript::Compile(const PRUnichar* aText,
|
|||
NS_ASSERTION(context != nsnull, "no context for script global");
|
||||
if (! context)
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
|
||||
scopeObject = global->GetGlobalJSObject();
|
||||
if (!scopeObject)
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
// Use the enclosing document's principal
|
||||
|
@ -5262,43 +5285,14 @@ nsXULPrototypeScript::Compile(const PRUnichar* aText,
|
|||
// Ok, compile it to create a prototype script object!
|
||||
rv = context->CompileScript(aText,
|
||||
aTextLength,
|
||||
scopeObject,
|
||||
nsnull,
|
||||
principal,
|
||||
urlspec.get(),
|
||||
aLineNo,
|
||||
mLangVersion,
|
||||
(void**)&mJSObject);
|
||||
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
if (mJSObject) {
|
||||
// Root the compiled prototype script object.
|
||||
JSContext* cx = NS_REINTERPRET_CAST(JSContext*,
|
||||
context->GetNativeContext());
|
||||
if (!cx)
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
|
||||
|
||||
if (mOutOfLine) {
|
||||
nsCOMPtr<nsIFastLoadService> fastLoadService;
|
||||
|
||||
nsIXULPrototypeCache* cache = GetXULCache();
|
||||
cache->GetFastLoadService(getter_AddRefs(fastLoadService));
|
||||
|
||||
if (fastLoadService) {
|
||||
nsCOMPtr<nsIObjectOutputStream> objectOutput;
|
||||
fastLoadService->GetOutputStream(getter_AddRefs(objectOutput));
|
||||
if (objectOutput) {
|
||||
rv = Serialize(objectOutput, context, nsnull);
|
||||
if (NS_FAILED(rv))
|
||||
cache->AbortFastLoads();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
@ -5323,7 +5317,7 @@ nsXULPrototypeText::Serialize(nsIObjectOutputStream* aStream,
|
|||
|
||||
nsresult
|
||||
nsXULPrototypeText::Deserialize(nsIObjectInputStream* aStream,
|
||||
nsIScriptContext* aContext,
|
||||
nsIScriptContext* aContext,
|
||||
nsIURI* aDocumentURI,
|
||||
nsISupportsArray* aNodeInfos)
|
||||
{
|
||||
|
@ -5331,6 +5325,6 @@ nsXULPrototypeText::Deserialize(nsIObjectInputStream* aStream,
|
|||
|
||||
// Write basic prototype data
|
||||
rv = aStream->ReadString(mValue);
|
||||
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
*
|
||||
* The Original Code is Mozilla Communicator client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1998
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
|
@ -195,7 +195,7 @@ public:
|
|||
Type mType;
|
||||
|
||||
PRInt32 mRefCnt;
|
||||
|
||||
|
||||
virtual ~nsXULPrototypeNode() {}
|
||||
virtual nsresult Serialize(nsIObjectOutputStream* aStream,
|
||||
nsIScriptContext* aContext,
|
||||
|
@ -206,11 +206,11 @@ public:
|
|||
nsISupportsArray* aNodeInfos) = 0;
|
||||
|
||||
void AddRef() { ++mRefCnt; };
|
||||
void Release()
|
||||
{
|
||||
--mRefCnt;
|
||||
if (mRefCnt == 0)
|
||||
delete this;
|
||||
void Release()
|
||||
{
|
||||
--mRefCnt;
|
||||
if (mRefCnt == 0)
|
||||
delete this;
|
||||
};
|
||||
virtual void ReleaseSubtree() { Release(); };
|
||||
|
||||
|
@ -242,7 +242,7 @@ public:
|
|||
delete[] mChildren;
|
||||
}
|
||||
|
||||
virtual void ReleaseSubtree()
|
||||
virtual void ReleaseSubtree()
|
||||
{
|
||||
if (mChildren) {
|
||||
for (PRInt32 i = mNumChildren-1; i >= 0; i--) {
|
||||
|
@ -277,8 +277,8 @@ public:
|
|||
nsresult GetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, nsAString& aValue);
|
||||
|
||||
|
||||
static void ReleaseGlobals()
|
||||
{
|
||||
static void ReleaseGlobals()
|
||||
{
|
||||
NS_IF_RELEASE(sCSSParser);
|
||||
}
|
||||
|
||||
|
@ -305,12 +305,14 @@ public:
|
|||
virtual nsresult Serialize(nsIObjectOutputStream* aStream,
|
||||
nsIScriptContext* aContext,
|
||||
nsISupportsArray* aNodeInfos);
|
||||
nsresult SerializeOutOfLine(nsIObjectOutputStream* aStream,
|
||||
nsIScriptContext* aContext);
|
||||
virtual nsresult Deserialize(nsIObjectInputStream* aStream,
|
||||
nsIScriptContext* aContext,
|
||||
nsIURI* aDocumentURI,
|
||||
nsISupportsArray* aNodeInfos);
|
||||
virtual nsresult DeserializeOutOfLineScript(nsIObjectInputStream* aInput,
|
||||
nsIScriptContext* aContext);
|
||||
nsresult DeserializeOutOfLine(nsIObjectInputStream* aInput,
|
||||
nsIScriptContext* aContext);
|
||||
|
||||
nsresult Compile(const PRUnichar* aText, PRInt32 aTextLength,
|
||||
nsIURI* aURI, PRUint16 aLineNo,
|
||||
|
@ -325,9 +327,9 @@ public:
|
|||
JSObject* mJSObject;
|
||||
const char* mLangVersion;
|
||||
|
||||
static void ReleaseGlobals()
|
||||
{
|
||||
NS_IF_RELEASE(sXULPrototypeCache);
|
||||
static void ReleaseGlobals()
|
||||
{
|
||||
NS_IF_RELEASE(sXULPrototypeCache);
|
||||
}
|
||||
|
||||
protected:
|
||||
|
@ -402,7 +404,7 @@ public:
|
|||
|
||||
// nsISupports
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
|
||||
// nsIContent (from nsIStyledContent)
|
||||
NS_IMETHOD GetDocument(nsIDocument*& aResult) const;
|
||||
NS_IMETHOD SetDocument(nsIDocument* aDocument, PRBool aDeep, PRBool aCompileEventHandlers);
|
||||
|
@ -431,7 +433,7 @@ public:
|
|||
NS_IMETHOD GetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, nsIAtom*& aPrefix, nsAString& aResult) const;
|
||||
NS_IMETHOD_(PRBool) HasAttr(PRInt32 aNameSpaceID, nsIAtom* aName) const;
|
||||
NS_IMETHOD UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, PRBool aNotify);
|
||||
NS_IMETHOD GetAttrNameAt(PRInt32 aIndex, PRInt32& aNameSpaceID,
|
||||
NS_IMETHOD GetAttrNameAt(PRInt32 aIndex, PRInt32& aNameSpaceID,
|
||||
nsIAtom*& aName, nsIAtom*& aPrefix) const;
|
||||
NS_IMETHOD GetAttrCount(PRInt32& aResult) const;
|
||||
#ifdef DEBUG
|
||||
|
@ -449,7 +451,7 @@ public:
|
|||
NS_IMETHOD SetContentID(PRUint32 aID);
|
||||
|
||||
NS_IMETHOD RangeAdd(nsIDOMRange* aRange);
|
||||
NS_IMETHOD RangeRemove(nsIDOMRange* aRange);
|
||||
NS_IMETHOD RangeRemove(nsIDOMRange* aRange);
|
||||
NS_IMETHOD GetRangeList(nsVoidArray*& aResult) const;
|
||||
NS_IMETHOD SetFocus(nsIPresContext* aPresContext);
|
||||
NS_IMETHOD RemoveFocus(nsIPresContext* aPresContext);
|
||||
|
@ -480,10 +482,10 @@ public:
|
|||
NS_IMETHOD ClearLazyState(LazyState aFlags);
|
||||
NS_IMETHOD GetLazyState(LazyState aFlag, PRBool& aValue);
|
||||
NS_IMETHOD AddScriptEventListener(nsIAtom* aName, const nsAString& aValue);
|
||||
|
||||
|
||||
// nsIDOMNode (from nsIDOMElement)
|
||||
NS_DECL_NSIDOMNODE
|
||||
|
||||
|
||||
// nsIDOMElement
|
||||
NS_DECL_NSIDOMELEMENT
|
||||
|
||||
|
@ -641,7 +643,7 @@ protected:
|
|||
nsresult AddListenerFor(nsINodeInfo *aNodeInfo,
|
||||
PRBool aCompileEventHandlers);
|
||||
|
||||
|
||||
|
||||
nsresult HideWindowChrome(PRBool aShouldHide);
|
||||
|
||||
protected:
|
||||
|
|
|
@ -1443,7 +1443,7 @@ XULContentSinkImpl::OpenScript(const PRUnichar** aAttributes,
|
|||
nsCOMPtr<nsIScriptContext> scriptContext;
|
||||
globalObject->GetContext(getter_AddRefs(scriptContext));
|
||||
if (scriptContext)
|
||||
script->DeserializeOutOfLineScript(nsnull, scriptContext);
|
||||
script->DeserializeOutOfLine(nsnull, scriptContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
*
|
||||
* The Original Code is Mozilla Communicator client code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 1998
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
|
@ -642,7 +642,10 @@ nsXULDocument::StartDocumentLoad(const char* aCommand, nsIChannel* aChannel,
|
|||
getter_AddRefs(parser));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
mIsWritingFastLoad = PR_TRUE;
|
||||
// Predicate mIsWritingFastLoad on the XUL cache being enabled,
|
||||
// so we don't have to re-check whether the cache is enabled all
|
||||
// the time.
|
||||
mIsWritingFastLoad = useXULCache;
|
||||
|
||||
nsCOMPtr<nsIStreamListener> listener = do_QueryInterface(parser, &rv);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "parser doesn't support nsIStreamListener");
|
||||
|
@ -740,7 +743,6 @@ nsXULDocument::EndLoad()
|
|||
// its load completion via proto->AwaitLoadDone().
|
||||
rv = mCurrentPrototype->NotifyLoadDone();
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
}
|
||||
|
||||
// Now walk the prototype to build content.
|
||||
|
@ -3081,21 +3083,21 @@ nsXULDocument::ResumeWalk()
|
|||
// - Ben Goodger
|
||||
//
|
||||
// We don't abort on failure here because there are too many valid
|
||||
// cases that can return failure, and the null-ness of |proto| is enough
|
||||
// to trigger the fail-safe parse-from-disk solution. Example failure cases
|
||||
// (for reference) include:
|
||||
// cases that can return failure, and the null-ness of |proto| is
|
||||
// enough to trigger the fail-safe parse-from-disk solution.
|
||||
// Example failure cases (for reference) include:
|
||||
//
|
||||
// NS_ERROR_NOT_AVAILABLE: the URI cannot be found in the FastLoad cache,
|
||||
// NS_ERROR_NOT_AVAILABLE: the URI was not found in the FastLoad file,
|
||||
// parse from disk
|
||||
// other: the FastLoad cache file, XUL.mfl, could not be found, probably
|
||||
// due to being accessed before a profile has been selected (e.g.
|
||||
// loading chrome for the profile manager itself). This must be
|
||||
// parsed from disk.
|
||||
// other: the FastLoad file, XUL.mfl, could not be found, probably
|
||||
// due to being accessed before a profile has been selected
|
||||
// (e.g. loading chrome for the profile manager itself).
|
||||
// The .xul file must be parsed from disk.
|
||||
|
||||
PRBool cache;
|
||||
gXULCache->GetEnabled(&cache);
|
||||
PRBool useXULCache;
|
||||
gXULCache->GetEnabled(&useXULCache);
|
||||
|
||||
if (cache && mCurrentPrototype) {
|
||||
if (useXULCache && mCurrentPrototype) {
|
||||
NS_ASSERTION(IsChromeURI(uri), "XUL cache hit on non-chrome URI?");
|
||||
PRBool loaded;
|
||||
rv = mCurrentPrototype->AwaitLoadDone(this, &loaded);
|
||||
|
@ -3127,7 +3129,10 @@ nsXULDocument::ResumeWalk()
|
|||
rv = PrepareToLoadPrototype(uri, "view", nsnull, getter_AddRefs(parser));
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
|
||||
mIsWritingFastLoad = PR_TRUE;
|
||||
// Predicate mIsWritingFastLoad on the XUL cache being enabled,
|
||||
// so we don't have to re-check whether the cache is enabled all
|
||||
// the time.
|
||||
mIsWritingFastLoad = useXULCache;
|
||||
|
||||
nsCOMPtr<nsIStreamListener> listener = do_QueryInterface(parser);
|
||||
if (! listener)
|
||||
|
@ -3153,7 +3158,7 @@ nsXULDocument::ResumeWalk()
|
|||
// each time. We must do this after NS_OpenURI and AsyncOpen,
|
||||
// or chrome code will wrongly create a cached chrome channel
|
||||
// instead of a real one.
|
||||
if (cache && IsChromeURI(uri)) {
|
||||
if (useXULCache && IsChromeURI(uri)) {
|
||||
rv = gXULCache->PutPrototype(mCurrentPrototype);
|
||||
if (NS_FAILED(rv)) return rv;
|
||||
}
|
||||
|
@ -3179,10 +3184,7 @@ nsXULDocument::ResumeWalk()
|
|||
|
||||
StartLayout();
|
||||
|
||||
PRBool useXULCache;
|
||||
gXULCache->GetEnabled(&useXULCache);
|
||||
|
||||
if (useXULCache && mIsWritingFastLoad && IsChromeURI(mDocumentURL))
|
||||
if (mIsWritingFastLoad && IsChromeURI(mDocumentURL))
|
||||
gXULCache->WritePrototype(mMasterPrototype);
|
||||
|
||||
for (PRInt32 i = mObservers.Count() - 1; i >= 0; --i) {
|
||||
|
@ -3325,43 +3327,12 @@ nsXULDocument::OnStreamComplete(nsIStreamLoader* aLoader,
|
|||
// nsXULContentSink.cpp) would have already deserialized a non-null
|
||||
// script->mJSObject, causing control flow at the top of LoadScript
|
||||
// not to reach here.
|
||||
//
|
||||
// Start and Select the .js document in the FastLoad multiplexor
|
||||
// before serializing script data under scriptProto->Compile, and
|
||||
// End muxing afterward.
|
||||
nsCOMPtr<nsIURI> uri = scriptProto->mSrcURI;
|
||||
|
||||
nsCOMPtr<nsIFastLoadService> fastLoadService;
|
||||
PRBool useXULCache;
|
||||
gXULCache->GetEnabled(&useXULCache);
|
||||
if (useXULCache)
|
||||
gXULCache->GetFastLoadService(getter_AddRefs(fastLoadService));
|
||||
|
||||
nsresult rv2 = NS_OK;
|
||||
if (fastLoadService) {
|
||||
nsCAutoString urispec;
|
||||
uri->GetAsciiSpec(urispec);
|
||||
rv2 = fastLoadService->StartMuxedDocument(uri, urispec.get(),
|
||||
nsIFastLoadService::NS_FASTLOAD_WRITE);
|
||||
NS_ASSERTION(rv2 != NS_ERROR_NOT_AVAILABLE, "reading FastLoad?!");
|
||||
if (NS_SUCCEEDED(rv2)) {
|
||||
nsCOMPtr<nsIURI> oldURI;
|
||||
fastLoadService->SelectMuxedDocument(uri, getter_AddRefs(oldURI));
|
||||
}
|
||||
}
|
||||
|
||||
nsString stringStr; stringStr.AssignWithConversion(string, stringLen);
|
||||
rv = scriptProto->Compile(stringStr.get(), stringLen, uri, 1, this,
|
||||
mCurrentPrototype);
|
||||
|
||||
// End muxing the .js file into the FastLoad file. We don't Abort
|
||||
// the FastLoad process here, when writing, as we do when reading.
|
||||
// XXXbe maybe we should...
|
||||
// NB: we don't need to Select mDocumentURL again, because scripts
|
||||
// load after their including prototype document has fully loaded.
|
||||
if (fastLoadService && NS_SUCCEEDED(rv2))
|
||||
fastLoadService->EndMuxedDocument(uri);
|
||||
|
||||
aStatus = rv;
|
||||
if (NS_SUCCEEDED(rv) && scriptProto->mJSObject) {
|
||||
rv = ExecuteScript(scriptProto->mJSObject);
|
||||
|
@ -3394,6 +3365,24 @@ nsXULDocument::OnStreamComplete(nsIStreamLoader* aLoader,
|
|||
gXULCache->PutScript(scriptProto->mSrcURI,
|
||||
NS_REINTERPRET_CAST(void*, scriptProto->mJSObject));
|
||||
}
|
||||
|
||||
if (mIsWritingFastLoad && mCurrentPrototype != mMasterPrototype) {
|
||||
// If we are loading an overlay script, try to serialize
|
||||
// it to the FastLoad file here. Master scripts will be
|
||||
// serialized when the master prototype document gets
|
||||
// written, at the bottom of ResumeWalk. That way, master
|
||||
// out-of-line scripts are serialized in the same order that
|
||||
// they'll be read, in the FastLoad file, which reduces the
|
||||
// number of seeks that dump the underlying stream's buffer.
|
||||
//
|
||||
// Ignore the return value, as we don't need to propagate
|
||||
// a failure to write to the FastLoad file, because this
|
||||
// method aborts that whole process on error.
|
||||
nsCOMPtr<nsIScriptContext> scriptContext;
|
||||
mScriptGlobalObject->GetContext(getter_AddRefs(scriptContext));
|
||||
if (scriptContext)
|
||||
scriptProto->SerializeOutOfLine(nsnull, scriptContext);
|
||||
}
|
||||
}
|
||||
// ignore any evaluation errors
|
||||
}
|
||||
|
|
|
@ -110,6 +110,34 @@ nsBufferedStream::Close()
|
|||
mBufferStartOffset = 0;
|
||||
mCursor = 0;
|
||||
}
|
||||
#ifdef METERING
|
||||
{
|
||||
static FILE *tfp;
|
||||
if (!tfp) {
|
||||
tfp = fopen("/tmp/bufstats", "w");
|
||||
if (tfp)
|
||||
setvbuf(tfp, NULL, _IOLBF, 0);
|
||||
}
|
||||
if (tfp) {
|
||||
fprintf(tfp, "seeks within buffer: %u\n",
|
||||
bufstats.mSeeksWithinBuffer);
|
||||
fprintf(tfp, "seeks outside buffer: %u\n",
|
||||
bufstats.mSeeksOutsideBuffer);
|
||||
fprintf(tfp, "buffer read on seek: %u\n",
|
||||
bufstats.mBufferReadUponSeek);
|
||||
fprintf(tfp, "buffer unread on seek: %u\n",
|
||||
bufstats.mBufferUnreadUponSeek);
|
||||
fprintf(tfp, "bytes read from buffer: %u\n",
|
||||
bufstats.mBytesReadFromBuffer);
|
||||
for (PRUint32 i = 0; i < bufstats.mBigSeekIndex; i++) {
|
||||
fprintf(tfp, "bigseek[%u] = {old: %u, new: %u}\n",
|
||||
i,
|
||||
bufstats.mBigSeek[i].mOldOffset,
|
||||
bufstats.mBigSeek[i].mNewOffset);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
*
|
||||
* The Original Code is Mozilla FastLoad code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* The Initial Developer of the Original Code is
|
||||
* Netscape Communications Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2001
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
|
@ -23,7 +23,7 @@
|
|||
* Brendan Eich <brendan@mozilla.org> (original author)
|
||||
*
|
||||
* 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
|
||||
* 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
|
||||
|
@ -255,7 +255,7 @@ static const char magic[] = MFL_FILE_MAGIC;
|
|||
|
||||
nsID nsFastLoadFileReader::nsFastLoadFooter::gDummyID;
|
||||
nsFastLoadFileReader::nsObjectMapEntry
|
||||
nsFastLoadFileReader::nsFastLoadFooter::gDummySharpObjectEntry;
|
||||
nsFastLoadFileReader::nsFastLoadFooter::gDummySharpObjectEntry;
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED5(nsFastLoadFileReader,
|
||||
nsBinaryInputStream,
|
||||
|
@ -317,7 +317,11 @@ struct nsDocumentMapEntry : public nsStringMapEntry {
|
|||
|
||||
struct nsDocumentMapReadEntry : public nsDocumentMapEntry {
|
||||
PRUint32 mNextSegmentOffset; // offset of URI's next segment to read
|
||||
PRUint32 mBytesLeft; // bytes remaining in current segment
|
||||
PRUint32 mBytesLeft : 31, // bytes remaining in current segment
|
||||
mNeedToSeek : 1; // flag to defer Seek from Select to
|
||||
// Read, in case there is no Read before
|
||||
// another entry is Selected (to improve
|
||||
// input stream buffer utilization)
|
||||
PRUint32 mSaveOffset; // in case demux schedule differs from
|
||||
// mux schedule
|
||||
};
|
||||
|
@ -393,6 +397,18 @@ static const PLDHashTableOps objmap_DHashTableOps = {
|
|||
NULL
|
||||
};
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFastLoadFileReader::HasMuxedDocument(const char* aURISpec, PRBool *aResult)
|
||||
{
|
||||
nsDocumentMapReadEntry* docMapEntry =
|
||||
NS_STATIC_CAST(nsDocumentMapReadEntry*,
|
||||
PL_DHashTableOperate(&mFooter.mDocumentMap, aURISpec,
|
||||
PL_DHASH_LOOKUP));
|
||||
|
||||
*aResult = PL_DHASH_ENTRY_IS_BUSY(docMapEntry);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFastLoadFileReader::StartMuxedDocument(nsISupports* aURI, const char* aURISpec)
|
||||
{
|
||||
|
@ -447,9 +463,13 @@ nsFastLoadFileReader::SelectMuxedDocument(nsISupports* aURI,
|
|||
return NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
// If we're interrupting another document's segment, save its offset so
|
||||
// we can seek back when it's reselected.
|
||||
// we can seek back when it's reselected. If prevDocMapEntry->mNeedToSeek
|
||||
// is set, that means the stream is not positioned for prevDocMapEntry, to
|
||||
// avoid buffer thrashing. See below in this function for more.
|
||||
nsDocumentMapReadEntry* prevDocMapEntry = mCurrentDocumentMapEntry;
|
||||
if (prevDocMapEntry && prevDocMapEntry->mBytesLeft) {
|
||||
if (prevDocMapEntry &&
|
||||
prevDocMapEntry->mBytesLeft &&
|
||||
!prevDocMapEntry->mNeedToSeek) {
|
||||
rv = Tell(&prevDocMapEntry->mSaveOffset);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
@ -460,23 +480,22 @@ nsFastLoadFileReader::SelectMuxedDocument(nsISupports* aURI,
|
|||
// As more data gets FastLoaded, the number of these useless selects will
|
||||
// decline.
|
||||
nsDocumentMapReadEntry* docMapEntry = uriMapEntry->mDocMapEntry;
|
||||
if (docMapEntry == mCurrentDocumentMapEntry) {
|
||||
if (docMapEntry == prevDocMapEntry) {
|
||||
TRACE_MUX(('r', "select prev %s same as current!\n",
|
||||
docMapEntry->mString));
|
||||
}
|
||||
|
||||
// Invariant: docMapEntry->mBytesLeft implies docMapEntry->mSaveOffset has
|
||||
// been set non-zero by the Tell call above.
|
||||
if (docMapEntry->mBytesLeft) {
|
||||
else if (docMapEntry->mBytesLeft) {
|
||||
NS_ASSERTION(docMapEntry->mSaveOffset != 0,
|
||||
"reselecting from multiplex at unsaved offset?");
|
||||
|
||||
// Don't call our Seek wrapper, as it clears mCurrentDocumentMapEntry.
|
||||
nsCOMPtr<nsISeekableStream> seekable(do_QueryInterface(mInputStream));
|
||||
rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET,
|
||||
docMapEntry->mSaveOffset);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
// Defer Seek till Read, in case of "ping-pong" Selects without any
|
||||
// intervening Reads, to avoid dumping the underlying mInputStream's
|
||||
// input buffer for cases where alternate "pongs" fall in the same
|
||||
// buffer.
|
||||
docMapEntry->mNeedToSeek = PR_TRUE;
|
||||
}
|
||||
|
||||
*aResult = prevDocMapEntry ? prevDocMapEntry->mURI : nsnull;
|
||||
|
@ -528,15 +547,23 @@ nsFastLoadFileReader::Read(char* aBuffer, PRUint32 aCount, PRUint32 *aBytesRead)
|
|||
nsresult rv;
|
||||
|
||||
nsDocumentMapReadEntry* entry = mCurrentDocumentMapEntry;
|
||||
if (entry && entry->mBytesLeft == 0) {
|
||||
if (entry) {
|
||||
// Don't call our Seek wrapper, as it clears mCurrentDocumentMapEntry.
|
||||
nsCOMPtr<nsISeekableStream> seekable(do_QueryInterface(mInputStream));
|
||||
if (entry->mNeedToSeek) {
|
||||
rv = seekable->Seek(nsISeekableStream::NS_SEEK_SET,
|
||||
entry->mSaveOffset);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
entry->mNeedToSeek = PR_FALSE;
|
||||
}
|
||||
|
||||
// Loop to handle empty segments, which may be generated by the
|
||||
// writer, given Start A; Start B; Select A; Select B; write B data;
|
||||
// multiplexing schedules, which do tend to occur given non-blocking
|
||||
// i/o with LIFO scheduling. XXXbe investigate LIFO issues
|
||||
do {
|
||||
while (entry->mBytesLeft == 0) {
|
||||
// Check for unexpected end of multiplexed stream.
|
||||
NS_ASSERTION(entry->mNextSegmentOffset != 0,
|
||||
"document demuxed from FastLoad file more than once?");
|
||||
|
@ -552,8 +579,11 @@ nsFastLoadFileReader::Read(char* aBuffer, PRUint32 aCount, PRUint32 *aBytesRead)
|
|||
mCurrentDocumentMapEntry = nsnull;
|
||||
|
||||
rv = Read32(&entry->mNextSegmentOffset);
|
||||
if (NS_SUCCEEDED(rv))
|
||||
rv = Read32(&entry->mBytesLeft);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
PRUint32 bytesLeft = 0;
|
||||
rv = Read32(&bytesLeft);
|
||||
entry->mBytesLeft = bytesLeft;
|
||||
}
|
||||
|
||||
mCurrentDocumentMapEntry = entry;
|
||||
if (NS_FAILED(rv))
|
||||
|
@ -561,13 +591,13 @@ nsFastLoadFileReader::Read(char* aBuffer, PRUint32 aCount, PRUint32 *aBytesRead)
|
|||
|
||||
NS_ASSERTION(entry->mBytesLeft >= 8, "demux segment length botch!");
|
||||
entry->mBytesLeft -= 8;
|
||||
} while (entry->mBytesLeft == 0);
|
||||
}
|
||||
}
|
||||
|
||||
rv = mInputStream->Read(aBuffer, aCount, aBytesRead);
|
||||
|
||||
if (NS_SUCCEEDED(rv) && entry) {
|
||||
NS_ASSERTION(entry->mBytesLeft >= *aBytesRead, "demux underflow!");
|
||||
NS_ASSERTION(entry->mBytesLeft >= *aBytesRead, "demux Read underflow!");
|
||||
entry->mBytesLeft -= *aBytesRead;
|
||||
|
||||
#ifdef NS_DEBUG
|
||||
|
@ -579,6 +609,31 @@ nsFastLoadFileReader::Read(char* aBuffer, PRUint32 aCount, PRUint32 *aBytesRead)
|
|||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFastLoadFileReader::ReadSegments(nsWriteSegmentFun aWriter, void* aClosure,
|
||||
PRUint32 aCount, PRUint32 *aResult)
|
||||
{
|
||||
nsDocumentMapReadEntry* entry = mCurrentDocumentMapEntry;
|
||||
|
||||
NS_ASSERTION(!entry || (!entry->mNeedToSeek && entry->mBytesLeft != 0),
|
||||
"ReadSegments called from above nsFastLoadFileReader layer?!");
|
||||
|
||||
nsresult rv = nsBinaryInputStream::ReadSegments(aWriter, aClosure, aCount,
|
||||
aResult);
|
||||
if (NS_SUCCEEDED(rv) && entry) {
|
||||
NS_ASSERTION(entry->mBytesLeft >= *aResult,
|
||||
"demux ReadSegments underflow!");
|
||||
entry->mBytesLeft -= *aResult;
|
||||
|
||||
#ifdef NS_DEBUG
|
||||
// Invariant: !entry->mBytesLeft implies entry->mSaveOffset == 0.
|
||||
if (entry->mBytesLeft == 0)
|
||||
entry->mSaveOffset = 0;
|
||||
#endif
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**
|
||||
* XXX tuneme
|
||||
*/
|
||||
|
@ -735,6 +790,7 @@ nsFastLoadFileReader::ReadFooter(nsFastLoadFooter *aFooter)
|
|||
entry->mInitialSegmentOffset = info.mInitialSegmentOffset;
|
||||
entry->mNextSegmentOffset = info.mInitialSegmentOffset;
|
||||
entry->mBytesLeft = 0;
|
||||
entry->mNeedToSeek = PR_FALSE;
|
||||
entry->mSaveOffset = 0;
|
||||
}
|
||||
|
||||
|
@ -852,7 +908,7 @@ nsFastLoadFileReader::ReadSharpObjectInfo(nsFastLoadSharpObjectInfo *aInfo)
|
|||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
NS_ASSERTION(aInfo->mCIDOffset != 0,
|
||||
NS_ASSERTION(aInfo->mCIDOffset != 0,
|
||||
"fastload reader: mCIDOffset cannot be zero!");
|
||||
|
||||
rv = Read16(&aInfo->mStrongRefCnt);
|
||||
|
@ -1027,8 +1083,10 @@ nsFastLoadFileReader::ReadObject(PRBool aIsStrongRef, nsISupports* *aObject)
|
|||
if (entry->mCIDOffset != saveOffset) {
|
||||
// We skipped deserialization of this object from its position
|
||||
// earlier in the input stream, presumably due to the reference
|
||||
// there being an nsFastLoadPtr or some such thing. Seek back
|
||||
// and read it now.
|
||||
// there being an nsFastLoadPtr, or (more likely) because the
|
||||
// object was muxed in another document, and deserialization
|
||||
// order does not match serialization order. So we must seek
|
||||
// back and read it now.
|
||||
NS_ASSERTION(entry->mCIDOffset < saveOffset,
|
||||
"out of order object?!");
|
||||
|
||||
|
@ -1306,6 +1364,18 @@ struct nsURIMapWriteEntry : public nsObjectMapEntry {
|
|||
const char* mURISpec;
|
||||
};
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFastLoadFileWriter::HasMuxedDocument(const char* aURISpec, PRBool *aResult)
|
||||
{
|
||||
nsDocumentMapWriteEntry* docMapEntry =
|
||||
NS_STATIC_CAST(nsDocumentMapWriteEntry*,
|
||||
PL_DHashTableOperate(&mDocumentMap, aURISpec,
|
||||
PL_DHASH_LOOKUP));
|
||||
|
||||
*aResult = PL_DHASH_ENTRY_IS_BUSY(docMapEntry);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFastLoadFileWriter::StartMuxedDocument(nsISupports* aURI,
|
||||
const char* aURISpec)
|
||||
|
@ -1629,7 +1699,7 @@ nsFastLoadFileWriter::WriteSharpObjectInfo(const nsFastLoadSharpObjectInfo& aInf
|
|||
{
|
||||
nsresult rv;
|
||||
|
||||
NS_ASSERTION(aInfo.mCIDOffset != 0,
|
||||
NS_ASSERTION(aInfo.mCIDOffset != 0,
|
||||
"fastload writer: mCIDOffset cannot be zero!");
|
||||
|
||||
rv = Write32(aInfo.mCIDOffset);
|
||||
|
@ -1961,7 +2031,7 @@ nsFastLoadFileWriter::Close()
|
|||
PRUint32 checksum = 0;
|
||||
|
||||
// Ok, we're finally ready to checksum the FastLoad file we just wrote!
|
||||
while (NS_SUCCEEDED(rv =
|
||||
while (NS_SUCCEEDED(rv =
|
||||
input->Read(buf + rem, sizeof buf - rem, &len)) &&
|
||||
len) {
|
||||
len += rem;
|
||||
|
|
|
@ -290,6 +290,14 @@ class nsFastLoadFileReader
|
|||
// Override Read so we can demultiplex a document interleaved with others.
|
||||
NS_IMETHOD Read(char* aBuffer, PRUint32 aCount, PRUint32 *aBytesRead);
|
||||
|
||||
// Override ReadSegments too, as nsBinaryInputStream::ReadSegments does
|
||||
// not call through our overridden Read method -- it calls directly into
|
||||
// the underlying input stream.
|
||||
NS_IMETHODIMP nsFastLoadFileReader::ReadSegments(nsWriteSegmentFun aWriter,
|
||||
void* aClosure,
|
||||
PRUint32 aCount,
|
||||
PRUint32 *aResult);
|
||||
|
||||
nsresult ReadHeader(nsFastLoadHeader *aHeader);
|
||||
|
||||
/**
|
||||
|
|
|
@ -231,6 +231,30 @@ nsFastLoadService::GetDirection(PRInt32 *aResult)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFastLoadService::HasMuxedDocument(const char* aURISpec, PRBool *aResult)
|
||||
{
|
||||
nsresult rv = NS_ERROR_NOT_AVAILABLE;
|
||||
nsCOMPtr<nsIFastLoadFileControl> control;
|
||||
|
||||
*aResult = PR_FALSE;
|
||||
nsAutoLock lock(mLock);
|
||||
|
||||
if (mInputStream) {
|
||||
control = do_QueryInterface(mInputStream);
|
||||
if (control)
|
||||
rv = control->HasMuxedDocument(aURISpec, aResult);
|
||||
}
|
||||
|
||||
if (! *aResult && mOutputStream) {
|
||||
control = do_QueryInterface(mOutputStream);
|
||||
if (control)
|
||||
rv = control->HasMuxedDocument(aURISpec, aResult);
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFastLoadService::StartMuxedDocument(nsISupports* aURI, const char* aURISpec,
|
||||
PRInt32 aDirectionFlags)
|
||||
|
|
|
@ -85,6 +85,12 @@ interface nsIFastLoadFileControl : nsISupports
|
|||
void startMuxedDocument(in nsISupports aURI, in string aURISpec);
|
||||
nsISupports selectMuxedDocument(in nsISupports aURI);
|
||||
void endMuxedDocument(in nsISupports aURI);
|
||||
|
||||
/**
|
||||
* Return true if aURISpec identifies a muxed document in the FastLoad
|
||||
* file, false otherwise.
|
||||
*/
|
||||
boolean hasMuxedDocument(in string aURISpec);
|
||||
};
|
||||
|
||||
[scriptable, uuid(652ecec6-d40b-45b6-afef-641d6c63a35b)]
|
||||
|
|
|
@ -106,6 +106,12 @@ interface nsIFastLoadService : nsISupports
|
|||
|
||||
[noscript] void writeFastLoadPtr(in nsIObjectOutputStream aOutputStream,
|
||||
in nsISupports aPtr);
|
||||
|
||||
/**
|
||||
* Return true if aURISpec identifies a muxed document in the FastLoad
|
||||
* file, false otherwise.
|
||||
*/
|
||||
boolean hasMuxedDocument(in string aURISpec);
|
||||
};
|
||||
|
||||
%{C++
|
||||
|
|
Загрузка…
Ссылка в новой задаче