diff --git a/mozilla/xpcom/io/nsFastLoadFile.cpp b/mozilla/xpcom/io/nsFastLoadFile.cpp index eda33380375..cdc616070da 100644 --- a/mozilla/xpcom/io/nsFastLoadFile.cpp +++ b/mozilla/xpcom/io/nsFastLoadFile.cpp @@ -307,7 +307,8 @@ nsFastLoadFileReader::SetChecksum(PRUint32 aChecksum) } struct nsStringMapEntry : public PLDHashEntryHdr { - const char* mString; // key, must come first + const char* mString; // key, must come first + nsISupports* mURI; // for SelectMuxedDocument return value }; struct nsDocumentMapEntry : public nsStringMapEntry { @@ -340,6 +341,7 @@ strmap_ClearEntry(PLDHashTable *aTable, PLDHashEntryHdr *aHdr) if (entry->mString) nsMemory::Free((void*) entry->mString); + NS_IF_RELEASE(entry->mURI); PL_DHashClearEntryStub(aTable, aHdr); } @@ -417,6 +419,8 @@ nsFastLoadFileReader::StartMuxedDocument(nsISupports* aURI, const char* aURISpec if (uriMapEntry->mDocMapEntry) return NS_ERROR_UNEXPECTED; + docMapEntry->mURI = aURI; + NS_ADDREF(docMapEntry->mURI); uriMapEntry->mObject = key; NS_ADDREF(uriMapEntry->mObject); uriMapEntry->mDocMapEntry = docMapEntry; @@ -425,7 +429,8 @@ nsFastLoadFileReader::StartMuxedDocument(nsISupports* aURI, const char* aURISpec } NS_IMETHODIMP -nsFastLoadFileReader::SelectMuxedDocument(nsISupports* aURI) +nsFastLoadFileReader::SelectMuxedDocument(nsISupports* aURI, + nsISupports** aResult) { nsresult rv; @@ -443,9 +448,9 @@ nsFastLoadFileReader::SelectMuxedDocument(nsISupports* aURI) // If we're interrupting another document's segment, save its offset so // we can seek back when it's reselected. - nsDocumentMapReadEntry* docMapEntry = mCurrentDocumentMapEntry; - if (docMapEntry && docMapEntry->mBytesLeft) { - rv = Tell(&docMapEntry->mSaveOffset); + nsDocumentMapReadEntry* prevDocMapEntry = mCurrentDocumentMapEntry; + if (prevDocMapEntry && prevDocMapEntry->mBytesLeft) { + rv = Tell(&prevDocMapEntry->mSaveOffset); if (NS_FAILED(rv)) return rv; } @@ -454,7 +459,7 @@ nsFastLoadFileReader::SelectMuxedDocument(nsISupports* aURI) // non-blocking hunks of data from the parser that are devoid of scripts. // As more data gets FastLoaded, the number of these useless selects will // decline. - docMapEntry = uriMapEntry->mDocMapEntry; + nsDocumentMapReadEntry* docMapEntry = uriMapEntry->mDocMapEntry; if (docMapEntry == mCurrentDocumentMapEntry) { TRACE_MUX(('r', "select prev %s same as current!\n", docMapEntry->mString)); @@ -474,6 +479,9 @@ nsFastLoadFileReader::SelectMuxedDocument(nsISupports* aURI) return rv; } + *aResult = prevDocMapEntry ? prevDocMapEntry->mURI : nsnull; + NS_IF_ADDREF(*aResult); + mCurrentDocumentMapEntry = docMapEntry; #ifdef DEBUG_MUX PRUint32 currentSegmentOffset; @@ -498,6 +506,11 @@ nsFastLoadFileReader::EndMuxedDocument(nsISupports* aURI) if (PL_DHASH_ENTRY_IS_FREE(uriMapEntry)) return NS_ERROR_NOT_AVAILABLE; + // Drop our ref to the URI object that was passed to StartMuxedDocument, + // we no longer need it, and we do not want to extend its lifetime. + if (uriMapEntry->mDocMapEntry) + NS_RELEASE(uriMapEntry->mDocMapEntry->mURI); + // Shrink the table if half the entries are removed sentinels. PRUint32 size = PL_DHASH_TABLE_SIZE(&mFooter.mURIMap); if (mFooter.mURIMap.removedCount >= (size >> 2)) @@ -681,6 +694,8 @@ nsFastLoadFileReader::ReadFooter(nsFastLoadFooter *aFooter) entry->mReadObject = nsnull; entry->mSkipOffset = 0; + entry->mSaveStrongRefCnt = entry->mStrongRefCnt; + entry->mSaveWeakRefCnt = entry->mWeakRefCnt; } if (!PL_DHashTableInit(&aFooter->mDocumentMap, &strmap_DHashTableOps, @@ -716,6 +731,7 @@ nsFastLoadFileReader::ReadFooter(nsFastLoadFooter *aFooter) NS_ASSERTION(!entry->mString, "duplicate URISpec in MuxedDocumentMap"); entry->mString = info.mURISpec; + entry->mURI = nsnull; entry->mInitialSegmentOffset = info.mInitialSegmentOffset; entry->mNextSegmentOffset = info.mInitialSegmentOffset; entry->mBytesLeft = 0; @@ -1327,6 +1343,8 @@ nsFastLoadFileWriter::StartMuxedDocument(nsISupports* aURI, if (!spec) return NS_ERROR_OUT_OF_MEMORY; docMapEntry->mString = NS_REINTERPRET_CAST(const char*, spec); + docMapEntry->mURI = aURI; + NS_ADDREF(docMapEntry->mURI); nsCOMPtr key(do_QueryInterface(aURI)); nsURIMapWriteEntry* uriMapEntry = @@ -1350,7 +1368,8 @@ nsFastLoadFileWriter::StartMuxedDocument(nsISupports* aURI, } NS_IMETHODIMP -nsFastLoadFileWriter::SelectMuxedDocument(nsISupports* aURI) +nsFastLoadFileWriter::SelectMuxedDocument(nsISupports* aURI, + nsISupports** aResult) { // Avoid repeatedly QI'ing to nsISeekableStream as we tell and seek. nsCOMPtr seekable(do_QueryInterface(mOutputStream)); @@ -1397,6 +1416,8 @@ nsFastLoadFileWriter::SelectMuxedDocument(nsISupports* aURI) if (prevDocMapEntry == docMapEntry) { TRACE_MUX(('w', "select prev %s same as current!\n", prevDocMapEntry->mString)); + *aResult = docMapEntry->mURI; + NS_ADDREF(*aResult); return NS_OK; } @@ -1460,6 +1481,9 @@ nsFastLoadFileWriter::SelectMuxedDocument(nsISupports* aURI) if (NS_FAILED(rv)) return rv; + *aResult = prevDocMapEntry ? prevDocMapEntry->mURI : nsnull; + NS_IF_ADDREF(*aResult); + mCurrentDocumentMapEntry = docMapEntry; TRACE_MUX(('w', "select %p (%p) offset %lu\n", aURI, key.get(), currentSegmentOffset)); @@ -1470,15 +1494,24 @@ NS_IMETHODIMP nsFastLoadFileWriter::EndMuxedDocument(nsISupports* aURI) { nsCOMPtr key(do_QueryInterface(aURI)); -#ifdef NS_DEBUG nsURIMapWriteEntry* uriMapEntry = NS_STATIC_CAST(nsURIMapWriteEntry*, PL_DHashTableOperate(&mURIMap, key, PL_DHASH_LOOKUP)); - NS_ASSERTION(uriMapEntry && uriMapEntry->mDocMapEntry, + NS_ASSERTION(uriMapEntry->mDocMapEntry, "unknown aURI passed to EndMuxedDocument!"); -#endif - PL_DHashTableOperate(&mURIMap, key, PL_DHASH_REMOVE); + // Drop our ref to the URI object that was passed to StartMuxedDocument, + // we no longer need it, and we do not want to extend its lifetime. + if (uriMapEntry->mDocMapEntry) + NS_RELEASE(uriMapEntry->mDocMapEntry->mURI); + + // Shrink the table if half the entries are removed sentinels. + PRUint32 size = PL_DHASH_TABLE_SIZE(&mURIMap); + if (mURIMap.removedCount >= (size >> 2)) + PL_DHashTableOperate(&mURIMap, key, PL_DHASH_REMOVE); + else + PL_DHashTableRawRemove(&mURIMap, uriMapEntry); + TRACE_MUX(('w', "end %p (%p)\n", aURI, key.get())); return NS_OK; } @@ -1507,7 +1540,19 @@ nsFastLoadFileWriter::AddDependency(nsIFile* aFile) if (!tmp) return NS_ERROR_OUT_OF_MEMORY; entry->mString = tmp; + + // If we can't get the last modified time from aFile, assume it does + // not exist, or is otherwise inaccessible to us (due to permissions), + // remove the dependency, and suppress the failure. + // + // Otherwise, we would end up aborting the fastload process due to a + // missing .js or .xul or other file on every startup. + rv = aFile->GetLastModifiedTime(&entry->mLastModified); + if (NS_FAILED(rv)) { + PL_DHashTableOperate(&mDependencyMap, path.get(), PL_DHASH_REMOVE); + rv = NS_OK; + } } return rv; } @@ -2229,6 +2274,7 @@ nsFastLoadFileUpdater::CopyReadDocumentMapEntryToUpdater(PLDHashTable *aTable, } writeEntry->mString = NS_REINTERPRET_CAST(const char*, spec); + writeEntry->mURI = nsnull; writeEntry->mInitialSegmentOffset = readEntry->mInitialSegmentOffset; writeEntry->mCurrentSegmentOffset = 0; return PL_DHASH_NEXT; @@ -2284,12 +2330,13 @@ nsFastLoadFileUpdater::Open(nsFastLoadFileReader* aReader) NS_IF_ADDREF(obj); writeEntry->mObject = NS_REINTERPRET_CAST(nsISupports*, key); writeEntry->mOID = oid; - writeEntry->mInfo = *NS_STATIC_CAST(nsFastLoadSharpObjectInfo*, - readEntry); + writeEntry->mInfo.mCIDOffset = readEntry->mCIDOffset; + writeEntry->mInfo.mStrongRefCnt = readEntry->mSaveStrongRefCnt; + writeEntry->mInfo.mWeakRefCnt = readEntry->mSaveWeakRefCnt; } // Copy URI spec string and initial segment offset in FastLoad file from - // nsDocumentMapReadEntry in reader to mDocumentMapWriteEntry in updater. + // nsDocumentMapReadEntry in reader to nsDocumentMapWriteEntry in updater. // If we didn't enumerate all entries, we ran out of memory. n = PL_DHashTableEnumerate(&aReader->mFooter.mDocumentMap, CopyReadDocumentMapEntryToUpdater, diff --git a/mozilla/xpcom/io/nsFastLoadFile.h b/mozilla/xpcom/io/nsFastLoadFile.h index 2cff50ed2bb..8d610f95cae 100644 --- a/mozilla/xpcom/io/nsFastLoadFile.h +++ b/mozilla/xpcom/io/nsFastLoadFile.h @@ -284,6 +284,8 @@ class nsFastLoadFileReader struct nsObjectMapEntry : public nsFastLoadSharpObjectInfo { nsCOMPtr mReadObject; PRUint32 mSkipOffset; + PRUint16 mSaveStrongRefCnt; // saved for an Update + PRUint16 mSaveWeakRefCnt; // after a Read }; /** diff --git a/mozilla/xpcom/io/nsIFastLoadFileControl.idl b/mozilla/xpcom/io/nsIFastLoadFileControl.idl index 787e5f903ec..81e63e38865 100644 --- a/mozilla/xpcom/io/nsIFastLoadFileControl.idl +++ b/mozilla/xpcom/io/nsIFastLoadFileControl.idl @@ -75,10 +75,16 @@ interface nsIFastLoadFileControl : nsISupports * some (but not all, at first, or for a while during development) of the * results of parsing and compiling various inputs can be multiplexed to * or from a FastLoad file. + * + * Note: Select returns the previously selected URI object in case the + * caller is synchronously selecting and writing data to the FastLoad + * file, so the caller can reselect the previous URI and return to code + * the continues to write FastLoad data for the previous URI, unaware of + * the nested select/write/reselect. */ - void startMuxedDocument(in nsISupports aURI, in string aURISpec); - void selectMuxedDocument(in nsISupports aURI); - void endMuxedDocument(in nsISupports aURI); + void startMuxedDocument(in nsISupports aURI, in string aURISpec); + nsISupports selectMuxedDocument(in nsISupports aURI); + void endMuxedDocument(in nsISupports aURI); }; [scriptable, uuid(652ecec6-d40b-45b6-afef-641d6c63a35b)] diff --git a/mozilla/xpcom/io/nsIFastLoadService.idl b/mozilla/xpcom/io/nsIFastLoadService.idl index af91d1f7607..57590350d64 100644 --- a/mozilla/xpcom/io/nsIFastLoadService.idl +++ b/mozilla/xpcom/io/nsIFastLoadService.idl @@ -72,24 +72,32 @@ interface nsIFastLoadService : nsISupports readonly attribute PRInt32 direction; /** + * These methods associate a URI object with its spec, for faster select + * using the object pointer as a key, rather than the spec string. The + * selectMuxedDocument method returns the previously selected URI object, + * in case a caller needs to reselect the previous after muxing data for + * a given URI synchronously. For the non-blocking or "asynchronous" i/o + * case, the caller must select the source URI from the FastLoad multiplex + * before writing a new burst of data parsed from the slow-loaded source. + * * Clients of inputStream and outputStream should try to demultiplex data * from the input stream only if fastLoadService->StartMuxedDocument(uri, * urispec, NS_FASTLOAD_READ) succeeds. If StartMuxedDocument fails with * NS_ERROR_NOT_AVAILABLE, callers should slow-load the documents, muxing * their data to the current output stream. */ - void startMuxedDocument(in nsISupports aURI, - in string aURISpec, - in PRInt32 aDirectionFlags); - void selectMuxedDocument(in nsISupports aURI); - void endMuxedDocument(in nsISupports aURI); + void startMuxedDocument(in nsISupports aURI, + in string aURISpec, + in PRInt32 aDirectionFlags); + nsISupports selectMuxedDocument(in nsISupports aURI); + void endMuxedDocument(in nsISupports aURI); - void addDependency(in nsIFile aFile); + void addDependency(in nsIFile aFile); - PRUint32 computeChecksum(in nsIFile aFile, - in nsIFastLoadReadControl aControl); - void cacheChecksum(in nsIFile aFile, - in nsIObjectOutputStream aStream); + PRUint32 computeChecksum(in nsIFile aFile, + in nsIFastLoadReadControl aControl); + void cacheChecksum(in nsIFile aFile, + in nsIObjectOutputStream aStream); [noscript] void getFastLoadReferent(inout nsISupports aPtr);